Merge pull request #205 from ivanlanin/develop

Add DomPDF to composer.json and enable archive image source
This commit is contained in:
Ivan Lanin 2014-04-16 18:15:41 +07:00
commit 898be23a12
20 changed files with 769 additions and 382 deletions

View File

@ -18,8 +18,9 @@ before_script:
## Composer
# - curl -s http://getcomposer.org/installer | php
# - php composer.phar install --prefer-source
- composer self-update
- composer require dompdf/dompdf:0.6.*
- composer install --prefer-source
- composer selfupdate --quiet
## PHP_CodeSniffer
- pyrus install pear/PHP_CodeSniffer
- phpenv rehash

View File

@ -27,13 +27,13 @@ This release marked heavy refactorings on internal code structure with the creat
- Object: Ability to add object in header, footer, textrun, and footnote - @ivanlanin GH-187
- Media: Add `Media::resetElements()` to reset all media data - @juzi GH-19
- General: Add `Style::resetStyles()`, `Footnote::resetElements()`, and `TOC::resetTitles()` - @ivanlanin GH-187
- Reader: Ability to read header, footer, footnotes, link, preservetext, textbreak, pagebreak, table, and list - @ivanlanin
- DOCX Reader: Ability to read header, footer, footnotes, link, preservetext, textbreak, pagebreak, table, list, image - @ivanlanin
- Endnote: Ability to add endnotes - @ivanlanin
- ListItem: Ability to create custom list and reset list number - @ivanlanin GH-10 GH-198
- ODT Writer: Basic table writing support - @ivanlanin
- Image: Keep image aspect ratio if only 1 dimension styled - @japonicus GH-194
- HTML Writer: Basic HTML writer initiated - @ivanlanin GH-203 GH-67 GH-147
- PDF Writer: Basic PDF writer initiated using DomPDF - @ivanlanin GH-68
- HTML Writer: Basic HTML writer: text, textrun, link, title, textbreak, table, image (as Base64), footnote, endnote - @ivanlanin GH-203 GH-67 GH-147
- PDF Writer: Basic PDF writer using DomPDF: All HTML element except image - @ivanlanin GH-68
### Bugfixes

View File

