Failed Conditions
Push — master ( 36acc3...2eb342 )
by Adrien
36:49
created

Drawing::writeVMLHeaderFooterImage()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 32
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 20
nc 1
nop 3
dl 0
loc 32
ccs 21
cts 21
cp 1
crap 1
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Writer\Xlsx;
4
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;
11
12
class Drawing extends WriterPart
13
{
14
    /**
15
     * Write drawings to XML format.
16
     *
17
     * @param \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet
18
     * @param bool $includeCharts Flag indicating if we should include drawing details for charts
19
     *
20
     * @throws WriterException
21
     *
22
     * @return string XML Output
23
     */
24 23
    public function writeDrawings(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet, $includeCharts = false)
25
    {
26
        // Create XML writer
27 23
        $objWriter = null;
28 23
        if ($this->getParentWriter()->getUseDiskCaching()) {
29
            $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
30
        } else {
31 23
            $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
32
        }
33
34
        // XML header
35 23
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
36
37
        // xdr:wsDr
38 23
        $objWriter->startElement('xdr:wsDr');
39 23
        $objWriter->writeAttribute('xmlns:xdr', 'http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing');
40 23
        $objWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main');
41
42
        // Loop through images and write drawings
43 23
        $i = 1;
44 23
        $iterator = $pWorksheet->getDrawingCollection()->getIterator();
45 23
        while ($iterator->valid()) {
46 10
            $this->writeDrawing($objWriter, $iterator->current(), $i);
47
48 10
            $iterator->next();
49 10
            ++$i;
50
        }
51
52 23
        if ($includeCharts) {
53 13
            $chartCount = $pWorksheet->getChartCount();
54
            // Loop through charts and write the chart position
55 13
            if ($chartCount > 0) {
56 13
                for ($c = 0; $c < $chartCount; ++$c) {
57 13
                    $this->writeChart($objWriter, $pWorksheet->getChartByIndex($c), $c + $i);
1 ignored issue
show
Bug introduced by
It seems like $pWorksheet->getChartByIndex($c) can also be of type false; however, parameter $pChart of PhpOffice\PhpSpreadsheet...x\Drawing::writeChart() does only seem to accept PhpOffice\PhpSpreadsheet\Chart\Chart, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

57
                    $this->writeChart($objWriter, /** @scrutinizer ignore-type */ $pWorksheet->getChartByIndex($c), $c + $i);
Loading history...
58
                }
59
            }
60
        }
61
62
        // unparsed AlternateContent
63 23
        $unparsedLoadedData = $pWorksheet->getParent()->getUnparsedLoadedData();
64 23
        if (isset($unparsedLoadedData['sheets'][$pWorksheet->getCodeName()]['drawingAlternateContents'])) {
65 1
            foreach ($unparsedLoadedData['sheets'][$pWorksheet->getCodeName()]['drawingAlternateContents'] as $drawingAlternateContent) {
66 1
                $objWriter->writeRaw($drawingAlternateContent);
67
            }
68
        }
69
70 23
        $objWriter->endElement();
71
72
        // Return
73 23
        return $objWriter->getData();
74
    }
75
76
    /**
77
     * Write drawings to XML format.
78
     *
79
     * @param XMLWriter $objWriter XML Writer
80
     * @param \PhpOffice\PhpSpreadsheet\Chart\Chart $pChart
81
     * @param int $pRelationId
82
     */
83 13
    public function writeChart(XMLWriter $objWriter, \PhpOffice\PhpSpreadsheet\Chart\Chart $pChart, $pRelationId = -1)
84
    {
85 13
        $tl = $pChart->getTopLeftPosition();
86 13
        $tl['colRow'] = Coordinate::coordinateFromString($tl['cell']);
87 13
        $br = $pChart->getBottomRightPosition();
88 13
        $br['colRow'] = Coordinate::coordinateFromString($br['cell']);
89
90 13
        $objWriter->startElement('xdr:twoCellAnchor');
91
92 13
        $objWriter->startElement('xdr:from');
93 13
        $objWriter->writeElement('xdr:col', Coordinate::columnIndexFromString($tl['colRow'][0]) - 1);
94 13
        $objWriter->writeElement('xdr:colOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($tl['xOffset']));
95 13
        $objWriter->writeElement('xdr:row', $tl['colRow'][1] - 1);
96 13
        $objWriter->writeElement('xdr:rowOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($tl['yOffset']));
97 13
        $objWriter->endElement();
98 13
        $objWriter->startElement('xdr:to');
99 13
        $objWriter->writeElement('xdr:col', Coordinate::columnIndexFromString($br['colRow'][0]) - 1);
100 13
        $objWriter->writeElement('xdr:colOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($br['xOffset']));
101 13
        $objWriter->writeElement('xdr:row', $br['colRow'][1] - 1);
102 13
        $objWriter->writeElement('xdr:rowOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($br['yOffset']));
103 13
        $objWriter->endElement();
104
105 13
        $objWriter->startElement('xdr:graphicFrame');
106 13
        $objWriter->writeAttribute('macro', '');
107 13
        $objWriter->startElement('xdr:nvGraphicFramePr');
108 13
        $objWriter->startElement('xdr:cNvPr');
109 13
        $objWriter->writeAttribute('name', 'Chart ' . $pRelationId);
110 13
        $objWriter->writeAttribute('id', 1025 * $pRelationId);
111 13
        $objWriter->endElement();
112 13
        $objWriter->startElement('xdr:cNvGraphicFramePr');
113 13
        $objWriter->startElement('a:graphicFrameLocks');
114 13
        $objWriter->endElement();
115 13
        $objWriter->endElement();
116 13
        $objWriter->endElement();
117
118 13
        $objWriter->startElement('xdr:xfrm');
119 13
        $objWriter->startElement('a:off');
120 13
        $objWriter->writeAttribute('x', '0');
121 13
        $objWriter->writeAttribute('y', '0');
122 13
        $objWriter->endElement();
123 13
        $objWriter->startElement('a:ext');
124 13
        $objWriter->writeAttribute('cx', '0');
125 13
        $objWriter->writeAttribute('cy', '0');
126 13
        $objWriter->endElement();
127 13
        $objWriter->endElement();
128
129 13
        $objWriter->startElement('a:graphic');
130 13
        $objWriter->startElement('a:graphicData');
131 13
        $objWriter->writeAttribute('uri', 'http://schemas.openxmlformats.org/drawingml/2006/chart');
132 13
        $objWriter->startElement('c:chart');
133 13
        $objWriter->writeAttribute('xmlns:c', 'http://schemas.openxmlformats.org/drawingml/2006/chart');
134 13
        $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
135 13
        $objWriter->writeAttribute('r:id', 'rId' . $pRelationId);
136 13
        $objWriter->endElement();
137 13
        $objWriter->endElement();
138 13
        $objWriter->endElement();
139 13
        $objWriter->endElement();
140
141 13
        $objWriter->startElement('xdr:clientData');
142 13
        $objWriter->endElement();
143
144 13
        $objWriter->endElement();
145 13
    }
146
147
    /**
148
     * Write drawings to XML format.
149
     *
150
     * @param XMLWriter $objWriter XML Writer
151
     * @param BaseDrawing $pDrawing
152
     * @param int $pRelationId
153
     *
154
     * @throws WriterException
155
     */
156 10
    public function writeDrawing(XMLWriter $objWriter, BaseDrawing $pDrawing, $pRelationId = -1)
157
    {
158 10
        if ($pRelationId >= 0) {
159
            // xdr:oneCellAnchor
160 10
            $objWriter->startElement('xdr:oneCellAnchor');
161
            // Image location
162 10
            $aCoordinates = Coordinate::coordinateFromString($pDrawing->getCoordinates());
163 10
            $aCoordinates[0] = Coordinate::columnIndexFromString($aCoordinates[0]);
164
165
            // xdr:from
166 10
            $objWriter->startElement('xdr:from');
167 10
            $objWriter->writeElement('xdr:col', $aCoordinates[0] - 1);
168 10
            $objWriter->writeElement('xdr:colOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($pDrawing->getOffsetX()));
169 10
            $objWriter->writeElement('xdr:row', $aCoordinates[1] - 1);
170 10
            $objWriter->writeElement('xdr:rowOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($pDrawing->getOffsetY()));
171 10
            $objWriter->endElement();
172
173
            // xdr:ext
174 10
            $objWriter->startElement('xdr:ext');
175 10
            $objWriter->writeAttribute('cx', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($pDrawing->getWidth()));
176 10
            $objWriter->writeAttribute('cy', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($pDrawing->getHeight()));
177 10
            $objWriter->endElement();
178
179
            // xdr:pic
180 10
            $objWriter->startElement('xdr:pic');
181
182
            // xdr:nvPicPr
183 10
            $objWriter->startElement('xdr:nvPicPr');
184
185
            // xdr:cNvPr
186 10
            $objWriter->startElement('xdr:cNvPr');
187 10
            $objWriter->writeAttribute('id', $pRelationId);
188 10
            $objWriter->writeAttribute('name', $pDrawing->getName());
189 10
            $objWriter->writeAttribute('descr', $pDrawing->getDescription());
190 10
            $objWriter->endElement();
191
192
            // xdr:cNvPicPr
193 10
            $objWriter->startElement('xdr:cNvPicPr');
194
195
            // a:picLocks
196 10
            $objWriter->startElement('a:picLocks');
197 10
            $objWriter->writeAttribute('noChangeAspect', '1');
198 10
            $objWriter->endElement();
199
200 10
            $objWriter->endElement();
201
202 10
            $objWriter->endElement();
203
204
            // xdr:blipFill
205 10
            $objWriter->startElement('xdr:blipFill');
206
207
            // a:blip
208 10
            $objWriter->startElement('a:blip');
209 10
            $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
210 10
            $objWriter->writeAttribute('r:embed', 'rId' . $pRelationId);
211 10
            $objWriter->endElement();
212
213
            // a:stretch
214 10
            $objWriter->startElement('a:stretch');
215 10
            $objWriter->writeElement('a:fillRect', null);
216 10
            $objWriter->endElement();
217
218 10
            $objWriter->endElement();
219
220
            // xdr:spPr
221 10
            $objWriter->startElement('xdr:spPr');
222
223
            // a:xfrm
224 10
            $objWriter->startElement('a:xfrm');
225 10
            $objWriter->writeAttribute('rot', \PhpOffice\PhpSpreadsheet\Shared\Drawing::degreesToAngle($pDrawing->getRotation()));
226 10
            $objWriter->endElement();
227
228
            // a:prstGeom
229 10
            $objWriter->startElement('a:prstGeom');
230 10
            $objWriter->writeAttribute('prst', 'rect');
231
232
            // a:avLst
233 10
            $objWriter->writeElement('a:avLst', null);
234
235 10
            $objWriter->endElement();
236
237 10
            if ($pDrawing->getShadow()->getVisible()) {
238
                // a:effectLst
239 5
                $objWriter->startElement('a:effectLst');
240
241
                // a:outerShdw
242 5
                $objWriter->startElement('a:outerShdw');
243 5
                $objWriter->writeAttribute('blurRad', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($pDrawing->getShadow()->getBlurRadius()));
244 5
                $objWriter->writeAttribute('dist', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($pDrawing->getShadow()->getDistance()));
245 5
                $objWriter->writeAttribute('dir', \PhpOffice\PhpSpreadsheet\Shared\Drawing::degreesToAngle($pDrawing->getShadow()->getDirection()));
246 5
                $objWriter->writeAttribute('algn', $pDrawing->getShadow()->getAlignment());
247 5
                $objWriter->writeAttribute('rotWithShape', '0');
248
249
                // a:srgbClr
250 5
                $objWriter->startElement('a:srgbClr');
251 5
                $objWriter->writeAttribute('val', $pDrawing->getShadow()->getColor()->getRGB());
252
253
                // a:alpha
254 5
                $objWriter->startElement('a:alpha');
255 5
                $objWriter->writeAttribute('val', $pDrawing->getShadow()->getAlpha() * 1000);
256 5
                $objWriter->endElement();
257
258 5
                $objWriter->endElement();
259
260 5
                $objWriter->endElement();
261
262 5
                $objWriter->endElement();
263
            }
264 10
            $objWriter->endElement();
265
266 10
            $objWriter->endElement();
267
268
            // xdr:clientData
269 10
            $objWriter->writeElement('xdr:clientData', null);
270
271 10
            $objWriter->endElement();
272
        } else {
273
            throw new WriterException('Invalid parameters passed.');
274
        }
275 10
    }
276
277
    /**
278
     * Write VML header/footer images to XML format.
279
     *
280
     * @param \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet
281
     *
282
     * @throws WriterException
283
     *
284
     * @return string XML Output
285
     */
286 1
    public function writeVMLHeaderFooterImages(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet)
287
    {
288
        // Create XML writer
289 1
        $objWriter = null;
290 1
        if ($this->getParentWriter()->getUseDiskCaching()) {
291
            $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
292
        } else {
293 1
            $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
294
        }
295
296
        // XML header
297 1
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
298
299
        // Header/footer images
300 1
        $images = $pWorksheet->getHeaderFooter()->getImages();
301
302
        // xml
303 1
        $objWriter->startElement('xml');
304 1
        $objWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml');
305 1
        $objWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office');
306 1
        $objWriter->writeAttribute('xmlns:x', 'urn:schemas-microsoft-com:office:excel');
307
308
        // o:shapelayout
309 1
        $objWriter->startElement('o:shapelayout');
310 1
        $objWriter->writeAttribute('v:ext', 'edit');
311
312
        // o:idmap
313 1
        $objWriter->startElement('o:idmap');
314 1
        $objWriter->writeAttribute('v:ext', 'edit');
315 1
        $objWriter->writeAttribute('data', '1');
316 1
        $objWriter->endElement();
317
318 1
        $objWriter->endElement();
319
320
        // v:shapetype
321 1
        $objWriter->startElement('v:shapetype');
322 1
        $objWriter->writeAttribute('id', '_x0000_t75');
323 1
        $objWriter->writeAttribute('coordsize', '21600,21600');
324 1
        $objWriter->writeAttribute('o:spt', '75');
325 1
        $objWriter->writeAttribute('o:preferrelative', 't');
326 1
        $objWriter->writeAttribute('path', 'm@4@5l@4@11@9@11@9@5xe');
327 1
        $objWriter->writeAttribute('filled', 'f');
328 1
        $objWriter->writeAttribute('stroked', 'f');
329
330
        // v:stroke
331 1
        $objWriter->startElement('v:stroke');
332 1
        $objWriter->writeAttribute('joinstyle', 'miter');
333 1
        $objWriter->endElement();
334
335
        // v:formulas
336 1
        $objWriter->startElement('v:formulas');
337
338
        // v:f
339 1
        $objWriter->startElement('v:f');
340 1
        $objWriter->writeAttribute('eqn', 'if lineDrawn pixelLineWidth 0');
341 1
        $objWriter->endElement();
342
343
        // v:f
344 1
        $objWriter->startElement('v:f');
345 1
        $objWriter->writeAttribute('eqn', 'sum @0 1 0');
346 1
        $objWriter->endElement();
347
348
        // v:f
349 1
        $objWriter->startElement('v:f');
350 1
        $objWriter->writeAttribute('eqn', 'sum 0 0 @1');
351 1
        $objWriter->endElement();
352
353
        // v:f
354 1
        $objWriter->startElement('v:f');
355 1
        $objWriter->writeAttribute('eqn', 'prod @2 1 2');
356 1
        $objWriter->endElement();
357
358
        // v:f
359 1
        $objWriter->startElement('v:f');
360 1
        $objWriter->writeAttribute('eqn', 'prod @3 21600 pixelWidth');
361 1
        $objWriter->endElement();
362
363
        // v:f
364 1
        $objWriter->startElement('v:f');
365 1
        $objWriter->writeAttribute('eqn', 'prod @3 21600 pixelHeight');
366 1
        $objWriter->endElement();
367
368
        // v:f
369 1
        $objWriter->startElement('v:f');
370 1
        $objWriter->writeAttribute('eqn', 'sum @0 0 1');
371 1
        $objWriter->endElement();
372
373
        // v:f
374 1
        $objWriter->startElement('v:f');
375 1
        $objWriter->writeAttribute('eqn', 'prod @6 1 2');
376 1
        $objWriter->endElement();
377
378
        // v:f
379 1
        $objWriter->startElement('v:f');
380 1
        $objWriter->writeAttribute('eqn', 'prod @7 21600 pixelWidth');
381 1
        $objWriter->endElement();
382
383
        // v:f
384 1
        $objWriter->startElement('v:f');
385 1
        $objWriter->writeAttribute('eqn', 'sum @8 21600 0');
386 1
        $objWriter->endElement();
387
388
        // v:f
389 1
        $objWriter->startElement('v:f');
390 1
        $objWriter->writeAttribute('eqn', 'prod @7 21600 pixelHeight');
391 1
        $objWriter->endElement();
392
393
        // v:f
394 1
        $objWriter->startElement('v:f');
395 1
        $objWriter->writeAttribute('eqn', 'sum @10 21600 0');
396 1
        $objWriter->endElement();
397
398 1
        $objWriter->endElement();
399
400
        // v:path
401 1
        $objWriter->startElement('v:path');
402 1
        $objWriter->writeAttribute('o:extrusionok', 'f');
403 1
        $objWriter->writeAttribute('gradientshapeok', 't');
404 1
        $objWriter->writeAttribute('o:connecttype', 'rect');
405 1
        $objWriter->endElement();
406
407
        // o:lock
408 1
        $objWriter->startElement('o:lock');
409 1
        $objWriter->writeAttribute('v:ext', 'edit');
410 1
        $objWriter->writeAttribute('aspectratio', 't');
411 1
        $objWriter->endElement();
412
413 1
        $objWriter->endElement();
414
415
        // Loop through images
416 1
        foreach ($images as $key => $value) {
417 1
            $this->writeVMLHeaderFooterImage($objWriter, $key, $value);
418
        }
419
420 1
        $objWriter->endElement();
421
422
        // Return
423 1
        return $objWriter->getData();
424
    }
425
426
    /**
427
     * Write VML comment to XML format.
428
     *
429
     * @param XMLWriter $objWriter XML Writer
430
     * @param string $pReference Reference
431
     * @param HeaderFooterDrawing $pImage Image
432
     */
433 1
    private function writeVMLHeaderFooterImage(XMLWriter $objWriter, $pReference, HeaderFooterDrawing $pImage)
434
    {
435
        // Calculate object id
436 1
        preg_match('{(\d+)}', md5($pReference), $m);
437 1
        $id = 1500 + (substr($m[1], 0, 2) * 1);
438
439
        // Calculate offset
440 1
        $width = $pImage->getWidth();
441 1
        $height = $pImage->getHeight();
442 1
        $marginLeft = $pImage->getOffsetX();
443 1
        $marginTop = $pImage->getOffsetY();
444
445
        // v:shape
446 1
        $objWriter->startElement('v:shape');
447 1
        $objWriter->writeAttribute('id', $pReference);
448 1
        $objWriter->writeAttribute('o:spid', '_x0000_s' . $id);
449 1
        $objWriter->writeAttribute('type', '#_x0000_t75');
450 1
        $objWriter->writeAttribute('style', "position:absolute;margin-left:{$marginLeft}px;margin-top:{$marginTop}px;width:{$width}px;height:{$height}px;z-index:1");
451
452
        // v:imagedata
453 1
        $objWriter->startElement('v:imagedata');
454 1
        $objWriter->writeAttribute('o:relid', 'rId' . $pReference);
455 1
        $objWriter->writeAttribute('o:title', $pImage->getName());
456 1
        $objWriter->endElement();
457
458
        // o:lock
459 1
        $objWriter->startElement('o:lock');
460 1
        $objWriter->writeAttribute('v:ext', 'edit');
461 1
        $objWriter->writeAttribute('textRotation', 't');
462 1
        $objWriter->endElement();
463
464 1
        $objWriter->endElement();
465 1
    }
466
467
    /**
468
     * Get an array of all drawings.
469
     *
470
     * @param Spreadsheet $spreadsheet
471
     *
472
     * @return \PhpOffice\PhpSpreadsheet\Worksheet\Drawing[] All drawings in PhpSpreadsheet
473
     */
474 78
    public function allDrawings(Spreadsheet $spreadsheet)
475
    {
476
        // Get an array of all drawings
477 78
        $aDrawings = [];
478
479
        // Loop through PhpSpreadsheet
480 78
        $sheetCount = $spreadsheet->getSheetCount();
481 78
        for ($i = 0; $i < $sheetCount; ++$i) {
482
            // Loop through images and add to array
483 78
            $iterator = $spreadsheet->getSheet($i)->getDrawingCollection()->getIterator();
484 78
            while ($iterator->valid()) {
485 10
                $aDrawings[] = $iterator->current();
486
487 10
                $iterator->next();
488
            }
489
        }
490
491 78
        return $aDrawings;
492
    }
493
}
494