PptSlides::render()   A
last analyzed

Complexity

Conditions 5
Paths 7

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5.0187

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 10
cts 11
cp 0.9091
rs 9.2568
c 0
b 0
f 0
cc 5
nc 7
nop 0
crap 5.0187
1
<?php
2
3
namespace PhpOffice\PhpPresentation\Writer\PowerPoint2007;
4
5
use PhpOffice\Common\Drawing as CommonDrawing;
6
use PhpOffice\Common\XMLWriter;
7
use PhpOffice\PhpPresentation\Shape\Chart as ShapeChart;
8
use PhpOffice\PhpPresentation\Shape\Comment;
9
use PhpOffice\PhpPresentation\Shape\Drawing as ShapeDrawing;
10
use PhpOffice\PhpPresentation\Shape\Group;
11
use PhpOffice\PhpPresentation\Shape\Media;
12
use PhpOffice\PhpPresentation\Shape\RichText;
13
use PhpOffice\PhpPresentation\Shape\RichText\Run;
14
use PhpOffice\PhpPresentation\Shape\RichText\TextElement;
15
use PhpOffice\PhpPresentation\Shape\Table as ShapeTable;
16
use PhpOffice\PhpPresentation\Slide;
17
use PhpOffice\PhpPresentation\Slide\Background\Image;
18
use PhpOffice\PhpPresentation\Slide\Note;
19
20
class PptSlides extends AbstractSlide
21
{
22
    /**
23
     * Add slides (drawings, ...) and slide relationships (drawings, ...)
24
     * @return \PhpOffice\Common\Adapter\Zip\ZipInterface
25
     * @throws \Exception
26
     */
27 112
    public function render()
28
    {
29 112
        foreach ($this->oPresentation->getAllSlides() as $idx => $oSlide) {
30 112
            $this->oZip->addFromString('ppt/slides/_rels/slide' . ($idx + 1) . '.xml.rels', $this->writeSlideRelationships($oSlide));
31 112
            $this->oZip->addFromString('ppt/slides/slide' . ($idx + 1) . '.xml', $this->writeSlide($oSlide));
32
33
            // Add note slide
34 112
            if ($oSlide->getNote() instanceof Note) {
35 112
                if ($oSlide->getNote()->getShapeCollection()->count() > 0) {
36 1
                    $this->oZip->addFromString('ppt/notesSlides/notesSlide' . ($idx + 1) . '.xml', $this->writeNote($oSlide->getNote()));
37
                }
38
            }
39
40
            // Add background image slide
41 112
            $oBkgImage = $oSlide->getBackground();
42 112
            if ($oBkgImage instanceof Image) {
43
                $this->oZip->addFromString('ppt/media/'.$oBkgImage->getIndexedFilename($idx), file_get_contents($oBkgImage->getPath()));
44
            }
45
        }
46
47 112
        return $this->oZip;
48
    }
49
50
    /**
51
     * Write slide relationships to XML format
52
     *
53
     * @param  \PhpOffice\PhpPresentation\Slide $pSlide
54
     * @return string              XML Output
55
     * @throws \Exception
56
     */
57 112
    protected function writeSlideRelationships(Slide $pSlide)
58
    {
59
        //@todo Group all getShapeCollection()->getIterator
60
61
        // Create XML writer
62 112
        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
63
64
        // XML header
65 112
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
66
67
        // Relationships
68 112
        $objWriter->startElement('Relationships');
69 112
        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
70
71
        // Starting relation id
72 112
        $relId = 1;
73 112
        $idxSlide = $pSlide->getParent()->getIndex($pSlide);
74
75
        // Write slideLayout relationship
76 112
        $layoutId = 1;
77 112
        if ($pSlide->getSlideLayout()) {
78 112
            $layoutId = $pSlide->getSlideLayout()->layoutNr;
79
        }
80 112
        $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout', '../slideLayouts/slideLayout' . $layoutId . '.xml');
81 112
        ++$relId;
82
83
        // Write drawing relationships?
84 112
        if ($pSlide->getShapeCollection()->count() > 0) {
85
            // Loop trough images and write relationships
86 85
            $iterator = $pSlide->getShapeCollection()->getIterator();
87 85
            while ($iterator->valid()) {
88 85
                if ($iterator->current() instanceof Media) {
89
                    // Write relationship for image drawing
90 1
                    $iterator->current()->relationId = 'rId' . $relId;
91 1
                    $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/video', '../media/' . $iterator->current()->getIndexedFilename());
92 1
                    ++$relId;
93 1
                    $this->writeRelationship($objWriter, $relId, 'http://schemas.microsoft.com/office/2007/relationships/media', '../media/' . $iterator->current()->getIndexedFilename());
94 1
                    ++$relId;
95 84
                } elseif ($iterator->current() instanceof ShapeDrawing\AbstractDrawingAdapter) {
96
                    // Write relationship for image drawing
97 8
                    $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image', '../media/' . $iterator->current()->getIndexedFilename());
98 8
                    $iterator->current()->relationId = 'rId' . $relId;
99 8
                    ++$relId;
100 76
                } elseif ($iterator->current() instanceof ShapeChart) {
101
                    // Write relationship for chart drawing
102 34
                    $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart', '../charts/' . $iterator->current()->getIndexedFilename());
103
104 34
                    $iterator->current()->relationId = 'rId' . $relId;
105
106 34
                    ++$relId;
107 42
                } elseif ($iterator->current() instanceof Group) {
108 1
                    $iterator2 = $iterator->current()->getShapeCollection()->getIterator();
109 1
                    while ($iterator2->valid()) {
110 1
                        if ($iterator2->current() instanceof Media) {
111
                            // Write relationship for image drawing
112
                            $iterator2->current()->relationId = 'rId' . $relId;
113
                            $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/video', '../media/' . $iterator->current()->getIndexedFilename());
114
                            ++$relId;
115
                            $this->writeRelationship($objWriter, $relId, 'http://schemas.microsoft.com/office/2007/relationships/media', '../media/' . $iterator->current()->getIndexedFilename());
116
                            ++$relId;
117 1
                        } elseif ($iterator2->current() instanceof ShapeDrawing\AbstractDrawingAdapter) {
118
                            // Write relationship for image drawing
119
                            $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image', '../media/' . $iterator2->current()->getIndexedFilename());
120
                            $iterator2->current()->relationId = 'rId' . $relId;
121
122
                            ++$relId;
123 1
                        } elseif ($iterator2->current() instanceof ShapeChart) {
124
                            // Write relationship for chart drawing
125
                            $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart', '../charts/' . $iterator2->current()->getIndexedFilename());
126
                            $iterator2->current()->relationId = 'rId' . $relId;
127
128
                            ++$relId;
129
                        }
130 1
                        $iterator2->next();
131
                    }
132
                }
133
134 85
                $iterator->next();
135
            }
136
        }
137
138
        // Write background relationships?
139 112
        $oBackground = $pSlide->getBackground();
140 112
        if ($oBackground instanceof Image) {
141
            $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image', '../media/' . $oBackground->getIndexedFilename($idxSlide));
142
            $oBackground->relationId = 'rId' . $relId;
143
            ++$relId;
144
        }
145
146
        // Write hyperlink relationships?
147 112
        if ($pSlide->getShapeCollection()->count() > 0) {
148
            // Loop trough hyperlinks and write relationships
149 85
            $iterator = $pSlide->getShapeCollection()->getIterator();
150 85
            while ($iterator->valid()) {
151
                // Hyperlink on shape
152 85
                if ($iterator->current()->hasHyperlink()) {
153
                    // Write relationship for hyperlink
154 2
                    $hyperlink               = $iterator->current()->getHyperlink();
155 2
                    $hyperlink->relationId = 'rId' . $relId;
156
157 2
                    if (!$hyperlink->isInternal()) {
158 2
                        $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', $hyperlink->getUrl(), 'External');
159
                    } else {
160
                        $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide', 'slide' . $hyperlink->getSlideNumber() . '.xml');
161
                    }
162
163 2
                    ++$relId;
164
                }
165
166
                // Hyperlink on rich text run
167 85
                if ($iterator->current() instanceof RichText) {
168 24
                    foreach ($iterator->current()->getParagraphs() as $paragraph) {
169 24
                        foreach ($paragraph->getRichTextElements() as $element) {
170 19
                            if ($element instanceof Run || $element instanceof TextElement) {
171 18
                                if ($element->hasHyperlink()) {
172
                                    // Write relationship for hyperlink
173 2
                                    $hyperlink               = $element->getHyperlink();
174 2
                                    $hyperlink->relationId = 'rId' . $relId;
175
176 2
                                    if (!$hyperlink->isInternal()) {
177 1
                                        $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', $hyperlink->getUrl(), 'External');
178
                                    } else {
179 1
                                        $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide', 'slide' . $hyperlink->getSlideNumber() . '.xml');
180
                                    }
181
182 2
                                    ++$relId;
183
                                }
184
                            }
185
                        }
186
                    }
187
                }
188
189
                // Hyperlink in table
190 85
                if ($iterator->current() instanceof ShapeTable) {
191
                    // Rows
192 10
                    $countRows = count($iterator->current()->getRows());
193 10
                    for ($row = 0; $row < $countRows; $row++) {
194
                        // Cells in rows
195 10
                        $countCells = count($iterator->current()->getRow($row)->getCells());
196 10
                        for ($cell = 0; $cell < $countCells; $cell++) {
197 10
                            $currentCell = $iterator->current()->getRow($row)->getCell($cell);
198
                            // Paragraphs in cell
199 10
                            foreach ($currentCell->getParagraphs() as $paragraph) {
200
                                // RichText in paragraph
201 10
                                foreach ($paragraph->getRichTextElements() as $element) {
202
                                    // Run or Text in RichText
203 10
                                    if ($element instanceof Run || $element instanceof TextElement) {
204 10
                                        if ($element->hasHyperlink()) {
205
                                            // Write relationship for hyperlink
206 1
                                            $hyperlink               = $element->getHyperlink();
207 1
                                            $hyperlink->relationId = 'rId' . $relId;
208
209 1
                                            if (!$hyperlink->isInternal()) {
210 1
                                                $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', $hyperlink->getUrl(), 'External');
211
                                            } else {
212
                                                $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide', 'slide' . $hyperlink->getSlideNumber() . '.xml');
213
                                            }
214
215 1
                                            ++$relId;
216
                                        }
217
                                    }
218
                                }
219
                            }
220
                        }
221
                    }
222
                }
223
224 85
                if ($iterator->current() instanceof Group) {
225 1
                    $iterator2 = $pSlide->getShapeCollection()->getIterator();
226 1
                    while ($iterator2->valid()) {
227
                        // Hyperlink on shape
228 1
                        if ($iterator2->current()->hasHyperlink()) {
229
                            // Write relationship for hyperlink
230
                            $hyperlink             = $iterator2->current()->getHyperlink();
231
                            $hyperlink->relationId = 'rId' . $relId;
232
233
                            if (!$hyperlink->isInternal()) {
234
                                $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', $hyperlink->getUrl(), 'External');
235
                            } else {
236
                                $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide', 'slide' . $hyperlink->getSlideNumber() . '.xml');
237
                            }
238
239
                            ++$relId;
240
                        }
241
242
                        // Hyperlink on rich text run
243 1
                        if ($iterator2->current() instanceof RichText) {
244
                            foreach ($iterator2->current()->getParagraphs() as $paragraph) {
245
                                foreach ($paragraph->getRichTextElements() as $element) {
246
                                    if ($element instanceof Run || $element instanceof TextElement) {
247
                                        if ($element->hasHyperlink()) {
248
                                            // Write relationship for hyperlink
249
                                            $hyperlink              = $element->getHyperlink();
250
                                            $hyperlink->relationId = 'rId' . $relId;
251
252
                                            if (!$hyperlink->isInternal()) {
253
                                                $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', $hyperlink->getUrl(), 'External');
254
                                            } else {
255
                                                $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide', 'slide' . $hyperlink->getSlideNumber() . '.xml');
256
                                            }
257
258
                                            ++$relId;
259
                                        }
260
                                    }
261
                                }
262
                            }
263
                        }
264
265
                        // Hyperlink in table
266 1
                        if ($iterator2->current() instanceof ShapeTable) {
267
                            // Rows
268
                            $countRows = count($iterator2->current()->getRows());
269
                            for ($row = 0; $row < $countRows; $row++) {
270
                                // Cells in rows
271
                                $countCells = count($iterator2->current()->getRow($row)->getCells());
272
                                for ($cell = 0; $cell < $countCells; $cell++) {
273
                                    $currentCell = $iterator2->current()->getRow($row)->getCell($cell);
274
                                    // Paragraphs in cell
275
                                    foreach ($currentCell->getParagraphs() as $paragraph) {
276
                                        // RichText in paragraph
277
                                        foreach ($paragraph->getRichTextElements() as $element) {
278
                                            // Run or Text in RichText
279
                                            if ($element instanceof Run || $element instanceof TextElement) {
280
                                                if ($element->hasHyperlink()) {
281
                                                    // Write relationship for hyperlink
282
                                                    $hyperlink               = $element->getHyperlink();
283
                                                    $hyperlink->relationId = 'rId' . $relId;
284
285
                                                    if (!$hyperlink->isInternal()) {
286
                                                        $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', $hyperlink->getUrl(), 'External');
287
                                                    } else {
288
                                                        $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide', 'slide' . $hyperlink->getSlideNumber() . '.xml');
289
                                                    }
290
291
                                                    ++$relId;
292
                                                }
293
                                            }
294
                                        }
295
                                    }
296
                                }
297
                            }
298
                        }
299
300 1
                        $iterator2->next();
301
                    }
302
                }
303
304 85
                $iterator->next();
305
            }
306
        }
307
308
        // Write comment relationships
309 112
        if ($pSlide->getShapeCollection()->count() > 0) {
310 85
            $hasSlideComment = false;
311
312
            // Loop trough images and write relationships
313 85
            $iterator = $pSlide->getShapeCollection()->getIterator();
314 85
            while ($iterator->valid()) {
315 85
                if ($iterator->current() instanceof Comment) {
316 6
                    $hasSlideComment = true;
317 6
                    break;
318 79
                } elseif ($iterator->current() instanceof Group) {
319 1
                    $iterator2 = $iterator->current()->getShapeCollection()->getIterator();
320 1
                    while ($iterator2->valid()) {
321 1
                        if ($iterator2->current() instanceof Comment) {
322 1
                            $hasSlideComment = true;
323 1
                            break 2;
324
                        }
325
                        $iterator2->next();
326
                    }
327
                }
328
329 78
                $iterator->next();
330
            }
331
332 85
            if ($hasSlideComment) {
333 7
                $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments', '../comments/comment'.($idxSlide + 1).'.xml');
334 7
                ++$relId;
335
            }
336
        }
337
338 112
        if ($pSlide->getNote()->getShapeCollection()->count() > 0) {
339 1
            $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide', '../notesSlides/notesSlide'.($idxSlide + 1).'.xml');
340
        }
341
342 112
        $objWriter->endElement();
343
344
        // Return
345 112
        return $objWriter->getData();
346
    }
347
348
    /**
349
     * Write slide to XML format
350
     *
351
     * @param  \PhpOffice\PhpPresentation\Slide $pSlide
352
     * @return string              XML Output
353
     * @throws \Exception
354
     */
355 112
    public function writeSlide(Slide $pSlide)
356
    {
357
        // Create XML writer
358 112
        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
359
360
        // XML header
361 112
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
362
363
        // p:sld
364 112
        $objWriter->startElement('p:sld');
365 112
        $objWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main');
366 112
        $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
367 112
        $objWriter->writeAttribute('xmlns:p', 'http://schemas.openxmlformats.org/presentationml/2006/main');
368 112
        $objWriter->writeAttributeIf(!$pSlide->isVisible(), 'show', 0);
369
370
        // p:sld/p:cSld
371 112
        $objWriter->startElement('p:cSld');
372
373
        // Background
374 112
        if ($pSlide->getBackground() instanceof Slide\AbstractBackground) {
375
            $oBackground = $pSlide->getBackground();
376
            // p:bg
377
            $objWriter->startElement('p:bg');
378
379
            // p:bgPr
380
            $objWriter->startElement('p:bgPr');
381
382
            if ($oBackground instanceof Slide\Background\Color) {
383
                // a:solidFill
384
                $objWriter->startElement('a:solidFill');
385
386
                $this->writeColor($objWriter, $oBackground->getColor());
387
388
                // > a:solidFill
389
                $objWriter->endElement();
390
            }
391
392
            if ($oBackground instanceof Slide\Background\Image) {
393
                // a:blipFill
394
                $objWriter->startElement('a:blipFill');
395
396
                // a:blip
397
                $objWriter->startElement('a:blip');
398
                $objWriter->writeAttribute('r:embed', $oBackground->relationId);
399
400
                // > a:blipFill
401
                $objWriter->endElement();
402
403
                // a:stretch
404
                $objWriter->startElement('a:stretch');
405
406
                // a:fillRect
407
                $objWriter->writeElement('a:fillRect');
408
409
                // > a:stretch
410
                $objWriter->endElement();
411
412
                // > a:blipFill
413
                $objWriter->endElement();
414
            }
415
416
            // > p:bgPr
417
            $objWriter->endElement();
418
419
            // > p:bg
420
            $objWriter->endElement();
421
        }
422
423
        // p:spTree
424 112
        $objWriter->startElement('p:spTree');
425
426
        // p:nvGrpSpPr
427 112
        $objWriter->startElement('p:nvGrpSpPr');
428
429
        // p:cNvPr
430 112
        $objWriter->startElement('p:cNvPr');
431 112
        $objWriter->writeAttribute('id', '1');
432 112
        $objWriter->writeAttribute('name', '');
433 112
        $objWriter->endElement();
434
435
        // p:cNvGrpSpPr
436 112
        $objWriter->writeElement('p:cNvGrpSpPr', null);
437
438
        // p:nvPr
439 112
        $objWriter->writeElement('p:nvPr', null);
440
441 112
        $objWriter->endElement();
442
443
        // p:grpSpPr
444 112
        $objWriter->startElement('p:grpSpPr');
445
446
        // a:xfrm
447 112
        $objWriter->startElement('a:xfrm');
448
449
        // a:off
450 112
        $objWriter->startElement('a:off');
451 112
        $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($pSlide->getOffsetX()));
452 112
        $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($pSlide->getOffsetY()));
