ODT Writer: Basic image writing support

This commit is contained in:
Ivan Lanin 2014-04-18 23:12:51 +07:00
parent f5f03a5b2b
commit f829559f65
10 changed files with 281 additions and 125 deletions

View File

@ -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

View File

@ -89,7 +89,7 @@ Writers
+ +-----------------------+--------+-------+-------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | Table | ✓ | ✓ | | ✓ | ✓ | | | Table | ✓ | ✓ | | ✓ | ✓ |
+ +-----------------------+--------+-------+-------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | Image | ✓ | | | ✓ | | | | Image | ✓ | | | ✓ | |
+ +-----------------------+--------+-------+-------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+
| | Object | ✓ | | | | | | | Object | ✓ | | | | |
+ +-----------------------+--------+-------+-------+-------+-------+ + +-----------------------+--------+-------+-------+-------+-------+

View File

@ -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
* *

View File

@ -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'];
} }
} }

View File

@ -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
* *

View File

@ -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));

View File

@ -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
} }
} }

View File

@ -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();
} }
} }

View File

@ -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';
}
}
}
}
} }

View File

@ -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);
} }