Skip to content

Commit

Permalink
Merge pull request #666 from Progi1984/supportSVG
Browse files Browse the repository at this point in the history
Support for Drawing (SVG format)
  • Loading branch information
Progi1984 authored Aug 5, 2021
2 parents 6ecc77c + e27128c commit f996495
Show file tree
Hide file tree
Showing 26 changed files with 3,513 additions and 307 deletions.
5 changes: 5 additions & 0 deletions docs/changes/1.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@
- Support for RadarChart - [@Progi1984](https:/Progi1984) GH-253
- ODPresentation Writer
- PowerPoint2007 Writer
- Support for Drawing (SVG format) - [@Aggiekev](https:/Aggiekev) GH-531 & [@Progi1984](https:/Progi1984) GH-666
- ODPresentation Reader
- ODPresentation Writer
- PowerPoint2007 Reader
- PowerPoint2007 Writer

## Project Management
- Migrated from Travis CI to Github Actions - [@Progi1984](https:/Progi1984) GH-635
Expand Down
14 changes: 13 additions & 1 deletion docs/usage/shapes/drawing.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
# Drawing

To create a drawing, you have four sources : File, GD, Base64 and ZipFile.
To create a drawing, you have multiples sources :

- Base64
- File
- GD
- ZipFile

You can add multiples formats of image :

- GIF
- JPEG
- PNG
- SVG

## File

Expand Down
63 changes: 38 additions & 25 deletions samples/Sample_03_Image.php

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions samples/resources/base64.txt

Large diffs are not rendered by default.

726 changes: 726 additions & 0 deletions samples/resources/tiger.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 30 additions & 16 deletions src/PhpPresentation/Reader/ODPresentation.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
use PhpOffice\PhpPresentation\DocumentProperties;
use PhpOffice\PhpPresentation\PhpPresentation;
use PhpOffice\PhpPresentation\PresentationProperties;
use PhpOffice\PhpPresentation\Shape\Drawing\Base64;
use PhpOffice\PhpPresentation\Shape\Drawing\Gd;
use PhpOffice\PhpPresentation\Shape\RichText;
use PhpOffice\PhpPresentation\Shape\RichText\Paragraph;
Expand Down Expand Up @@ -532,42 +533,55 @@ protected function loadSlide(DOMElement $nodeSlide): bool
protected function loadShapeDrawing(DOMElement $oNodeFrame): void
{
// Core
$oShape = new Gd();
$oShape->getShadow()->setVisible(false);
$mimetype = '';

$oNodeImage = $this->oXMLReader->getElement('draw:image', $oNodeFrame);
if ($oNodeImage instanceof DOMElement) {
if ($oNodeImage->hasAttribute('loext:mime-type')) {
$mimetype = $oNodeImage->getAttribute('loext:mime-type');
}
if ($oNodeImage->hasAttribute('xlink:href')) {
$sFilename = $oNodeImage->getAttribute('xlink:href');
// svm = StarView Metafile
if ('svm' == pathinfo($sFilename, PATHINFO_EXTENSION)) {
return;
}
$imageFile = $this->oZip->getFromName($sFilename);
if (!empty($imageFile)) {
$oShape->setImageResource(imagecreatefromstring($imageFile));
}
}
}

$oShape->setName($oNodeFrame->hasAttribute('draw:name') ? $oNodeFrame->getAttribute('draw:name') : '');
$oShape->setDescription($oNodeFrame->hasAttribute('draw:name') ? $oNodeFrame->getAttribute('draw:name') : '');
$oShape->setResizeProportional(false);
$oShape->setWidth($oNodeFrame->hasAttribute('svg:width') ? CommonDrawing::centimetersToPixels((float) substr($oNodeFrame->getAttribute('svg:width'), 0, -2)) : 0);
$oShape->setHeight($oNodeFrame->hasAttribute('svg:height') ? CommonDrawing::centimetersToPixels((float) substr($oNodeFrame->getAttribute('svg:height'), 0, -2)) : 0);
$oShape->setResizeProportional(true);
$oShape->setOffsetX($oNodeFrame->hasAttribute('svg:x') ? CommonDrawing::centimetersToPixels((float) substr($oNodeFrame->getAttribute('svg:x'), 0, -2)) : 0);
$oShape->setOffsetY($oNodeFrame->hasAttribute('svg:y') ? CommonDrawing::centimetersToPixels((float) substr($oNodeFrame->getAttribute('svg:y'), 0, -2)) : 0);
if (empty($imageFile)) {
return;
}

// Contents of file
if (empty($mimetype)) {
$shape = new Gd();
$shape->setImageResource(imagecreatefromstring($imageFile));
} else {
$shape = new Base64();
$shape->setData('data:' . $mimetype . ';base64,' . base64_encode($imageFile));
}

$shape->getShadow()->setVisible(false);
$shape->setName($oNodeFrame->hasAttribute('draw:name') ? $oNodeFrame->getAttribute('draw:name') : '');
$shape->setDescription($oNodeFrame->hasAttribute('draw:name') ? $oNodeFrame->getAttribute('draw:name') : '');
$shape->setResizeProportional(false);
$shape->setWidth($oNodeFrame->hasAttribute('svg:width') ? CommonDrawing::centimetersToPixels((float) substr($oNodeFrame->getAttribute('svg:width'), 0, -2)) : 0);
$shape->setHeight($oNodeFrame->hasAttribute('svg:height') ? CommonDrawing::centimetersToPixels((float) substr($oNodeFrame->getAttribute('svg:height'), 0, -2)) : 0);
$shape->setResizeProportional(true);
$shape->setOffsetX($oNodeFrame->hasAttribute('svg:x') ? CommonDrawing::centimetersToPixels((float) substr($oNodeFrame->getAttribute('svg:x'), 0, -2)) : 0);
$shape->setOffsetY($oNodeFrame->hasAttribute('svg:y') ? CommonDrawing::centimetersToPixels((float) substr($oNodeFrame->getAttribute('svg:y'), 0, -2)) : 0);

if ($oNodeFrame->hasAttribute('draw:style-name')) {
$keyStyle = $oNodeFrame->getAttribute('draw:style-name');
if (isset($this->arrayStyles[$keyStyle])) {
$oShape->setShadow($this->arrayStyles[$keyStyle]['shadow']);
$oShape->setFill($this->arrayStyles[$keyStyle]['fill']);
$shape->setShadow($this->arrayStyles[$keyStyle]['shadow']);
$shape->setFill($this->arrayStyles[$keyStyle]['fill']);
}
}

$this->oPhpPresentation->getActiveSlide()->addShape($oShape);
$this->oPhpPresentation->getActiveSlide()->addShape($shape);
}

