Skip to content

Commit f829559

Browse files
committed
ODT Writer: Basic image writing support
1 parent f5f03a5 commit f829559

File tree

10 files changed

+281
-125
lines changed

10 files changed

+281
-125
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ This release marked heavy refactorings on internal code structure with the creat
3636
- PDF Writer: Basic PDF writer using DomPDF: All HTML element except image - @ivanlanin GH-68
3737
- DOCX Writer: Change `docProps/app.xml` `Application` to `PHPWord` - @ivanlanin
3838
- DOCX Writer: Create `word/settings.xml` and `word/webSettings.xml` dynamically - @ivanlanin
39+
- ODT Writer: Basic image writing - @ivanlanin
3940

4041
### Bugfixes
4142

docs/intro.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ Writers
8989
+ +-----------------------+--------+-------+-------+-------+-------+
9090
| | Table ||| |||
9191
+ +-----------------------+--------+-------+-------+-------+-------+
92-
| | Image || | || |
92+
| | Image || | || |
9393
+ +-----------------------+--------+-------+-------+-------+-------+
9494
| | Object || | | | |
9595
+ +-----------------------+--------+-------+-------+-------+-------+

src/PhpWord/Element/Image.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,20 @@ class Image extends AbstractElement
8989
*/
9090
private $isMemImage;
9191

