ODT Writer: Basic image writing support
This commit is contained in:
parent
f5f03a5b2b
commit
f829559f65
|
|
@ -36,6 +36,7 @@ This release marked heavy refactorings on internal code structure with the creat
|
||||||
- PDF Writer: Basic PDF writer using DomPDF: All HTML element except image - @ivanlanin GH-68
|
- PDF Writer: Basic PDF writer using DomPDF: All HTML element except image - @ivanlanin GH-68
|
||||||
- DOCX Writer: Change `docProps/app.xml` `Application` to `PHPWord` - @ivanlanin
|
- DOCX Writer: Change `docProps/app.xml` `Application` to `PHPWord` - @ivanlanin
|
||||||
- DOCX Writer: Create `word/settings.xml` and `word/webSettings.xml` dynamically - @ivanlanin
|
- DOCX Writer: Create `word/settings.xml` and `word/webSettings.xml` dynamically - @ivanlanin
|
||||||
|
- ODT Writer: Basic image writing - @ivanlanin
|
||||||
|
|
||||||
### Bugfixes
|
### Bugfixes
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ Writers
|
||||||
+ +-----------------------+--------+-------+-------+-------+-------+
|
+ +-----------------------+--------+-------+-------+-------+-------+
|
||||||
| | Table | ✓ | ✓ | | ✓ | ✓ |
|
| | Table | ✓ | ✓ | | ✓ | ✓ |
|
||||||
+ +-----------------------+--------+-------+-------+-------+-------+
|
+ +-----------------------+--------+-------+-------+-------+-------+
|
||||||
| | Image | ✓ | | | ✓ | |
|
| | Image | ✓ | ✓ | | ✓ | |
|
||||||
+ +-----------------------+--------+-------+-------+-------+-------+
|
+ +-----------------------+--------+-------+-------+-------+-------+
|
||||||
| | Object | ✓ | | | | |
|
| | Object | ✓ | | | | |
|
||||||
+ +-----------------------+--------+-------+-------+-------+-------+
|
+ +-----------------------+--------+-------+-------+-------+-------+
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,20 @@ class Image extends AbstractElement
|
||||||
*/
|
*/
|
||||||
private $isMemImage;
|
private $isMemImage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Image target file name
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Image media index
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
private $mediaIndex;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new image element
|
* Create new image element
|
||||||
*
|
*
|
||||||
|
|
@ -217,6 +231,46 @@ class Image extends AbstractElement
|
||||||
return $this->isMemImage;
|
return $this->isMemImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get target file name
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getTarget()
|
||||||
|
{
|
||||||
|
return $this->target;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set target file name
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
*/
|
||||||
|
public function setTarget($value)
|
||||||
|
{
|
||||||
|
$this->target = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get media index
|
||||||
|
*
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public function getMediaIndex()
|
||||||
|
{
|
||||||
|
return $this->mediaIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set media index
|
||||||
|
*
|
||||||
|
* @param integer $value
|
||||||
|
*/
|
||||||
|
public function setMediaIndex($value)
|
||||||
|
{
|
||||||
|
$this->mediaIndex = $value;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check memory image, supported type, image functions, and proportional width/height
|
* Check memory image, supported type, image functions, and proportional width/height
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ class Media
|
||||||
* @since 0.9.2
|
* @since 0.9.2
|
||||||
* @since 0.10.0
|
* @since 0.10.0
|
||||||
*/
|
*/
|
||||||
public static function addElement($container, $mediaType, $source, Image $image = null)
|
public static function addElement($container, $mediaType, $source, Image &$image = null)
|
||||||
{
|
{
|
||||||
// Assign unique media Id and initiate media container if none exists
|
// Assign unique media Id and initiate media container if none exists
|
||||||
$mediaId = md5($container . $source);
|
$mediaId = md5($container . $source);
|
||||||
|
|
@ -48,10 +48,10 @@ class Media
|
||||||
if (!array_key_exists($mediaId, self::$elements[$container])) {
|
if (!array_key_exists($mediaId, self::$elements[$container])) {
|
||||||
$mediaCount = self::countElements($container);
|
$mediaCount = self::countElements($container);
|
||||||
$mediaTypeCount = self::countElements($container, $mediaType);
|
$mediaTypeCount = self::countElements($container, $mediaType);
|
||||||
$mediaData = array();
|
$mediaTypeCount++;
|
||||||
$rId = ++$mediaCount;
|
$rId = ++$mediaCount;
|
||||||
$target = null;
|
$target = null;
|
||||||
$mediaTypeCount++;
|
$mediaData = array('mediaIndex' => $mediaTypeCount);
|
||||||
|
|
||||||
switch ($mediaType) {
|
switch ($mediaType) {
|
||||||
// Images
|
// Images
|
||||||
|
|
@ -68,12 +68,14 @@ class Media
|
||||||
$mediaData['createFunction'] = $image->getImageCreateFunction();
|
$mediaData['createFunction'] = $image->getImageCreateFunction();
|
||||||
$mediaData['imageFunction'] = $image->getImageFunction();
|
$mediaData['imageFunction'] = $image->getImageFunction();
|
||||||
}
|
}
|
||||||
$target = "media/{$container}_image{$mediaTypeCount}.{$extension}";
|
$target = "{$container}_image{$mediaTypeCount}.{$extension}";
|
||||||
|
$image->setTarget($target);
|
||||||
|
$image->setMediaIndex($mediaTypeCount);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Objects
|
// Objects
|
||||||
case 'object':
|
case 'object':
|
||||||
$target = "embeddings/{$container}_oleObject{$mediaTypeCount}.bin";
|
$target = "{$container}_oleObject{$mediaTypeCount}.bin";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Links
|
// Links
|
||||||
|
|
@ -89,7 +91,12 @@ class Media
|
||||||
self::$elements[$container][$mediaId] = $mediaData;
|
self::$elements[$container][$mediaId] = $mediaData;
|
||||||
return $rId;
|
return $rId;
|
||||||
} else {
|
} else {
|
||||||
return self::$elements[$container][$mediaId]['rID'];
|
$mediaData = self::$elements[$container][$mediaId];
|
||||||
|
if (!is_null($image)) {
|
||||||
|
$image->setTarget($mediaData['target']);
|
||||||
|
$image->setMediaIndex($mediaData['mediaIndex']);
|
||||||
|
}
|
||||||
|
return $mediaData['rID'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,10 +30,17 @@ abstract class AbstractWriter implements WriterInterface
|
||||||
/**
|
/**
|
||||||
* Individual writers
|
* Individual writers
|
||||||
*
|
*
|
||||||
* @var mixed
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $writerParts = array();
|
protected $writerParts = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Paths to store media files
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $mediaPaths = array('image' => '', 'object' => '');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use disk caching
|
* Use disk caching
|
||||||
*
|
*
|
||||||
|
|
@ -263,6 +270,73 @@ abstract class AbstractWriter implements WriterInterface
|
||||||
return $objZip;
|
return $objZip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add files to package
|
||||||
|
*
|
||||||
|
* @param mixed $objZip
|
||||||
|
* @param mixed $elements
|
||||||
|
*/
|
||||||
|
protected function addFilesToPackage($objZip, $elements)
|
||||||
|
{
|
||||||
|
foreach ($elements as $element) {
|
||||||
|
$type = $element['type']; // image|object|link
|
||||||
|
|
||||||
|
// Skip nonregistered types and set target
|
||||||
|
if (!array_key_exists($type, $this->mediaPaths)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$target = $this->mediaPaths[$type] . $element['target'];
|
||||||
|
|
||||||
|
// Retrive GD image content or get local media
|
||||||
|
if (isset($element['isMemImage']) && $element['isMemImage']) {
|
||||||
|
$image = call_user_func($element['createFunction'], $element['source']);
|
||||||
|
ob_start();
|
||||||
|
call_user_func($element['imageFunction'], $image);
|
||||||
|
$imageContents = ob_get_contents();
|
||||||
|
ob_end_clean();
|
||||||
|
$objZip->addFromString($target, $imageContents);
|
||||||
|
imagedestroy($image);
|
||||||
|
} else {
|
||||||
|
$this->addFileToPackage($objZip, $element['source'], $target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add file to package
|
||||||
|
*
|
||||||
|
* Get the actual source from an archive image
|
||||||
|
*
|
||||||
|
* @param mixed $objZip
|
||||||
|
* @param string $source
|
||||||
|
* @param string $target
|
||||||
|
*/
|
||||||
|
protected function addFileToPackage($objZip, $source, $target)
|
||||||
|
{
|
||||||
|
$isArchive = strpos($source, 'zip://') !== false;
|
||||||
|
$actualSource = null;
|
||||||
|
if ($isArchive) {
|
||||||
|
$source = substr($source, 6);
|
||||||
|
list($zipFilename, $imageFilename) = explode('#', $source);
|
||||||
|
|
||||||
|
$zipClass = \PhpOffice\PhpWord\Settings::getZipClass();
|
||||||
|
$zip = new $zipClass();
|
||||||
|
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, $target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete directory
|
* Delete directory
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,9 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpWord\Writer;
|
namespace PhpOffice\PhpWord\Writer;
|
||||||
|
|
||||||
use PhpOffice\PhpWord\Exception\Exception;
|
use PhpOffice\PhpWord\Media;
|
||||||
use PhpOffice\PhpWord\PhpWord;
|
use PhpOffice\PhpWord\PhpWord;
|
||||||
|
use PhpOffice\PhpWord\Exception\Exception;
|
||||||
use PhpOffice\PhpWord\Writer\ODText\Content;
|
use PhpOffice\PhpWord\Writer\ODText\Content;
|
||||||
use PhpOffice\PhpWord\Writer\ODText\Manifest;
|
use PhpOffice\PhpWord\Writer\ODText\Manifest;
|
||||||
use PhpOffice\PhpWord\Writer\ODText\Meta;
|
use PhpOffice\PhpWord\Writer\ODText\Meta;
|
||||||
|
|
@ -43,6 +44,9 @@ class ODText extends AbstractWriter implements WriterInterface
|
||||||
foreach ($this->writerParts as $writer) {
|
foreach ($this->writerParts as $writer) {
|
||||||
$writer->setParentWriter($this);
|
$writer->setParentWriter($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set package paths
|
||||||
|
$this->mediaPaths = array('image' => 'Pictures/');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -57,7 +61,13 @@ class ODText extends AbstractWriter implements WriterInterface
|
||||||
$filename = $this->getTempFile($filename);
|
$filename = $this->getTempFile($filename);
|
||||||
$objZip = $this->getZipArchive($filename);
|
$objZip = $this->getZipArchive($filename);
|
||||||
|
|
||||||
// Add mimetype to ZIP file
|
// Add section media files
|
||||||
|
$sectionMedia = Media::getElements('section');
|
||||||
|
if (!empty($sectionMedia)) {
|
||||||
|
$this->addFilesToPackage($objZip, $sectionMedia);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add parts
|
||||||
$objZip->addFromString('mimetype', $this->getWriterPart('mimetype')->writeMimetype());
|
$objZip->addFromString('mimetype', $this->getWriterPart('mimetype')->writeMimetype());
|
||||||
$objZip->addFromString('content.xml', $this->getWriterPart('content')->writeContent($this->phpWord));
|
$objZip->addFromString('content.xml', $this->getWriterPart('content')->writeContent($this->phpWord));
|
||||||
$objZip->addFromString('meta.xml', $this->getWriterPart('meta')->writeMeta($this->phpWord));
|
$objZip->addFromString('meta.xml', $this->getWriterPart('meta')->writeMeta($this->phpWord));
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,9 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpWord\Writer\ODText;
|
namespace PhpOffice\PhpWord\Writer\ODText;
|
||||||
|
|
||||||
use PhpOffice\PhpWord\Exception\Exception;
|
use PhpOffice\PhpWord\Media;
|
||||||
|
use PhpOffice\PhpWord\Style;
|
||||||
|
use PhpOffice\PhpWord\PhpWord;
|
||||||
use PhpOffice\PhpWord\Element\Image;
|
use PhpOffice\PhpWord\Element\Image;
|
||||||
use PhpOffice\PhpWord\Element\Link;
|
use PhpOffice\PhpWord\Element\Link;
|
||||||
use PhpOffice\PhpWord\Element\ListItem;
|
use PhpOffice\PhpWord\Element\ListItem;
|
||||||
|
|
@ -20,11 +22,11 @@ use PhpOffice\PhpWord\Element\Text;
|
||||||
use PhpOffice\PhpWord\Element\TextBreak;
|
use PhpOffice\PhpWord\Element\TextBreak;
|
||||||
use PhpOffice\PhpWord\Element\TextRun;
|
use PhpOffice\PhpWord\Element\TextRun;
|
||||||
use PhpOffice\PhpWord\Element\Title;
|
use PhpOffice\PhpWord\Element\Title;
|
||||||
use PhpOffice\PhpWord\PhpWord;
|
use PhpOffice\PhpWord\Exception\Exception;
|
||||||
|
use PhpOffice\PhpWord\Shared\Drawing;
|
||||||
use PhpOffice\PhpWord\Shared\XMLWriter;
|
use PhpOffice\PhpWord\Shared\XMLWriter;
|
||||||
use PhpOffice\PhpWord\Style\Font;
|
use PhpOffice\PhpWord\Style\Font;
|
||||||
use PhpOffice\PhpWord\Style\Paragraph;
|
use PhpOffice\PhpWord\Style\Paragraph;
|
||||||
use PhpOffice\PhpWord\Style;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ODText content part writer
|
* ODText content part writer
|
||||||
|
|
@ -98,33 +100,7 @@ class Content extends Base
|
||||||
|
|
||||||
$this->writeFontFaces($xmlWriter); // office:font-face-decls
|
$this->writeFontFaces($xmlWriter); // office:font-face-decls
|
||||||
|
|
||||||
$this->writeAutomaticStyles($xmlWriter); // office:automatic-styles
|
$this->writeAutomaticStyles($xmlWriter, $phpWord); // office:automatic-styles
|
||||||
|
|
||||||
// Tables
|
|
||||||
$sections = $phpWord->getSections();
|
|
||||||
$countSections = count($sections);
|
|
||||||
if ($countSections > 0) {
|
|
||||||
$sectionId = 0;
|
|
||||||
foreach ($sections as $section) {
|
|
||||||
$sectionId++;
|
|
||||||
$elements = $section->getElements();
|
|
||||||
foreach ($elements as $element) {
|
|
||||||
if ($elements instanceof Table) {
|
|
||||||
$xmlWriter->startElement('style:style');
|
|
||||||
$xmlWriter->writeAttribute('style:name', $element->getElementId());
|
|
||||||
$xmlWriter->writeAttribute('style:family', 'table');
|
|
||||||
$xmlWriter->startElement('style:table-properties');
|
|
||||||
//$xmlWriter->writeAttribute('style:width', 'table');
|
|
||||||
$xmlWriter->writeAttribute('style:rel-width', 100);
|
|
||||||
$xmlWriter->writeAttribute('table:align', 'center');
|
|
||||||
$xmlWriter->endElement();
|
|
||||||
$xmlWriter->endElement();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$xmlWriter->endElement();
|
|
||||||
|
|
||||||
// office:body
|
// office:body
|
||||||
$xmlWriter->startElement('office:body');
|
$xmlWriter->startElement('office:body');
|
||||||
|
|
@ -371,7 +347,33 @@ class Content extends Base
|
||||||
*/
|
*/
|
||||||
protected function writeImage(XMLWriter $xmlWriter, Image $element)
|
protected function writeImage(XMLWriter $xmlWriter, Image $element)
|
||||||
{
|
{
|
||||||
$this->writeUnsupportedElement($xmlWriter, 'Image');
|
$mediaIndex = $element->getMediaIndex();
|
||||||
|
$target = 'Pictures/' . $element->getTarget();
|
||||||
|
$style = $element->getStyle();
|
||||||
|
$width = Drawing::pixelsToCentimeters($style->getWidth());
|
||||||
|
$height = Drawing::pixelsToCentimeters($style->getHeight());
|
||||||
|
|
||||||
|
$xmlWriter->startElement('text:p');
|
||||||
|
$xmlWriter->writeAttribute('text:style-name', 'Standard');
|
||||||
|
|
||||||
|
$xmlWriter->startElement('draw:frame');
|
||||||
|
$xmlWriter->writeAttribute('draw:style-name', 'fr' . $mediaIndex);
|
||||||
|
$xmlWriter->writeAttribute('draw:name', $element->getElementId());
|
||||||
|
$xmlWriter->writeAttribute('text:anchor-type', 'as-char');
|
||||||
|
$xmlWriter->writeAttribute('svg:width', $width . 'cm');
|
||||||
|
$xmlWriter->writeAttribute('svg:height', $height . 'cm');
|
||||||
|
$xmlWriter->writeAttribute('draw:z-index', $mediaIndex);
|
||||||
|
|
||||||
|
$xmlWriter->startElement('draw:image');
|
||||||
|
$xmlWriter->writeAttribute('xlink:href', $target);
|
||||||
|
$xmlWriter->writeAttribute('xlink:type', 'simple');
|
||||||
|
$xmlWriter->writeAttribute('xlink:show', 'embed');
|
||||||
|
$xmlWriter->writeAttribute('xlink:actuate', 'onLoad');
|
||||||
|
$xmlWriter->endElement(); // draw:image
|
||||||
|
|
||||||
|
$xmlWriter->endElement(); // draw:frame
|
||||||
|
|
||||||
|
$xmlWriter->endElement(); // text:p
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -398,9 +400,11 @@ class Content extends Base
|
||||||
/**
|
/**
|
||||||
* Write automatic styles
|
* Write automatic styles
|
||||||
*/
|
*/
|
||||||
private function writeAutomaticStyles(XMLWriter $xmlWriter)
|
private function writeAutomaticStyles(XMLWriter $xmlWriter, PhpWord $phpWord)
|
||||||
{
|
{
|
||||||
$xmlWriter->startElement('office:automatic-styles');
|
$xmlWriter->startElement('office:automatic-styles');
|
||||||
|
|
||||||
|
// Font and paragraph
|
||||||
$styles = Style::getStyles();
|
$styles = Style::getStyles();
|
||||||
$numPStyles = 0;
|
$numPStyles = 0;
|
||||||
if (count($styles) > 0) {
|
if (count($styles) > 0) {
|
||||||
|
|
@ -437,7 +441,6 @@ class Content extends Base
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($numPStyles == 0) {
|
if ($numPStyles == 0) {
|
||||||
// style:style
|
// style:style
|
||||||
$xmlWriter->startElement('style:style');
|
$xmlWriter->startElement('style:style');
|
||||||
|
|
@ -452,5 +455,47 @@ class Content extends Base
|
||||||
$xmlWriter->endElement();
|
$xmlWriter->endElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Images
|
||||||
|
$imageData = Media::getElements('section');
|
||||||
|
foreach ($imageData as $imageId => $image) {
|
||||||
|
if ($image['type'] == 'image') {
|
||||||
|
$xmlWriter->startElement('style:style');
|
||||||
|
$xmlWriter->writeAttribute('style:name', 'fr' . $image['rID']);
|
||||||
|
$xmlWriter->writeAttribute('style:family', 'graphic');
|
||||||
|
$xmlWriter->writeAttribute('style:parent-style-name', 'Graphics');
|
||||||
|
$xmlWriter->startElement('style:graphic-properties');
|
||||||
|
$xmlWriter->writeAttribute('style:vertical-pos', 'top');
|
||||||
|
$xmlWriter->writeAttribute('style:vertical-rel', 'baseline');
|
||||||
|
$xmlWriter->endElement();
|
||||||
|
$xmlWriter->endElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tables
|
||||||
|
$sections = $phpWord->getSections();
|
||||||
|
$countSections = count($sections);
|
||||||
|
if ($countSections > 0) {
|
||||||
|
$sectionId = 0;
|
||||||
|
foreach ($sections as $section) {
|
||||||
|
$sectionId++;
|
||||||
|
$elements = $section->getElements();
|
||||||
|
foreach ($elements as $element) {
|
||||||
|
if ($elements instanceof Table) {
|
||||||
|
$xmlWriter->startElement('style:style');
|
||||||
|
$xmlWriter->writeAttribute('style:name', $element->getElementId());
|
||||||
|
$xmlWriter->writeAttribute('style:family', 'table');
|
||||||
|
$xmlWriter->startElement('style:table-properties');
|
||||||
|
//$xmlWriter->writeAttribute('style:width', 'table');
|
||||||
|
$xmlWriter->writeAttribute('style:rel-width', 100);
|
||||||
|
$xmlWriter->writeAttribute('table:align', 'center');
|
||||||
|
$xmlWriter->endElement();
|
||||||
|
$xmlWriter->endElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$xmlWriter->endElement(); // office:automatic-styles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpWord\Writer\ODText;
|
namespace PhpOffice\PhpWord\Writer\ODText;
|
||||||
|
|
||||||
|
use PhpOffice\PhpWord\Media;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ODText manifest part writer
|
* ODText manifest part writer
|
||||||
*/
|
*/
|
||||||
|
|
@ -54,9 +56,19 @@ class Manifest extends AbstractWriterPart
|
||||||
$xmlWriter->writeAttribute('manifest:full-path', 'styles.xml');
|
$xmlWriter->writeAttribute('manifest:full-path', 'styles.xml');
|
||||||
$xmlWriter->endElement();
|
$xmlWriter->endElement();
|
||||||
|
|
||||||
|
// Media files
|
||||||
|
$media = Media::getElements('section');
|
||||||
|
foreach ($media as $medium) {
|
||||||
|
if ($medium['type'] == 'image') {
|
||||||
|
$xmlWriter->startElement('manifest:file-entry');
|
||||||
|
$xmlWriter->writeAttribute('manifest:media-type', $medium['imageType']);
|
||||||
|
$xmlWriter->writeAttribute('manifest:full-path', 'Pictures/' . $medium['target']);
|
||||||
|
$xmlWriter->endElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$xmlWriter->endElement(); // manifest:manifest
|
$xmlWriter->endElement(); // manifest:manifest
|
||||||
|
|
||||||
// Return
|
|
||||||
return $xmlWriter->getData();
|
return $xmlWriter->getData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,9 @@ class Word2007 extends AbstractWriter implements WriterInterface
|
||||||
foreach ($this->writerParts as $writer) {
|
foreach ($this->writerParts as $writer) {
|
||||||
$writer->setParentWriter($this);
|
$writer->setParentWriter($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set package paths
|
||||||
|
$this->mediaPaths = array('image' => 'word/media/', 'object' => 'word/embeddings/');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -93,6 +96,7 @@ class Word2007 extends AbstractWriter implements WriterInterface
|
||||||
$sectionMedia = Media::getElements('section');
|
$sectionMedia = Media::getElements('section');
|
||||||
if (!empty($sectionMedia)) {
|
if (!empty($sectionMedia)) {
|
||||||
$this->addFilesToPackage($objZip, $sectionMedia);
|
$this->addFilesToPackage($objZip, $sectionMedia);
|
||||||
|
$this->registerContentTypes($sectionMedia);
|
||||||
foreach ($sectionMedia as $element) {
|
foreach ($sectionMedia as $element) {
|
||||||
$this->docRels[] = $element;
|
$this->docRels[] = $element;
|
||||||
}
|
}
|
||||||
|
|
@ -140,83 +144,6 @@ class Word2007 extends AbstractWriter implements WriterInterface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Add section files to package
|
|
||||||
*
|
|
||||||
* @param mixed $objZip
|
|
||||||
* @param mixed $elements
|
|
||||||
*/
|
|
||||||
private function addFilesToPackage($objZip, $elements)
|
|
||||||
{
|
|
||||||
foreach ($elements as $element) {
|
|
||||||
// Skip link
|
|
||||||
if ($element['type'] == 'link') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve remote image
|
|
||||||
if (isset($element['isMemImage']) && $element['isMemImage']) {
|
|
||||||
$image = call_user_func($element['createFunction'], $element['source']);
|
|
||||||
ob_start();
|
|
||||||
call_user_func($element['imageFunction'], $image);
|
|
||||||
$imageContents = ob_get_contents();
|
|
||||||
ob_end_clean();
|
|
||||||
$objZip->addFromString('word/' . $element['target'], $imageContents);
|
|
||||||
imagedestroy($image);
|
|
||||||
} else {
|
|
||||||
$this->addFileToPackage($objZip, $element['source'], $element['target']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register content types
|
|
||||||
if ($element['type'] == 'image') {
|
|
||||||
$imageExtension = $element['imageExtension'];
|
|
||||||
$imageType = $element['imageType'];
|
|
||||||
if (!array_key_exists($imageExtension, $this->cTypes['default'])) {
|
|
||||||
$this->cTypes['default'][$imageExtension] = $imageType;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!array_key_exists('bin', $this->cTypes['default'])) {
|
|
||||||
$this->cTypes['default']['bin'] = 'application/vnd.openxmlformats-officedocument.oleObject';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
|
|
||||||
$zipClass = \PhpOffice\PhpWord\Settings::getZipClass();
|
|
||||||
$zip = new $zipClass();
|
|
||||||
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
|
* Add header/footer media files
|
||||||
*
|
*
|
||||||
|
|
@ -231,6 +158,7 @@ class Word2007 extends AbstractWriter implements WriterInterface
|
||||||
if (count($media) > 0) {
|
if (count($media) > 0) {
|
||||||
if (!empty($media)) {
|
if (!empty($media)) {
|
||||||
$this->addFilesToPackage($objZip, $media);
|
$this->addFilesToPackage($objZip, $media);
|
||||||
|
$this->registerContentTypes($media);
|
||||||
}
|
}
|
||||||
$relsFile = "word/_rels/{$file}.xml.rels";
|
$relsFile = "word/_rels/{$file}.xml.rels";
|
||||||
$objZip->addFromString($relsFile, $this->getWriterPart('rels')->writeMediaRels($media));
|
$objZip->addFromString($relsFile, $this->getWriterPart('rels')->writeMediaRels($media));
|
||||||
|
|
@ -281,14 +209,37 @@ class Word2007 extends AbstractWriter implements WriterInterface
|
||||||
// Add footnotes media files, relations, and contents
|
// Add footnotes media files, relations, and contents
|
||||||
if ($collection::countElements() > 0) {
|
if ($collection::countElements() > 0) {
|
||||||
$media = Media::getElements($notesType);
|
$media = Media::getElements($notesType);
|
||||||
$elements = $collection::getElements();
|
|
||||||
$this->addFilesToPackage($objZip, $media);
|
$this->addFilesToPackage($objZip, $media);
|
||||||
|
$this->registerContentTypes($media);
|
||||||
if (!empty($media)) {
|
if (!empty($media)) {
|
||||||
$objZip->addFromString($relsFile, $this->getWriterPart('rels')->writeMediaRels($media));
|
$objZip->addFromString($relsFile, $this->getWriterPart('rels')->writeMediaRels($media));
|
||||||
}
|
}
|
||||||
|
$elements = $collection::getElements();
|
||||||
$objZip->addFromString($xmlPath, $this->getWriterPart($notesTypes)->writeNotes($elements, $notesTypes));
|
$objZip->addFromString($xmlPath, $this->getWriterPart($notesTypes)->writeNotes($elements, $notesTypes));
|
||||||
$this->cTypes['override']["/{$xmlPath}"] = $notesTypes;
|
$this->cTypes['override']["/{$xmlPath}"] = $notesTypes;
|
||||||
$this->docRels[] = array('target' => $xmlFile, 'type' => $notesTypes, 'rID' => ++$rId);
|
$this->docRels[] = array('target' => $xmlFile, 'type' => $notesTypes, 'rID' => ++$rId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register content types for each media
|
||||||
|
*
|
||||||
|
* @param array $media
|
||||||
|
*/
|
||||||
|
private function registerContentTypes($media)
|
||||||
|
{
|
||||||
|
foreach ($media as $medium) {
|
||||||
|
$mediumType = $medium['type'];
|
||||||
|
if ($mediumType == 'image') {
|
||||||
|
$extension = $medium['imageExtension'];
|
||||||
|
if (!array_key_exists($extension, $this->cTypes['default'])) {
|
||||||
|
$this->cTypes['default'][$extension] = $medium['imageType'];
|
||||||
|
}
|
||||||
|
} elseif ($mediumType == 'object') {
|
||||||
|
if (!array_key_exists('bin', $this->cTypes['default'])) {
|
||||||
|
$this->cTypes['default']['bin'] = 'application/vnd.openxmlformats-officedocument.oleObject';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -98,10 +98,12 @@ class Rels extends AbstractWriterPart
|
||||||
// Media relationships
|
// Media relationships
|
||||||
if (!is_null($mediaRels) && is_array($mediaRels)) {
|
if (!is_null($mediaRels) && is_array($mediaRels)) {
|
||||||
$mapping = array('image' => 'image', 'object' => 'oleObject', 'link' => 'hyperlink');
|
$mapping = array('image' => 'image', 'object' => 'oleObject', 'link' => 'hyperlink');
|
||||||
|
$targetPaths = array('image' => 'media/', 'object' => 'embeddings/');
|
||||||
foreach ($mediaRels as $mediaRel) {
|
foreach ($mediaRels as $mediaRel) {
|
||||||
$type = $mediaRel['type'];
|
$mediaType = $mediaRel['type'];
|
||||||
$type = array_key_exists($type, $mapping) ? $mapping[$type] : $type;
|
$type = array_key_exists($mediaType, $mapping) ? $mapping[$mediaType] : $mediaType;
|
||||||
$target = $mediaRel['target'];
|
$target = array_key_exists($mediaType, $targetPaths) ? $targetPaths[$mediaType] : '';
|
||||||
|
$target .= $mediaRel['target'];
|
||||||
$targetMode = ($type == 'hyperlink') ? 'External' : '';
|
$targetMode = ($type == 'hyperlink') ? 'External' : '';
|
||||||
$this->writeRel($xmlWriter, $id++, "officeDocument/2006/relationships/{$type}", $target, $targetMode);
|
$this->writeRel($xmlWriter, $id++, "officeDocument/2006/relationships/{$type}", $target, $targetMode);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue