diff --git a/docs/changes/1.x/1.5.0.md b/docs/changes/1.x/1.5.0.md
index b96865bada..25683768db 100644
--- a/docs/changes/1.x/1.5.0.md
+++ b/docs/changes/1.x/1.5.0.md
@@ -4,6 +4,8 @@
## Enhancements
+- Template Processor: Add support for svg images by [@geo-fret](https://github.com/geo-fret) fixing part of [#2795](https://github.com/PHPOffice/PHPWord/issues/2795) in [#2806](https://github.com/PHPOffice/PHPWord/pull/2806)
+
### Bug fixes
- Set writeAttribute return type by [@radarhere](https://github.com/radarhere) fixing [#2204](https://github.com/PHPOffice/PHPWord/issues/2204) in [#2776](https://github.com/PHPOffice/PHPWord/pull/2776)
diff --git a/docs/usage/template.md b/docs/usage/template.md
index a0c885e75e..54798c1a6a 100644
--- a/docs/usage/template.md
+++ b/docs/usage/template.md
@@ -106,6 +106,9 @@ Where:
- [width] and [height] can be just numbers or numbers with measure, which supported by Word (cm, mm, in, pt, pc, px, %, em, ex)
- [ratio] uses only for ``false``, ``-`` or ``f`` to turn off respect aspect ration of image. By default template image size uses as 'container' size.
+You can use an array as first argument to replace all search patterns with the same file. If you use an indexed array as second argument,
+the first item in the first argument will be replaced by the first item in the second argument.
+
Example:
``` clean
@@ -121,13 +124,22 @@ $templateProcessor = new TemplateProcessor('Template.docx');
$templateProcessor->setValue('Name', 'John Doe');
$templateProcessor->setValue(array('City', 'Street'), array('Detroit', '12th Street'));
-$templateProcessor->setImageValue('CompanyLogo', 'path/to/company/logo.png');
+$templateProcessor->setImageValue('CompanyLogo', 'path/to/company/logo.svg');
$templateProcessor->setImageValue('UserLogo', array('path' => 'path/to/logo.png', 'width' => 100, 'height' => 100, 'ratio' => false));
$templateProcessor->setImageValue('FeatureImage', function () {
// Closure will only be executed if the replacement tag is found in the template
return array('path' => SlowFeatureImageGenerator::make(), 'width' => 100, 'height' => 100, 'ratio' => false);
});
+
+// use array to replace multiple values
+$templateProcessor->setImageValue(
+ array('CompanyLogo', 'UserLogo'),
+ array(
+ 'path/to/company/logo.svg',
+ array('path' => 'path/to/logo.png', 'width' => 100, 'height' => 100, 'ratio' => false)
+ )
+);
```
## cloneBlock
diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php
index 073393ffc4..ff64720578 100644
--- a/src/PhpWord/TemplateProcessor.php
+++ b/src/PhpWord/TemplateProcessor.php
@@ -563,11 +563,26 @@ private function prepareImageAttrs($replaceImage, $varInlineArgs)
$width = $this->chooseImageDimension($width, $varInlineArgs['width'] ?? null, 115);
$height = $this->chooseImageDimension($height, $varInlineArgs['height'] ?? null, 70);
- $imageData = @getimagesize($imgPath);
- if (!is_array($imageData)) {
- throw new Exception(sprintf('Invalid image: %s', $imgPath));
+ $mime = mime_content_type($imgPath);
+ if ($mime === 'image/svg+xml') {
+ $content = file_get_contents($imgPath);
+ if (!$content) {
+ throw new Exception(sprintf('Invalid image: %s', $imgPath));
+ }
+ $svgXml = simplexml_load_string($content);
+ if (!$svgXml) {
+ throw new Exception(sprintf('Invalid image: %s', $imgPath));
+ }
+ $svgAttributes = $svgXml->attributes();
+ $actualWidth = $svgAttributes->width;
+ $actualHeight = $svgAttributes->height;
+ } else {
+ $imageData = @getimagesize($imgPath);
+ if (!is_array($imageData)) {
+ throw new Exception(sprintf('Invalid image: %s', $imgPath));
+ }
+ [$actualWidth, $actualHeight] = $imageData;
}
- [$actualWidth, $actualHeight, $imageType] = $imageData;
// fix aspect ratio (by default)
if (null === $ratio && isset($varInlineArgs['ratio'])) {
@@ -579,7 +594,7 @@ private function prepareImageAttrs($replaceImage, $varInlineArgs)
$imageAttrs = [
'src' => $imgPath,
- 'mime' => image_type_to_mime_type($imageType),
+ 'mime' => $mime,
'width' => $width,
'height' => $height,
];
@@ -599,6 +614,7 @@ private function addImageToRelations($partFileName, $rid, $imgPath, $imageMimeTy
'image/png' => 'png',
'image/bmp' => 'bmp',
'image/gif' => 'gif',
+ 'image/svg+xml' => 'svg',
];
// get image embed name
@@ -674,6 +690,48 @@ public function setImageValue($search, $replace, $limit = self::MAXIMUM_REPLACEM
// define templates
// result can be verified via "Open XML SDK 2.5 Productivity Tool" (http://www.microsoft.com/en-us/download/details.aspx?id=30425)
$imgTpl = '';
+ // use drawing for svg, see https://www.datypic.com/sc/ooxml/e-w_drawing-1.html
+ $svgTpl = '
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ';
$i = 0;
foreach ($searchParts as $partFileName => &$partContent) {
@@ -695,7 +753,11 @@ public function setImageValue($search, $replace, $limit = self::MAXIMUM_REPLACEM
// replace preparations
$this->addImageToRelations($partFileName, $rid, $imgPath, $preparedImageAttrs['mime']);
- $xmlImage = str_replace(['{RID}', '{WIDTH}', '{HEIGHT}'], [$rid, $preparedImageAttrs['width'], $preparedImageAttrs['height']], $imgTpl);
+ if ($preparedImageAttrs['mime'] === 'image/svg+xml') {
+ $xmlImage = str_replace(['{RID}', '{WIDTH}', '{HEIGHT}', '{ID}', '{NAME}'], [$rid, $preparedImageAttrs['width'], $preparedImageAttrs['height'], $imgIndex, 'graphic'], $svgTpl);
+ } else {
+ $xmlImage = str_replace(['{RID}', '{WIDTH}', '{HEIGHT}'], [$rid, $preparedImageAttrs['width'], $preparedImageAttrs['height']], $imgTpl);
+ }
// replace variable
$varNameWithArgsFixed = static::ensureMacroCompleted($varNameWithArgs);
diff --git a/tests/PhpWordTests/TemplateProcessorTest.php b/tests/PhpWordTests/TemplateProcessorTest.php
index 8ae4dfa59a..fc37884c16 100644
--- a/tests/PhpWordTests/TemplateProcessorTest.php
+++ b/tests/PhpWordTests/TemplateProcessorTest.php
@@ -859,14 +859,17 @@ public function testSetCheckboxWithCustomMacro(): void
public function testSetImageValue(): void
{
$templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/header-footer.docx');
- $imagePath = __DIR__ . '/_files/images/earth.jpg';
+ $imageJpg = __DIR__ . '/_files/images/earth.jpg';
+ $imageGif = __DIR__ . '/_files/images/mario.gif';
+ $imagePng = __DIR__ . '/_files/images/firefox.png';
+ $imageSvg = __DIR__ . '/_files/images/phpword.svg';
$variablesReplace = [
- 'headerValue' => function () use ($imagePath) {
- return $imagePath;
+ 'headerValue' => function () use ($imageJpg) {
+ return $imageJpg;
},
- 'documentContent' => ['path' => $imagePath, 'width' => 500, 'height' => 500],
- 'footerValue' => ['path' => $imagePath, 'width' => 100, 'height' => 50, 'ratio' => false],
+ 'documentContent' => ['path' => $imageJpg, 'width' => 500, 'height' => 500],
+ 'footerValue' => ['path' => $imageJpg, 'width' => 100, 'height' => 50, 'ratio' => false],
];
$templateProcessor->setImageValue(array_keys($variablesReplace), $variablesReplace);
@@ -906,7 +909,10 @@ public function testSetImageValue(): void
$testFileName = 'images-test-sample.docx';
$phpWord = new PhpWord();
$section = $phpWord->addSection();
- $section->addText('${Test:width=100:ratio=true}');
+ $section->addText('${Test0:width=100:ratio=true}');
+ $section->addText('${Test1::50:true}');
+ $section->addText('${Test2:size=10cmx7cm:ratio=false}');
+ $section->addText('${Test3}');
$objWriter = IOFactory::createWriter($phpWord, 'Word2007');
$objWriter->save($testFileName);
self::assertFileExists($testFileName, "Generated file '{$testFileName}' not found!");
@@ -914,9 +920,7 @@ public function testSetImageValue(): void
$resultFileName = 'images-test-result.docx';
$templateProcessor = new TemplateProcessor($testFileName);
unlink($testFileName);
- $templateProcessor->setImageValue('Test', $imagePath);
- $templateProcessor->setImageValue('Test1', $imagePath);
- $templateProcessor->setImageValue('Test2', $imagePath);
+ $templateProcessor->setImageValue(['Test0', 'Test1', 'Test2', 'Test3'], [$imageJpg, $imageGif, $imageSvg, $imagePng]);
$templateProcessor->saveAs($resultFileName);
self::assertFileExists($resultFileName, "Generated file '{$resultFileName}' not found!");
@@ -928,7 +932,7 @@ public function testSetImageValue(): void
}
unlink($resultFileName);
- self::assertStringNotContainsString('${Test}', $expectedMainPartXml, 'word/document.xml has no image.');
+ self::assertStringNotContainsString('${Test', $expectedMainPartXml, 'word/document.xml has no image.');
}
/**
diff --git a/tests/PhpWordTests/_files/images/phpword.svg b/tests/PhpWordTests/_files/images/phpword.svg
new file mode 100644
index 0000000000..2fbeeb4af0
--- /dev/null
+++ b/tests/PhpWordTests/_files/images/phpword.svg
@@ -0,0 +1,50 @@
+
+
+