PHPPresentation
PHPPresentation copied to clipboard
Powerpoint2007 Reader : Implement fill in RichText
I'm having an issue where I'm attempting to load an existing PPTX file, with a background fill colour, defined as an "Area" in LibreOffice Impress, or as a solidFill in the slide XML.
All background fill colours, or "Area" shapes, appear to be completely discarded by IOFactory's load function.
I thought it was just me, so I modified Sample_06_Fill.php to attempt to reload, then resave the PPTX file it just generated, adding the following block of code just before the Sample_Footer:
$oReaderPPTX = IOFactory::createReader('PowerPoint2007');
$phpPowerpoint = $oReaderPPTX->load('results/Sample_06_Fill.pptx');
$oWriterPPTX = IOFactory::createWriter($phpPowerpoint, 'PowerPoint2007');
$oWriterPPTX->save("results/Sample_06_Fill_Reload.pptx");
The resultant PPTX file has all its background colours stripped out.
I've done tests with very simple PPTX files, where there's a single area of colour on the page and nothing else, and the slide's shape collection is entirely empty.
Does the load function discard areas?
<?php
include_once 'Sample_Header.php';
use PhpOffice\PhpPresentation\PhpPresentation;
use PhpOffice\PhpPresentation\Style\Alignment;
use PhpOffice\PhpPresentation\Style\Color;
use PhpOffice\PhpPresentation\Style\Fill;
use PhpOffice\PhpPresentation\IOFactory;
// Create new PHPPresentation object
echo date('H:i:s') . ' Create new PHPPresentation object' . EOL;
$objPHPPresentation = new PhpPresentation();
// Set properties
echo date('H:i:s') . ' Set properties'.EOL;
$objPHPPresentation->getDocumentProperties()->setCreator('PHPOffice')
->setLastModifiedBy('PHPPresentation Team')
->setTitle('Sample 01 Title')
->setSubject('Sample 01 Subject')
->setDescription('Sample 01 Description')
->setKeywords('office 2007 openxml libreoffice odt php')
->setCategory('Sample Category');
// Create slide
echo date('H:i:s') . ' Create slide'.EOL;
$currentSlide = $objPHPPresentation->getActiveSlide();
for($inc = 1 ; $inc <= 4 ; $inc++){
// Create a shape (text)
echo date('H:i:s') . ' Create a shape (rich text)'.EOL;
$shape = $currentSlide->createRichTextShape()
->setHeight(200)
->setWidth(300);
if($inc == 1 || $inc == 3){
$shape->setOffsetX(10);
} else {
$shape->setOffsetX(320);
}
if($inc == 1 || $inc == 2){
$shape->setOffsetY(10);
} else {
$shape->setOffsetY(220);
}
$shape->getActiveParagraph()->getAlignment()->setHorizontal( Alignment::HORIZONTAL_CENTER );
switch ($inc) {
case 1 :
$shape->getFill()->setFillType(Fill::FILL_NONE);
break;
case 2 :
$shape->getFill()->setFillType(Fill::FILL_GRADIENT_LINEAR)->setRotation(90)->setStartColor(new Color( 'FF4672A8' ))->setEndColor(new Color( 'FF000000' ));
break;
case 3 :
$shape->getFill()->setFillType(Fill::FILL_GRADIENT_PATH)->setRotation(90)->setStartColor(new Color( 'FF4672A8' ))->setEndColor(new Color( 'FF000000' ));
break;
case 4 :
$shape->getFill()->setFillType(Fill::FILL_SOLID)->setRotation(90)->setStartColor(new Color( 'FF4672A8' ))->setEndColor(new Color( 'FF4672A8' ));
break;
}
$textRun = $shape->createTextRun('Use PHPPresentation!');
$textRun->getFont()->setBold(true)
->setSize(30)
->setColor( new Color('FFE06B20') );
}
$oReaderPPTX = IOFactory::createReader('PowerPoint2007');
$phpPowerpoint = $oReaderPPTX->load('results/Sample_06_Fill.pptx');
$oWriterPPTX = IOFactory::createWriter($phpPowerpoint, 'PowerPoint2007');
$oWriterPPTX->save("results/Sample_06_Fill_Reload.pptx");
// Save file
echo write($objPHPPresentation, basename(__FILE__, '.php'), $writers);
if (!CLI) {
include_once 'Sample_Footer.php';
}
SampleArea's Slide XML:
<p:sp> <p:nvSpPr> <p:cNvPr id="82" name="CustomShape 1"></p:cNvPr> <p:cNvSpPr/> <p:nvPr/> </p:nvSpPr> <p:spPr> <a:xfrm> <a:off x="0" y="0"/> <a:ext cx="9143640" cy="3456000"/> </a:xfrm> <a:prstGeom prst="rect"> <a:avLst></a:avLst> </a:prstGeom> <a:solidFill> <a:srgbClr val="ff0000"/> </a:solidFill> <a:ln> <a:noFill/> </a:ln> </p:spPr> <p:style> <a:lnRef idx="2"> <a:schemeClr val="accent1"> <a:shade val="50000"/> </a:schemeClr> </a:lnRef> <a:fillRef idx="1"> <a:schemeClr val="accent1"/> </a:fillRef> <a:effectRef idx="0"> <a:schemeClr val="accent1"/> </a:effectRef> <a:fontRef idx="minor"/> </p:style> </p:sp>
It's not implemented for the moment :).
Here's hoping for Hacktoberfest then. :)
I wasn't patient enough for Hacktoberfest. :)
Note that this is NOT a complete solution. It only takes into account solid backgrounds. But it might be a strong hint to anyone who wishes to tackle this.
I subclassed Reader/PowerPoint2007.php for my own purposes. Here's my revised loadShapeRichText(). Note that the initial return statement has been dropped, that a final else statement has been handled to add a paragraph in case one has been missing, and a new $oElement block that watches for a p:spPr/a:solidFill/a:srgbClr block.
protected function loadShapeRichText(XMLReader $document, \DOMElement $node, $oSlide)
{
// Core
$oShape = $oSlide->createRichTextShape();
$oShape->setParagraphs(array());
// Variables
if ($oSlide instanceof AbstractSlide) {
$this->fileRels = $oSlide->getRelsIndex();
}
$oElement = $document->getElement('p:spPr/a:xfrm', $node);
if ($oElement instanceof \DOMElement && $oElement->hasAttribute('rot')) {
$oShape->setRotation(CommonDrawing::angleToDegrees($oElement->getAttribute('rot')));
}
$oElement = $document->getElement('p:spPr/a:xfrm/a:off', $node);
if ($oElement instanceof \DOMElement) {
if ($oElement->hasAttribute('x')) {
$oShape->setOffsetX(CommonDrawing::emuToPixels($oElement->getAttribute('x')));
}
if ($oElement->hasAttribute('y')) {
$oShape->setOffsetY(CommonDrawing::emuToPixels($oElement->getAttribute('y')));
}
}
$oElement = $document->getElement('p:spPr/a:xfrm/a:ext', $node);
if ($oElement instanceof \DOMElement) {
if ($oElement->hasAttribute('cx')) {
$oShape->setWidth(CommonDrawing::emuToPixels($oElement->getAttribute('cx')));
}
if ($oElement->hasAttribute('cy')) {
$oShape->setHeight(CommonDrawing::emuToPixels($oElement->getAttribute('cy')));
}
}
$oElement = $document->getElement('p:spPr/a:solidFill/a:srgbClr', $node);
if (is_object($oElement) && $oElement->hasAttribute('val')) {
$oColor = new Color();
$oColor->setRGB($oElement->getAttribute('val'));
$oShape->getFill()->setFillType(Fill::FILL_SOLID)
->setStartColor($oColor)
->setEndColor($oColor);
}
$oElement = $document->getElement('p:nvSpPr/p:nvPr/p:ph', $node);
if ($oElement instanceof \DOMElement) {
if ($oElement->hasAttribute('type')) {
$placeholder = new Placeholder($oElement->getAttribute('type'));
$oShape->setPlaceHolder($placeholder);
}
}
$arrayElements = $document->getElements('p:txBody/a:p', $node);
foreach ($arrayElements as $oElement) {
$this->loadParagraph($document, $oElement, $oShape);
}
if (count($oShape->getParagraphs()) > 0) {
$oShape->setActiveParagraph(0);
} else {
// Create missing shape
$oShape->createParagraph();
}
}