453 112
        $objWriter->endElement(); // a:off
454
455
        // a:ext
456 112
        $objWriter->startElement('a:ext');
457 112
        $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu($pSlide->getExtentX()));
458 112
        $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu($pSlide->getExtentY()));
459 112
        $objWriter->endElement(); // a:ext
460
461
        // a:chOff
462 112
        $objWriter->startElement('a:chOff');
463 112
        $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($pSlide->getOffsetX()));
464 112
        $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($pSlide->getOffsetY()));
465 112
        $objWriter->endElement(); // a:chOff
466
467
        // a:chExt
468 112
        $objWriter->startElement('a:chExt');
469 112
        $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu($pSlide->getExtentX()));
470 112
        $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu($pSlide->getExtentY()));
471 112
        $objWriter->endElement(); // a:chExt
472
473 112
        $objWriter->endElement();
474
475 112
        $objWriter->endElement();
476
477
        // Loop shapes
478 112
        $this->writeShapeCollection($objWriter, $pSlide->getShapeCollection());
479
480
        // TODO
481 112
        $objWriter->endElement();
482
483 112
        $objWriter->endElement();
484
485
        // p:clrMapOvr
486 112
        $objWriter->startElement('p:clrMapOvr');
487
        // p:clrMapOvr\a:masterClrMapping
488 112
        $objWriter->writeElement('a:masterClrMapping', null);
489
        // ##p:clrMapOvr
490 112
        $objWriter->endElement();
491
492 112
        $this->writeSlideTransition($objWriter, $pSlide->getTransition());
493
494 112
        $this->writeSlideAnimations($objWriter, $pSlide);
495
496 112
        $objWriter->endElement();
497
498
        // Return
499 112
        return $objWriter->getData();
500
    }
501
502
    /**
503
     * @param XMLWriter $objWriter
504
     * @param Slide $oSlide
505
     */
506 112
    protected function writeSlideAnimations(XMLWriter $objWriter, Slide $oSlide)
507
    {
508 112
        $arrayAnimations = $oSlide->getAnimations();
509 112
        if (empty($arrayAnimations)) {
510 111
            return;
511
        }
512
513
        // Variables
514 1
        $shapeId = 1;
515 1
        $idCount = 1;
516 1
        $hashToIdMap = array();
517 1
        $arrayAnimationIds = array();
518
519 1
        foreach ($oSlide->getShapeCollection() as $shape) {
520 1
            $hashToIdMap[$shape->getHashCode()] = ++$shapeId;
521
        }
522 1
        foreach ($arrayAnimations as $oAnimation) {
523 1
            foreach ($oAnimation->getShapeCollection() as $oShape) {
524 1
                $arrayAnimationIds[] = $hashToIdMap[$oShape->getHashCode()];
525
            }
526
        }
527
528
        // p:timing
529 1
        $objWriter->startElement('p:timing');
530
        // p:timing/p:tnLst
531 1
        $objWriter->startElement('p:tnLst');
532
        // p:timing/p:tnLst/p:par
533 1
        $objWriter->startElement('p:par');
534
        // p:timing/p:tnLst/p:par/p:cTn
535 1
        $objWriter->startElement('p:cTn');
536 1
        $objWriter->writeAttribute('id', $idCount++);
537 1
        $objWriter->writeAttribute('dur', 'indefinite');
538 1
        $objWriter->writeAttribute('restart', 'never');
539 1
        $objWriter->writeAttribute('nodeType', 'tmRoot');
540
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst
541 1
        $objWriter->startElement('p:childTnLst');
542
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq
543 1
        $objWriter->startElement('p:seq');
544 1
        $objWriter->writeAttribute('concurrent', '1');
545 1
        $objWriter->writeAttribute('nextAc', 'seek');
546
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn
547 1
        $objWriter->startElement('p:cTn');
548 1
        $objWriter->writeAttribute('id', $idCount++);
549 1
        $objWriter->writeAttribute('dur', 'indefinite');
550 1
        $objWriter->writeAttribute('nodeType', 'mainSeq');
551
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst
552 1
        $objWriter->startElement('p:childTnLst');
553
554
        // Each animation has multiple shapes
555 1
        foreach ($arrayAnimations as $oAnimation) {
556
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par
557 1
            $objWriter->startElement('p:par');
558
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn
559 1
            $objWriter->startElement('p:cTn');
560 1
            $objWriter->writeAttribute('id', $idCount++);
561 1
            $objWriter->writeAttribute('fill', 'hold');
562
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:stCondLst
563 1
            $objWriter->startElement('p:stCondLst');
564
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:stCondLst/p:cond
565 1
            $objWriter->startElement('p:cond');
566 1
            $objWriter->writeAttribute('delay', 'indefinite');
567 1
            $objWriter->endElement();
568
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn\##p:stCondLst
569 1
            $objWriter->endElement();
570
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst
571 1
            $objWriter->startElement('p:childTnLst');
572
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst/p:par
573 1
            $objWriter->startElement('p:par');
574
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst/p:par/p:cTn
575 1
            $objWriter->startElement('p:cTn');
576 1
            $objWriter->writeAttribute('id', $idCount++);
577 1
            $objWriter->writeAttribute('fill', 'hold');
578
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst/p:par/p:cTn/p:stCondLst
579 1
            $objWriter->startElement('p:stCondLst');
580
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst/p:par/p:cTn/p:stCondLst/p:cond
581 1
            $objWriter->startElement('p:cond');
582 1
            $objWriter->writeAttribute('delay', '0');
583 1
            $objWriter->endElement();
584
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst/p:par/p:cTn\##p:stCondLst
585 1
            $objWriter->endElement();
586
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst
587 1
            $objWriter->startElement('p:childTnLst');
588
589 1
            $firstAnimation = true;
590 1
            foreach ($oAnimation->getShapeCollection() as $oShape) {
591 1
                $nodeType = $firstAnimation ? 'clickEffect' : 'withEffect';
592 1
                $shapeId = $hashToIdMap[$oShape->getHashCode()];
593
594
                // p:par
595 1
                $objWriter->startElement('p:par');
596
                // p:par/p:cTn
597 1
                $objWriter->startElement('p:cTn');
598 1
                $objWriter->writeAttribute('id', $idCount++);
599 1
                $objWriter->writeAttribute('presetID', '1');
600 1
                $objWriter->writeAttribute('presetClass', 'entr');
601 1
                $objWriter->writeAttribute('fill', 'hold');
602 1
                $objWriter->writeAttribute('presetSubtype', '0');
603 1
                $objWriter->writeAttribute('grpId', '0');
604 1
                $objWriter->writeAttribute('nodeType', $nodeType);
605
                // p:par/p:cTn/p:stCondLst
606 1
                $objWriter->startElement('p:stCondLst');
607
                // p:par/p:cTn/p:stCondLst/p:cond
608 1
                $objWriter->startElement('p:cond');
609 1
                $objWriter->writeAttribute('delay', '0');
610 1
                $objWriter->endElement();
611
                // p:par/p:cTn\##p:stCondLst
612 1
                $objWriter->endElement();
613
                // p:par/p:cTn/p:childTnLst
614 1
                $objWriter->startElement('p:childTnLst');
615
                // p:par/p:cTn/p:childTnLst/p:set
616 1
                $objWriter->startElement('p:set');
617
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr
618 1
                $objWriter->startElement('p:cBhvr');
619
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:cTn
620 1
                $objWriter->startElement('p:cTn');
621 1
                $objWriter->writeAttribute('id', $idCount++);
622 1
                $objWriter->writeAttribute('dur', '1');
623 1
                $objWriter->writeAttribute('fill', 'hold');
624
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:cTn/p:stCondLst
625 1
                $objWriter->startElement('p:stCondLst');
626
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:cTn/p:stCondLst/p:cond
627 1
                $objWriter->startElement('p:cond');
628 1
                $objWriter->writeAttribute('delay', '0');
629 1
                $objWriter->endElement();
630
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:cTn\##p:stCondLst
631 1
                $objWriter->endElement();
632
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr\##p:cTn
633 1
                $objWriter->endElement();
634
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:tgtEl
635 1
                $objWriter->startElement('p:tgtEl');
636
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:tgtEl/p:spTgt
637 1
                $objWriter->startElement('p:spTgt');
638 1
                $objWriter->writeAttribute('spid', $shapeId);
639 1
                $objWriter->endElement();
640
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr\##p:tgtEl
641 1
                $objWriter->endElement();
642
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:attrNameLst
643 1
                $objWriter->startElement('p:attrNameLst');
644
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:attrNameLst/p:attrName
645 1
                $objWriter->writeElement('p:attrName', 'style.visibility');
646
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr\##p:attrNameLst
647 1
                $objWriter->endElement();
648
                // p:par/p:cTn/p:childTnLst/p:set\##p:cBhvr
649 1
                $objWriter->endElement();
650
                // p:par/p:cTn/p:childTnLst/p:set/p:to
651 1
                $objWriter->startElement('p:to');
652
                // p:par/p:cTn/p:childTnLst/p:set/p:to/p:strVal
653 1
                $objWriter->startElement('p:strVal');
654 1
                $objWriter->writeAttribute('val', 'visible');
655 1
                $objWriter->endElement();
656
                // p:par/p:cTn/p:childTnLst/p:set\##p:to
657 1
                $objWriter->endElement();
658
                // p:par/p:cTn/p:childTnLst\##p:set
659 1
                $objWriter->endElement();
660
                // p:par/p:cTn\##p:childTnLst
661 1
                $objWriter->endElement();
662
                // p:par\##p:cTn
663 1
                $objWriter->endElement();
664
                // ##p:par
665 1
                $objWriter->endElement();
666
667 1
                $firstAnimation = false;
668
            }
669
670
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst/p:par/p:cTn\##p:childTnLst
671 1
            $objWriter->endElement();
672
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst/p:par\##p:cTn
673 1
            $objWriter->endElement();
674
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst\##p:par
675 1
            $objWriter->endElement();
676
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn\##p:childTnLst
677 1
            $objWriter->endElement();
678
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par\##p:cTn
679 1
            $objWriter->endElement();
680
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst\##p:par
681 1
            $objWriter->endElement();
682
        }
683
684
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn\##p:childTnLst
685 1
        $objWriter->endElement();
686
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq\##p:cTn
687 1
        $objWriter->endElement();
688
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:prevCondLst
689 1
        $objWriter->startElement('p:prevCondLst');
690
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:prevCondLst/p:cond
691 1
        $objWriter->startElement('p:cond');
692 1
        $objWriter->writeAttribute('evt', 'onPrev');
693 1
        $objWriter->writeAttribute('delay', '0');
694
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:prevCondLst/p:cond/p:tgtEl
695 1
        $objWriter->startElement('p:tgtEl');
696
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:prevCondLst/p:cond/p:tgtEl/p:sldTgt
697 1
        $objWriter->writeElement('p:sldTgt', null);
698
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:prevCondLst/p:cond\##p:tgtEl
699 1
        $objWriter->endElement();
700
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:prevCondLst\##p:cond
701 1
        $objWriter->endElement();
702
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq\##p:prevCondLst
703 1
        $objWriter->endElement();
704
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:nextCondLst
705 1
        $objWriter->startElement('p:nextCondLst');
706
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:nextCondLst/p:cond
707 1
        $objWriter->startElement('p:cond');
708 1
        $objWriter->writeAttribute('evt', 'onNext');
709 1
        $objWriter->writeAttribute('delay', '0');
710
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:nextCondLst/p:cond/p:tgtEl
711 1
        $objWriter->startElement('p:tgtEl');
712
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:nextCondLst/p:cond/p:tgtEl/p:sldTgt
713 1
        $objWriter->writeElement('p:sldTgt', null);
714
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:nextCondLst/p:cond\##p:tgtEl
715 1
        $objWriter->endElement();
716
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:nextCondLst\##p:cond
717 1
        $objWriter->endElement();
718
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq\##p:nextCondLst
719 1
        $objWriter->endElement();
720
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst\##p:seq
721 1
        $objWriter->endElement();
722
        // p:timing/p:tnLst/p:par/p:cTn\##p:childTnLst
723 1
        $objWriter->endElement();
724
        // p:timing/p:tnLst/p:par\##p:cTn
725 1
        $objWriter->endElement();
726
        // p:timing/p:tnLst\##p:par
727 1
        $objWriter->endElement();
728
        // p:timing\##p:tnLst
729 1
        $objWriter->endElement();
730
731
        // p:timing/p:bldLst
732 1
        $objWriter->startElement('p:bldLst');
733
734
        // Add in ids of all shapes in this slides animations
735 1
        foreach ($arrayAnimationIds as $id) {
736
            // p:timing/p:bldLst/p:bldP
737 1
            $objWriter->startElement('p:bldP');
738 1
            $objWriter->writeAttribute('spid', $id);
739 1
            $objWriter->writeAttribute('grpId', 0);
740 1
            $objWriter->endELement();
741
        }
742
743
        // p:timing\##p:bldLst
744 1
        $objWriter->endElement();
745
746
        // ##p:timing
747 1
        $objWriter->endElement();
748 1
    }
