From 2829fd82160df459c96065efdd2703b82745046a Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Wed, 16 Apr 2014 12:12:32 +0700 Subject: [PATCH] Enable image in HTML writer --- CHANGELOG.md | 4 +- docs/intro.rst | 114 ++++++++++---------- src/PhpWord/Element/Image.php | 13 +++ src/PhpWord/Writer/AbstractWriter.php | 34 +++--- src/PhpWord/Writer/HTML.php | 60 ++++++++++- src/PhpWord/Writer/PDF/AbstractRenderer.php | 30 +----- src/PhpWord/Writer/Word2007.php | 2 + tests/PhpWord/Tests/SettingsTest.php | 3 + 8 files changed, 161 insertions(+), 99 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b06aa79c..0b9cf9a2 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,8 +32,8 @@ This release marked heavy refactorings on internal code structure with the creat - 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) - @ivanlanin GH-203 GH-67 GH-147 +- PDF Writer: Basic PDF writer using DomPDF: All HTML element except image - @ivanlanin GH-68 ### Bugfixes diff --git a/docs/intro.rst b/docs/intro.rst index 0f1f3d74..53a352fe 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -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 diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index f7752b27..e4e91fe6 100755 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -126,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 * @@ -324,6 +334,9 @@ class Image extends AbstractElement /** * Set proportional width/height if one dimension not available + * + * @param integer $actualWidth + * @param integer $actualHeight */ private function setProportionalSize($actualWidth, $actualHeight) { diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index 9403d724..08785ecd 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -164,11 +164,7 @@ abstract class AbstractWriter implements WriterInterface protected function getTempFile($filename) { // Temporary directory - $tempDir = sys_get_temp_dir() . '/PHPWordMedia/'; - if (!is_dir($tempDir)) { - mkdir($tempDir); - } - $this->tempDir = $tempDir; + $this->setTempDir(); // Temporary file $this->originalFilename = $filename; @@ -184,23 +180,30 @@ abstract class AbstractWriter implements WriterInterface } /** - * Cleanup temporary file - * - * If a temporary file was used, copy it to the correct file stream + * Get temporary directory */ protected function getTempDir() { return $this->tempDir; } + /** + * Set temporary directory + */ + protected function setTempDir() + { + $tempDir = sys_get_temp_dir() . '/PHPWordMedia/'; + if (!is_dir($tempDir)) { + mkdir($tempDir); + } + $this->tempDir = $tempDir; + } + /** * Cleanup temporary file - * - * If a temporary file was used, copy it to the correct file stream */ protected function cleanupTempFile() { - // File if ($this->originalFilename != $this->tempFilename) { if (copy($this->tempFilename, $this->originalFilename) === false) { throw new Exception("Could not copy temporary zip file {$this->tempFilename} to {$this->originalFilename}."); @@ -208,7 +211,14 @@ abstract class AbstractWriter implements WriterInterface @unlink($this->tempFilename); } - // Directory + $this->clearTempDir(); + } + + /** + * Clear temporary directory + */ + protected function clearTempDir() + { if (is_dir($this->tempDir)) { $this->deleteDir($this->tempDir); } diff --git a/src/PhpWord/Writer/HTML.php b/src/PhpWord/Writer/HTML.php index f0720f66..1205f112 100644 --- a/src/PhpWord/Writer/HTML.php +++ b/src/PhpWord/Writer/HTML.php @@ -36,6 +36,13 @@ use PhpOffice\PhpWord\TOC; */ class HTML extends AbstractWriter implements WriterInterface { + /** + * Is the current writer creating PDF? + * + * @var boolean + */ + protected $isPdf = false; + /** * Create new instance */ @@ -53,9 +60,11 @@ class HTML extends AbstractWriter implements WriterInterface public function save($filename = null) { if (!is_null($this->getPhpWord())) { + $this->setTempDir(); $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."); } @@ -421,7 +430,18 @@ 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)) { + $html = ''; + if (!$withoutP) { + $html = '

' . $html . '

' . PHP_EOL; + } + } + } + + return $html; } /** @@ -597,4 +617,42 @@ class HTML extends AbstractWriter implements WriterInterface return $string; } + + /** + * Get Base64 image data + * + * @return string|null + */ + private function getBase64ImageData(Image $element) + { + $imageData = null; + $source = $element->getSource(); + $imageType = $element->getImageType(); + + // Get actual source + if ($element->getSourceType() == '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 ($fp = fopen($actualSource, "rb", 0)) { + $image = fread($fp, filesize($actualSource)); + fclose($fp); + $base64 = chunk_split(base64_encode($image)); + $imageData = 'data:' . $imageType . ';base64,' . $base64; + } + + return $imageData; + } } diff --git a/src/PhpWord/Writer/PDF/AbstractRenderer.php b/src/PhpWord/Writer/PDF/AbstractRenderer.php index be48a9f2..64f196e9 100644 --- a/src/PhpWord/Writer/PDF/AbstractRenderer.php +++ b/src/PhpWord/Writer/PDF/AbstractRenderer.php @@ -69,7 +69,6 @@ abstract class AbstractRenderer extends \PhpOffice\PhpWord\Writer\HTML public function __construct(PhpWord $phpWord) { parent::__construct($phpWord); - $this->setTempDir(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; } diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 0d0c0f69..920a159c 100755 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -181,6 +181,8 @@ 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 diff --git a/tests/PhpWord/Tests/SettingsTest.php b/tests/PhpWord/Tests/SettingsTest.php index 46efdf76..e7968355 100644 --- a/tests/PhpWord/Tests/SettingsTest.php +++ b/tests/PhpWord/Tests/SettingsTest.php @@ -39,6 +39,9 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertFalse(Settings::setZipClass('foo')); } + /** + * Test set/get PDF renderer + */ public function testSetGetPdfRenderer() { $domPdfPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf');