1<?php
2
3/**
4 * PHPExcel_Writer_Excel2007_Drawing
5 *
6 * Copyright (c) 2006 - 2015 PHPExcel
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21 *
22 * @category   PHPExcel
23 * @package    PHPExcel_Writer_Excel2007
24 * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
25 * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
26 * @version    ##VERSION##, ##DATE##
27 */
28class PHPExcel_Writer_Excel2007_Drawing extends PHPExcel_Writer_Excel2007_WriterPart
29{
30    /**
31     * Write drawings to XML format
32     *
33     * @param     PHPExcel_Worksheet    $pWorksheet
34     * @param    int                    &$chartRef        Chart ID
35     * @param    boolean                $includeCharts    Flag indicating if we should include drawing details for charts
36     * @return     string                 XML Output
37     * @throws     PHPExcel_Writer_Exception
38     */
39    public function writeDrawings(PHPExcel_Worksheet $pWorksheet = null, &$chartRef, $includeCharts = false)
40    {
41        // Create XML writer
42        $objWriter = null;
43        if ($this->getParentWriter()->getUseDiskCaching()) {
44            $objWriter = new PHPExcel_Shared_XMLWriter(PHPExcel_Shared_XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
45        } else {
46            $objWriter = new PHPExcel_Shared_XMLWriter(PHPExcel_Shared_XMLWriter::STORAGE_MEMORY);
47        }
48
49        // XML header
50        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
51
52        // xdr:wsDr
53        $objWriter->startElement('xdr:wsDr');
54        $objWriter->writeAttribute('xmlns:xdr', 'http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing');
55        $objWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main');
56
57        // Loop through images and write drawings
58        $i = 1;
59        $iterator = $pWorksheet->getDrawingCollection()->getIterator();
60        while ($iterator->valid()) {
61            $this->writeDrawing($objWriter, $iterator->current(), $i);
62
63            $iterator->next();
64            ++$i;
65        }
66
67        if ($includeCharts) {
68            $chartCount = $pWorksheet->getChartCount();
69            // Loop through charts and write the chart position
70            if ($chartCount > 0) {
71                for ($c = 0; $c < $chartCount; ++$c) {
72                    $this->writeChart($objWriter, $pWorksheet->getChartByIndex($c), $c+$i);
73                }
74            }
75        }
76
77        $objWriter->endElement();
78
79        // Return
80        return $objWriter->getData();
81    }
82
83    /**
84     * Write drawings to XML format
85     *
86     * @param     PHPExcel_Shared_XMLWriter    $objWriter         XML Writer
87     * @param     PHPExcel_Chart                $pChart
88     * @param     int                            $pRelationId
89     * @throws     PHPExcel_Writer_Exception
90     */
91    public function writeChart(PHPExcel_Shared_XMLWriter $objWriter = null, PHPExcel_Chart $pChart = null, $pRelationId = -1)
92    {
93        $tl = $pChart->getTopLeftPosition();
94        $tl['colRow'] = PHPExcel_Cell::coordinateFromString($tl['cell']);
95        $br = $pChart->getBottomRightPosition();
96        $br['colRow'] = PHPExcel_Cell::coordinateFromString($br['cell']);
97
98        $objWriter->startElement('xdr:twoCellAnchor');
99
100            $objWriter->startElement('xdr:from');
101                $objWriter->writeElement('xdr:col', PHPExcel_Cell::columnIndexFromString($tl['colRow'][0]) - 1);
102                $objWriter->writeElement('xdr:colOff', PHPExcel_Shared_Drawing::pixelsToEMU($tl['xOffset']));
103                $objWriter->writeElement('xdr:row', $tl['colRow'][1] - 1);
104                $objWriter->writeElement('xdr:rowOff', PHPExcel_Shared_Drawing::pixelsToEMU($tl['yOffset']));
105            $objWriter->endElement();
106            $objWriter->startElement('xdr:to');
107                $objWriter->writeElement('xdr:col', PHPExcel_Cell::columnIndexFromString($br['colRow'][0]) - 1);
108                $objWriter->writeElement('xdr:colOff', PHPExcel_Shared_Drawing::pixelsToEMU($br['xOffset']));
109                $objWriter->writeElement('xdr:row', $br['colRow'][1] - 1);
110                $objWriter->writeElement('xdr:rowOff', PHPExcel_Shared_Drawing::pixelsToEMU($br['yOffset']));
111            $objWriter->endElement();
112
113            $objWriter->startElement('xdr:graphicFrame');
114                $objWriter->writeAttribute('macro', '');
115                $objWriter->startElement('xdr:nvGraphicFramePr');
116                    $objWriter->startElement('xdr:cNvPr');
117                        $objWriter->writeAttribute('name', 'Chart '.$pRelationId);
118                        $objWriter->writeAttribute('id', 1025 * $pRelationId);
119                    $objWriter->endElement();
120                    $objWriter->startElement('xdr:cNvGraphicFramePr');
121                        $objWriter->startElement('a:graphicFrameLocks');
122                        $objWriter->endElement();
123                    $objWriter->endElement();
124                $objWriter->endElement();
125
126                $objWriter->startElement('xdr:xfrm');
127                    $objWriter->startElement('a:off');
128                        $objWriter->writeAttribute('x', '0');
129                        $objWriter->writeAttribute('y', '0');
130                    $objWriter->endElement();
131                    $objWriter->startElement('a:ext');
132                        $objWriter->writeAttribute('cx', '0');
133                        $objWriter->writeAttribute('cy', '0');
134                    $objWriter->endElement();
135                $objWriter->endElement();
136
137                $objWriter->startElement('a:graphic');
138                    $objWriter->startElement('a:graphicData');
139                        $objWriter->writeAttribute('uri', 'http://schemas.openxmlformats.org/drawingml/2006/chart');
140                        $objWriter->startElement('c:chart');
141                            $objWriter->writeAttribute('xmlns:c', 'http://schemas.openxmlformats.org/drawingml/2006/chart');
142                            $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
143                            $objWriter->writeAttribute('r:id', 'rId'.$pRelationId);
144                        $objWriter->endElement();
145                    $objWriter->endElement();
146                $objWriter->endElement();
147            $objWriter->endElement();
148
149            $objWriter->startElement('xdr:clientData');
150            $objWriter->endElement();
151
152        $objWriter->endElement();
153    }
154
155    /**
156     * Write drawings to XML format
157     *
158     * @param     PHPExcel_Shared_XMLWriter            $objWriter         XML Writer
159     * @param     PHPExcel_Worksheet_BaseDrawing        $pDrawing
160     * @param     int                                    $pRelationId
161     * @throws     PHPExcel_Writer_Exception
162     */
163    public function writeDrawing(PHPExcel_Shared_XMLWriter $objWriter = null, PHPExcel_Worksheet_BaseDrawing $pDrawing = null, $pRelationId = -1)
164    {
165        if ($pRelationId >= 0) {
166            // xdr:oneCellAnchor
167            $objWriter->startElement('xdr:oneCellAnchor');
168            // Image location
169            $aCoordinates         = PHPExcel_Cell::coordinateFromString($pDrawing->getCoordinates());
170            $aCoordinates[0]     = PHPExcel_Cell::columnIndexFromString($aCoordinates[0]);
171
172            // xdr:from
173            $objWriter->startElement('xdr:from');
174            $objWriter->writeElement('xdr:col', $aCoordinates[0] - 1);
175            $objWriter->writeElement('xdr:colOff', PHPExcel_Shared_Drawing::pixelsToEMU($pDrawing->getOffsetX()));
176            $objWriter->writeElement('xdr:row', $aCoordinates[1] - 1);
177            $objWriter->writeElement('xdr:rowOff', PHPExcel_Shared_Drawing::pixelsToEMU($pDrawing->getOffsetY()));
178            $objWriter->endElement();
179
180            // xdr:ext
181            $objWriter->startElement('xdr:ext');
182            $objWriter->writeAttribute('cx', PHPExcel_Shared_Drawing::pixelsToEMU($pDrawing->getWidth()));
183            $objWriter->writeAttribute('cy', PHPExcel_Shared_Drawing::pixelsToEMU($pDrawing->getHeight()));
184            $objWriter->endElement();
185
186            // xdr:pic
187            $objWriter->startElement('xdr:pic');
188
189            // xdr:nvPicPr
190            $objWriter->startElement('xdr:nvPicPr');
191
192            // xdr:cNvPr
193            $objWriter->startElement('xdr:cNvPr');
194            $objWriter->writeAttribute('id', $pRelationId);
195            $objWriter->writeAttribute('name', $pDrawing->getName());
196            $objWriter->writeAttribute('descr', $pDrawing->getDescription());
197            $objWriter->endElement();
198
199            // xdr:cNvPicPr
200            $objWriter->startElement('xdr:cNvPicPr');
201
202            // a:picLocks
203            $objWriter->startElement('a:picLocks');
204            $objWriter->writeAttribute('noChangeAspect', '1');
205            $objWriter->endElement();
206
207            $objWriter->endElement();
208
209            $objWriter->endElement();
210
211            // xdr:blipFill
212            $objWriter->startElement('xdr:blipFill');
213
214            // a:blip
215            $objWriter->startElement('a:blip');
216            $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
217            $objWriter->writeAttribute('r:embed', 'rId' . $pRelationId);
218            $objWriter->endElement();
219
220            // a:stretch
221            $objWriter->startElement('a:stretch');
222                $objWriter->writeElement('a:fillRect', null);
223            $objWriter->endElement();
224
225            $objWriter->endElement();
226
227            // xdr:spPr
228            $objWriter->startElement('xdr:spPr');
229
230            // a:xfrm
231            $objWriter->startElement('a:xfrm');
232            $objWriter->writeAttribute('rot', PHPExcel_Shared_Drawing::degreesToAngle($pDrawing->getRotation()));
233            $objWriter->endElement();
234
235            // a:prstGeom
236            $objWriter->startElement('a:prstGeom');
237            $objWriter->writeAttribute('prst', 'rect');
238
239            // a:avLst
240            $objWriter->writeElement('a:avLst', null);
241
242            $objWriter->endElement();
243
244//                        // a:solidFill
245//                        $objWriter->startElement('a:solidFill');
246
247//                            // a:srgbClr
248//                            $objWriter->startElement('a:srgbClr');
249//                            $objWriter->writeAttribute('val', 'FFFFFF');
250
251///* SHADE
252//                                // a:shade
253//                                $objWriter->startElement('a:shade');
254//                                $objWriter->writeAttribute('val', '85000');
255//                                $objWriter->endElement();
256//*/
257
258//                            $objWriter->endElement();
259
260//                        $objWriter->endElement();
261/*
262            // a:ln
263            $objWriter->startElement('a:ln');
264            $objWriter->writeAttribute('w', '88900');
265            $objWriter->writeAttribute('cap', 'sq');
266
267                // a:solidFill
268                $objWriter->startElement('a:solidFill');
269
270                    // a:srgbClr
271                    $objWriter->startElement('a:srgbClr');
272                    $objWriter->writeAttribute('val', 'FFFFFF');
273                    $objWriter->endElement();
274
275                $objWriter->endElement();
276
277                // a:miter
278                $objWriter->startElement('a:miter');
279                $objWriter->writeAttribute('lim', '800000');
280                $objWriter->endElement();
281
282            $objWriter->endElement();
283*/
284
285            if ($pDrawing->getShadow()->getVisible()) {
286                // a:effectLst
287                $objWriter->startElement('a:effectLst');
288
289                // a:outerShdw
290                $objWriter->startElement('a:outerShdw');
291                $objWriter->writeAttribute('blurRad', PHPExcel_Shared_Drawing::pixelsToEMU($pDrawing->getShadow()->getBlurRadius()));
292                $objWriter->writeAttribute('dist', PHPExcel_Shared_Drawing::pixelsToEMU($pDrawing->getShadow()->getDistance()));
293                $objWriter->writeAttribute('dir', PHPExcel_Shared_Drawing::degreesToAngle($pDrawing->getShadow()->getDirection()));
294                $objWriter->writeAttribute('algn', $pDrawing->getShadow()->getAlignment());
295                $objWriter->writeAttribute('rotWithShape', '0');
296
297                // a:srgbClr
298                $objWriter->startElement('a:srgbClr');
299                $objWriter->writeAttribute('val', $pDrawing->getShadow()->getColor()->getRGB());
300
301                // a:alpha
302                $objWriter->startElement('a:alpha');
303                $objWriter->writeAttribute('val', $pDrawing->getShadow()->getAlpha() * 1000);
304                $objWriter->endElement();
305
306                $objWriter->endElement();
307
308                $objWriter->endElement();
309
310                $objWriter->endElement();
311            }
312/*
313
314                // a:scene3d
315                $objWriter->startElement('a:scene3d');
316
317                    // a:camera
318                    $objWriter->startElement('a:camera');
319                    $objWriter->writeAttribute('prst', 'orthographicFront');
320                    $objWriter->endElement();
321
322                    // a:lightRig
323                    $objWriter->startElement('a:lightRig');
324                    $objWriter->writeAttribute('rig', 'twoPt');
325                    $objWriter->writeAttribute('dir', 't');
326
327                        // a:rot
328                        $objWriter->startElement('a:rot');
329                        $objWriter->writeAttribute('lat', '0');
330                        $objWriter->writeAttribute('lon', '0');
331                        $objWriter->writeAttribute('rev', '0');
332                        $objWriter->endElement();
333
334                    $objWriter->endElement();
335
336                $objWriter->endElement();
337*/
338/*
339                // a:sp3d
340                $objWriter->startElement('a:sp3d');
341
342                    // a:bevelT
343                    $objWriter->startElement('a:bevelT');
344                    $objWriter->writeAttribute('w', '25400');
345                    $objWriter->writeAttribute('h', '19050');
346                    $objWriter->endElement();
347
348                    // a:contourClr
349                    $objWriter->startElement('a:contourClr');
350
351                        // a:srgbClr
352                        $objWriter->startElement('a:srgbClr');
353                        $objWriter->writeAttribute('val', 'FFFFFF');
354                        $objWriter->endElement();
355
356                    $objWriter->endElement();
357
358                $objWriter->endElement();
359*/
360            $objWriter->endElement();
361
362            $objWriter->endElement();
363
364            // xdr:clientData
365            $objWriter->writeElement('xdr:clientData', null);
366
367            $objWriter->endElement();
368        } else {
369            throw new PHPExcel_Writer_Exception("Invalid parameters passed.");
370        }
371    }
372
373    /**
374     * Write VML header/footer images to XML format
375     *
376     * @param     PHPExcel_Worksheet                $pWorksheet
377     * @return     string                                 XML Output
378     * @throws     PHPExcel_Writer_Exception
379     */
380    public function writeVMLHeaderFooterImages(PHPExcel_Worksheet $pWorksheet = null)
381    {
382        // Create XML writer
383        $objWriter = null;
384        if ($this->getParentWriter()->getUseDiskCaching()) {
385            $objWriter = new PHPExcel_Shared_XMLWriter(PHPExcel_Shared_XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
386        } else {
387            $objWriter = new PHPExcel_Shared_XMLWriter(PHPExcel_Shared_XMLWriter::STORAGE_MEMORY);
388        }
389
390        // XML header
391        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
392
393        // Header/footer images
394        $images = $pWorksheet->getHeaderFooter()->getImages();
395
396        // xml
397        $objWriter->startElement('xml');
398        $objWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml');
399        $objWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office');
400        $objWriter->writeAttribute('xmlns:x', 'urn:schemas-microsoft-com:office:excel');
401
402        // o:shapelayout
403        $objWriter->startElement('o:shapelayout');
404        $objWriter->writeAttribute('v:ext', 'edit');
405
406        // o:idmap
407        $objWriter->startElement('o:idmap');
408        $objWriter->writeAttribute('v:ext', 'edit');
409        $objWriter->writeAttribute('data', '1');
410        $objWriter->endElement();
411
412        $objWriter->endElement();
413
414        // v:shapetype
415        $objWriter->startElement('v:shapetype');
416        $objWriter->writeAttribute('id', '_x0000_t75');
417        $objWriter->writeAttribute('coordsize', '21600,21600');
418        $objWriter->writeAttribute('o:spt', '75');
419        $objWriter->writeAttribute('o:preferrelative', 't');
420        $objWriter->writeAttribute('path', 'm@4@5l@4@11@9@11@9@5xe');
421        $objWriter->writeAttribute('filled', 'f');
422        $objWriter->writeAttribute('stroked', 'f');
423
424        // v:stroke
425        $objWriter->startElement('v:stroke');
426        $objWriter->writeAttribute('joinstyle', 'miter');
427        $objWriter->endElement();
428
429        // v:formulas
430        $objWriter->startElement('v:formulas');
431
432        // v:f
433        $objWriter->startElement('v:f');
434        $objWriter->writeAttribute('eqn', 'if lineDrawn pixelLineWidth 0');
435        $objWriter->endElement();
436
437        // v:f
438        $objWriter->startElement('v:f');
439        $objWriter->writeAttribute('eqn', 'sum @0 1 0');
440        $objWriter->endElement();
441
442        // v:f
443        $objWriter->startElement('v:f');
444        $objWriter->writeAttribute('eqn', 'sum 0 0 @1');
445        $objWriter->endElement();
446
447        // v:f
448        $objWriter->startElement('v:f');
449        $objWriter->writeAttribute('eqn', 'prod @2 1 2');
450        $objWriter->endElement();
451
452        // v:f
453        $objWriter->startElement('v:f');
454        $objWriter->writeAttribute('eqn', 'prod @3 21600 pixelWidth');
455        $objWriter->endElement();
456
457        // v:f
458        $objWriter->startElement('v:f');
459        $objWriter->writeAttribute('eqn', 'prod @3 21600 pixelHeight');
460        $objWriter->endElement();
461
462        // v:f
463        $objWriter->startElement('v:f');
464        $objWriter->writeAttribute('eqn', 'sum @0 0 1');
465        $objWriter->endElement();
466
467        // v:f
468        $objWriter->startElement('v:f');
469        $objWriter->writeAttribute('eqn', 'prod @6 1 2');
470        $objWriter->endElement();
471
472        // v:f
473        $objWriter->startElement('v:f');
474        $objWriter->writeAttribute('eqn', 'prod @7 21600 pixelWidth');
475        $objWriter->endElement();
476
477        // v:f
478        $objWriter->startElement('v:f');
479        $objWriter->writeAttribute('eqn', 'sum @8 21600 0');
480        $objWriter->endElement();
481
482        // v:f
483        $objWriter->startElement('v:f');
484        $objWriter->writeAttribute('eqn', 'prod @7 21600 pixelHeight');
485        $objWriter->endElement();
486
487        // v:f
488        $objWriter->startElement('v:f');
489        $objWriter->writeAttribute('eqn', 'sum @10 21600 0');
490        $objWriter->endElement();
491
492        $objWriter->endElement();
493
494        // v:path
495        $objWriter->startElement('v:path');
496        $objWriter->writeAttribute('o:extrusionok', 'f');
497        $objWriter->writeAttribute('gradientshapeok', 't');
498        $objWriter->writeAttribute('o:connecttype', 'rect');
499        $objWriter->endElement();
500
501        // o:lock
502        $objWriter->startElement('o:lock');
503        $objWriter->writeAttribute('v:ext', 'edit');
504        $objWriter->writeAttribute('aspectratio', 't');
505        $objWriter->endElement();
506
507        $objWriter->endElement();
508
509        // Loop through images
510        foreach ($images as $key => $value) {
511            $this->writeVMLHeaderFooterImage($objWriter, $key, $value);
512        }
513
514        $objWriter->endElement();
515
516        // Return
517        return $objWriter->getData();
518    }
519
520    /**
521     * Write VML comment to XML format
522     *
523     * @param     PHPExcel_Shared_XMLWriter        $objWriter             XML Writer
524     * @param    string                            $pReference            Reference
525     * @param     PHPExcel_Worksheet_HeaderFooterDrawing    $pImage        Image
526     * @throws     PHPExcel_Writer_Exception
527     */
528    private function writeVMLHeaderFooterImage(PHPExcel_Shared_XMLWriter $objWriter = null, $pReference = '', PHPExcel_Worksheet_HeaderFooterDrawing $pImage = null)
529    {
530        // Calculate object id
531        preg_match('{(\d+)}', md5($pReference), $m);
532        $id = 1500 + (substr($m[1], 0, 2) * 1);
533
534        // Calculate offset
535        $width = $pImage->getWidth();
536        $height = $pImage->getHeight();
537        $marginLeft = $pImage->getOffsetX();
538        $marginTop = $pImage->getOffsetY();
539
540        // v:shape
541        $objWriter->startElement('v:shape');
542        $objWriter->writeAttribute('id', $pReference);
543        $objWriter->writeAttribute('o:spid', '_x0000_s' . $id);
544        $objWriter->writeAttribute('type', '#_x0000_t75');
545        $objWriter->writeAttribute('style', "position:absolute;margin-left:{$marginLeft}px;margin-top:{$marginTop}px;width:{$width}px;height:{$height}px;z-index:1");
546
547        // v:imagedata
548        $objWriter->startElement('v:imagedata');
549        $objWriter->writeAttribute('o:relid', 'rId' . $pReference);
550        $objWriter->writeAttribute('o:title', $pImage->getName());
551        $objWriter->endElement();
552
553        // o:lock
554        $objWriter->startElement('o:lock');
555        $objWriter->writeAttribute('v:ext', 'edit');
556        $objWriter->writeAttribute('rotation', 't');
557        $objWriter->endElement();
558
559        $objWriter->endElement();
560    }
561
562
563    /**
564     * Get an array of all drawings
565     *
566     * @param     PHPExcel                            $pPHPExcel
567     * @return     PHPExcel_Worksheet_Drawing[]        All drawings in PHPExcel
568     * @throws     PHPExcel_Writer_Exception
569     */
570    public function allDrawings(PHPExcel $pPHPExcel = null)
571    {
572        // Get an array of all drawings
573        $aDrawings    = array();
574
575        // Loop through PHPExcel
576        $sheetCount = $pPHPExcel->getSheetCount();
577        for ($i = 0; $i < $sheetCount; ++$i) {
578            // Loop through images and add to array
579            $iterator = $pPHPExcel->getSheet($i)->getDrawingCollection()->getIterator();
580            while ($iterator->valid()) {
581                $aDrawings[] = $iterator->current();
582
583                  $iterator->next();
584            }
585        }
586
587        return $aDrawings;
588    }
589}
590