749
750
    /**
751
     * Write pic
752
     *
753
     * @param  \PhpOffice\Common\XMLWriter  $objWriter XML Writer
754
     * @param  \PhpOffice\PhpPresentation\Shape\Drawing\AbstractDrawingAdapter $shape
755
     * @param  int $shapeId
756
     * @throws \Exception
757
     */
758
    protected function writeShapeDrawing(XMLWriter $objWriter, ShapeDrawing\AbstractDrawingAdapter $shape, $shapeId)
759
    {
760
        // p:pic
761
        $objWriter->startElement('p:pic');
762
763
        // p:nvPicPr
764
        $objWriter->startElement('p:nvPicPr');
765
766
        // p:cNvPr
767
        $objWriter->startElement('p:cNvPr');
768
        $objWriter->writeAttribute('id', $shapeId);
769
        $objWriter->writeAttribute('name', $shape->getName());
770
        $objWriter->writeAttribute('descr', $shape->getDescription());
771
772
        // a:hlinkClick
773
        if ($shape->hasHyperlink()) {
774
            $this->writeHyperlink($objWriter, $shape);
775
        }
776
777
        $objWriter->endElement();
778
779
        // p:cNvPicPr
780
        $objWriter->startElement('p:cNvPicPr');
781
782
        // a:picLocks
783
        $objWriter->startElement('a:picLocks');
784
        $objWriter->writeAttribute('noChangeAspect', '1');
785
        $objWriter->endElement();
786
787
        $objWriter->endElement();
788
789
        // p:nvPr
790
        $objWriter->startElement('p:nvPr');
791
        // PlaceHolder
792
        if ($shape->isPlaceholder()) {
793
            $objWriter->startElement('p:ph');
794
            $objWriter->writeAttribute('type', $shape->getPlaceholder()->getType());
795
            $objWriter->endElement();
796
        }
797
        /**
798
         * @link : https://github.com/stefslon/exportToPPTX/blob/master/exportToPPTX.m#L2128
799
         */
800
        if ($shape instanceof Media) {
801
            // p:nvPr > a:videoFile
802
            $objWriter->startElement('a:videoFile');
803
            $objWriter->writeAttribute('r:link', $shape->relationId);
804
            $objWriter->endElement();
805
            // p:nvPr > p:extLst
806
            $objWriter->startElement('p:extLst');
807
            // p:nvPr > p:extLst > p:ext
808
            $objWriter->startElement('p:ext');
809
            $objWriter->writeAttribute('uri', '{DAA4B4D4-6D71-4841-9C94-3DE7FCFB9230}');
810
            // p:nvPr > p:extLst > p:ext > p14:media
811
            $objWriter->startElement('p14:media');
812
            $objWriter->writeAttribute('r:embed', ($shape->relationId + 1));
813
            $objWriter->writeAttribute('xmlns:p14', 'http://schemas.microsoft.com/office/powerpoint/2010/main');
814
            // p:nvPr > p:extLst > p:ext > ##p14:media
815
            $objWriter->endElement();
816
            // p:nvPr > p:extLst > ##p:ext
817
            $objWriter->endElement();
818
            // p:nvPr > ##p:extLst
819
            $objWriter->endElement();
820
        }
821
        // ##p:nvPr
822
        $objWriter->endElement();
823
        $objWriter->endElement();
824
825
        // p:blipFill
826
        $objWriter->startElement('p:blipFill');
827
828
        // a:blip
829
        $objWriter->startElement('a:blip');
830
        $objWriter->writeAttribute('r:embed', $shape->relationId);
831
        $objWriter->endElement();
832
833
        // a:stretch
834
        $objWriter->startElement('a:stretch');
835
        $objWriter->writeElement('a:fillRect');
836
        $objWriter->endElement();
837
838
        $objWriter->endElement();
839
840
        // p:spPr
841
        $objWriter->startElement('p:spPr');
842
        // a:xfrm
843
        $objWriter->startElement('a:xfrm');
844
        $objWriter->writeAttributeIf($shape->getRotation() != 0, 'rot', CommonDrawing::degreesToAngle($shape->getRotation()));
845
846
        // a:off
847
        $objWriter->startElement('a:off');
848
        $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($shape->getOffsetX()));
849
        $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($shape->getOffsetY()));
850
        $objWriter->endElement();
851
852
        // a:ext
853
        $objWriter->startElement('a:ext');
854
        $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu($shape->getWidth()));
855
        $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu($shape->getHeight()));
856
        $objWriter->endElement();
857
858
        $objWriter->endElement();
859
860
        // a:prstGeom
861
        $objWriter->startElement('a:prstGeom');
862
        $objWriter->writeAttribute('prst', 'rect');
863
        // // a:prstGeom/a:avLst
864
        $objWriter->writeElement('a:avLst', null);
865
        // ##a:prstGeom
866
        $objWriter->endElement();
867
868
        $objWriter->endElement();
869
870
        $objWriter->endElement();
871
    }
872
}
873