/**
Expand Down
20 changes: 15 additions & 5 deletions src/PhpPresentation/Reader/PowerPoint2007.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use PhpOffice\PhpPresentation\DocumentProperties;
use PhpOffice\PhpPresentation\PhpPresentation;
use PhpOffice\PhpPresentation\PresentationProperties;
use PhpOffice\PhpPresentation\Shape\Drawing\Base64;
use PhpOffice\PhpPresentation\Shape\Drawing\Gd;
use PhpOffice\PhpPresentation\Shape\Placeholder;
use PhpOffice\PhpPresentation\Shape\RichText;
Expand Down Expand Up @@ -777,7 +778,12 @@ protected function loadSlideNote(string $baseFile, Slide $oSlide): void
protected function loadShapeDrawing(XMLReader $document, DOMElement $node, AbstractSlide $oSlide): void
{
// Core
$oShape = new Gd();
$document->registerNamespace('asvg', 'http://schemas.microsoft.com/office/drawing/2016/SVG/main');
if ($document->getElement('p:blipFill/a:blip/a:extLst/a:ext/asvg:svgBlip', $node)) {
$oShape = new Base64();
} else {
$oShape = new Gd();
}
$oShape->getShadow()->setVisible(false);
// Variables
$fileRels = $oSlide->getRelsIndex();
Expand Down Expand Up @@ -813,10 +819,14 @@ protected function loadShapeDrawing(XMLReader $document, DOMElement $node, Abstr
$pathImage = implode('/', $pathImage);
$imageFile = $this->oZip->getFromName($pathImage);
if (!empty($imageFile)) {
$info = getimagesizefromstring($imageFile);
$oShape->setMimeType($info['mime']);
$oShape->setRenderingFunction(str_replace('/', '', $info['mime']));
$oShape->setImageResource(imagecreatefromstring($imageFile));
if ($oShape instanceof Gd) {
$info = getimagesizefromstring($imageFile);
$oShape->setMimeType($info['mime']);
$oShape->setRenderingFunction(str_replace('/', '', $info['mime']));
$oShape->setImageResource(imagecreatefromstring($imageFile));
} elseif ($oShape instanceof Base64) {
$oShape->setData('data:image/svg+xml;base64,' . base64_encode($imageFile));
}
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/PhpPresentation/Shape/Drawing/Base64.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class Base64 extends AbstractDrawingAdapter
'image/jpeg' => 'jpg',
'image/png' => 'png',
'image/gif' => 'gif',
'image/svg+xml' => 'svg',
];

/**
Expand Down Expand Up @@ -85,6 +86,13 @@ public function getIndexedFilename(): string

public function getMimeType(): string
{
list($data) = explode(';', $this->getData());
list(, $mime) = explode(':', $data);

if (!empty($mime)) {
return $mime;
}

$sImage = $this->getContents();
if (!function_exists('getimagesizefromstring')) {
$uri = 'data://application/octet-stream;base64,' . base64_encode($sImage);
Expand Down
6 changes: 5 additions & 1 deletion src/PhpPresentation/Shape/Drawing/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@ public function getMimeType(): string
}
$image = getimagesizefromstring(CommonFile::fileGetContents($this->getPath()));

return image_type_to_mime_type($image[2]);
if (is_array($image)) {
return image_type_to_mime_type($image[2]);
}

return mime_content_type($this->getPath());
}

public function getIndexedFilename(): string
Expand Down
2 changes: 1 addition & 1 deletion src/PhpPresentation/Slide/Background/Image.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public function getFilename()
*
* @return string
*/
public function getExtension()
public function getExtension(): string
{
$exploded = explode('.', basename($this->path));

Expand Down
2 changes: 2 additions & 0 deletions src/PhpPresentation/Writer/ODPresentation/Content.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ public function writeContent(): string
$objWriter->writeAttribute('xmlns:rdfa', 'http://docs.oasis-open.org/opendocument/meta/rdfa#');
$objWriter->writeAttribute('xmlns:field', 'urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0');
$objWriter->writeAttribute('xmlns:officeooo', 'http://openoffice.org/2009/office');
$objWriter->writeAttribute('xmlns:loext', 'urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0');
$objWriter->writeAttribute('office:version', '1.2');

// office:automatic-styles
Expand Down Expand Up @@ -435,6 +436,7 @@ public function writeShapeDrawing(XMLWriter $objWriter, ShapeDrawing\AbstractDra
$objWriter->writeAttribute('xlink:type', 'simple');
$objWriter->writeAttribute('xlink:show', 'embed');
$objWriter->writeAttribute('xlink:actuate', 'onLoad');
$objWriter->writeAttribute('loext:mime-type', $shape->getMimeType());
$objWriter->writeElement('text:p');
$objWriter->endElement();

Expand Down
78 changes: 75 additions & 3 deletions src/PhpPresentation/Writer/PowerPoint2007/AbstractSlide.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use PhpOffice\PhpPresentation\Shape\AbstractGraphic;
use PhpOffice\PhpPresentation\Shape\Chart as ShapeChart;
use PhpOffice\PhpPresentation\Shape\Comment;
use PhpOffice\PhpPresentation\Shape\Drawing\AbstractDrawingAdapter;
use PhpOffice\PhpPresentation\Shape\Drawing\File as ShapeDrawingFile;
use PhpOffice\PhpPresentation\Shape\Drawing\Gd as ShapeDrawingGd;
use PhpOffice\PhpPresentation\Shape\Group;
Expand Down Expand Up @@ -1148,27 +1149,54 @@ protected function writeShapePic(XMLWriter $objWriter, AbstractGraphic $shape, i
{
// p:pic
$objWriter->startElement('p:pic');

// p:nvPicPr
$objWriter->startElement('p:nvPicPr');

// p:cNvPr
$objWriter->startElement('p:cNvPr');
$objWriter->writeAttribute('id', $shapeId);
$objWriter->writeAttribute('name', $shape->getName());
$objWriter->writeAttribute('descr', $shape->getDescription());

// a:hlinkClick
if ($shape->hasHyperlink()) {
$this->writeHyperlink($objWriter, $shape);
}

if ($shape instanceof AbstractDrawingAdapter && $shape->getExtension() == 'svg') {
$objWriter->startElement('a:extLst');
$objWriter->startElement('a:ext');
$objWriter->writeAttribute('uri', '{FF2B5EF4-FFF2-40B4-BE49-F238E27FC236}');
$objWriter->startElement('a16:creationId');
$objWriter->writeAttribute('xmlns:a16', 'http://schemas.microsoft.com/office/drawing/2014/main');
$objWriter->writeAttribute('id', '{F8CFD691-5332-EB49-9B42-7D7B3DB9185D}');
$objWriter->endElement();
$objWriter->endElement();
$objWriter->endElement();
}

$objWriter->endElement();

// p:cNvPicPr
$objWriter->startElement('p:cNvPicPr');

// a:picLocks
$objWriter->startElement('a:picLocks');
$objWriter->writeAttribute('noChangeAspect', '1');
$objWriter->endElement();

// #p:cNvPicPr
$objWriter->endElement();

// p:nvPr
$objWriter->startElement('p:nvPr');
// PlaceHolder
if ($shape->isPlaceholder()) {
$objWriter->startElement('p:ph');
$objWriter->writeAttribute('type', $shape->getPlaceholder()->getType());
$objWriter->endElement();
}
/*
* @link : https:/stefslon/exportToPPTX/blob/master/exportToPPTX.m#L2128
*/
Expand All @@ -1184,7 +1212,7 @@ protected function writeShapePic(XMLWriter $objWriter, AbstractGraphic $shape, i
$objWriter->writeAttribute('uri', '{DAA4B4D4-6D71-4841-9C94-3DE7FCFB9230}');
// p:nvPr > p:extLst > p:ext > p14:media
$objWriter->startElement('p14:media');
$objWriter->writeAttribute('r:embed', $shape->relationId);
$objWriter->writeAttribute('r:embed', ((int) $shape->relationId + 1));
$objWriter->writeAttribute('xmlns:p14', 'http://schemas.microsoft.com/office/powerpoint/2010/main');
// p:nvPr > p:extLst > p:ext > ##p14:media
$objWriter->endElement();
Expand All @@ -1196,45 +1224,89 @@ protected function writeShapePic(XMLWriter $objWriter, AbstractGraphic $shape, i
// ##p:nvPr
$objWriter->endElement();
$objWriter->endElement();

// p:blipFill
$objWriter->startElement('p:blipFill');

// a:blip
$objWriter->startElement('a:blip');
$objWriter->writeAttribute('r:embed', $shape->relationId);

if ($shape instanceof AbstractDrawingAdapter && $shape->getExtension() == 'svg') {
// a:extLst
$objWriter->startElement('a:extLst');

// a:extLst > a:ext
$objWriter->startElement('a:ext');
$objWriter->writeAttribute('uri', '{28A0092B-C50C-407E-A947-70E740481C1C}');
// a:extLst > a:ext > a14:useLocalDpi
$objWriter->startElement('a14:useLocalDpi');
$objWriter->writeAttribute('xmlns:a14', 'http://schemas.microsoft.com/office/drawing/2010/main');
$objWriter->writeAttribute('val', '0');
// a:extLst > a:ext > ##a14:useLocalDpi
$objWriter->endElement();
// a:extLst > ##a:ext
$objWriter->endElement();

// a:extLst > a:ext
$objWriter->startElement('a:ext');
$objWriter->writeAttribute('uri', '{96DAC541-7B7A-43D3-8B79-37D633B846F1}');
// a:extLst > a:ext > asvg:svgBlip
$objWriter->startElement('asvg:svgBlip');
$objWriter->writeAttribute('xmlns:asvg', 'http://schemas.microsoft.com/office/drawing/2016/SVG/main');
$objWriter->writeAttribute('r:embed', $shape->relationId);
// a:extLst > a:ext > ##asvg:svgBlip
$objWriter->endElement();
// a:extLst > ##a:ext
$objWriter->endElement();

// ##a:extLst
$objWriter->endElement();
}

$objWriter->endElement();

// a:stretch
$objWriter->startElement('a:stretch');
$objWriter->writeElement('a:fillRect', null);
$objWriter->writeElement('a:fillRect');
$objWriter->endElement();

$objWriter->endElement();

// p:spPr
$objWriter->startElement('p:spPr');
// a:xfrm
$objWriter->startElement('a:xfrm');
$objWriter->writeAttributeIf(0 != $shape->getRotation(), 'rot', CommonDrawing::degreesToAngle($shape->getRotation()));

// a:off
$objWriter->startElement('a:off');
$objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($shape->getOffsetX()));
$objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($shape->getOffsetY()));
$objWriter->endElement();

// a:ext
$objWriter->startElement('a:ext');
$objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu($shape->getWidth()));
$objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu($shape->getHeight()));
$objWriter->endElement();

$objWriter->endElement();

// a:prstGeom
$objWriter->startElement('a:prstGeom');
$objWriter->writeAttribute('prst', 'rect');
// a:avLst
// // a:prstGeom/a:avLst
$objWriter->writeElement('a:avLst', null);
// ##a:prstGeom
$objWriter->endElement();

$this->writeFill($objWriter, $shape->getFill());
$this->writeBorder($objWriter, $shape->getBorder(), '');
$this->writeShadow($objWriter, $shape->getShadow());

$objWriter->endElement();

$objWriter->endElement();
}

Expand Down
3 changes: 3 additions & 0 deletions src/PhpPresentation/Writer/PowerPoint2007/ContentTypes.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ public function render()
// XML
$this->writeDefaultContentType($objWriter, 'xml', 'application/xml');

// SVG
$this->writeDefaultContentType($objWriter, 'svg', 'image/svg+xml');

// Presentation
$this->writeOverrideContentType($objWriter, '/ppt/presentation.xml', 'application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml');

Expand Down
Loading

0 comments on commit f996495

Please sign in to comment.