From ca52b0997a333e24a2ffe21eb93a9147f657dcf4 Mon Sep 17 00:00:00 2001 From: Robert Rosebury Date: Mon, 29 Jun 2015 16:20:30 +0100 Subject: [PATCH 1/3] #260 - A quick hack around A quick hack solution I came up with today. This isn't pretty in the slightest and is my first pull request so apologise if I've done it wrong. I normally work on BitBucket. Example Usage ------------------ $templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor('C:\Users\Robert\Desktop\sample.docx'); $templateProcessor->cloneRow('rowValue', 10); $templateProcessor->setValue('test#1', htmlspecialchars('Text goes here')); $templateProcessor->setImageValue('testPhoto#1', 'image3.png', 'my-other-image.jpg'); $templateProcessor->setValue('test#2', htmlspecialchars('Text2 goes here')); $templateProcessor->setImageValue('testPhoto#2', 'image4.png', my-image.jpg'); --- src/PhpWord/Reader/Word2007.php | 2 +- src/PhpWord/TemplateProcessor.php | 127 ++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index ebe6c4f765..db30df4658 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -102,7 +102,7 @@ private function readPart(PhpWord $phpWord, $relationships, $partName, $docFile, * @param string $docFile * @return array */ - private function readRelationships($docFile) + public function readRelationships($docFile) { $relationships = array(); diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index cbed973011..86f91fdc68 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -22,6 +22,7 @@ use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Shared\String; use PhpOffice\PhpWord\Shared\ZipArchive; +use PhpOffice\PhpWord\Reader\Word2007; class TemplateProcessor { @@ -58,6 +59,13 @@ class TemplateProcessor */ private $temporaryDocumentFooters = array(); + /** + * Contents of the images added to the template + * + * @var string[] + */ + private $imageData = array(); + /** * @since 0.12.0 Throws CreateTemporaryFileException and CopyFileException instead of Exception. * @@ -145,6 +153,35 @@ public function setValue($search, $replace, $limit = -1) } } + /** + * Set a new image + * + * @param string $search + * @param string $replace + */ + public function setImageValue($search, $img, $imgSource) + { + // Sanity check + if (!file_exists($imgSource)) { + return; + } + + // Delete current image + $this->zipClass->deleteName('word/media/' . $img); + + // Add a new one + $this->zipClass->addFile($imgSource, 'word/media/' . $img); + + $id = 1000; + if (strpos($search, "#")) { + $id = ($id + (int) substr($search, strpos($search, "#") + 1)); + } + + $this->imageData['rId'.$id] = ['type' => 'image', 'target' => 'word/media/'.$img, 'docPart' => 'media/'.$img]; + + $this->setValue($search, $this->getImgTag($id, $img)); + } + /** * Returns array of all variables in template. * @@ -175,6 +212,7 @@ public function getVariables() */ public function cloneRow($search, $numberOfClones) { + if (substr($search, 0, 2) !== '${' && substr($search, -1) !== '}') { $search = '${' . $search . '}'; } @@ -307,6 +345,40 @@ public function save() $this->zipClass->addFromString('word/document.xml', $this->temporaryDocumentMainPart); + $word = new Word2007(); + $read = $word->readRelationships($this->zipClass->filename); + + if (count($this->imageData)) { + $read['document'] = array_merge($read['document'], $this->imageData); + $xml = new \XMLWriter(); + $xml->openMemory(); + $xml->setIndent(true); + $xml->startDocument('1.0', 'UTF-8'); + $xml->startElement('Relationships'); + $xml->startAttribute('xmlns'); + $xml->text('http://schemas.openxmlformats.org/package/2006/relationships'); + $xml->endAttribute(); + foreach ($read['document'] as $key => $data) { + $xml->startElement('Relationship'); + $xml->startAttribute('Id'); + $xml->text($key); + $xml->endAttribute(); + $xml->startAttribute('Type'); + $xml->text( + 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/'.$data['type'] + ); + $xml->endAttribute(); + $xml->startAttribute('Target'); + $xml->text($data['type'] === 'image' ? $data['docPart'] : $data['docPart'].'.xml'); + $xml->endAttribute(); + $xml->endElement(); + } + $xml->endElement(); + $xml->endDocument(); + } + + $this->zipClass->addFromString('word/_rels/document.xml.rels', $xml->outputMemory(true)); + foreach ($this->temporaryDocumentFooters as $index => $headerXML) { $this->zipClass->addFromString($this->getFooterName($index), $this->temporaryDocumentFooters[$index]); } @@ -383,6 +455,61 @@ protected function getVariablesForPart($documentPartXML) return $matches[1]; } + protected function getImgTag($id, $imgName) + { + return ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''; + } + /** * Get the name of the footer file for $index. * From d7dedf6be777e400d169ebbfae2fc4e624e99960 Mon Sep 17 00:00:00 2001 From: Robert Rosebury Date: Mon, 6 Jul 2015 11:24:53 +0100 Subject: [PATCH 2/3] #260 - Added in image sizes Image sizes now come from the actual image instead of being hard coded. --- src/PhpWord/TemplateProcessor.php | 44 ++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 86f91fdc68..d515c64f60 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -26,6 +26,12 @@ class TemplateProcessor { + /** + * EMU units per pixel + * @staticvar integer EMU_UNIT + */ + const EMU_UNIT = 9525; + /** * ZipArchive object. * @@ -66,6 +72,18 @@ class TemplateProcessor */ private $imageData = array(); + /** + * Image width in pixels * by EMU unit i.e. 100 * self::EMU_UNIT = 952500 + * @var integer $imageWidth + */ + private $imageWidth = 952500; + + /** + * Image height in pixels * by EMU unit i.e. 100 * self::EMU_UNIT = 952500 + * @var integer $imageHeight + */ + private $imageHeight = 952500; + /** * @since 0.12.0 Throws CreateTemporaryFileException and CopyFileException instead of Exception. * @@ -172,13 +190,14 @@ public function setImageValue($search, $img, $imgSource) // Add a new one $this->zipClass->addFile($imgSource, 'word/media/' . $img); + /** Create an id that the template has unlikely to have reached */ $id = 1000; if (strpos($search, "#")) { $id = ($id + (int) substr($search, strpos($search, "#") + 1)); } $this->imageData['rId'.$id] = ['type' => 'image', 'target' => 'word/media/'.$img, 'docPart' => 'media/'.$img]; - + $this->setImageSizes($imgSource); $this->setValue($search, $this->getImgTag($id, $img)); } @@ -455,6 +474,23 @@ protected function getVariablesForPart($documentPartXML) return $matches[1]; } + /** + * Sets the image sizes required for word + * @param string $imageSource + */ + protected function setImageSizes($imageSource) + { + $data = getimagesize($imageSource); + $this->imageWidth = ($data[0] * self::EMU_UNIT); + $this->imageHeight = ($data[1] * self::EMU_UNIT); + } + + /** + * Forces in an image tag into word + * @param integer $id + * @param string $imgName + * @return string + */ protected function getImgTag($id, $imgName) { return ''. @@ -466,9 +502,9 @@ protected function getImgTag($id, $imgName) ''. ''. ''. - ''. + ''. ''. - ''. + ''. ''. ''. ''. @@ -494,7 +530,7 @@ protected function getImgTag($id, $imgName) ''. ''. ''. - ''. + ''. ''. ''. ''. From 34ba3bf91d8b7aae4816f9266580c9dfbfe39476 Mon Sep 17 00:00:00 2001 From: Robert Rosebury Date: Tue, 11 Aug 2015 09:20:07 +0100 Subject: [PATCH 3/3] Moved $xml within image count if $xml may not be created if there isn't any images causing an error. --- src/PhpWord/TemplateProcessor.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index d515c64f60..aa9b000e9b 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -394,9 +394,11 @@ public function save() } $xml->endElement(); $xml->endDocument(); + + $this->zipClass->addFromString('word/_rels/document.xml.rels', $xml->outputMemory(true)); } - $this->zipClass->addFromString('word/_rels/document.xml.rels', $xml->outputMemory(true)); + foreach ($this->temporaryDocumentFooters as $index => $headerXML) { $this->zipClass->addFromString($this->getFooterName($index), $this->temporaryDocumentFooters[$index]);