92+
/**
93+
* Image target file name
94+
*
95+
* @var string
96+
*/
97+
private $target;
98+
99+
/**
100+
* Image media index
101+
*
102+
* @var integer
103+
*/
104+
private $mediaIndex;
105+
92106
/**
93107
* Create new image element
94108
*
@@ -217,6 +231,46 @@ public function getIsMemImage()
217231
return $this->isMemImage;
218232
}
219233

234+
/**
235+
* Get target file name
236+
*
237+
* @return string
238+
*/
239+
public function getTarget()
240+
{
241+
return $this->target;
242+
}
243+
244+
/**
245+
* Set target file name
246+
*
247+
* @param string $value
248+
*/
249+
public function setTarget($value)
250+
{
251+
$this->target = $value;
252+
}
253+
254+
/**
255+
* Get media index
256+
*
257+
* @return integer
258+
*/
259+
public function getMediaIndex()
260+
{
261+
return $this->mediaIndex;
262+
}
263+
264+
/**
265+
* Set media index
266+
*
267+
* @param integer $value
268+
*/
269+
public function setMediaIndex($value)
270+
{
271+
$this->mediaIndex = $value;
272+
}
273+
220274
/**
221275
* Check memory image, supported type, image functions, and proportional width/height
222276
*

src/PhpWord/Media.php

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class Media
3636
* @since 0.9.2
3737
* @since 0.10.0
3838
*/
39-
public static function addElement($container, $mediaType, $source, Image $image = null)
39+
public static function addElement($container, $mediaType, $source, Image &$image = null)
4040
{
4141
// Assign unique media Id and initiate media container if none exists
4242
$mediaId = md5($container . $source);
@@ -48,10 +48,10 @@ public static function addElement($container, $mediaType, $source, Image $image
4848
if (!array_key_exists($mediaId, self::$elements[$container])) {
4949
$mediaCount = self::countElements($container);
5050
$mediaTypeCount = self::countElements($container, $mediaType);
51-
$mediaData = array();
51+
$mediaTypeCount++;
5252
$rId = ++$mediaCount;
5353
$target = null;
54-
$mediaTypeCount++;
54+
$mediaData = array('mediaIndex' => $mediaTypeCount);
5555

5656
switch ($mediaType) {
5757
// Images
@@ -68,12 +68,14 @@ public static function addElement($container, $mediaType, $source, Image $image
6868
$mediaData['createFunction'] = $image->getImageCreateFunction();
6969
$mediaData['imageFunction'] = $image->getImageFunction();
7070
}
71-
$target = "media/{$container}_image{$mediaTypeCount}.{$extension}";
71+
$target = "{$container}_image{$mediaTypeCount}.{$extension}";
72+
$image->setTarget($target);
73+
$image->setMediaIndex($mediaTypeCount);
7274
break;
7375

7476
// Objects
7577
case 'object':
76-
$target = "embeddings/{$container}_oleObject{$mediaTypeCount}.bin";
78+
$target = "{$container}_oleObject{$mediaTypeCount}.bin";
7779
break;
7880

7981
// Links
@@ -89,7 +91,12 @@ public static function addElement($container, $mediaType, $source, Image $image
8991
self::$elements[$container][$mediaId] = $mediaData;
9092
return $rId;
9193
} else {
92-
return self::$elements[$container][$mediaId]['rID'];
94+
$mediaData = self::$elements[$container][$mediaId];
95+
if (!is_null($image)) {
96+
$image->setTarget($mediaData['target']);
97+
$image->setMediaIndex($mediaData['mediaIndex']);
98+
}
99+
return $mediaData['rID'];
93100
}
94101
}
95102

src/PhpWord/Writer/AbstractWriter.php

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,17 @@ abstract class AbstractWriter implements WriterInterface
3030
/**
3131
* Individual writers
3232
*
33-
* @var mixed
33+
* @var array
3434
*/
3535
protected $writerParts = array();
3636

37+
/**
38+
* Paths to store media files
39+
*
40+
* @var array
41+
*/
42+
protected $mediaPaths = array('image' => '', 'object' => '');
43+
3744
/**
3845
* Use disk caching
3946
*
@@ -263,6 +270,73 @@ protected function getZipArchive($filename)
263270
return $objZip;
264271
}
265272

273+
/**
274+
* Add files to package
275+
*
276+
* @param mixed $objZip
277+
* @param mixed $elements
278+
*/
279+
protected function addFilesToPackage($objZip, $elements)
280+
{
281+
foreach ($elements as $element) {
282+
$type = $element['type']; // image|object|link
283+
284+
// Skip nonregistered types and set target
285+
if (!array_key_exists($type, $this->mediaPaths)) {
286+
continue;
287+
}
288+
$target = $this->mediaPaths[$type] . $element['target'];
289+
290+
// Retrive GD image content or get local media
291+
if (isset($element['isMemImage']) && $element['isMemImage']) {
292+
$image = call_user_func($element['createFunction'], $element['source']);
293+
ob_start();
294+
call_user_func($element['imageFunction'], $image);
295+
$imageContents = ob_get_contents();
296+
ob_end_clean();
297+
$objZip->addFromString($target, $imageContents);
298+
imagedestroy($image);
299+
} else {
300+
$this->addFileToPackage($objZip, $element['source'], $target);
301+
}
302+
}
303+
}
304+
305+
/**
306+
* Add file to package
307+
*
308+
* Get the actual source from an archive image
309+
*
310+
* @param mixed $objZip
311+
* @param string $source
312+
* @param string $target
313+
*/
314+
protected function addFileToPackage($objZip, $source, $target)
315+
{
316+
$isArchive = strpos($source, 'zip://') !== false;
317+
$actualSource = null;
318+
if ($isArchive) {
319+
$source = substr($source, 6);
320+
list($zipFilename, $imageFilename) = explode('#', $source);
321+
322+
$zipClass = \PhpOffice\PhpWord\Settings::getZipClass();
323+
$zip = new $zipClass();
324+
if ($zip->open($zipFilename) !== false) {
325+
if ($zip->locateName($imageFilename)) {
326+
$zip->extractTo($this->getTempDir(), $imageFilename);
327+
$actualSource = $this->getTempDir() . DIRECTORY_SEPARATOR . $imageFilename;
328+
}
329+
}
330+
$zip->close();
331+
} else {
332+
$actualSource = $source;
333+
}
334+
335+
if (!is_null($actualSource)) {
336+
$objZip->addFile($actualSource, $target);
337+
}
338+
}
339+
266340
/**
267341
* Delete directory
268342
*

src/PhpWord/Writer/ODText.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99

1010
namespace PhpOffice\PhpWord\Writer;
1111

12-
use PhpOffice\PhpWord\Exception\Exception;
12+
use PhpOffice\PhpWord\Media;
1313
use PhpOffice\PhpWord\PhpWord;
14+
use PhpOffice\PhpWord\Exception\Exception;
1415
use PhpOffice\PhpWord\Writer\ODText\Content;
1516
use PhpOffice\PhpWord\Writer\ODText\Manifest;
1617
use PhpOffice\PhpWord\Writer\ODText\Meta;
@@ -43,6 +44,9 @@ public function __construct(PhpWord $phpWord = null)
4344
foreach ($this->writerParts as $writer) {
4445
$writer->setParentWriter($this);
4546
}
47+
48+
// Set package paths
49+
$this->mediaPaths = array('image' => 'Pictures/');
4650
}
4751

4852
/**
@@ -57,7 +61,13 @@ public function save($filename = null)
5761
$filename = $this->getTempFile($filename);
5862
$objZip = $this->getZipArchive($filename);
5963

60-
// Add mimetype to ZIP file
64+
// Add section media files
65+
$sectionMedia = Media::getElements('section');
66+
if (!empty($sectionMedia)) {
67+
$this->addFilesToPackage($objZip, $sectionMedia);
68+
}
69+
70+
// Add parts
6171
$objZip->addFromString('mimetype', $this->getWriterPart('mimetype')->writeMimetype());
6272
$objZip->addFromString('content.xml', $this->getWriterPart('content')->writeContent($this->phpWord));
6373
$objZip->addFromString('meta.xml', $this->getWriterPart('meta')->writeMeta($this->phpWord));

0 commit comments

Comments
 (0)