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 $objWriter->endElement();
65 return $objWriter->getData();
69 * Write drawings to XML format.
71 * @param XMLWriter $objWriter XML Writer
72 * @param \PhpOffice\PhpSpreadsheet\Chart\Chart $pChart
73 * @param int $pRelationId
75 public function writeChart(XMLWriter
$objWriter, \PhpOffice\PhpSpreadsheet\Chart\Chart
$pChart, $pRelationId = -1)
77 $tl = $pChart->getTopLeftPosition();
78 $tl['colRow'] = Coordinate
::coordinateFromString($tl['cell']);
79 $br = $pChart->getBottomRightPosition();
80 $br['colRow'] = Coordinate
::coordinateFromString($br['cell']);
82 $objWriter->startElement('xdr:twoCellAnchor');
84 $objWriter->startElement('xdr:from');
85 $objWriter->writeElement('xdr:col', Coordinate
::columnIndexFromString($tl['colRow'][0]) - 1);
86 $objWriter->writeElement('xdr:colOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing
::pixelsToEMU($tl['xOffset']));
87 $objWriter->writeElement('xdr:row', $tl['colRow'][1] - 1);
88 $objWriter->writeElement('xdr:rowOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing
::pixelsToEMU($tl['yOffset']));
89 $objWriter->endElement();
90 $objWriter->startElement('xdr:to');
91 $objWriter->writeElement('xdr:col', Coordinate
::columnIndexFromString($br['colRow'][0]) - 1);
92 $objWriter->writeElement('xdr:colOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing
::pixelsToEMU($br['xOffset']));
93 $objWriter->writeElement('xdr:row', $br['colRow'][1] - 1);
94 $objWriter->writeElement('xdr:rowOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing
::pixelsToEMU($br['yOffset']));
95 $objWriter->endElement();
97 $objWriter->startElement('xdr:graphicFrame');
98 $objWriter->writeAttribute('macro', '');
99 $objWriter->startElement('xdr:nvGraphicFramePr');
100 $objWriter->startElement('xdr:cNvPr');
101 $objWriter->writeAttribute('name', 'Chart ' . $pRelationId);
102 $objWriter->writeAttribute('id', 1025 * $pRelationId);
103 $objWriter->endElement();
104 $objWriter->startElement('xdr:cNvGraphicFramePr');
105 $objWriter->startElement('a:graphicFrameLocks');
106 $objWriter->endElement();
107 $objWriter->endElement();
108 $objWriter->endElement();
110 $objWriter->startElement('xdr:xfrm');
111 $objWriter->startElement('a:off');
112 $objWriter->writeAttribute('x', '0');
113 $objWriter->writeAttribute('y', '0');
114 $objWriter->endElement();
115 $objWriter->startElement('a:ext');
116 $objWriter->writeAttribute('cx', '0');
117 $objWriter->writeAttribute('cy', '0');
118 $objWriter->endElement();
119 $objWriter->endElement();
121 $objWriter->startElement('a:graphic');
122 $objWriter->startElement('a:graphicData');
123 $objWriter->writeAttribute('uri', 'http://schemas.openxmlformats.org/drawingml/2006/chart');
124 $objWriter->startElement('c:chart');
125 $objWriter->writeAttribute('xmlns:c', 'http://schemas.openxmlformats.org/drawingml/2006/chart');
126 $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
127 $objWriter->writeAttribute('r:id', 'rId' . $pRelationId);
128 $objWriter->endElement();
129 $objWriter->endElement();
130 $objWriter->endElement();
131 $objWriter->endElement();
133 $objWriter->startElement('xdr:clientData');
134 $objWriter->endElement();
136 $objWriter->endElement();
140 * Write drawings to XML format.
142 * @param XMLWriter $objWriter XML Writer
143 * @param BaseDrawing $pDrawing
144 * @param int $pRelationId
146 * @throws WriterException
148 public function writeDrawing(XMLWriter
$objWriter, BaseDrawing
$pDrawing, $pRelationId = -1)
150 if ($pRelationId >= 0) {
152 $objWriter->startElement('xdr:oneCellAnchor');
154 $aCoordinates = Coordinate
::coordinateFromString($pDrawing->getCoordinates());
155 $aCoordinates[0] = Coordinate
::columnIndexFromString($aCoordinates[0]);
158 $objWriter->startElement('xdr:from');
159 $objWriter->writeElement('xdr:col', $aCoordinates[0] - 1);
160 $objWriter->writeElement('xdr:colOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing
::pixelsToEMU($pDrawing->getOffsetX()));
161 $objWriter->writeElement('xdr:row', $aCoordinates[1] - 1);
162 $objWriter->writeElement('xdr:rowOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing
::pixelsToEMU($pDrawing->getOffsetY()));
163 $objWriter->endElement();
166 $objWriter->startElement('xdr:ext');
167 $objWriter->writeAttribute('cx', \PhpOffice\PhpSpreadsheet\Shared\Drawing
::pixelsToEMU($pDrawing->getWidth()));
168 $objWriter->writeAttribute('cy', \PhpOffice\PhpSpreadsheet\Shared\Drawing
::pixelsToEMU($pDrawing->getHeight()));
169 $objWriter->endElement();
172 $objWriter->startElement('xdr:pic');
175 $objWriter->startElement('xdr:nvPicPr');
178 $objWriter->startElement('xdr:cNvPr');
179 $objWriter->writeAttribute('id', $pRelationId);
180 $objWriter->writeAttribute('name', $pDrawing->getName());
181 $objWriter->writeAttribute('descr', $pDrawing->getDescription());
182 $objWriter->endElement();
185 $objWriter->startElement('xdr:cNvPicPr');
188 $objWriter->startElement('a:picLocks');
189 $objWriter->writeAttribute('noChangeAspect', '1');
190 $objWriter->endElement();
192 $objWriter->endElement();
194 $objWriter->endElement();
197 $objWriter->startElement('xdr:blipFill');
200 $objWriter->startElement('a:blip');
201 $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
202 $objWriter->writeAttribute('r:embed', 'rId' . $pRelationId);
203 $objWriter->endElement();
206 $objWriter->startElement('a:stretch');
207 $objWriter->writeElement('a:fillRect', null);
208 $objWriter->endElement();
210 $objWriter->endElement();
213 $objWriter->startElement('xdr:spPr');
216 $objWriter->startElement('a:xfrm');
217 $objWriter->writeAttribute('rot', \PhpOffice\PhpSpreadsheet\Shared\Drawing
::degreesToAngle($pDrawing->getRotation()));
218 $objWriter->endElement();
221 $objWriter->startElement('a:prstGeom');
222 $objWriter->writeAttribute('prst', 'rect');
225 $objWriter->writeElement('a:avLst', null);
227 $objWriter->endElement();
229 if ($pDrawing->getShadow()->getVisible()) {
231 $objWriter->startElement('a:effectLst');
234 $objWriter->startElement('a:outerShdw');
235 $objWriter->writeAttribute('blurRad', \PhpOffice\PhpSpreadsheet\Shared\Drawing
::pixelsToEMU($pDrawing->getShadow()->getBlurRadius()));
236 $objWriter->writeAttribute('dist', \PhpOffice\PhpSpreadsheet\Shared\Drawing
::pixelsToEMU($pDrawing->getShadow()->getDistance()));
237 $objWriter->writeAttribute('dir', \PhpOffice\PhpSpreadsheet\Shared\Drawing
::degreesToAngle($pDrawing->getShadow()->getDirection()));
238 $objWriter->writeAttribute('algn', $pDrawing->getShadow()->getAlignment());
239 $objWriter->writeAttribute('rotWithShape', '0');
242 $objWriter->startElement('a:srgbClr');
243 $objWriter->writeAttribute('val', $pDrawing->getShadow()->getColor()->getRGB());
246 $objWriter->startElement('a:alpha');
247 $objWriter->writeAttribute('val', $pDrawing->getShadow()->getAlpha() * 1000);
248 $objWriter->endElement();
250 $objWriter->endElement();
252 $objWriter->endElement();
254 $objWriter->endElement();
256 $objWriter->endElement();
258 $objWriter->endElement();
261 $objWriter->writeElement('xdr:clientData', null);
263 $objWriter->endElement();
265 throw new WriterException('Invalid parameters passed.');
270 * Write VML header/footer images to XML format.
272 * @param \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet
274 * @throws WriterException
276 * @return string XML Output
278 public function writeVMLHeaderFooterImages(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet
$pWorksheet)
282 if ($this->getParentWriter()->getUseDiskCaching()) {
283 $objWriter = new XMLWriter(XMLWriter
::STORAGE_DISK
, $this->getParentWriter()->getDiskCachingDirectory());
285 $objWriter = new XMLWriter(XMLWriter
::STORAGE_MEMORY
);
289 $objWriter->startDocument('1.0', 'UTF-8', 'yes');
291 // Header/footer images
292 $images = $pWorksheet->getHeaderFooter()->getImages();
295 $objWriter->startElement('xml');
296 $objWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml');
297 $objWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office');
298 $objWriter->writeAttribute('xmlns:x', 'urn:schemas-microsoft-com:office:excel');
301 $objWriter->startElement('o:shapelayout');
302 $objWriter->writeAttribute('v:ext', 'edit');
305 $objWriter->startElement('o:idmap');
306 $objWriter->writeAttribute('v:ext', 'edit');
307 $objWriter->writeAttribute('data', '1');
308 $objWriter->endElement();
310 $objWriter->endElement();
313 $objWriter->startElement('v:shapetype');
314 $objWriter->writeAttribute('id', '_x0000_t75');
315 $objWriter->writeAttribute('coordsize', '21600,21600');
316 $objWriter->writeAttribute('o:spt', '75');
317 $objWriter->writeAttribute('o:preferrelative', 't');
318 $objWriter->writeAttribute('path', 'm@4@5l@4@11@9@11@9@5xe');
319 $objWriter->writeAttribute('filled', 'f');
320 $objWriter->writeAttribute('stroked', 'f');
323 $objWriter->startElement('v:stroke');
324 $objWriter->writeAttribute('joinstyle', 'miter');
325 $objWriter->endElement();
328 $objWriter->startElement('v:formulas');
331 $objWriter->startElement('v:f');
332 $objWriter->writeAttribute('eqn', 'if lineDrawn pixelLineWidth 0');
333 $objWriter->endElement();
336 $objWriter->startElement('v:f');
337 $objWriter->writeAttribute('eqn', 'sum @0 1 0');
338 $objWriter->endElement();
341 $objWriter->startElement('v:f');
342 $objWriter->writeAttribute('eqn', 'sum 0 0 @1');
343 $objWriter->endElement();
346 $objWriter->startElement('v:f');
347 $objWriter->writeAttribute('eqn', 'prod @2 1 2');
348 $objWriter->endElement();
351 $objWriter->startElement('v:f');
352 $objWriter->writeAttribute('eqn', 'prod @3 21600 pixelWidth');
353 $objWriter->endElement();
356 $objWriter->startElement('v:f');
357 $objWriter->writeAttribute('eqn', 'prod @3 21600 pixelHeight');
358 $objWriter->endElement();
361 $objWriter->startElement('v:f');
362 $objWriter->writeAttribute('eqn', 'sum @0 0 1');
363 $objWriter->endElement();
366 $objWriter->startElement('v:f');
367 $objWriter->writeAttribute('eqn', 'prod @6 1 2');
368 $objWriter->endElement();
371 $objWriter->startElement('v:f');
372 $objWriter->writeAttribute('eqn', 'prod @7 21600 pixelWidth');
373 $objWriter->endElement();
376 $objWriter->startElement('v:f');
377 $objWriter->writeAttribute('eqn', 'sum @8 21600 0');
378 $objWriter->endElement();
381 $objWriter->startElement('v:f');
382 $objWriter->writeAttribute('eqn', 'prod @7 21600 pixelHeight');
383 $objWriter->endElement();
386 $objWriter->startElement('v:f');
387 $objWriter->writeAttribute('eqn', 'sum @10 21600 0');
388 $objWriter->endElement();
390 $objWriter->endElement();
393 $objWriter->startElement('v:path');
394 $objWriter->writeAttribute('o:extrusionok', 'f');
395 $objWriter->writeAttribute('gradientshapeok', 't');
396 $objWriter->writeAttribute('o:connecttype', 'rect');
397 $objWriter->endElement();
400 $objWriter->startElement('o:lock');
401 $objWriter->writeAttribute('v:ext', 'edit');
402 $objWriter->writeAttribute('aspectratio', 't');
403 $objWriter->endElement();
405 $objWriter->endElement();
407 // Loop through images
408 foreach ($images as $key => $value) {
409 $this->writeVMLHeaderFooterImage($objWriter, $key, $value);
412 $objWriter->endElement();
415 return $objWriter->getData();
419 * Write VML comment to XML format.
421 * @param XMLWriter $objWriter XML Writer
422 * @param string $pReference Reference
423 * @param HeaderFooterDrawing $pImage Image
425 private function writeVMLHeaderFooterImage(XMLWriter
$objWriter, $pReference, HeaderFooterDrawing
$pImage)
427 // Calculate object id
428 preg_match('{(\d+)}', md5($pReference), $m);
429 $id = 1500 +
(substr($m[1], 0, 2) * 1);
432 $width = $pImage->getWidth();
433 $height = $pImage->getHeight();
434 $marginLeft = $pImage->getOffsetX();
435 $marginTop = $pImage->getOffsetY();
438 $objWriter->startElement('v:shape');
439 $objWriter->writeAttribute('id', $pReference);
440 $objWriter->writeAttribute('o:spid', '_x0000_s' . $id);
441 $objWriter->writeAttribute('type', '#_x0000_t75');
442 $objWriter->writeAttribute('style', "position:absolute;margin-left:{$marginLeft}px;margin-top:{$marginTop}px;width:{$width}px;height:{$height}px;z-index:1");
445 $objWriter->startElement('v:imagedata');
446 $objWriter->writeAttribute('o:relid', 'rId' . $pReference);
447 $objWriter->writeAttribute('o:title', $pImage->getName());
448 $objWriter->endElement();
451 $objWriter->startElement('o:lock');
452 $objWriter->writeAttribute('v:ext', 'edit');
453 $objWriter->writeAttribute('textRotation', 't');
454 $objWriter->endElement();
456 $objWriter->endElement();
460 * Get an array of all drawings.
462 * @param Spreadsheet $spreadsheet
464 * @return \PhpOffice\PhpSpreadsheet\Worksheet\Drawing[] All drawings in PhpSpreadsheet
466 public function allDrawings(Spreadsheet
$spreadsheet)
468 // Get an array of all drawings
471 // Loop through PhpSpreadsheet
472 $sheetCount = $spreadsheet->getSheetCount();
473 for ($i = 0; $i < $sheetCount; ++
$i) {
474 // Loop through images and add to array
475 $iterator = $spreadsheet->getSheet($i)->getDrawingCollection()->getIterator();
476 while ($iterator->valid()) {
477 $aDrawings[] = $iterator->current();