Skip to content

Improved Word2007 Reader to read images when pictures is between <wp:anchor> #1799

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/PhpWord/Element/Image.php
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ class Image extends AbstractElement
public function __construct($source, $style = null, $watermark = false, $name = null)
{
$this->source = $source;
$this->style = $this->setNewStyle(new ImageStyle(), $style, true);
$this->style = $this->setNewStyle(new ImageStyle(), $style, is_null($style));
$this->setIsWatermark($watermark);
$this->setName($name);

Expand Down
65 changes: 49 additions & 16 deletions src/PhpWord/Reader/Word2007/AbstractPart.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use PhpOffice\PhpWord\Element\TextRun;
use PhpOffice\PhpWord\Element\TrackChange;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Style\Image as ImageStyle;
use PhpOffice\PhpWord\Shared\XMLReader;

/**
Expand Down Expand Up @@ -263,22 +264,7 @@ protected function readRunChild(XMLReader $xmlReader, \DOMElement $node, Abstrac
}
} elseif ($node->nodeName == 'w:drawing') {
// Office 2011 Image
$xmlReader->registerNamespace('wp', 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing');
$xmlReader->registerNamespace('r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
$xmlReader->registerNamespace('pic', 'http://schemas.openxmlformats.org/drawingml/2006/picture');
$xmlReader->registerNamespace('a', 'http://schemas.openxmlformats.org/drawingml/2006/main');

$name = $xmlReader->getAttribute('name', $node, 'wp:inline/a:graphic/a:graphicData/pic:pic/pic:nvPicPr/pic:cNvPr');
$embedId = $xmlReader->getAttribute('r:embed', $node, 'wp:inline/a:graphic/a:graphicData/pic:pic/pic:blipFill/a:blip');
if ($name === null && $embedId === null) { // some Converters puts images on a different path
$name = $xmlReader->getAttribute('name', $node, 'wp:anchor/a:graphic/a:graphicData/pic:pic/pic:nvPicPr/pic:cNvPr');
$embedId = $xmlReader->getAttribute('r:embed', $node, 'wp:anchor/a:graphic/a:graphicData/pic:pic/pic:blipFill/a:blip');
}
$target = $this->getMediaTarget($docPart, $embedId);
if (!is_null($target)) {
$imageSource = "zip://{$this->docFile}#{$target}";
$parent->addImage($imageSource, null, false, $name);
}
$this->readImage($xmlReader, $node, $parent, $docPart);
} elseif ($node->nodeName == 'w:object') {
// Object
$rId = $xmlReader->getAttribute('r:id', $node, 'o:OLEObject');
Expand Down Expand Up @@ -330,6 +316,53 @@ protected function readRunChild(XMLReader $xmlReader, \DOMElement $node, Abstrac
}
}

/**
* Parses node w:drawing
*
* @param XMLReader $xmlReader
* @param \DOMElement $node
* @param AbstractContainer $parent
* @param string $docPart
*/
protected function readImage(XMLReader $xmlReader, \DOMElement $node, AbstractContainer $parent, $docPart)
{
$xmlReader->registerNamespace('wp', 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing');
$xmlReader->registerNamespace('r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
$xmlReader->registerNamespace('pic', 'http://schemas.openxmlformats.org/drawingml/2006/picture');
$xmlReader->registerNamespace('a', 'http://schemas.openxmlformats.org/drawingml/2006/main');

$name = null;
$embedId = null;

$graphicParent = $xmlReader->getElement('wp:inline', $node);
if (is_null($graphicParent)) {
$graphicParent = $xmlReader->getElement('wp:anchor', $node);
}
/* get the height and width of the image in this document */
$imageWidth = $xmlReader->getAttribute('cx', $graphicParent, 'wp:extent');
$imageHeight = $xmlReader->getAttribute('cy', $graphicParent, 'wp:extent');
$style = null;
if (!is_null($imageWidth) && !is_null($imageHeight)) {
$style = new ImageStyle();
$style->setUnit(ImageStyle::UNIT_PT);

/* transform EMUs to pt - 1 inch is 914400 EMUs */
$imageWidth = (int) ($imageWidth) / (914400 / 72);
$imageHeight = (int) ($imageHeight) / (914400 / 72);
$style->setWidth($imageWidth);
$style->setHeight($imageHeight);
}

$name = $xmlReader->getAttribute('name', $graphicParent, 'a:graphic/a:graphicData/pic:pic/pic:nvPicPr/pic:cNvPr');
$embedId = $xmlReader->getAttribute('r:embed', $graphicParent, 'a:graphic/a:graphicData/pic:pic/pic:blipFill/a:blip');

$target = $this->getMediaTarget($docPart, $embedId);
if (!is_null($target)) {
$imageSource = "zip://{$this->docFile}#{$target}";
$parent->addImage($imageSource, $style, false, $name);
}
}

/**
* Read w:tbl.
*
Expand Down
81 changes: 79 additions & 2 deletions tests/PhpWord/Reader/Word2007/ElementTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ public function testReadDrawing()
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:nvPicPr>
<pic:cNvPr id="1" name="file_name.jpg"/>
<pic:cNvPr id="1" name="mars.jpg"/>
<pic:cNvPicPr/>
</pic:nvPicPr>
<pic:blipFill>
Expand All @@ -307,9 +307,86 @@ public function testReadDrawing()
</w:r>
</w:p>';

$phpWord = $this->getDocumentFromString(array('document' => $documentXml));
//$resolutionXml = '<Relationship Id="rId4" Target="media/mars.jpg" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"/>';
$relationships = array(
'document' => array(
'rId4' => array(
'target' => 'media/mars.jpg',
'type' => 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image',
),
),
);

$media = array(
__DIR__ . '/../../_files/images/mars.jpg',
);

$phpWord = $this->getDocumentFromString(array('document' => $documentXml), $relationships, $media);

$elements = $phpWord->getSection(0)->getElements();
$this->assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]);

$children = $elements[0]->getElements();
$this->assertInstanceOf('PhpOffice\PhpWord\Element\Image', $children[0]);
}

/**
* Test reading Drawing with anchors
*/
public function testReadDrawingWithAnchor()
{
$documentXml = '<w:p>
<w:r>
<w:drawing xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing">
<wp:anchor allowOverlap="1" behindDoc="0" distB="0" distL="0" distR="0" distT="0" layoutInCell="1" locked="0" relativeHeight="2" simplePos="0">
<wp:extent cx="5727700" cy="6621145"/>
<wp:docPr id="1" name="Picture 1"/>
<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:nvPicPr>
<pic:cNvPr id="1" name="mars.jpg"/>
<pic:cNvPicPr/>
</pic:nvPicPr>
<pic:blipFill>
<a:blip r:embed="rId4" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
</a:blip>
</pic:blipFill>
</pic:pic>
</a:graphicData>
</a:graphic>
</wp:anchor>
</w:drawing>
</w:r>
</w:p>';

//$resolutionXml = '<Relationship Id="rId4" Target="media/mars.jpg" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"/>';
$relationships = array(
'document' => array(
'rId4' => array(
'target' => 'media/mars.jpg',
'type' => 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image',
),
),
);

$media = array(
__DIR__ . '/../../_files/images/mars.jpg',
);

$phpWord = $this->getDocumentFromString(array('document' => $documentXml), $relationships, $media);

$elements = $phpWord->getSection(0)->getElements();
$this->assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]);

$children = $elements[0]->getElements();
$this->assertInstanceOf('PhpOffice\PhpWord\Element\Image', $children[0]);

$style = $children[0]->getStyle();
$this->assertInstanceOf('PhpOffice\PhpWord\Style\Image', $style);

$this->assertEquals('pt', $style->getUnit());
$this->assertEquals('451', $style->getWidth());
$this->assertEquals('521.35', $style->getHeight());
}
}
20 changes: 17 additions & 3 deletions tests/PhpWord/_includes/AbstractTestReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ abstract class AbstractTestReader extends \PHPUnit\Framework\TestCase
/**
* Builds a PhpWord instance based on the xml passed
*
* @param string $documentXml
* @param null|string $stylesXml
* @param array $partXmls
* @param array $rels
* @param array $media
* @return \PhpOffice\PhpWord\PhpWord
*/
protected function getDocumentFromString(array $partXmls = array())
protected function getDocumentFromString(array $partXmls = array(), array $rels = array(), array $media = array())
{
$file = __DIR__ . '/../_files/temp.docx';
$zip = new \ZipArchive();
Expand All @@ -47,13 +48,26 @@ protected function getDocumentFromString(array $partXmls = array())
$zip->addFromString("{$partName}.xml", str_replace('{toReplace}', $partXmls[$partName], $this->parts[$partName]['xml']));
}
}

if (!empty($media)) {
$zip->addEmptyDir('media');

foreach ($media as $image) {
$zip->addFile($image, 'media/' . basename($image));
}
}
$zip->close();

$phpWord = new PhpWord();
foreach ($this->parts as $partName => $part) {
if (array_key_exists($partName, $partXmls)) {
$className = $this->parts[$partName]['class'];
$reader = new $className($file, "{$partName}.xml");

if (isset($rels[$partName])) {
$reader->setRels($rels);
}

$reader->read($phpWord);
}
}
Expand Down