3 namespace PhpOffice\PhpSpreadsheet\Writer\Xlsx
;
5 use PhpOffice\PhpSpreadsheet\Cell\Coordinate
;
6 use PhpOffice\PhpSpreadsheet\Shared\XMLWriter
;
7 use PhpOffice\PhpSpreadsheet\Spreadsheet
;
8 use PhpOffice\PhpSpreadsheet\Worksheet\BaseDrawing
;
9 use PhpOffice\PhpSpreadsheet\Worksheet\HeaderFooterDrawing
;
10 use PhpOffice\PhpSpreadsheet\Writer\Exception
as WriterException
;
12 class Drawing
extends WriterPart
15 * Write drawings to XML format.
17 * @param \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet
18 * @param bool $includeCharts Flag indicating if we should include drawing details for charts
20 * @throws WriterException
22 * @return string XML Output
24 public function writeDrawings(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet
$pWorksheet, $includeCharts = false)
28 if ($this->getParentWriter()->getUseDiskCaching()) {
29 $objWriter = new XMLWriter(XMLWriter
::STORAGE_DISK
, $this->getParentWriter()->getDiskCachingDirectory());
31 $objWriter = new XMLWriter(XMLWriter
::STORAGE_MEMORY
);
35 $objWriter->startDocument('1.0', 'UTF-8', 'yes');
38 $objWriter->startElement('xdr:wsDr');
39 $objWriter->writeAttribute('xmlns:xdr', 'http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing');
40 $objWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main');
42 // Loop through images and write drawings
44 $iterator = $pWorksheet->getDrawingCollection()->getIterator();
45 while ($iterator->valid()) {
46 $this->writeDrawing($objWriter, $iterator->current(), $i);
53 $chartCount = $pWorksheet->getChartCount();
54 // Loop through charts and write the chart position
55 if ($chartCount > 0) {
56 for ($c = 0; $c < $chartCount; ++
$c) {
57 $this->writeChart($objWriter, $pWorksheet->getChartByIndex($c), $c +
$i);
62 // unparsed AlternateContent
63 $unparsedLoadedData = $pWorksheet->getParent()->getUnparsedLoadedData();
64 if (isset($unparsedLoadedData['sheets'][$pWorksheet->getCodeName()]['drawingAlternateContents'])) {
65 foreach ($unparsedLoadedData['sheets'][$pWorksheet->getCodeName()]['drawingAlternateContents'] as $drawingAlternateContent) {
66 $objWriter->writeRaw($drawingAlternateContent);
70 $objWriter->endElement();
73 return $objWriter->getData();
77 * Write drawings to XML format.
79 * @param XMLWriter $objWriter XML Writer
80 * @param \PhpOffice\PhpSpreadsheet\Chart\Chart $pChart
81 * @param int $pRelationId
83 public function writeChart(XMLWriter
$objWriter, \PhpOffice\PhpSpreadsheet\Chart\Chart
$pChart, $pRelationId = -1)
85 $tl = $pChart->getTopLeftPosition();
86 $tl['colRow'] = Coordinate
::coordinateFromString($tl['cell']);
87 $br = $pChart->getBottomRightPosition();
88 $br['colRow'] = Coordinate
::coordinateFromString($br['cell']);
90 $objWriter->startElement('xdr:twoCellAnchor');
92 $objWriter->startElement('xdr:from');
93 $objWriter->writeElement('xdr:col', Coordinate
::columnIndexFromString($tl['colRow'][0]) - 1);
94 $objWriter->writeElement('xdr:colOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing
::pixelsToEMU($tl['xOffset']));
95 $objWriter->writeElement('xdr:row', $tl['colRow'][1] - 1);
96 $objWriter->writeElement('xdr:rowOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing
::pixelsToEMU($tl['yOffset']));
97 $objWriter->endElement();
98 $objWriter->startElement('xdr:to');
99 $objWriter->writeElement('xdr:col', Coordinate
::columnIndexFromString($br['colRow'][0]) - 1);
100 $objWriter->writeElement('xdr:colOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing
::pixelsToEMU($br['xOffset']));
101 $objWriter->writeElement('xdr:row', $br['colRow'][1] - 1);
102 $objWriter->writeElement('xdr:rowOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing
::pixelsToEMU($br['yOffset']));
103 $objWriter->endElement();
105 $objWriter->startElement('xdr:graphicFrame');
106 $objWriter->writeAttribute('macro', '');
107 $objWriter->startElement('xdr:nvGraphicFramePr');
108 $objWriter->startElement('xdr:cNvPr');
109 $objWriter->writeAttribute('name', 'Chart ' . $pRelationId);
110 $objWriter->writeAttribute('id', 1025 * $pRelationId);
111 $objWriter->endElement();
112 $objWriter->startElement('xdr:cNvGraphicFramePr');
113 $objWriter->startElement('a:graphicFrameLocks');
114 $objWriter->endElement();
115 $objWriter->endElement();
116 $objWriter->endElement();
118 $objWriter->startElement('xdr:xfrm');
119 $objWriter->startElement('a:off');
120 $objWriter->writeAttribute('x', '0');
121 $objWriter->writeAttribute('y', '0');
122 $objWriter->endElement();
123 $objWriter->startElement('a:ext');
124 $objWriter->writeAttribute('cx', '0');
125 $objWriter->writeAttribute('cy', '0');
126 $objWriter->endElement();
127 $objWriter->endElement();
129 $objWriter->startElement('a:graphic');
130 $objWriter->startElement('a:graphicData');
131 $objWriter->writeAttribute('uri', 'http://schemas.openxmlformats.org/drawingml/2006/chart');
132 $objWriter->startElement('c:chart');
133 $objWriter->writeAttribute('xmlns:c', 'http://schemas.openxmlformats.org/drawingml/2006/chart');
134 $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
135 $objWriter->writeAttribute('r:id', 'rId' . $pRelationId);
136 $objWriter->endElement();
137 $objWriter->endElement();
138 $objWriter->endElement();
139 $objWriter->endElement();
141 $objWriter->startElement('xdr:clientData');
142 $objWriter->endElement();
144 $objWriter->endElement();
148 * Write drawings to XML format.
150 * @param XMLWriter $objWriter XML Writer
151 * @param BaseDrawing $pDrawing
152 * @param int $pRelationId
154 * @throws WriterException
156 public function writeDrawing(XMLWriter
$objWriter, BaseDrawing
$pDrawing, $pRelationId = -1)
158 if ($pRelationId >= 0) {
160 $objWriter->startElement('xdr:oneCellAnchor');
162 $aCoordinates = Coordinate
::coordinateFromString($pDrawing->getCoordinates());
163 $aCoordinates[0] = Coordinate
::columnIndexFromString($aCoordinates[0]);
166 $objWriter->startElement('xdr:from');
167 $objWriter->writeElement('xdr:col', $aCoordinates[0] - 1);
168 $objWriter->writeElement('xdr:colOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing
::pixelsToEMU($pDrawing->getOffsetX()));
169 $objWriter->writeElement('xdr:row', $aCoordinates[1] - 1);
170 $objWriter->writeElement('xdr:rowOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing
::pixelsToEMU($pDrawing->getOffsetY()));
171 $objWriter->endElement();
174 $objWriter->startElement('xdr:ext');
175 $objWriter->writeAttribute('cx', \PhpOffice\PhpSpreadsheet\Shared\Drawing
::pixelsToEMU($pDrawing->getWidth()));
176 $objWriter->writeAttribute('cy', \PhpOffice\PhpSpreadsheet\Shared\Drawing
::pixelsToEMU($pDrawing->getHeight()));
177 $objWriter->endElement();
180 $objWriter->startElement('xdr:pic');
183 $objWriter->startElement('xdr:nvPicPr');
186 $objWriter->startElement('xdr:cNvPr');
187 $objWriter->writeAttribute('id', $pRelationId);
188 $objWriter->writeAttribute('name', $pDrawing->getName());
189 $objWriter->writeAttribute('descr', $pDrawing->getDescription());
190 $objWriter->endElement();
193 $objWriter->startElement('xdr:cNvPicPr');
196 $objWriter->startElement('a:picLocks');
197 $objWriter->writeAttribute('noChangeAspect', '1');
198 $objWriter->endElement();
200 $objWriter->endElement();
202 $objWriter->endElement();
205 $objWriter->startElement('xdr:blipFill');
208 $objWriter->startElement('a:blip');
209 $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
210 $objWriter->writeAttribute('r:embed', 'rId' . $pRelationId);
211 $objWriter->endElement();
214 $objWriter->startElement('a:stretch');
215 $objWriter->writeElement('a:fillRect', null);
216 $objWriter->endElement();
218 $objWriter->endElement();
221 $objWriter->startElement('xdr:spPr');
224 $objWriter->startElement('a:xfrm');
225 $objWriter->writeAttribute('rot', \PhpOffice\PhpSpreadsheet\Shared\Drawing
::degreesToAngle($pDrawing->getRotation()));
226 $objWriter->endElement();
229 $objWriter->startElement('a:prstGeom');
230 $objWriter->writeAttribute('prst', 'rect');
233 $objWriter->writeElement('a:avLst', null);
235 $objWriter->endElement();
237 if ($pDrawing->getShadow()->getVisible()) {
239 $objWriter->startElement('a:effectLst');
242 $objWriter->startElement('a:outerShdw');
243 $objWriter->writeAttribute('blurRad', \PhpOffice\PhpSpreadsheet\Shared\Drawing
::pixelsToEMU($pDrawing->getShadow()->getBlurRadius()));
244 $objWriter->writeAttribute('dist', \PhpOffice\PhpSpreadsheet\Shared\Drawing
::pixelsToEMU($pDrawing->getShadow()->getDistance()));
245 $objWriter->writeAttribute('dir', \PhpOffice\PhpSpreadsheet\Shared\Drawing
::degreesToAngle($pDrawing->getShadow()->getDirection()));
246 $objWriter->writeAttribute('algn', $pDrawing->getShadow()->getAlignment());
247 $objWriter->writeAttribute('rotWithShape', '0');
250 $objWriter->startElement('a:srgbClr');
251 $objWriter->writeAttribute('val', $pDrawing->getShadow()->getColor()->getRGB());
254 $objWriter->startElement('a:alpha');
255 $objWriter->writeAttribute('val', $pDrawing->getShadow()->getAlpha() * 1000);
256 $objWriter->endElement();
258 $objWriter->endElement();
260 $objWriter->endElement();
262 $objWriter->endElement();
264 $objWriter->endElement();
266 $objWriter->endElement();
269 $objWriter->writeElement('xdr:clientData', null);
271 $objWriter->endElement();
273 throw new WriterException('Invalid parameters passed.');
278 * Write VML header/footer images to XML format.
280 * @param \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet
282 * @throws WriterException
284 * @return string XML Output
286 public function writeVMLHeaderFooterImages(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet
$pWorksheet)
290 if ($this->getParentWriter()->getUseDiskCaching()) {
291 $objWriter = new XMLWriter(XMLWriter
::STORAGE_DISK
, $this->getParentWriter()->getDiskCachingDirectory());
293 $objWriter = new XMLWriter(XMLWriter
::STORAGE_MEMORY
);
297 $objWriter->startDocument('1.0', 'UTF-8', 'yes');
299 // Header/footer images
300 $images = $pWorksheet->getHeaderFooter()->getImages();
303 $objWriter->startElement('xml');
304 $objWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml');
305 $objWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office');
306 $objWriter->writeAttribute('xmlns:x', 'urn:schemas-microsoft-com:office:excel');
309 $objWriter->startElement('o:shapelayout');
310 $objWriter->writeAttribute('v:ext', 'edit');
313 $objWriter->startElement('o:idmap');
314 $objWriter->writeAttribute('v:ext', 'edit');
315 $objWriter->writeAttribute('data', '1');
316 $objWriter->endElement();
318 $objWriter->endElement();
321 $objWriter->startElement('v:shapetype');
322 $objWriter->writeAttribute('id', '_x0000_t75');
323 $objWriter->writeAttribute('coordsize', '21600,21600');
324 $objWriter->writeAttribute('o:spt', '75');
325 $objWriter->writeAttribute('o:preferrelative', 't');
326 $objWriter->writeAttribute('path', 'm@4@5l@4@11@9@11@9@5xe');
327 $objWriter->writeAttribute('filled', 'f');
328 $objWriter->writeAttribute('stroked', 'f');
331 $objWriter->startElement('v:stroke');
332 $objWriter->writeAttribute('joinstyle', 'miter');
333 $objWriter->endElement();
336 $objWriter->startElement('v:formulas');
339 $objWriter->startElement('v:f');
340 $objWriter->writeAttribute('eqn', 'if lineDrawn pixelLineWidth 0');
341 $objWriter->endElement();
344 $objWriter->startElement('v:f');
345 $objWriter->writeAttribute('eqn', 'sum @0 1 0');
346 $objWriter->endElement();
349 $objWriter->startElement('v:f');
350 $objWriter->writeAttribute('eqn', 'sum 0 0 @1');
351 $objWriter->endElement();
354 $objWriter->startElement('v:f');
355 $objWriter->writeAttribute('eqn', 'prod @2 1 2');
356 $objWriter->endElement();
359 $objWriter->startElement('v:f');
360 $objWriter->writeAttribute('eqn', 'prod @3 21600 pixelWidth');
361 $objWriter->endElement();
364 $objWriter->startElement('v:f');
365 $objWriter->writeAttribute('eqn', 'prod @3 21600 pixelHeight');
366 $objWriter->endElement();
369 $objWriter->startElement('v:f');
370 $objWriter->writeAttribute('eqn', 'sum @0 0 1');
371 $objWriter->endElement();
374 $objWriter->startElement('v:f');
375 $objWriter->writeAttribute('eqn', 'prod @6 1 2');
376 $objWriter->endElement();
379 $objWriter->startElement('v:f');
380 $objWriter->writeAttribute('eqn', 'prod @7 21600 pixelWidth');
381 $objWriter->endElement();
384 $objWriter->startElement('v:f');
385 $objWriter->writeAttribute('eqn', 'sum @8 21600 0');
386 $objWriter->endElement();
389 $objWriter->startElement('v:f');
390 $objWriter->writeAttribute('eqn', 'prod @7 21600 pixelHeight');
391 $objWriter->endElement();
394 $objWriter->startElement('v:f');
395 $objWriter->writeAttribute('eqn', 'sum @10 21600 0');
396 $objWriter->endElement();
398 $objWriter->endElement();
401 $objWriter->startElement('v:path');
402 $objWriter->writeAttribute('o:extrusionok', 'f');
403 $objWriter->writeAttribute('gradientshapeok', 't');
404 $objWriter->writeAttribute('o:connecttype', 'rect');
405 $objWriter->endElement();
408 $objWriter->startElement('o:lock');
409 $objWriter->writeAttribute('v:ext', 'edit');
410 $objWriter->writeAttribute('aspectratio', 't');
411 $objWriter->endElement();
413 $objWriter->endElement();
415 // Loop through images
416 foreach ($images as $key => $value) {
417 $this->writeVMLHeaderFooterImage($objWriter, $key, $value);
420 $objWriter->endElement();
423 return $objWriter->getData();
427 * Write VML comment to XML format.
429 * @param XMLWriter $objWriter XML Writer
430 * @param string $pReference Reference
431 * @param HeaderFooterDrawing $pImage Image
433 private function writeVMLHeaderFooterImage(XMLWriter
$objWriter, $pReference, HeaderFooterDrawing
$pImage)
435 // Calculate object id
436 preg_match('{(\d+)}', md5($pReference), $m);
437 $id = 1500 +
(substr($m[1], 0, 2) * 1);
440 $width = $pImage->getWidth();
441 $height = $pImage->getHeight();
442 $marginLeft = $pImage->getOffsetX();
443 $marginTop = $pImage->getOffsetY();
446 $objWriter->startElement('v:shape');
447 $objWriter->writeAttribute('id', $pReference);
448 $objWriter->writeAttribute('o:spid', '_x0000_s' . $id);
449 $objWriter->writeAttribute('type', '#_x0000_t75');
450 $objWriter->writeAttribute('style', "position:absolute;margin-left:{$marginLeft}px;margin-top:{$marginTop}px;width:{$width}px;height:{$height}px;z-index:1");
453 $objWriter->startElement('v:imagedata');
454 $objWriter->writeAttribute('o:relid', 'rId' . $pReference);
455 $objWriter->writeAttribute('o:title', $pImage->getName());
456 $objWriter->endElement();
459 $objWriter->startElement('o:lock');
460 $objWriter->writeAttribute('v:ext', 'edit');
461 $objWriter->writeAttribute('textRotation', 't');
462 $objWriter->endElement();
464 $objWriter->endElement();
468 * Get an array of all drawings.
470 * @param Spreadsheet $spreadsheet
472 * @return \PhpOffice\PhpSpreadsheet\Worksheet\Drawing[] All drawings in PhpSpreadsheet
474 public function allDrawings(Spreadsheet
$spreadsheet)
476 // Get an array of all drawings
479 // Loop through PhpSpreadsheet
480 $sheetCount = $spreadsheet->getSheetCount();
481 for ($i = 0; $i < $sheetCount; ++
$i) {
482 // Loop through images and add to array
483 $iterator = $spreadsheet->getSheet($i)->getDrawingCollection()->getIterator();
484 while ($iterator->valid()) {
485 $aDrawings[] = $iterator->current();