@ -40,9 +40,10 @@
"phpunit/phpunit": "3.7.*"
},
"suggest": {
"ext-gd2": "*",
"ext-xmlwriter": "*",
"ext-xsl": "*"
"ext-gd2": "Required to add images",
"ext-xmlwriter": "Required to write DOCX and ODT",
"ext-xsl": "Required to apply XSL style sheet to template part",
"dompdf/dompdf": "Required to write PDF"
},
"autoload": {
"psr-4": {

View File

@ -62,63 +62,63 @@ Below are the supported features for each file formats.
Writers
~~~~~~~
+-------------------------------------------------+--------+-------+-------+
| Features | DOCX | ODT | RTF |
+=========================+=======================+========+=======+=======+
| **Document Properties** | Standard | | | |
+ +-----------------------+--------+-------+-------+
| | Extended | | | |
+ +-----------------------+--------+-------+-------+
| | UserDefined | | | |
+-------------------------+-----------------------+--------+-------+-------+
| **Element Type** | Text | ✓ | ✓ | ✓ |
+ +-----------------------+--------+-------+-------+
| | Text Run | ✓ | ✓ | ✓ |
+ +-----------------------+--------+-------+-------+
| | Title | ✓ | | |
+ +-----------------------+--------+-------+-------+
| | Link | ✓ | | |
+ +-----------------------+--------+-------+-------+
| | Preserve Text | ✓ | | |
+ +-----------------------+--------+-------+-------+
| | Text Break | ✓ | ✓ | ✓ |
+ +-----------------------+--------+-------+-------+
| | Page Break | ✓ | | |
+ +-----------------------+--------+-------+-------+
| | List | ✓ | | |
+ +-----------------------+--------+-------+-------+
| | Table | ✓ | | |
+ +-----------------------+--------+-------+-------+
| | Image | ✓ | | |
+ +-----------------------+--------+-------+-------+
| | Object | ✓ | | |
+ +-----------------------+--------+-------+-------+
| | Watermark | ✓ | | |
+ +-----------------------+--------+-------+-------+
| | Table of Contents | ✓ | | |
+ +-----------------------+--------+-------+-------+
| | Header | ✓ | | |
+ +-----------------------+--------+-------+-------+
| | Footer | ✓ | | |
+ +-----------------------+--------+-------+-------+
| | Footnote | ✓ | | |
+ +-----------------------+--------+-------+-------+
| | Endnote | ✓ | | |
+-------------------------+-----------------------+--------+-------+-------+
| **Graphs** | 2D basic graphs | | | |
+ +-----------------------+--------+-------+-------+
| | 2D advanced graphs | | | |
+ +-----------------------+--------+-------+-------+
| | 3D graphs | | | |
+-------------------------+-----------------------+--------+-------+-------+
| **Math** | OMML support | | | |
+ +-----------------------+--------+-------+-------+
| | MathML support | | | |
+-------------------------+-----------------------+--------+-------+-------+
| **Bonus** | Encryption | | | |
+ +-----------------------+--------+-------+-------+
| | Protection | | | |
+-------------------------+-----------------------+--------+-------+-------+
+-------------------------------------------------+--------+-------+-------+-------+-------+
| Features | DOCX | ODT | RTF | HTML | PDF |
+=========================+=======================+========+=======+=======+=======+=======+
| **Document Properties** | Standard | ✓ | | | | |
+ +-----------------------+--------+-------+-------+-------+-------+
| | Extended | ✓ | | | | |
+ +-----------------------+--------+-------+-------+-------+-------+
| | UserDefined | ✓ | | | | |
+-------------------------+-----------------------+--------+-------+-------+-------+-------+
| **Element Type** | Text | ✓ | ✓ | ✓ | ✓ | ✓ |
+ +-----------------------+--------+-------+-------+-------+-------+
| | Text Run | ✓ | ✓ | ✓ | ✓ | ✓ |
+ +-----------------------+--------+-------+-------+-------+-------+
| | Title | ✓ | | | ✓ | ✓ |
+ +-----------------------+--------+-------+-------+-------+-------+
| | Link | ✓ | | | ✓ | ✓ |
+ +-----------------------+--------+-------+-------+-------+-------+
| | Preserve Text | ✓ | | | | |
+ +-----------------------+--------+-------+-------+-------+-------+
| | Text Break | ✓ | ✓ | ✓ | ✓ | ✓ |
+ +-----------------------+--------+-------+-------+-------+-------+
| | Page Break | ✓ | | | | |
+ +-----------------------+--------+-------+-------+-------+-------+
| | List | ✓ | | | | |
+ +-----------------------+--------+-------+-------+-------+-------+
| | Table | ✓ | ✓ | | | ✓ |
+ +-----------------------+--------+-------+-------+-------+-------+
| | Image | ✓ | | | ✓ | |
+ +-----------------------+--------+-------+-------+-------+-------+
| | Object | ✓ | | | | |
+ +-----------------------+--------+-------+-------+-------+-------+
| | Watermark | ✓ | | | | |
+ +-----------------------+--------+-------+-------+-------+-------+
| | Table of Contents | ✓ | | | | |
+ +-----------------------+--------+-------+-------+-------+-------+
| | Header | ✓ | | | | |
+ +-----------------------+--------+-------+-------+-------+-------+
| | Footer | ✓ | | | | |
+ +-----------------------+--------+-------+-------+-------+-------+
| | Footnote | ✓ | | | ✓ | |
+ +-----------------------+--------+-------+-------+-------+-------+
| | Endnote | ✓ | | | ✓ | |
+-------------------------+-----------------------+--------+-------+-------+-------+-------+
| **Graphs** | 2D basic graphs | | | | | |
+ +-----------------------+--------+-------+-------+-------+-------+
| | 2D advanced graphs | | | | | |
+ +-----------------------+--------+-------+-------+-------+-------+
| | 3D graphs | | | | | |
+-------------------------+-----------------------+--------+-------+-------+-------+-------+
| **Math** | OMML support | | | | | |
+ +-----------------------+--------+-------+-------+-------+-------+
| | MathML support | | | | | |
+-------------------------+-----------------------+--------+-------+-------+-------+-------+
| **Bonus** | Encryption | | | | | |
+ +-----------------------+--------+-------+-------+-------+-------+
| | Protection | | | | | |
+-------------------------+-----------------------+--------+-------+-------+-------+-------+
Readers

View File

@ -60,4 +60,8 @@ echo date('H:i:s'), " Write to Word2007 format", EOL;
$document->saveAs($name);
rename($name, "results/{$name}");
include_once 'Sample_Footer.php';
$writers = array('Word2007' => 'docx');
echo getEndingNotes($writers);
if (!CLI) {
include_once 'Sample_Footer.php';
}

View File

@ -18,4 +18,8 @@ echo date('H:i:s'), " Write to Word2007 format", EOL;
$document->saveAs($name);
rename($name, "results/{$name}");
include_once 'Sample_Footer.php';
$writers = array('Word2007' => 'docx');
echo getEndingNotes($writers);
if (!CLI) {
include_once 'Sample_Footer.php';
}

View File

@ -46,18 +46,17 @@ if ($handle = opendir('.')) {
}
/**
* Get results
* Write documents
*
* @param \PhpOffice\PhpWord\PhpWord $phpWord
* @param string $filename
* @param array $writers
* @return string
*/
function write($phpWord, $filename, $writers)
{
$result = '';
// Write
// Write documents
foreach ($writers as $writer => $extension) {
$result .= date('H:i:s') . " Write to {$writer} format";
if (!is_null($extension)) {
@ -70,6 +69,20 @@ function write($phpWord, $filename, $writers)
$result .= EOL;
}
$result .= getEndingNotes($writers);
return $result;
}
/**
* Get ending notes
*
* @param array $writers
*/
function getEndingNotes($writers)
{
$result = '';
// Do not show execution time for index
if (!IS_INDEX) {
$result .= date('H:i:s') . " Done writing file(s)" . EOL;
@ -85,9 +98,11 @@ function write($phpWord, $filename, $writers)
$result .= '<p>&nbsp;</p>';
$result .= '<p>Results: ';
foreach ($types as $type) {
$resultFile = 'results/' . SCRIPT_FILENAME . '.' . $type;
if (file_exists($resultFile)) {
$result .= "<a href='{$resultFile}' class='btn btn-primary'>{$type}</a> ";
if (!is_null($type)) {
$resultFile = 'results/' . SCRIPT_FILENAME . '.' . $type;
if (file_exists($resultFile)) {
$result .= "<a href='{$resultFile}' class='btn btn-primary'>{$type}</a> ";
}
}
}
$result .= '</p>';

View File

@ -18,6 +18,13 @@ use PhpOffice\PhpWord\Style\Image as ImageStyle;
*/
class Image extends AbstractElement
{
/**
* Image source type constants
*/
const SOURCE_LOCAL = 'local'; // Local images
const SOURCE_GD = 'gd'; // Generated using GD
const SOURCE_ARCHIVE = 'archive'; // Image in archives zip://$archive#$image
/**
* Image source
*
@ -25,6 +32,13 @@ class Image extends AbstractElement
*/
private $source;
/**
* Source type: local|gd|archive
*
* @var string
*/
private $sourceType;
/**
* Image style
*
@ -85,66 +99,11 @@ class Image extends AbstractElement
*/
public function __construct($source, $style = null, $isWatermark = false)
{
// Detect if it's a memory image, by .php ext or by URL
if (stripos(strrev($source), strrev('.php')) === 0) {
$this->isMemImage = true;
} else {
$this->isMemImage = (filter_var($source, FILTER_VALIDATE_URL) !== false);
}
// Check supported types
if ($this->isMemImage) {
$supportedTypes = array('image/jpeg', 'image/gif', 'image/png');
$imgData = @getimagesize($source);
if (!is_array($imgData)) {
throw new InvalidImageException();
}
$this->imageType = $imgData['mime']; // string
if (!in_array($this->imageType, $supportedTypes)) {
throw new UnsupportedImageTypeException();
}
} else {
$supportedTypes = array(
IMAGETYPE_JPEG, IMAGETYPE_GIF,
IMAGETYPE_PNG, IMAGETYPE_BMP,
IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM
);
if (!file_exists($source)) {
throw new InvalidImageException();
}
$imgData = getimagesize($source);
if (function_exists('exif_imagetype')) {
$this->imageType = exif_imagetype($source);
} else {
// @codeCoverageIgnoreStart
$tmp = getimagesize($source);
$this->imageType = $tmp[2];
// @codeCoverageIgnoreEnd
}
if (!in_array($this->imageType, $supportedTypes)) {
throw new UnsupportedImageTypeException();
}
$this->imageType = image_type_to_mime_type($this->imageType);
}
// Set private properties
$this->source = $source;
$this->isWatermark = $isWatermark;
$this->setIsWatermark($isWatermark);
$this->style = $this->setStyle(new ImageStyle(), $style, true);
$styleWidth = $this->style->getWidth();
$styleHeight = $this->style->getHeight();
list($actualWidth, $actualHeight) = $imgData;
if (!($styleWidth && $styleHeight)) {
if ($styleWidth == null && $styleHeight == null) {
$this->style->setWidth($actualWidth);
$this->style->setHeight($actualHeight);
} elseif ($styleWidth) {
$this->style->setHeight($actualHeight * ($styleWidth / $actualWidth));
} else {
$this->style->setWidth($actualWidth * ($styleHeight / $actualHeight));
}
}
$this->setImageFunctions();
$this->checkImage($source);
}
/**
@ -167,6 +126,16 @@ class Image extends AbstractElement
return $this->source;
}
/**
* Get image source type
*
* @return string
*/
public function getSourceType()
{
return $this->sourceType;
}
/**
* Get image media ID
*
@ -248,9 +217,92 @@ class Image extends AbstractElement
}
/**
* Set image functions
* Check memory image, supported type, image functions, and proportional width/height
*
* @param string $source
*/
private function setImageFunctions()
private function checkImage($source)
{
$this->setSourceType($source);
// Check image data
if ($this->sourceType == self::SOURCE_ARCHIVE) {
$imageData = $this->getArchiveImageSize($source);
} else {
$imageData = @getimagesize($source);
}
if (!is_array($imageData)) {
throw new InvalidImageException();
}
list($actualWidth, $actualHeight, $imageType) = $imageData;
// Check image type support
$supportedTypes = array(IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_PNG);
if ($this->sourceType != self::SOURCE_GD) {
$supportedTypes = array_merge($supportedTypes, array(IMAGETYPE_BMP, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM));
}
if (!in_array($imageType, $supportedTypes)) {
throw new UnsupportedImageTypeException();
}
// Define image functions
$this->imageType = image_type_to_mime_type($imageType);
$this->setFunctions();
$this->setProportionalSize($actualWidth, $actualHeight);
}
/**
* Set source type
*
* @param string $source
*/
private function setSourceType($source)
{
if (stripos(strrev($source), strrev('.php')) === 0) {
$this->isMemImage = true;
$this->sourceType = self::SOURCE_GD;
} elseif (strpos($source, 'zip://') !== false) {
$this->isMemImage = false;
$this->sourceType = self::SOURCE_ARCHIVE;
} else {
$this->isMemImage = (filter_var($source, FILTER_VALIDATE_URL) !== false);
$this->sourceType = $this->isMemImage ? self::SOURCE_GD : self::SOURCE_LOCAL;
}
}
/**
* Get image size from archive
*
* @param string $source
* @return array|null
*/
private function getArchiveImageSize($source)
{
$imageData = null;
$source = substr($source, 6);
list($zipFilename, $imageFilename) = explode('#', $source);
$tempFilename = tempnam(sys_get_temp_dir(), 'PHPWordImage');
$zip = new \ZipArchive();
if ($zip->open($zipFilename) !== false) {
if ($zip->locateName($imageFilename)) {
$imageContent = $zip->getFromName($imageFilename);
if ($imageContent !== false) {
file_put_contents($tempFilename, $imageContent);
$imageData = @getimagesize($tempFilename);
unlink($tempFilename);
}
}
$zip->close();
}
return $imageData;
}
/**
* Set image functions and extensions
*/
private function setFunctions()
{
switch ($this->imageType) {
case 'image/png':
@ -269,8 +321,8 @@ class Image extends AbstractElement
$this->imageFunc = 'imagejpeg';
$this->imageExtension = 'jpg';
break;
case 'image/x-ms-bmp':
case 'image/bmp':
case 'image/x-ms-bmp':
$this->imageType = 'image/bmp';
$this->imageExtension = 'bmp';
break;
@ -279,4 +331,26 @@ class Image extends AbstractElement
break;
}
}
/**
* Set proportional width/height if one dimension not available
*
* @param integer $actualWidth
* @param integer $actualHeight
*/
private function setProportionalSize($actualWidth, $actualHeight)
{
$styleWidth = $this->style->getWidth();
$styleHeight = $this->style->getHeight();
if (!($styleWidth && $styleHeight)) {
if ($styleWidth == null && $styleHeight == null) {
$this->style->setWidth($actualWidth);
$this->style->setHeight($actualHeight);
} elseif ($styleWidth) {
$this->style->setHeight($actualHeight * ($styleWidth / $actualWidth));
} else {
$this->style->setWidth($actualWidth * ($styleHeight / $actualHeight));
}
}
}
}

View File

@ -38,6 +38,13 @@ class Word2007 extends AbstractReader implements ReaderInterface
*/
private $rels = array('main' => array(), 'document' => array());
/**
* Filename
*
* @var string
*/
private $filename;
/**
* Loads PhpWord from file
*
@ -48,17 +55,17 @@ class Word2007 extends AbstractReader implements ReaderInterface
{
$this->phpWord = new PhpWord();
$this->readRelationships($filename);
$this->filename = $filename;
$this->readRelationships();
// Read styles and numbering first
foreach ($this->rels['document'] as $rId => $rel) {
switch ($rel['type']) {
case 'styles':
$this->readStyles($filename, $rel['target']);
$this->readStyles($rel['target']);
break;
case 'numbering':
$this->readNumbering($filename, $rel['target']);
$this->readNumbering($rel['target']);
break;
}
}
@ -68,7 +75,7 @@ class Word2007 extends AbstractReader implements ReaderInterface
switch ($rel['type']) {
case 'officeDocument':
$this->readDocument($filename, $rel['target']);
$this->readDocument($rel['target']);
break;
case 'core-properties':
@ -84,16 +91,16 @@ class Word2007 extends AbstractReader implements ReaderInterface
'dcterms:modified' => 'setModified',
);
$callbacks = array('dcterms:created' => 'strtotime', 'dcterms:modified' => 'strtotime');
$this->readDocProps($filename, $rel['target'], $mapping, $callbacks);
$this->readDocProps($rel['target'], $mapping, $callbacks);
break;
case 'extended-properties':
$mapping = array('Company' => 'setCompany', 'Manager' => 'setManager');
$this->readDocProps($filename, $rel['target'], $mapping);
$this->readDocProps($rel['target'], $mapping);
break;
case 'custom-properties':
$this->readDocPropsCustom($filename, $rel['target']);
$this->readDocPropsCustom($rel['target']);
break;
}
}
@ -103,7 +110,7 @@ class Word2007 extends AbstractReader implements ReaderInterface
switch ($rel['type']) {
case 'footnotes':
case 'endnotes':
$this->readNotes($filename, $rel['target'], $rel['type']);
$this->readNotes($rel['target'], $rel['type']);
break;
}
}
@ -113,24 +120,22 @@ class Word2007 extends AbstractReader implements ReaderInterface
/**
* Read all relationship files
*
* @param string $filename
*/
private function readRelationships($filename)
private function readRelationships()
{
// _rels/.rels
$this->rels['main'] = $this->getRels($filename, '_rels/.rels');
$this->rels['main'] = $this->getRels('_rels/.rels');
// word/_rels/*.xml.rels
$wordRelsPath = 'word/_rels/';
$zipClass = Settings::getZipClass();
$zip = new $zipClass();
if ($zip->open($filename) === true) {
if ($zip->open($this->filename) === true) {
for ($i = 0; $i < $zip->numFiles; $i++) {
$xmlFile = $zip->getNameIndex($i);
if ((substr($xmlFile, 0, strlen($wordRelsPath))) == $wordRelsPath && (substr($xmlFile, -1)) != '/') {
$docPart = str_replace('.xml.rels', '', str_replace($wordRelsPath, '', $xmlFile));
$this->rels[$docPart] = $this->getRels($filename, $xmlFile, 'word/');
$this->rels[$docPart] = $this->getRels($xmlFile, 'word/');
}
}
$zip->close();
@ -140,15 +145,14 @@ class Word2007 extends AbstractReader implements ReaderInterface
/**
* Read core and extended document properties
*
* @param string $filename
* @param string $xmlFile
* @param array $mapping
* @param array $callbacks
*/
private function readDocProps($filename, $xmlFile, $mapping, $callbacks = array())
private function readDocProps($xmlFile, $mapping, $callbacks = array())
{
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($filename, $xmlFile);
$xmlReader->getDomFromZip($this->filename, $xmlFile);
$docProps = $this->phpWord->getDocumentProperties();
$nodes = $xmlReader->getElements('*');
@ -172,13 +176,12 @@ class Word2007 extends AbstractReader implements ReaderInterface
/**
* Read custom document properties
*
* @param string $filename
* @param string $xmlFile
*/
private function readDocPropsCustom($filename, $xmlFile)
private function readDocPropsCustom($xmlFile)
{
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($filename, $xmlFile);
$xmlReader->getDomFromZip($this->filename, $xmlFile);
$docProps = $this->phpWord->getDocumentProperties();
$nodes = $xmlReader->getElements('*');
@ -198,13 +201,12 @@ class Word2007 extends AbstractReader implements ReaderInterface
/**
* Read document.xml
*
* @param string $filename
* @param string $xmlFile
*/
private function readDocument($filename, $xmlFile)
private function readDocument($xmlFile)
{
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($filename, $xmlFile);
$xmlReader->getDomFromZip($this->filename, $xmlFile);
$nodes = $xmlReader->getElements('w:body/*');
if ($nodes->length > 0) {
@ -225,7 +227,7 @@ class Word2007 extends AbstractReader implements ReaderInterface
$settings = $this->readSectionStyle($xmlReader, $settingsNode);
$section->setSettings($settings);
if (!is_null($settings)) {
$this->readHeaderFooter($filename, $settings, $section);
$this->readHeaderFooter($settings, $section);
}
}
$section = $this->phpWord->addSection();
@ -240,7 +242,7 @@ class Word2007 extends AbstractReader implements ReaderInterface
$settings = $this->readSectionStyle($xmlReader, $node);
$section->setSettings($settings);
if (!is_null($settings)) {
$this->readHeaderFooter($filename, $settings, $section);
$this->readHeaderFooter($settings, $section);
}
break;
}
@ -251,13 +253,12 @@ class Word2007 extends AbstractReader implements ReaderInterface
/**
* Read styles.xml
*
* @param string $filename
* @param string $xmlFile
*/
private function readStyles($filename, $xmlFile)
private function readStyles($xmlFile)
{
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($filename, $xmlFile);
$xmlReader->getDomFromZip($this->filename, $xmlFile);
$nodes = $xmlReader->getElements('w:style');
if ($nodes->length > 0) {
@ -303,15 +304,14 @@ class Word2007 extends AbstractReader implements ReaderInterface
/**
* Read numbering.xml
*
* @param string $filename
* @param string $xmlFile
*/
private function readNumbering($filename, $xmlFile)
private function readNumbering($xmlFile)
{
$abstracts = array();
$numberings = array();
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($filename, $xmlFile);
$xmlReader->getDomFromZip($this->filename, $xmlFile);
// Abstract numbering definition
$nodes = $xmlReader->getElements('w:abstractNum');
@ -395,11 +395,10 @@ class Word2007 extends AbstractReader implements ReaderInterface
/**
* Read header footer
*
* @param string $filename
* @param array $settings
* @param Section $section
*/
private function readHeaderFooter($filename, $settings, &$section)
private function readHeaderFooter($settings, &$section)
{
if (is_array($settings) && array_key_exists('hf', $settings)) {
foreach ($settings['hf'] as $rId => $hfSetting) {
@ -410,7 +409,7 @@ class Word2007 extends AbstractReader implements ReaderInterface
// Read header/footer content
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($filename, $xmlFile);
$xmlReader->getDomFromZip($this->filename, $xmlFile);
$nodes = $xmlReader->getElements('*');
if ($nodes->length > 0) {
foreach ($nodes as $node) {
@ -434,18 +433,17 @@ class Word2007 extends AbstractReader implements ReaderInterface
/**
* Read (footnotes|endnotes).xml
*
* @param string $filename
* @param string $xmlFile
* @param string $notesType
*/
private function readNotes($filename, $xmlFile, $notesType = 'footnotes')
private function readNotes($xmlFile, $notesType = 'footnotes')
{
$notesType = ($notesType == 'endnotes') ? 'endnotes' : 'footnotes';
$collectionClass = 'PhpOffice\\PhpWord\\' . ucfirst($notesType);
$collection = $collectionClass::getElements();
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($filename, $xmlFile);
$xmlReader->getDomFromZip($this->filename, $xmlFile);
$nodes = $xmlReader->getElements('*');
if ($nodes->length > 0) {
foreach ($nodes as $node) {
@ -581,8 +579,8 @@ class Word2007 extends AbstractReader implements ReaderInterface
$rId = $xmlReader->getAttribute('r:id', $domNode, 'w:pict/v:shape/v:imagedata');
$target = $this->getMediaTarget($docPart, $rId);
if (!is_null($target)) {
$textContent = "<Image: {$target}>";
$parent->addText($textContent, $fStyle, $pStyle);
$imageSource = "zip://{$this->filename}#{$target}";
$parent->addImage($imageSource);
}
// Object
@ -943,12 +941,11 @@ class Word2007 extends AbstractReader implements ReaderInterface
/**
* Get relationship array
*
* @param string $filename
* @param string $xmlFile
* @param string $targetPrefix
* @return array
*/
private function getRels($filename, $xmlFile, $targetPrefix = '')
private function getRels($xmlFile, $targetPrefix = '')
{
$metaPrefix = 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/';
$officePrefix = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/';
@ -956,7 +953,7 @@ class Word2007 extends AbstractReader implements ReaderInterface
$rels = array();
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($filename, $xmlFile);
$xmlReader->getDomFromZip($this->filename, $xmlFile);
$nodes = $xmlReader->getElements('*');
foreach ($nodes as $node) {
$rId = $xmlReader->getAttribute('Id', $node);

View File

@ -48,6 +48,13 @@ abstract class AbstractWriter implements WriterInterface
*/
private $diskCachingDirectory = './';
/**
* Temporary directory
*
* @var string
*/
private $tempDir = '';
/**
* Original file name
*
@ -81,7 +88,7 @@ abstract class AbstractWriter implements WriterInterface
* Set PhpWord object
*
* @param PhpWord
* @return $this
* @return self
*/
public function setPhpWord(PhpWord $phpWord = null)
{
@ -119,7 +126,7 @@ abstract class AbstractWriter implements WriterInterface
*
* @param boolean $pValue
* @param string $pDirectory
* @return $this
* @return self
*/
public function setUseDiskCaching($pValue = false, $pDirectory = null)
{
@ -146,6 +153,32 @@ abstract class AbstractWriter implements WriterInterface
return $this->diskCachingDirectory;
}
/**
* Get temporary directory
*
* @return string
*/
public function getTempDir()
{
return $this->tempDir;
}
/**
* Set temporary directory
*
* @param string $value
* @return self
*/
public function setTempDir($value)
{
if (!is_dir($value)) {
mkdir($value);
}
$this->tempDir = $value;
return $this;
}
/**
* Get temporary file name
*
@ -156,6 +189,10 @@ abstract class AbstractWriter implements WriterInterface
*/
protected function getTempFile($filename)
{
// Temporary directory
$this->setTempDir(sys_get_temp_dir() . '/PHPWordWriter/');
// Temporary file
$this->originalFilename = $filename;
if (strtolower($filename) == 'php://output' || strtolower($filename) == 'php://stdout') {
$filename = @tempnam(sys_get_temp_dir(), 'phpword_');
@ -170,8 +207,6 @@ abstract class AbstractWriter implements WriterInterface
/**
* Cleanup temporary file
*
* If a temporary file was used, copy it to the correct file stream
*/
protected function cleanupTempFile()
{
@ -181,6 +216,18 @@ abstract class AbstractWriter implements WriterInterface
}
@unlink($this->tempFilename);
}
$this->clearTempDir();
}
/**
* Clear temporary directory
*/
protected function clearTempDir()
{
if (is_dir($this->tempDir)) {
$this->deleteDir($this->tempDir);
}
}
/**
@ -215,4 +262,24 @@ abstract class AbstractWriter implements WriterInterface
return $objZip;
}
/**
* Delete directory
*
* @param string $dir
*/
private function deleteDir($dir)
{
foreach (scandir($dir) as $file) {
if ($file === '.' || $file === '..') {
continue;
} elseif (is_file($dir . "/" . $file)) {
unlink($dir . "/" . $file);
} elseif (is_dir($dir . "/" . $file)) {
$this->deleteDir($dir . "/" . $file);
}
}
rmdir($dir);
}
}

View File

@ -22,12 +22,13 @@ use PhpOffice\PhpWord\Element\Text;
use PhpOffice\PhpWord\Element\TextBreak;
use PhpOffice\PhpWord\Element\TextRun;
use PhpOffice\PhpWord\Element\Title;
use PhpOffice\PhpWord\Endnotes;
use PhpOffice\PhpWord\Exception\Exception;
use PhpOffice\PhpWord\Footnotes;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Style;
use PhpOffice\PhpWord\Style\Font;
use PhpOffice\PhpWord\Style\Paragraph;
use PhpOffice\PhpWord\TOC;
/**
* HTML writer
@ -36,6 +37,20 @@ use PhpOffice\PhpWord\TOC;
*/
class HTML extends AbstractWriter implements WriterInterface
{
/**
* Is the current writer creating PDF?
*
* @var boolean
*/
protected $isPdf = false;
/**
* Footnotes and endnotes collection
*
* @var array
*/
protected $notes = array();
/**
* Create new instance
*/
@ -53,9 +68,11 @@ class HTML extends AbstractWriter implements WriterInterface
public function save($filename = null)
{
if (!is_null($this->getPhpWord())) {
$this->setTempDir(sys_get_temp_dir() . '/PHPWordWriter/');
$hFile = fopen($filename, 'w') or die("can't open file");
fwrite($hFile, $this->writeDocument());
fclose($hFile);
$this->clearTempDir();
} else {
throw new Exception("No PHPWord assigned.");
}
@ -77,6 +94,7 @@ class HTML extends AbstractWriter implements WriterInterface
$html .= '</head>' . PHP_EOL;
$html .= '<body>' . PHP_EOL;
$html .= $this->writeHTMLBody();
$html .= $this->writeNotes();
$html .= '</body>' . PHP_EOL;
$html .= '</html>' . PHP_EOL;
@ -161,10 +179,10 @@ class HTML extends AbstractWriter implements WriterInterface
$html .= $this->writeImage($element);
} elseif ($element instanceof Object) {
$html .= $this->writeObject($element);
} elseif ($element instanceof Footnote) {
$html .= $this->writeFootnote($element);
} elseif ($element instanceof Endnote) {
$html .= $this->writeEndnote($element);
} elseif ($element instanceof Footnote) {
$html .= $this->writeFootnote($element);
}
}
}
@ -173,6 +191,32 @@ class HTML extends AbstractWriter implements WriterInterface
return $html;
}
/**
* Write footnote/endnote contents
*/
private function writeNotes()
{
$footnote = Footnotes::getElements();
$endnote = Endnotes::getElements();
$html = '';
if (count($this->notes) > 0) {
$html .= "<hr />";
foreach ($this->notes as $noteId => $noteMark) {
$noteAnchor = "note-{$noteId}";
list($noteType, $noteTypeId) = explode('-', $noteMark);
$collection = $$noteType;
if (array_key_exists($noteTypeId, $collection)) {
$element = $collection[$noteTypeId];
$content = "<a href=\"#{$noteMark}\" class=\"NoteRef\"><sup>{$noteId}</sup></a>" . $this->writeTextRun($element, true);
$html .= "<p><a name=\"{$noteAnchor}\" />{$content}</p>" . PHP_EOL;
}
}
}
return $html;
}
/**
* Get text
*
@ -218,19 +262,20 @@ class HTML extends AbstractWriter implements WriterInterface
}
/**
* Get text run content
* Write text run content
*
* @param TextRun $textrun
* @param TextRun|Footnote|Endnote $textrun
* @return string
*/
private function writeTextRun($textrun)
private function writeTextRun($textrun, $withoutP = false)
{
$html = '';
$elements = $textrun->getElements();
if (count($elements) > 0) {
$paragraphStyle = $textrun->getParagraphStyle();
$spIsObject = ($paragraphStyle instanceof Paragraph);
$html .= '<p';
$html .= $withoutP ? '<span' : '<p';
if ($paragraphStyle) {
if (!$spIsObject) {
$html .= ' class="' . $paragraphStyle . '"';
@ -248,13 +293,14 @@ class HTML extends AbstractWriter implements WriterInterface
$html .= $this->writeTextBreak($element, true);
} elseif ($element instanceof Image) {
$html .= $this->writeImage($element, true);
} elseif ($element instanceof Footnote) {
$html .= $this->writeFootnote($element);
} elseif ($element instanceof Endnote) {
$html .= $this->writeEndnote($element);
} elseif ($element instanceof Footnote) {
$html .= $this->writeFootnote($element);
}
}
$html .= '</p>' . PHP_EOL;
$html .= $withoutP ? '</span>' : '</p>';
$html .= PHP_EOL;
}
return $html;
@ -271,11 +317,14 @@ class HTML extends AbstractWriter implements WriterInterface
{
$url = $element->getLinkSrc();
$text = $element->getLinkName();
if ($text == '') {
$text = $url;
}
$html = '';
if (!$withoutP) {
$html .= "<p>" . PHP_EOL;
}
$html .= "<a href=\"{$url}'\">{$text}</a>" . PHP_EOL;
$html .= "<a href=\"{$url}\">{$text}</a>" . PHP_EOL;
if (!$withoutP) {
$html .= "</p>" . PHP_EOL;
}
@ -347,7 +396,10 @@ class HTML extends AbstractWriter implements WriterInterface
*/
private function writeListItem($element)
{
return $this->writeUnsupportedElement($element, false);
$text = htmlspecialchars($element->getTextObject()->getText());
$html = '<p>' . $text . '</{$p}>' . PHP_EOL;
return $html;
}
/**
@ -390,10 +442,10 @@ class HTML extends AbstractWriter implements WriterInterface
$html .= $this->writeImage($content);
} elseif ($content instanceof Object) {
$html .= $this->writeObject($content);
} elseif ($element instanceof Footnote) {
$html .= $this->writeFootnote($element);
} elseif ($element instanceof Endnote) {
$html .= $this->writeEndnote($element);
} elseif ($element instanceof Footnote) {
$html .= $this->writeFootnote($element);
}
}
} else {
@ -418,7 +470,22 @@ class HTML extends AbstractWriter implements WriterInterface
*/
private function writeImage($element, $withoutP = false)
{
return $this->writeUnsupportedElement($element, $withoutP);
$html = $this->writeUnsupportedElement($element, $withoutP);
if (!$this->isPdf) {
$imageData = $this->getBase64ImageData($element);
if (!is_null($imageData)) {
$style = $this->assembleCss(array(
'width' => $element->getStyle()->getWidth() . 'px',
'height' => $element->getStyle()->getHeight() . 'px',
));
$html = "<img border=\"0\" style=\"{$style}\" src=\"{$imageData}\"/>";
if (!$withoutP) {
$html = "<p>{$html}</p>" . PHP_EOL;
}
}
}
return $html;
}
/**
@ -441,7 +508,7 @@ class HTML extends AbstractWriter implements WriterInterface
*/
private function writeFootnote($element)
{
return $this->writeUnsupportedElement($element, true);
return $this->writeNote($element);
}
/**
@ -452,7 +519,25 @@ class HTML extends AbstractWriter implements WriterInterface
*/
private function writeEndnote($element)
{
return $this->writeUnsupportedElement($element, true);
return $this->writeNote($element);
}
/**
* Write footnote/endnote marks
*
* @param Footnote|Endnote $element
* @return string
*/
private function writeNote($element)
{
$index = count($this->notes) + 1;
$prefix = ($element instanceof Endnote) ? 'endnote' : 'footnote';
$noteMark = $prefix . '-' . $element->getRelationId();
$noteAnchor = "note-{$index}";
$this->notes[$index] = $noteMark;
$html = "<a name=\"{$noteMark}\"><a href=\"#{$noteAnchor}\" class=\"NoteRef\"><sup>{$index}</sup></a>";
return $html;
}
/**
@ -483,18 +568,33 @@ class HTML extends AbstractWriter implements WriterInterface
*/
private function writeStyles()
{
$bodyCss = array();
$css = '<style>' . PHP_EOL;
// Default styles
$bodyCss['font-family'] = "'" . $this->getPhpWord()->getDefaultFontName() . "'";
$bodyCss['font-size'] = $this->getPhpWord()->getDefaultFontSize() . 'pt';
$css .= '* ' . $this->assembleCss($bodyCss, true) . PHP_EOL;
$defaultStyles = array(
'*' => array(
'font-family' => $this->getPhpWord()->getDefaultFontName(),
'font-size' => $this->getPhpWord()->getDefaultFontSize() . 'pt',
),
'a.NoteRef' => array(
'text-decoration' => 'none',
),
'hr' => array(
'height' => '1px',
'padding' => '0',
'margin' => '1em 0',
'border' => '0',
'border-top' => '1px solid #CCC',
),
);
foreach ($defaultStyles as $selector => $style) {
$css .= $selector . ' ' . $this->assembleCss($style, true) . PHP_EOL;
}
// Custom styles
$styles = Style::getStyles();
if (is_array($styles)) {
foreach ($styles as $name => $style) {
$customStyles = Style::getStyles();
if (is_array($customStyles)) {
foreach ($customStyles as $name => $style) {
if ($style instanceof Font) {
if ($style->getStyleType() == 'title') {
$name = str_replace('Heading_', 'h', $name);
@ -594,4 +694,53 @@ class HTML extends AbstractWriter implements WriterInterface
return $string;
}
/**
* Get Base64 image data
*
* @return string|null
*/
private function getBase64ImageData(Image $element)
{
$imageData = null;
$imageBinary = null;
$source = $element->getSource();
$imageType = $element->getImageType();
// Get actual source from archive image
if ($element->getSourceType() == Image::SOURCE_ARCHIVE) {
$source = substr($source, 6);
list($zipFilename, $imageFilename) = explode('#', $source);
$zip = new \ZipArchive();
if ($zip->open($zipFilename) !== false) {
if ($zip->locateName($imageFilename)) {
$zip->extractTo($this->getTempDir(), $imageFilename);
$actualSource = $this->getTempDir() . DIRECTORY_SEPARATOR . $imageFilename;
}
}
$zip->close();
} else {
$actualSource = $source;
}
// Read image binary data and convert into Base64
if ($element->getSourceType() == Image::SOURCE_GD) {
$imageResource = call_user_func($element->getImageCreateFunction(), $actualSource);
ob_start();
call_user_func($element->getImageFunction(), $imageResource);
$imageBinary = ob_get_contents();
ob_end_clean();
} else {
if ($fp = fopen($actualSource, 'rb', false)) {
$imageBinary = fread($fp, filesize($actualSource));
fclose($fp);
}
}
if (!is_null($imageBinary)) {
$base64 = chunk_split(base64_encode($imageBinary));
$imageData = 'data:' . $imageType . ';base64,' . $base64;
}
return $imageData;
}
}

View File

@ -69,7 +69,6 @@ abstract class AbstractRenderer extends \PhpOffice\PhpWord\Writer\HTML
public function __construct(PhpWord $phpWord)
{
parent::__construct($phpWord);
$this->tempDir = sys_get_temp_dir();
}
/**
@ -141,36 +140,11 @@ abstract class AbstractRenderer extends \PhpOffice\PhpWord\Writer\HTML
return $this;
}
/**
* Get temporary storage directory
*
* @return string
*/
public function getTempDir()
{
return $this->tempDir;
}
/**
* Set temporary storage directory
*
* @param string $pValue Temporary storage directory
* @return self
*/
public function setTempDir($pValue = '')
{
if (is_dir($pValue)) {
$this->tempDir = $pValue;
} else {
throw new Exception("Directory does not exist: $pValue");
}
return $this;
}
/**
* Save PhpWord to PDF file, pre-save
*
* @param string $pFilename Name of the file to save as
* @return resource
*/
protected function prepareForSave($pFilename = null)
{
@ -178,6 +152,8 @@ abstract class AbstractRenderer extends \PhpOffice\PhpWord\Writer\HTML
if ($fileHandle === false) {
throw new Exception("Could not open file $pFilename for writing.");
}
$this->isPdf = true;
return $fileHandle;
}

View File

@ -13,14 +13,6 @@ use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\Exception\Exception;
/** Require DomPDF library */
$pdfRendererClassFile = Settings::getPdfRendererPath() . '/dompdf_config.inc.php';
if (file_exists($pdfRendererClassFile)) {
require_once $pdfRendererClassFile;
} else {
throw new Exception('Unable to load PDF Rendering library');
}
/**
* DomPDF writer
*/
@ -34,6 +26,12 @@ class DomPDF extends AbstractRenderer implements \PhpOffice\PhpWord\Writer\Write
public function __construct(PhpWord $phpWord)
{
parent::__construct($phpWord);
$configFile = Settings::getPdfRendererPath() . '/dompdf_config.inc.php';
if (file_exists($configFile)) {
require_once $configFile;
} else {
throw new Exception('Unable to load PDF Rendering library');
}
}
/**

View File

@ -145,10 +145,11 @@ class Word2007 extends AbstractWriter implements WriterInterface
private function addFilesToPackage($objZip, $elements)
{
foreach ($elements as $element) {
// Do not add link
// Skip link
if ($element['type'] == 'link') {
continue;
}
// Retrieve remote image
if (isset($element['isMemImage']) && $element['isMemImage']) {
$image = call_user_func($element['createFunction'], $element['source']);
@ -159,8 +160,9 @@ class Word2007 extends AbstractWriter implements WriterInterface
$objZip->addFromString('word/' . $element['target'], $imageContents);
imagedestroy($image);
} else {
$objZip->addFile($element['source'], 'word/' . $element['target']);
$this->addFileToPackage($objZip, $element['source'], $element['target']);
}
// Register content types
if ($element['type'] == 'image') {
$imageExtension = $element['imageExtension'];
@ -176,6 +178,40 @@ class Word2007 extends AbstractWriter implements WriterInterface
}
}
/**
* Add file to package
*
* Get the actual source from an archive image
*
* @param mixed $objZip
* @param string $source
* @param string $target
*/
private function addFileToPackage($objZip, $source, $target)
{
$isArchive = strpos($source, 'zip://') !== false;
$actualSource = null;
if ($isArchive) {
$source = substr($source, 6);
list($zipFilename, $imageFilename) = explode('#', $source);
$zip = new \ZipArchive();
if ($zip->open($zipFilename) !== false) {
if ($zip->locateName($imageFilename)) {
$zip->extractTo($this->getTempDir(), $imageFilename);
$actualSource = $this->getTempDir() . DIRECTORY_SEPARATOR . $imageFilename;
}
}
$zip->close();
} else {
$actualSource = $source;
}
if (!is_null($actualSource)) {
$objZip->addFile($actualSource, 'word/' . $target);
}
}
/**
* Add header/footer media files
*

View File

@ -51,34 +51,29 @@ class ImageTest extends \PHPUnit_Framework_TestCase
/**
* Valid image types
*/
public function testValidImageTypes()
public function testImages()
{
new Image(__DIR__ . "/../_files/images/mars_noext_jpg");
new Image(__DIR__ . "/../_files/images/mars.jpg");
new Image(__DIR__ . "/../_files/images/mario.gif");
new Image(__DIR__ . "/../_files/images/firefox.png");
new Image(__DIR__ . "/../_files/images/duke_nukem.bmp");
new Image(__DIR__ . "/../_files/images/angela_merkel.tif");
}
$images = array(
array('mars.jpg', 'image/jpeg', 'jpg', 'imagecreatefromjpeg', 'imagejpeg'),
array('mario.gif', 'image/gif', 'gif', 'imagecreatefromgif', 'imagegif'),
array('firefox.png', 'image/png', 'png', 'imagecreatefrompng', 'imagepng'),
array('duke_nukem.bmp', 'image/bmp', 'bmp', null, null),
array('angela_merkel.tif', 'image/tiff', 'tif', null, null),
);
/**
* Image not found
*
* @expectedException \PhpOffice\PhpWord\Exception\InvalidImageException
*/
public function testImageNotFound()
{
new Image(__DIR__ . "/../_files/images/thisisnotarealimage");
}
/**
* Invalid image types
*
* @expectedException \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException
*/
public function testInvalidImageTypes()
{
new Image(__DIR__ . "/../_files/images/alexz-johnson.pcx");
foreach ($images as $imageData) {
list($source, $type, $extension, $createFunction, $imageFunction) = $imageData;
$source = __DIR__ . "/../_files/images/" . $source;
$image = new Image($source);
$this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $image);
$this->assertEquals($image->getSource(), $source);
$this->assertEquals($image->getMediaId(), md5($source));
$this->assertEquals($image->getImageType(), $type);
$this->assertEquals($image->getImageExtension(), $extension);
$this->assertEquals($image->getImageCreateFunction(), $createFunction);
$this->assertEquals($image->getImageFunction(), $imageFunction);
$this->assertFalse($image->getIsMemImage());
}
}
/**
@ -88,18 +83,40 @@ class ImageTest extends \PHPUnit_Framework_TestCase
{
$oImage = new Image(
__DIR__ . "/../_files/images/earth.jpg",
array('width' => 210, 'height' => 210, 'align' => 'center')
array('height' => 210, 'align' => 'center')
);
$this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle());
}
/**
* Test set wrapping style
* Test invalid local image
*
* @expectedException \PhpOffice\PhpWord\Exception\InvalidImageException
*/
public function testStyleWrappingStyle()
public function testInvalidImageLocal()
{
new Image(__DIR__ . "/../_files/images/thisisnotarealimage");
}
/**
* Test invalid PHP Image
*
* @expectedException \PhpOffice\PhpWord\Exception\InvalidImageException
*/
public function testInvalidImagePhp()
{
$object = new Image('test.php');
}
/**
* Test unsupported image
*
* @expectedException \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException
*/
public function testUnsupportedImage()
{
$object = new Image('http://samples.libav.org/image-samples/RACECAR.BMP');
}
/**
@ -107,117 +124,20 @@ class ImageTest extends \PHPUnit_Framework_TestCase
*/
public function testRelationID()
{
$oImage = new Image(__DIR__ . "/../_files/images/earth.jpg");
$oImage = new Image(__DIR__ . "/../_files/images/earth.jpg", array('width' => 100));
$iVal = rand(1, 1000);
$oImage->setRelationId($iVal);
$this->assertEquals($oImage->getRelationId(), $iVal);
}
/**
* Get is watermark
* Test archived image
*/
public function testWatermark()
public function testArchivedImage()
{
$oImage = new Image(__DIR__ . "/../_files/images/earth.jpg");
$oImage->setIsWatermark(true);
$this->assertEquals($oImage->getIsWatermark(), true);
}
/**
* Test PNG
*/
public function testPNG()
{
$src = __DIR__ . "/../_files/images/firefox.png";
$oImage = new Image($src, array('width' => 100));
$this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage);
$this->assertEquals($oImage->getSource(), $src);
$this->assertEquals($oImage->getMediaId(), md5($src));
$this->assertEquals($oImage->getImageCreateFunction(), 'imagecreatefrompng');
$this->assertEquals($oImage->getImageFunction(), 'imagepng');
$this->assertEquals($oImage->getImageExtension(), 'png');
$this->assertEquals($oImage->getImageType(), 'image/png');
}
/**
* Test GIF
*/
public function testGIF()
{
$src = __DIR__ . "/../_files/images/mario.gif";
$oImage = new Image($src, array('height' => 100));
$this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage);
$this->assertEquals($oImage->getSource(), $src);
$this->assertEquals($oImage->getMediaId(), md5($src));
$this->assertEquals($oImage->getImageCreateFunction(), 'imagecreatefromgif');
$this->assertEquals($oImage->getImageFunction(), 'imagegif');
$this->assertEquals($oImage->getImageExtension(), 'gif');
$this->assertEquals($oImage->getImageType(), 'image/gif');
}
/**
* Test JPG
*/
public function testJPG()
{
$src = __DIR__ . "/../_files/images/earth.jpg";
$oImage = new Image($src);
$this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage);
$this->assertEquals($oImage->getSource(), $src);
$this->assertEquals($oImage->getMediaId(), md5($src));
$this->assertEquals($oImage->getImageCreateFunction(), 'imagecreatefromjpeg');
$this->assertEquals($oImage->getImageFunction(), 'imagejpeg');
$this->assertEquals($oImage->getImageExtension(), 'jpg');
$this->assertEquals($oImage->getImageType(), 'image/jpeg');
}
/**
* Test BMP
*/
public function testBMP()
{
$oImage = new Image(__DIR__ . "/../_files/images/duke_nukem.bmp");
$this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage);
$this->assertEquals($oImage->getImageCreateFunction(), null);
$this->assertEquals($oImage->getImageFunction(), null);
$this->assertEquals($oImage->getImageExtension(), 'bmp');
$this->assertEquals($oImage->getImageType(), 'image/bmp');
}
/**
* Test TIFF
*/
public function testTIFF()
{
$oImage = new Image(__DIR__ . "/../_files/images/angela_merkel.tif");
$this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage);
$this->assertEquals($oImage->getImageCreateFunction(), null);
$this->assertEquals($oImage->getImageFunction(), null);
$this->assertEquals($oImage->getImageType(), 'image/tiff');
}
/**
* Test PHP Image
*
* @expectedException \PhpOffice\PhpWord\Exception\InvalidImageException
*/
public function testPhpImage()
{
$object = new Image('test.php');
}
/**
* Test PCX Image and Memory
*
* @expectedException \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException
*/
public function testPcxImage()
{
$object = new Image('http://samples.libav.org/image-samples/RACECAR.BMP');
$archiveFile = __DIR__ . "/../_files/documents/reader.docx";
$imageFile = 'word/media/image1.jpeg';
$image = new Image("zip://{$archiveFile}#{$imageFile}");
$this->assertEquals('image/jpeg', $image->getImageType());
}
}

View File

@ -19,9 +19,9 @@ use PhpOffice\PhpWord\Settings;
class SettingsTest extends \PHPUnit_Framework_TestCase
{
/**
* Get/set compatibity option
* Test set/get compatibity option
*/
public function testGetSetCompatibility()
public function testSetGetCompatibility()
{
$this->assertTrue(Settings::getCompatibility());
$this->assertTrue(Settings::setCompatibility(false));
@ -30,12 +30,26 @@ class SettingsTest extends \PHPUnit_Framework_TestCase
}
/**
* Get/set zip class
* Test set/get zip class
*/
public function testGetSetZipClass()
public function testSetGetZipClass()
{
$this->assertEquals(Settings::ZIPARCHIVE, Settings::getZipClass());
$this->assertTrue(Settings::setZipClass(Settings::PCLZIP));
$this->assertFalse(Settings::setZipClass('foo'));
}
/**
* Test set/get PDF renderer
*/
public function testSetGetPdfRenderer()
{
$domPdfPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf');
$this->assertFalse(Settings::setPdfRenderer('FOO', 'dummy/path'));
$this->assertTrue(Settings::setPdfRenderer(Settings::PDF_RENDERER_DOMPDF, $domPdfPath));
$this->assertEquals(Settings::PDF_RENDERER_DOMPDF, Settings::getPdfRendererName());
$this->assertEquals($domPdfPath, Settings::getPdfRendererPath());
$this->assertFalse(Settings::setPdfRendererPath('dummy/path'));
}
}

View File

@ -45,7 +45,9 @@ class HTMLTest extends \PHPUnit_Framework_TestCase
*/
public function testSave()
{
$imageSrc = __DIR__ . "/../_files/images/PhpWord.png";
$localImage = __DIR__ . "/../_files/images/PhpWord.png";
$archiveImage = 'zip://' . __DIR__ . '/../_files/documents/reader.docx#word/media/image1.jpeg';
$gdImage = 'http://php.net/images/logos/php-med-trans-light.gif';
$objectSrc = __DIR__ . "/../_files/documents/sheet.xls";
$file = __DIR__ . "/../_files/temp.html";
@ -64,7 +66,9 @@ class HTMLTest extends \PHPUnit_Framework_TestCase
$section->addTitle('Test', 1);
$section->addPageBreak();
$section->addListItem('Test');
$section->addImage($imageSrc);
$section->addImage($localImage);
$section->addImage($archiveImage);
$section->addImage($gdImage);
$section->addObject($objectSrc);
$section->addFootnote();
$section->addEndnote();
@ -77,7 +81,7 @@ class HTMLTest extends \PHPUnit_Framework_TestCase
$textrun = $section->addTextRun('Paragraph');
$textrun->addLink('http://test.com');
$textrun->addImage($imageSrc);
$textrun->addImage($localImage);
$textrun->addFootnote();
$textrun->addEndnote();
@ -90,10 +94,11 @@ class HTMLTest extends \PHPUnit_Framework_TestCase
$cell->addLink('http://test.com');
$cell->addTextBreak();
$cell->addListItem('Test');
$cell->addImage($imageSrc);
$cell->addImage($localImage);
$cell->addObject($objectSrc);
$cell->addFootnote();
$cell->addEndnote();
$cell = $table->addRow()->addCell();
$writer = new HTML($phpWord);
$writer->save($file);

View File

@ -0,0 +1,70 @@
<?php
/**
* PHPWord
*
* @link https://github.com/PHPOffice/PHPWord
* @copyright 2014 PHPWord
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
*/
namespace PhpOffice\PhpWord\Tests\Writer\PDF;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\Writer\PDF;
/**
* Test class for PhpOffice\PhpWord\Writer\PDF\DomPDF
*
* @runTestsInSeparateProcesses
*/
class DomPDFTest extends \PHPUnit_Framework_TestCase
{
/**
* Test construct
*/
public function testConstruct()
{
define('DOMPDF_ENABLE_AUTOLOAD', false);
$file = __DIR__ . "/../../_files/temp.pdf";
$phpWord = new PhpWord();
$section = $phpWord->addSection();
$section->addText('Test 1');
$rendererName = Settings::PDF_RENDERER_DOMPDF;
$rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf');
Settings::setPdfRenderer($rendererName, $rendererLibraryPath);
$writer = new PDF($phpWord);
$writer->save($file);
$this->assertTrue(file_exists($file));
unlink($file);
}
/**
* Test set/get abstract renderer properties
*/
public function testSetGetAbstractRendererProperties()
{
define('DOMPDF_ENABLE_AUTOLOAD', false);
$file = __DIR__ . "/../../_files/temp.pdf";
$rendererName = Settings::PDF_RENDERER_DOMPDF;
$rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf');
Settings::setPdfRenderer($rendererName, $rendererLibraryPath);
$writer = new PDF(new PhpWord());
$writer->setFont('arial');
$this->assertEquals('arial', $writer->getFont());
$writer->setPaperSize();
$this->assertEquals(9, $writer->getPaperSize());
$writer->setOrientation();
$this->assertEquals('default', $writer->getOrientation());
$writer->setTempDir(sys_get_temp_dir());
$this->assertEquals(sys_get_temp_dir(), $writer->getTempDir());
}
}

View File

@ -0,0 +1,51 @@
<?php
/**
* PHPWord
*
* @link https://github.com/PHPOffice/PHPWord
* @copyright 2014 PHPWord
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
*/
namespace PhpOffice\PhpWord\Tests\Writer;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\Writer\PDF;
/**
* Test class for PhpOffice\PhpWord\Writer\PDF
*
* @runTestsInSeparateProcesses
*/
class PDFTest extends \PHPUnit_Framework_TestCase
{
/**
* Test normal construct
*/
public function testConstruct()
{
define('DOMPDF_ENABLE_AUTOLOAD', false);
$file = __DIR__ . "/../_files/temp.pdf";
$rendererName = Settings::PDF_RENDERER_DOMPDF;
$rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf');
Settings::setPdfRenderer($rendererName, $rendererLibraryPath);
$writer = new PDF(new PhpWord());
$writer->save($file);
$this->assertTrue(file_exists($file));
unlink($file);
}
/**
* Test construct exception
*
* @expectedException \PhpOffice\PhpWord\Exception\Exception
* @expectedExceptionMessage PDF rendering library or library path has not been defined.
*/
public function testConstructException()
{
$writer = new PDF(new PhpWord());
}
}

View File

@ -159,6 +159,11 @@ class BaseTest extends \PHPUnit_Framework_TestCase
$section->addImage(__DIR__ . "/../../_files/images/earth.jpg", $styles);
}
$archiveFile = realpath(__DIR__ . '/../../_files/documents/reader.docx');
$imageFile = 'word/media/image1.jpeg';
$source = 'zip://' . $archiveFile . '#' . $imageFile;
$section->addImage($source);
$doc = TestHelperDOCX::getDocument($phpWord);
// behind