Completed
Pull Request — develop (#337)
by Franck
07:31
created

PptSlides::writeNote()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 280
Code Lines 130

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 130
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 280
ccs 130
cts 130
cp 1
rs 8.2857
c 1
b 0
f 0
cc 3
eloc 130
nc 3
nop 1
crap 3

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace PhpOffice\PhpPresentation\Writer\PowerPoint2007;
4
5
use PhpOffice\Common\Drawing as CommonDrawing;
6
use PhpOffice\Common\Text;
7
use PhpOffice\Common\XMLWriter;
8
use PhpOffice\PhpPresentation\Shape\Chart as ShapeChart;
9
use PhpOffice\PhpPresentation\Shape\Comment;
10
use PhpOffice\PhpPresentation\Shape\Drawing as ShapeDrawing;
11
use PhpOffice\PhpPresentation\Shape\Group;
12
use PhpOffice\PhpPresentation\Shape\Line;
13
use PhpOffice\PhpPresentation\Shape\Media;
14
use PhpOffice\PhpPresentation\Shape\RichText;
15
use PhpOffice\PhpPresentation\Shape\RichText\BreakElement;
16
use PhpOffice\PhpPresentation\Shape\RichText\Run;
17
use PhpOffice\PhpPresentation\Shape\RichText\TextElement;
18
use PhpOffice\PhpPresentation\Shape\Table as ShapeTable;
19
use PhpOffice\PhpPresentation\Slide;
20
use PhpOffice\PhpPresentation\Slide\Background\Image;
21
use PhpOffice\PhpPresentation\Slide\Note;
22
use PhpOffice\PhpPresentation\Style\Alignment;
23
use PhpOffice\PhpPresentation\Style\Bullet;
24
use PhpOffice\PhpPresentation\Style\Border;
25
use PhpOffice\PhpPresentation\Style\Color;
26
27
class PptSlides extends AbstractSlide
28
{
29
    /**
30
     * Add slides (drawings, ...) and slide relationships (drawings, ...)
31
     * @return \PhpOffice\Common\Adapter\Zip\ZipInterface
32
     */
33 103
    public function render()
34
    {
35 103
        foreach ($this->oPresentation->getAllSlides() as $idx => $oSlide) {
36 103
            $this->oZip->addFromString('ppt/slides/_rels/slide' . ($idx + 1) . '.xml.rels', $this->writeSlideRelationships($oSlide));
37 103
            $this->oZip->addFromString('ppt/slides/slide' . ($idx + 1) . '.xml', $this->writeSlide($oSlide));
38
39
            // Add note slide
40 103
            if ($oSlide->getNote() instanceof Note) {
41 103
                if ($oSlide->getNote()->getShapeCollection()->count() > 0) {
42 1
                    $this->oZip->addFromString('ppt/notesSlides/notesSlide' . ($idx + 1) . '.xml', $this->writeNote($oSlide->getNote()));
43
                }
44
            }
45
46
            // Add background image slide
47 103
            $oBkgImage = $oSlide->getBackground();
48 103
            if ($oBkgImage instanceof Image) {
49 103
                $this->oZip->addFromString('ppt/media/'.$oBkgImage->getIndexedFilename($idx), file_get_contents($oBkgImage->getPath()));
50
            }
51
        }
52
53 103
        return $this->oZip;
54
    }
55
56
    /**
57
     * Write slide relationships to XML format
58
     *
59
     * @param  \PhpOffice\PhpPresentation\Slide $pSlide
60
     * @return string              XML Output
61
     * @throws \Exception
62
     */
63 103
    protected function writeSlideRelationships(Slide $pSlide)
64
    {
65
        //@todo Group all getShapeCollection()->getIterator
66
67
        // Create XML writer
68 103
        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
69
70
        // XML header
71 103
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
72
73
        // Relationships
74 103
        $objWriter->startElement('Relationships');
75 103
        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
76
77
        // Starting relation id
78 103
        $relId = 1;
79 103
        $idxSlide = $pSlide->getParent()->getIndex($pSlide);
80
81
        // Write slideLayout relationship
82 103
        $layoutId = 1;
83 103
        if ($pSlide->getSlideLayout()) {
84 103
            $layoutId = $pSlide->getSlideLayout()->layoutNr;
85
        }
86 103
        $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout', '../slideLayouts/slideLayout' . $layoutId . '.xml');
87 103
        ++$relId;
88
89
        // Write drawing relationships?
90 103
        if ($pSlide->getShapeCollection()->count() > 0) {
91
            // Loop trough images and write relationships
92 76
            $iterator = $pSlide->getShapeCollection()->getIterator();
93 76
            while ($iterator->valid()) {
94 76
                if ($iterator->current() instanceof Media) {
95
                    // Write relationship for image drawing
96 1
                    $iterator->current()->relationId = 'rId' . $relId;
97 1
                    $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/video', '../media/' . $iterator->current()->getIndexedFilename());
98 1
                    ++$relId;
99 1
                    $this->writeRelationship($objWriter, $relId, 'http://schemas.microsoft.com/office/2007/relationships/media', '../media/' . $iterator->current()->getIndexedFilename());
100 1
                    ++$relId;
101 75
                } elseif ($iterator->current() instanceof ShapeDrawing\AbstractDrawingAdapter) {
102
                    // Write relationship for image drawing
103 7
                    $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image', '../media/' . $iterator->current()->getIndexedFilename());
104 7
                    $iterator->current()->relationId = 'rId' . $relId;
105 7
                    ++$relId;
106 68
                } elseif ($iterator->current() instanceof ShapeChart) {
107
                    // Write relationship for chart drawing
108 26
                    $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart', '../charts/' . $iterator->current()->getIndexedFilename());
109
110 26
                    $iterator->current()->relationId = 'rId' . $relId;
111
112 26
                    ++$relId;
113 42
                } elseif ($iterator->current() instanceof Group) {
114 1
                    $iterator2 = $iterator->current()->getShapeCollection()->getIterator();
115 1
                    while ($iterator2->valid()) {
116 1
                        if ($iterator2->current() instanceof Media) {
117
                            // Write relationship for image drawing
118
                            $iterator2->current()->relationId = 'rId' . $relId;
119
                            $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/video', '../media/' . $iterator->current()->getIndexedFilename());
120
                            ++$relId;
121
                            $this->writeRelationship($objWriter, $relId, 'http://schemas.microsoft.com/office/2007/relationships/media', '../media/' . $iterator->current()->getIndexedFilename());
122
                            ++$relId;
123 1
                        } elseif ($iterator2->current() instanceof ShapeDrawing\AbstractDrawingAdapter) {
124
                            // Write relationship for image drawing
125
                            $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image', '../media/' . $iterator2->current()->getIndexedFilename());
126
                            $iterator2->current()->relationId = 'rId' . $relId;
127
128
                            ++$relId;
129 1
                        } elseif ($iterator2->current() instanceof ShapeChart) {
130
                            // Write relationship for chart drawing
131
                            $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart', '../charts/' . $iterator2->current()->getIndexedFilename());
132
                            $iterator2->current()->relationId = 'rId' . $relId;
133
134
                            ++$relId;
135
                        }
136 1
                        $iterator2->next();
137
                    }
138
                }
139
140 76
                $iterator->next();
141
            }
142
        }
143
144
        // Write background relationships?
145 103
        $oBackground = $pSlide->getBackground();
146 103
        if ($oBackground instanceof Image) {
147
            $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image', '../media/' . $oBackground->getIndexedFilename($idxSlide));
148
            $oBackground->relationId = 'rId' . $relId;
149
            ++$relId;
150
        }
151
152
        // Write hyperlink relationships?
153 103
        if ($pSlide->getShapeCollection()->count() > 0) {
154
            // Loop trough hyperlinks and write relationships
155 76
            $iterator = $pSlide->getShapeCollection()->getIterator();
156 76
            while ($iterator->valid()) {
157
                // Hyperlink on shape
158 76
                if ($iterator->current()->hasHyperlink()) {
159
                    // Write relationship for hyperlink
160 2
                    $hyperlink               = $iterator->current()->getHyperlink();
161 2
                    $hyperlink->relationId = 'rId' . $relId;
162
163 2
                    if (!$hyperlink->isInternal()) {
164 2
                        $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', $hyperlink->getUrl(), 'External');
165
                    } else {
166
                        $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide', 'slide' . $hyperlink->getSlideNumber() . '.xml');
167
                    }
168
169 2
                    ++$relId;
170
                }
171
172
                // Hyperlink on rich text run
173 76
                if ($iterator->current() instanceof RichText) {
174 24
                    foreach ($iterator->current()->getParagraphs() as $paragraph) {
175 24
                        foreach ($paragraph->getRichTextElements() as $element) {
176 19
                            if ($element instanceof Run || $element instanceof TextElement) {
177 18
                                if ($element->hasHyperlink()) {
178
                                    // Write relationship for hyperlink
179 2
                                    $hyperlink               = $element->getHyperlink();
180 2
                                    $hyperlink->relationId = 'rId' . $relId;
181
182 2
                                    if (!$hyperlink->isInternal()) {
183 1
                                        $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', $hyperlink->getUrl(), 'External');
184
                                    } else {
185 1
                                        $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide', 'slide' . $hyperlink->getSlideNumber() . '.xml');
186
                                    }
187
188 24
                                    ++$relId;
189
                                }
190
                            }
191
                        }
192
                    }
193
                }
194
195
                // Hyperlink in table
196 76
                if ($iterator->current() instanceof ShapeTable) {
197
                    // Rows
198 10
                    $countRows = count($iterator->current()->getRows());
199 10
                    for ($row = 0; $row < $countRows; $row++) {
200
                        // Cells in rows
201 10
                        $countCells = count($iterator->current()->getRow($row)->getCells());
202 10
                        for ($cell = 0; $cell < $countCells; $cell++) {
203 10
                            $currentCell = $iterator->current()->getRow($row)->getCell($cell);
204
                            // Paragraphs in cell
205 10
                            foreach ($currentCell->getParagraphs() as $paragraph) {
206
                                // RichText in paragraph
207 10
                                foreach ($paragraph->getRichTextElements() as $element) {
208
                                    // Run or Text in RichText
209 10
                                    if ($element instanceof Run || $element instanceof TextElement) {
210 10
                                        if ($element->hasHyperlink()) {
211
                                            // Write relationship for hyperlink
212 1
                                            $hyperlink               = $element->getHyperlink();
213 1
                                            $hyperlink->relationId = 'rId' . $relId;
214
215 1
                                            if (!$hyperlink->isInternal()) {
216 1
                                                $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', $hyperlink->getUrl(), 'External');
217
                                            } else {
218
                                                $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide', 'slide' . $hyperlink->getSlideNumber() . '.xml');
219
                                            }
220
221 10
                                            ++$relId;
222
                                        }
223
                                    }
224
                                }
225
                            }
226
                        }
227
                    }
228
                }
229
230 76
                if ($iterator->current() instanceof Group) {
231 1
                    $iterator2 = $pSlide->getShapeCollection()->getIterator();
232 1
                    while ($iterator2->valid()) {
233
                        // Hyperlink on shape
234 1
                        if ($iterator2->current()->hasHyperlink()) {
235
                            // Write relationship for hyperlink
236
                            $hyperlink             = $iterator2->current()->getHyperlink();
237
                            $hyperlink->relationId = 'rId' . $relId;
238
239
                            if (!$hyperlink->isInternal()) {
240
                                $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', $hyperlink->getUrl(), 'External');
241
                            } else {
242
                                $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide', 'slide' . $hyperlink->getSlideNumber() . '.xml');
243
                            }
244
245
                            ++$relId;
246
                        }
247
248
                        // Hyperlink on rich text run
249 1
                        if ($iterator2->current() instanceof RichText) {
250
                            foreach ($iterator2->current()->getParagraphs() as $paragraph) {
251
                                foreach ($paragraph->getRichTextElements() as $element) {
252
                                    if ($element instanceof Run || $element instanceof TextElement) {
253
                                        if ($element->hasHyperlink()) {
254
                                            // Write relationship for hyperlink
255
                                            $hyperlink              = $element->getHyperlink();
256
                                            $hyperlink->relationId = 'rId' . $relId;
257
258
                                            if (!$hyperlink->isInternal()) {
259
                                                $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', $hyperlink->getUrl(), 'External');
260
                                            } else {
261
                                                $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide', 'slide' . $hyperlink->getSlideNumber() . '.xml');
262
                                            }
263
264
                                            ++$relId;
265
                                        }
266
                                    }
267
                                }
268
                            }
269
                        }
270
271
                        // Hyperlink in table
272 1
                        if ($iterator2->current() instanceof ShapeTable) {
273
                            // Rows
274
                            $countRows = count($iterator2->current()->getRows());
275
                            for ($row = 0; $row < $countRows; $row++) {
276
                                // Cells in rows
277
                                $countCells = count($iterator2->current()->getRow($row)->getCells());
278
                                for ($cell = 0; $cell < $countCells; $cell++) {
279
                                    $currentCell = $iterator2->current()->getRow($row)->getCell($cell);
280
                                    // Paragraphs in cell
281
                                    foreach ($currentCell->getParagraphs() as $paragraph) {
282
                                        // RichText in paragraph
283
                                        foreach ($paragraph->getRichTextElements() as $element) {
284
                                            // Run or Text in RichText
285
                                            if ($element instanceof Run || $element instanceof TextElement) {
286
                                                if ($element->hasHyperlink()) {
287
                                                    // Write relationship for hyperlink
288
                                                    $hyperlink               = $element->getHyperlink();
289
                                                    $hyperlink->relationId = 'rId' . $relId;
290
291
                                                    if (!$hyperlink->isInternal()) {
292
                                                        $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', $hyperlink->getUrl(), 'External');
293
                                                    } else {
294
                                                        $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide', 'slide' . $hyperlink->getSlideNumber() . '.xml');
295
                                                    }
296
297
                                                    ++$relId;
298
                                                }
299
                                            }
300
                                        }
301
                                    }
302
                                }
303
                            }
304
                        }
305
306 1
                        $iterator2->next();
307
                    }
308
                }
309
310 76
                $iterator->next();
311
            }
312
        }
313
314
        // Write comment relationships
315 103
        if ($pSlide->getShapeCollection()->count() > 0) {
316 76
            $hasSlideComment = false;
317
318
            // Loop trough images and write relationships
319 76
            $iterator = $pSlide->getShapeCollection()->getIterator();
320 76
            while ($iterator->valid()) {
321 76
                if ($iterator->current() instanceof Comment) {
322 6
                    $hasSlideComment = true;
323 6
                    break;
324 70
                } elseif ($iterator->current() instanceof Group) {
325 1
                    $iterator2 = $iterator->current()->getShapeCollection()->getIterator();
326 1
                    while ($iterator2->valid()) {
327 1
                        if ($iterator2->current() instanceof Comment) {
328 1
                            $hasSlideComment = true;
329 1
                            break 2;
330
                        }
331
                        $iterator2->next();
332
                    }
333
                }
334
335 69
                $iterator->next();
336
            }
337
338 76
            if ($hasSlideComment) {
339 7
                $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments', '../comments/comment'.($idxSlide + 1).'.xml');
340 7
                ++$relId;
341
            }
342
        }
343
344 103
        if ($pSlide->getNote()->getShapeCollection()->count() > 0) {
345 1
            $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide', '../notesSlides/notesSlide'.($idxSlide + 1).'.xml');
346
        }
347
348 103
        $objWriter->endElement();
349
350
        // Return
351 103
        return $objWriter->getData();
352
    }
353
354
    /**
355
     * Write slide to XML format
356
     *
357
     * @param  \PhpOffice\PhpPresentation\Slide $pSlide
358
     * @return string              XML Output
359
     * @throws \Exception
360
     */
361 103
    public function writeSlide(Slide $pSlide)
362
    {
363
        // Create XML writer
364 103
        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
365
366
        // XML header
367 103
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
368
369
        // p:sld
370 103
        $objWriter->startElement('p:sld');
371 103
        $objWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main');
372 103
        $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
373 103
        $objWriter->writeAttribute('xmlns:p', 'http://schemas.openxmlformats.org/presentationml/2006/main');
374 103
        $objWriter->writeAttributeIf(!$pSlide->isVisible(), 'show', 0);
375
376
        // p:sld/p:cSld
377 103
        $objWriter->startElement('p:cSld');
378
379
        // Background
380 103
        if ($pSlide->getBackground() instanceof Slide\AbstractBackground) {
381
            $oBackground = $pSlide->getBackground();
382
            // p:bg
383
            $objWriter->startElement('p:bg');
384
385
            // p:bgPr
386
            $objWriter->startElement('p:bgPr');
387
388
            if ($oBackground instanceof Slide\Background\Color) {
389
                // a:solidFill
390
                $objWriter->startElement('a:solidFill');
391
392
                $this->writeColor($objWriter, $oBackground->getColor());
393
394
                // > a:solidFill
395
                $objWriter->endElement();
396
            }
397
398
            if ($oBackground instanceof Slide\Background\Image) {
399
                // a:blipFill
400
                $objWriter->startElement('a:blipFill');
401
402
                // a:blip
403
                $objWriter->startElement('a:blip');
404
                $objWriter->writeAttribute('r:embed', $oBackground->relationId);
405
406
                // > a:blipFill
407
                $objWriter->endElement();
408
409
                // a:stretch
410
                $objWriter->startElement('a:stretch');
411
412
                // a:fillRect
413
                $objWriter->writeElement('a:fillRect');
414
415
                // > a:stretch
416
                $objWriter->endElement();
417
418
                // > a:blipFill
419
                $objWriter->endElement();
420
            }
421
422
            // > p:bgPr
423
            $objWriter->endElement();
424
425
            // > p:bg
426
            $objWriter->endElement();
427
        }
428
429
        // p:spTree
430 103
        $objWriter->startElement('p:spTree');
431
432
        // p:nvGrpSpPr
433 103
        $objWriter->startElement('p:nvGrpSpPr');
434
435
        // p:cNvPr
436 103
        $objWriter->startElement('p:cNvPr');
437 103
        $objWriter->writeAttribute('id', '1');
438 103
        $objWriter->writeAttribute('name', '');
439 103
        $objWriter->endElement();
440
441
        // p:cNvGrpSpPr
442 103
        $objWriter->writeElement('p:cNvGrpSpPr', null);
443
444
        // p:nvPr
445 103
        $objWriter->writeElement('p:nvPr', null);
446
447 103
        $objWriter->endElement();
448
449
        // p:grpSpPr
450 103
        $objWriter->startElement('p:grpSpPr');
451
452
        // a:xfrm
453 103
        $objWriter->startElement('a:xfrm');
454
455
        // a:off
456 103
        $objWriter->startElement('a:off');
457 103
        $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($pSlide->getOffsetX()));
458 103
        $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($pSlide->getOffsetY()));
459 103
        $objWriter->endElement(); // a:off
460
461
        // a:ext
462 103
        $objWriter->startElement('a:ext');
463 103
        $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu($pSlide->getExtentX()));
464 103
        $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu($pSlide->getExtentY()));
465 103
        $objWriter->endElement(); // a:ext
466
467
        // a:chOff
468 103
        $objWriter->startElement('a:chOff');
469 103
        $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($pSlide->getOffsetX()));
470 103
        $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($pSlide->getOffsetY()));
471 103
        $objWriter->endElement(); // a:chOff
472
473
        // a:chExt
474 103
        $objWriter->startElement('a:chExt');
475 103
        $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu($pSlide->getExtentX()));
476 103
        $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu($pSlide->getExtentY()));
477 103
        $objWriter->endElement(); // a:chExt
478
479 103
        $objWriter->endElement();
480
481 103
        $objWriter->endElement();
482
483
        // Loop shapes
484 103
        $this->writeShapeCollection($objWriter, $pSlide->getShapeCollection());
485
486
        // TODO
487 103
        $objWriter->endElement();
488
489 103
        $objWriter->endElement();
490
491
        // p:clrMapOvr
492 103
        $objWriter->startElement('p:clrMapOvr');
493
        // p:clrMapOvr\a:masterClrMapping
494 103
        $objWriter->writeElement('a:masterClrMapping', null);
495
        // ##p:clrMapOvr
496 103
        $objWriter->endElement();
497
498 103
        $this->writeSlideTransition($objWriter, $pSlide->getTransition());
499
500 103
        $this->writeSlideAnimations($objWriter, $pSlide);
501
502 103
        $objWriter->endElement();
503
504
        // Return
505 103
        return $objWriter->getData();
506
    }
507
508
    /**
509
     * @param XMLWriter $objWriter
510
     * @param Slide $oSlide
511
     */
512 103
    protected function writeSlideAnimations(XMLWriter $objWriter, Slide $oSlide)
513
    {
514 103
        $arrayAnimations = $oSlide->getAnimations();
515 103
        if (empty($arrayAnimations)) {
516 102
            return;
517
        }
518
519
        // Variables
520 1
        $shapeId = 1;
521 1
        $idCount = 1;
522 1
        $hashToIdMap = array();
523 1
        $arrayAnimationIds = array();
524
525 1
        foreach ($oSlide->getShapeCollection() as $shape) {
526 1
            $hashToIdMap[$shape->getHashCode()] = ++$shapeId;
527
        }
528 1
        foreach ($arrayAnimations as $oAnimation) {
529 1
            foreach ($oAnimation->getShapeCollection() as $oShape) {
530 1
                $arrayAnimationIds[] = $hashToIdMap[$oShape->getHashCode()];
531
            }
532
        }
533
534
        // p:timing
535 1
        $objWriter->startElement('p:timing');
536
        // p:timing/p:tnLst
537 1
        $objWriter->startElement('p:tnLst');
538
        // p:timing/p:tnLst/p:par
539 1
        $objWriter->startElement('p:par');
540
        // p:timing/p:tnLst/p:par/p:cTn
541 1
        $objWriter->startElement('p:cTn');
542 1
        $objWriter->writeAttribute('id', $idCount++);
543 1
        $objWriter->writeAttribute('dur', 'indefinite');
544 1
        $objWriter->writeAttribute('restart', 'never');
545 1
        $objWriter->writeAttribute('nodeType', 'tmRoot');
546
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst
547 1
        $objWriter->startElement('p:childTnLst');
548
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq
549 1
        $objWriter->startElement('p:seq');
550 1
        $objWriter->writeAttribute('concurrent', '1');
551 1
        $objWriter->writeAttribute('nextAc', 'seek');
552
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn
553 1
        $objWriter->startElement('p:cTn');
554 1
        $objWriter->writeAttribute('id', $idCount++);
555 1
        $objWriter->writeAttribute('dur', 'indefinite');
556 1
        $objWriter->writeAttribute('nodeType', 'mainSeq');
557
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst
558 1
        $objWriter->startElement('p:childTnLst');
559
560
        // Each animation has multiple shapes
561 1
        foreach ($arrayAnimations as $oAnimation) {
562
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par
563 1
            $objWriter->startElement('p:par');
564
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn
565 1
            $objWriter->startElement('p:cTn');
566 1
            $objWriter->writeAttribute('id', $idCount++);
567 1
            $objWriter->writeAttribute('fill', 'hold');
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->startElement('p:stCondLst');
570
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:stCondLst/p:cond
571 1
            $objWriter->startElement('p:cond');
572 1
            $objWriter->writeAttribute('delay', 'indefinite');
573 1
            $objWriter->endElement();
574
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn\##p:stCondLst
575 1
            $objWriter->endElement();
576
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst
577 1
            $objWriter->startElement('p:childTnLst');
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
579 1
            $objWriter->startElement('p:par');
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
581 1
            $objWriter->startElement('p:cTn');
582 1
            $objWriter->writeAttribute('id', $idCount++);
583 1
            $objWriter->writeAttribute('fill', 'hold');
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->startElement('p:stCondLst');
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:stCondLst/p:cond
587 1
            $objWriter->startElement('p:cond');
588 1
            $objWriter->writeAttribute('delay', '0');
589 1
            $objWriter->endElement();
590
            // 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
591 1
            $objWriter->endElement();
592
            // 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
593 1
            $objWriter->startElement('p:childTnLst');
594
595 1
            $firstAnimation = true;
596 1
            foreach ($oAnimation->getShapeCollection() as $oShape) {
597 1
                $nodeType = $firstAnimation ? 'clickEffect' : 'withEffect';
598 1
                $shapeId = $hashToIdMap[$oShape->getHashCode()];
599
600
                // p:par
601 1
                $objWriter->startElement('p:par');
602
                // p:par/p:cTn
603 1
                $objWriter->startElement('p:cTn');
604 1
                $objWriter->writeAttribute('id', $idCount++);
605 1
                $objWriter->writeAttribute('presetID', '1');
606 1
                $objWriter->writeAttribute('presetClass', 'entr');
607 1
                $objWriter->writeAttribute('fill', 'hold');
608 1
                $objWriter->writeAttribute('presetSubtype', '0');
609 1
                $objWriter->writeAttribute('grpId', '0');
610 1
                $objWriter->writeAttribute('nodeType', $nodeType);
611
                // p:par/p:cTn/p:stCondLst
612 1
                $objWriter->startElement('p:stCondLst');
613
                // p:par/p:cTn/p:stCondLst/p:cond
614 1
                $objWriter->startElement('p:cond');
615 1
                $objWriter->writeAttribute('delay', '0');
616 1
                $objWriter->endElement();
617
                // p:par/p:cTn\##p:stCondLst
618 1
                $objWriter->endElement();
619
                // p:par/p:cTn/p:childTnLst
620 1
                $objWriter->startElement('p:childTnLst');
621
                // p:par/p:cTn/p:childTnLst/p:set
622 1
                $objWriter->startElement('p:set');
623
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr
624 1
                $objWriter->startElement('p:cBhvr');
625
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:cTn
626 1
                $objWriter->startElement('p:cTn');
627 1
                $objWriter->writeAttribute('id', $idCount++);
628 1
                $objWriter->writeAttribute('dur', '1');
629 1
                $objWriter->writeAttribute('fill', 'hold');
630
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:cTn/p:stCondLst
631 1
                $objWriter->startElement('p:stCondLst');
632
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:cTn/p:stCondLst/p:cond
633 1
                $objWriter->startElement('p:cond');
634 1
                $objWriter->writeAttribute('delay', '0');
635 1
                $objWriter->endElement();
636
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:cTn\##p:stCondLst
637 1
                $objWriter->endElement();
638
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr\##p:cTn
639 1
                $objWriter->endElement();
640
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:tgtEl
641 1
                $objWriter->startElement('p:tgtEl');
642
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:tgtEl/p:spTgt
643 1
                $objWriter->startElement('p:spTgt');
644 1
                $objWriter->writeAttribute('spid', $shapeId);
645 1
                $objWriter->endElement();
646
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr\##p:tgtEl
647 1
                $objWriter->endElement();
648
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:attrNameLst
649 1
                $objWriter->startElement('p:attrNameLst');
650
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:attrNameLst/p:attrName
651 1
                $objWriter->writeElement('p:attrName', 'style.visibility');
652
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr\##p:attrNameLst
653 1
                $objWriter->endElement();
654
                // p:par/p:cTn/p:childTnLst/p:set\##p:cBhvr
655 1
                $objWriter->endElement();
656
                // p:par/p:cTn/p:childTnLst/p:set/p:to
657 1
                $objWriter->startElement('p:to');
658
                // p:par/p:cTn/p:childTnLst/p:set/p:to/p:strVal
659 1
                $objWriter->startElement('p:strVal');
660 1
                $objWriter->writeAttribute('val', 'visible');
661 1
                $objWriter->endElement();
662
                // p:par/p:cTn/p:childTnLst/p:set\##p:to
663 1
                $objWriter->endElement();
664
                // p:par/p:cTn/p:childTnLst\##p:set
665 1
                $objWriter->endElement();
666
                // p:par/p:cTn\##p:childTnLst
667 1
                $objWriter->endElement();
668
                // p:par\##p:cTn
669 1
                $objWriter->endElement();
670
                // ##p:par
671 1
                $objWriter->endElement();
672
673 1
                $firstAnimation = false;
674
            }
675
676
            // 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
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/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/p:cTn/p:childTnLst\##p:par
681 1
            $objWriter->endElement();
682
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn\##p:childTnLst
683 1
            $objWriter->endElement();
684
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par\##p:cTn
685 1
            $objWriter->endElement();
686
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst\##p:par
687 1
            $objWriter->endElement();
688
        }
689
690
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn\##p:childTnLst
691 1
        $objWriter->endElement();
692
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq\##p:cTn
693 1
        $objWriter->endElement();
694
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:prevCondLst
695 1
        $objWriter->startElement('p:prevCondLst');
696
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:prevCondLst/p:cond
697 1
        $objWriter->startElement('p:cond');
698 1
        $objWriter->writeAttribute('evt', 'onPrev');
699 1
        $objWriter->writeAttribute('delay', '0');
700
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:prevCondLst/p:cond/p:tgtEl
701 1
        $objWriter->startElement('p:tgtEl');
702
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:prevCondLst/p:cond/p:tgtEl/p:sldTgt
703 1
        $objWriter->writeElement('p:sldTgt', null);
704
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:prevCondLst/p:cond\##p:tgtEl
705 1
        $objWriter->endElement();
706
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:prevCondLst\##p:cond
707 1
        $objWriter->endElement();
708
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq\##p:prevCondLst
709 1
        $objWriter->endElement();
710
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:nextCondLst
711 1
        $objWriter->startElement('p:nextCondLst');
712
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:nextCondLst/p:cond
713 1
        $objWriter->startElement('p:cond');
714 1
        $objWriter->writeAttribute('evt', 'onNext');
715 1
        $objWriter->writeAttribute('delay', '0');
716
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:nextCondLst/p:cond/p:tgtEl
717 1
        $objWriter->startElement('p:tgtEl');
718
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:nextCondLst/p:cond/p:tgtEl/p:sldTgt
719 1
        $objWriter->writeElement('p:sldTgt', null);
720
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:nextCondLst/p:cond\##p:tgtEl
721 1
        $objWriter->endElement();
722
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:nextCondLst\##p:cond
723 1
        $objWriter->endElement();
724
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq\##p:nextCondLst
725 1
        $objWriter->endElement();
726
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst\##p:seq
727 1
        $objWriter->endElement();
728
        // p:timing/p:tnLst/p:par/p:cTn\##p:childTnLst
729 1
        $objWriter->endElement();
730
        // p:timing/p:tnLst/p:par\##p:cTn
731 1
        $objWriter->endElement();
732
        // p:timing/p:tnLst\##p:par
733 1
        $objWriter->endElement();
734
        // p:timing\##p:tnLst
735 1
        $objWriter->endElement();
736
737
        // p:timing/p:bldLst
738 1
        $objWriter->startElement('p:bldLst');
739
740
        // Add in ids of all shapes in this slides animations
741 1
        foreach ($arrayAnimationIds as $id) {
742
            // p:timing/p:bldLst/p:bldP
743 1
            $objWriter->startElement('p:bldP');
744 1
            $objWriter->writeAttribute('spid', $id);
745 1
            $objWriter->writeAttribute('grpId', 0);
746 1
            $objWriter->endELement();
747
        }
748
749
        // p:timing\##p:bldLst
750 1
        $objWriter->endElement();
751
752
        // ##p:timing
753 1
        $objWriter->endElement();
754 1
    }
755
756
    /**
757
     * Write group
758
     *
759
     * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer
760
     * @param \PhpOffice\PhpPresentation\Shape\Group $group
761
     * @param  int $shapeId
762
     */
763 1
    protected function writeShapeGroup(XMLWriter $objWriter, Group $group, &$shapeId)
764
    {
765
        // p:grpSp
766 1
        $objWriter->startElement('p:grpSp');
767
768
        // p:nvGrpSpPr
769 1
        $objWriter->startElement('p:nvGrpSpPr');
770
771
        // p:cNvPr
772 1
        $objWriter->startElement('p:cNvPr');
773 1
        $objWriter->writeAttribute('name', 'Group '.$shapeId++);
774 1
        $objWriter->writeAttribute('id', $shapeId);
775 1
        $objWriter->endElement(); // p:cNvPr
776
        // NOTE: Re: $shapeId This seems to be how PowerPoint 2010 does business.
777
778
        // p:cNvGrpSpPr
779 1
        $objWriter->writeElement('p:cNvGrpSpPr', null);
780
781
        // p:nvPr
782 1
        $objWriter->writeElement('p:nvPr', null);
783
784 1
        $objWriter->endElement(); // p:nvGrpSpPr
785
786
        // p:grpSpPr
787 1
        $objWriter->startElement('p:grpSpPr');
788
789
        // a:xfrm
790 1
        $objWriter->startElement('a:xfrm');
791
792
        // a:off
793 1
        $objWriter->startElement('a:off');
794 1
        $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($group->getOffsetX()));
795 1
        $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($group->getOffsetY()));
796 1
        $objWriter->endElement(); // a:off
797
798
        // a:ext
799 1
        $objWriter->startElement('a:ext');
800 1
        $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu($group->getExtentX()));
801 1
        $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu($group->getExtentY()));
802 1
        $objWriter->endElement(); // a:ext
803
804
        // a:chOff
805 1
        $objWriter->startElement('a:chOff');
806 1
        $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($group->getOffsetX()));
807 1
        $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($group->getOffsetY()));
808 1
        $objWriter->endElement(); // a:chOff
809
810
        // a:chExt
811 1
        $objWriter->startElement('a:chExt');
812 1
        $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu($group->getExtentX()));
813 1
        $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu($group->getExtentY()));
814 1
        $objWriter->endElement(); // a:chExt
815
816 1
        $objWriter->endElement(); // a:xfrm
817
818 1
        $objWriter->endElement(); // p:grpSpPr
819
820 1
        $this->writeShapeCollection($objWriter, $group->getShapeCollection(), $shapeId);
821 1
        $objWriter->endElement(); // p:grpSp
822 1
    }
823
824
    /**
825
     * Write chart
826
     *
827
     * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer
828
     * @param \PhpOffice\PhpPresentation\Shape\Chart $shape
829
     * @param  int $shapeId
830
     */
831 26
    protected function writeShapeChart(XMLWriter $objWriter, ShapeChart $shape, $shapeId)
832
    {
833
        // p:graphicFrame
834 26
        $objWriter->startElement('p:graphicFrame');
835
836
        // p:nvGraphicFramePr
837 26
        $objWriter->startElement('p:nvGraphicFramePr');
838
839
        // p:cNvPr
840 26
        $objWriter->startElement('p:cNvPr');
841 26
        $objWriter->writeAttribute('id', $shapeId);
842 26
        $objWriter->writeAttribute('name', $shape->getName());
843 26
        $objWriter->writeAttribute('descr', $shape->getDescription());
844 26
        $objWriter->endElement();
845
846
        // p:cNvGraphicFramePr
847 26
        $objWriter->writeElement('p:cNvGraphicFramePr', null);
848
849
        // p:nvPr
850 26
        $objWriter->startElement('p:nvPr');
851 26
        if ($shape->isPlaceholder()) {
852
            $objWriter->startElement('p:ph');
853
            $objWriter->writeAttribute('type', $shape->getPlaceholder()->getType());
854
            $objWriter->endElement();
855
        }
856 26
        $objWriter->endElement();
857
858 26
        $objWriter->endElement();
859
860
        // p:xfrm
861 26
        $objWriter->startElement('p:xfrm');
862 26
        $objWriter->writeAttributeIf($shape->getRotation() != 0, 'rot', CommonDrawing::degreesToAngle($shape->getRotation()));
863
864
        // a:off
865 26
        $objWriter->startElement('a:off');
866 26
        $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($shape->getOffsetX()));
867 26
        $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($shape->getOffsetY()));
868 26
        $objWriter->endElement();
869
870
        // a:ext
871 26
        $objWriter->startElement('a:ext');
872 26
        $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu($shape->getWidth()));
873 26
        $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu($shape->getHeight()));
874 26
        $objWriter->endElement();
875
876 26
        $objWriter->endElement();
877
878
        // a:graphic
879 26
        $objWriter->startElement('a:graphic');
880
881
        // a:graphicData
882 26
        $objWriter->startElement('a:graphicData');
883 26
        $objWriter->writeAttribute('uri', 'http://schemas.openxmlformats.org/drawingml/2006/chart');
884
885
        // c:chart
886 26
        $objWriter->startElement('c:chart');
887 26
        $objWriter->writeAttribute('xmlns:c', 'http://schemas.openxmlformats.org/drawingml/2006/chart');
888 26
        $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
889 26
        $objWriter->writeAttribute('r:id', $shape->relationId);
890 26
        $objWriter->endElement();
891
892 26
        $objWriter->endElement();
893
894 26
        $objWriter->endElement();
895
896 26
        $objWriter->endElement();
897 26
    }
898
899
    /**
900
     * Write pic
901
     *
902
     * @param  \PhpOffice\Common\XMLWriter  $objWriter XML Writer
903
     * @param  \PhpOffice\PhpPresentation\Shape\Drawing\AbstractDrawingAdapter $shape
904
     * @param  int $shapeId
905
     * @throws \Exception
906
     */
907
    protected function writeShapeDrawing(XMLWriter $objWriter, ShapeDrawing\AbstractDrawingAdapter $shape, $shapeId)
908
    {
909
        // p:pic
910
        $objWriter->startElement('p:pic');
911
912
        // p:nvPicPr
913
        $objWriter->startElement('p:nvPicPr');
914
915
        // p:cNvPr
916
        $objWriter->startElement('p:cNvPr');
917
        $objWriter->writeAttribute('id', $shapeId);
918
        $objWriter->writeAttribute('name', $shape->getName());
919
        $objWriter->writeAttribute('descr', $shape->getDescription());
920
921
        // a:hlinkClick
922
        if ($shape->hasHyperlink()) {
923
            $this->writeHyperlink($objWriter, $shape);
924
        }
925
926
        $objWriter->endElement();
927
928
        // p:cNvPicPr
929
        $objWriter->startElement('p:cNvPicPr');
930
931
        // a:picLocks
932
        $objWriter->startElement('a:picLocks');
933
        $objWriter->writeAttribute('noChangeAspect', '1');
934
        $objWriter->endElement();
935
936
        $objWriter->endElement();
937
938
        // p:nvPr
939
        $objWriter->startElement('p:nvPr');
940
        // PlaceHolder
941
        if ($shape->isPlaceholder()) {
942
            $objWriter->startElement('p:ph');
943
            $objWriter->writeAttribute('type', $shape->getPlaceholder()->getType());
944
            $objWriter->endElement();
945
        }
946
        /**
947
         * @link : https://github.com/stefslon/exportToPPTX/blob/master/exportToPPTX.m#L2128
948
         */
949
        if ($shape instanceof Media) {
950
            // p:nvPr > a:videoFile
951
            $objWriter->startElement('a:videoFile');
952
            $objWriter->writeAttribute('r:link', $shape->relationId);
953
            $objWriter->endElement();
954
            // p:nvPr > p:extLst
955
            $objWriter->startElement('p:extLst');
956
            // p:nvPr > p:extLst > p:ext
957
            $objWriter->startElement('p:ext');
958
            $objWriter->writeAttribute('uri', '{DAA4B4D4-6D71-4841-9C94-3DE7FCFB9230}');
959
            // p:nvPr > p:extLst > p:ext > p14:media
960
            $objWriter->startElement('p14:media');
961
            $objWriter->writeAttribute('r:embed', ($shape->relationId + 1));
962
            $objWriter->writeAttribute('xmlns:p14', 'http://schemas.microsoft.com/office/powerpoint/2010/main');
963
            // p:nvPr > p:extLst > p:ext > ##p14:media
964
            $objWriter->endElement();
965
            // p:nvPr > p:extLst > ##p:ext
966
            $objWriter->endElement();
967
            // p:nvPr > ##p:extLst
968
            $objWriter->endElement();
969
        }
970
        // ##p:nvPr
971
        $objWriter->endElement();
972
        $objWriter->endElement();
973
974
        // p:blipFill
975
        $objWriter->startElement('p:blipFill');
976
977
        // a:blip
978
        $objWriter->startElement('a:blip');
979
        $objWriter->writeAttribute('r:embed', $shape->relationId);
980
        $objWriter->endElement();
981
982
        // a:stretch
983
        $objWriter->startElement('a:stretch');
984
        $objWriter->writeElement('a:fillRect', null);
985
        $objWriter->endElement();
986
987
        $objWriter->endElement();
988
989
        // p:spPr
990
        $objWriter->startElement('p:spPr');
991
        // a:xfrm
992
        $objWriter->startElement('a:xfrm');
993
        $objWriter->writeAttributeIf($shape->getRotation() != 0, 'rot', CommonDrawing::degreesToAngle($shape->getRotation()));
994
995
        // a:off
996
        $objWriter->startElement('a:off');
997
        $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($shape->getOffsetX()));
998
        $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($shape->getOffsetY()));
999
        $objWriter->endElement();
1000
1001
        // a:ext
1002
        $objWriter->startElement('a:ext');
1003
        $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu($shape->getWidth()));
1004
        $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu($shape->getHeight()));
1005
        $objWriter->endElement();
1006
1007
        $objWriter->endElement();
1008
1009
        // a:prstGeom
1010
        $objWriter->startElement('a:prstGeom');
1011
        $objWriter->writeAttribute('prst', 'rect');
1012
1013
        // a:avLst
1014
        $objWriter->writeElement('a:avLst', null);
1015
1016
        $objWriter->endElement();
1017
1018
        $this->writeBorder($objWriter, $shape->getBorder(), '');
1019
1020
        $this->writeShadow($objWriter, $shape->getShadow());
1021
1022
        $objWriter->endElement();
1023
1024
        $objWriter->endElement();
1025
    }
1026
1027
    /**
1028
     * Write txt
1029
     *
1030
     * @param  \PhpOffice\Common\XMLWriter $objWriter XML Writer
1031
     * @param  \PhpOffice\PhpPresentation\Shape\RichText   $shape
1032
     * @param  int                            $shapeId
1033
     * @throws \Exception
1034
     */
1035 24
    protected function writeShapeText(XMLWriter $objWriter, RichText $shape, $shapeId)
1036
    {
1037
        // p:sp
1038 24
        $objWriter->startElement('p:sp');
1039
1040
        // p:sp/p:nvSpPr
1041 24
        $objWriter->startElement('p:nvSpPr');
1042
1043
        // p:sp/p:nvSpPr/p:cNvPr
1044 24
        $objWriter->startElement('p:cNvPr');
1045 24
        $objWriter->writeAttribute('id', $shapeId);
1046 24
        $objWriter->writeAttribute('name', '');
1047
1048
        // Hyperlink
1049 24
        if ($shape->hasHyperlink()) {
1050 1
            $this->writeHyperlink($objWriter, $shape);
1051
        }
1052
        // > p:sp/p:nvSpPr
1053 24
        $objWriter->endElement();
1054
1055
        // p:sp/p:cNvSpPr
1056 24
        $objWriter->startElement('p:cNvSpPr');
1057 24
        $objWriter->writeAttribute('txBox', '1');
1058 24
        $objWriter->endElement();
1059
        // p:sp/p:cNvSpPr/p:nvPr
1060 24
        $objWriter->startElement('p:nvPr');
1061 24
        if ($shape->isPlaceholder()) {
1062
            $objWriter->startElement('p:ph');
1063
            $objWriter->writeAttribute('type', $shape->getPlaceholder()->getType());
1064
            $objWriter->endElement();
1065
        }
1066 24
        $objWriter->endElement();
1067
1068
        // > p:sp/p:cNvSpPr
1069 24
        $objWriter->endElement();
1070
1071
        // p:sp/p:spPr
1072 24
        $objWriter->startElement('p:spPr');
1073
1074 24
        if (!$shape->isPlaceholder()) {
1075
            // p:sp/p:spPr\a:xfrm
1076 24
            $objWriter->startElement('a:xfrm');
1077 24
            $objWriter->writeAttributeIf($shape->getRotation() != 0, 'rot', CommonDrawing::degreesToAngle($shape->getRotation()));
1078
1079
            // p:sp/p:spPr\a:xfrm\a:off
1080 24
            $objWriter->startElement('a:off');
1081 24
            $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($shape->getOffsetX()));
1082 24
            $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($shape->getOffsetY()));
1083 24
            $objWriter->endElement();
1084
1085
            // p:sp/p:spPr\a:xfrm\a:ext
1086 24
            $objWriter->startElement('a:ext');
1087 24
            $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu($shape->getWidth()));
1088 24
            $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu($shape->getHeight()));
1089 24
            $objWriter->endElement();
1090
1091
            // > p:sp/p:spPr\a:xfrm
1092 24
            $objWriter->endElement();
1093
1094
            // p:sp/p:spPr\a:prstGeom
1095 24
            $objWriter->startElement('a:prstGeom');
1096 24
            $objWriter->writeAttribute('prst', 'rect');
1097 24
            $objWriter->endElement();
1098
        }
1099
1100 24
        $this->writeFill($objWriter, $shape->getFill());
1101 24
        $this->writeBorder($objWriter, $shape->getBorder(), '');
1102 24
        $this->writeShadow($objWriter, $shape->getShadow());
1103
1104
        // > p:sp/p:spPr
1105 24
        $objWriter->endElement();
1106
1107
        // p:txBody
1108 24
        $objWriter->startElement('p:txBody');
1109
1110
        // a:bodyPr
1111
        //@link :http://msdn.microsoft.com/en-us/library/documentformat.openxml.drawing.bodyproperties%28v=office.14%29.aspx
1112 24
        $objWriter->startElement('a:bodyPr');
1113 24
        if (!$shape->isPlaceholder()) {
1114 24
            $verticalAlign = $shape->getActiveParagraph()->getAlignment()->getVertical();
1115 24
            if ($verticalAlign != Alignment::VERTICAL_BASE && $verticalAlign != Alignment::VERTICAL_AUTO) {
1116 3
                $objWriter->writeAttribute('anchor', $verticalAlign);
1117
            }
1118 24
            if ($shape->getWrap() != RichText::WRAP_SQUARE) {
1119
                $objWriter->writeAttribute('wrap', $shape->getWrap());
1120
            }
1121 24
            $objWriter->writeAttribute('rtlCol', '0');
1122
1123 24
            if ($shape->getHorizontalOverflow() != RichText::OVERFLOW_OVERFLOW) {
1124
                $objWriter->writeAttribute('horzOverflow', $shape->getHorizontalOverflow());
1125
            }
1126 24
            if ($shape->getVerticalOverflow() != RichText::OVERFLOW_OVERFLOW) {
1127
                $objWriter->writeAttribute('vertOverflow', $shape->getVerticalOverflow());
1128
            }
1129
1130 24
            if ($shape->isUpright()) {
1131 1
                $objWriter->writeAttribute('upright', '1');
1132
            }
1133 24
            if ($shape->isVertical()) {
1134 1
                $objWriter->writeAttribute('vert', 'vert');
1135
            }
1136
1137 24
            $objWriter->writeAttribute('bIns', CommonDrawing::pixelsToEmu($shape->getInsetBottom()));
1138 24
            $objWriter->writeAttribute('lIns', CommonDrawing::pixelsToEmu($shape->getInsetLeft()));
1139 24
            $objWriter->writeAttribute('rIns', CommonDrawing::pixelsToEmu($shape->getInsetRight()));
1140 24
            $objWriter->writeAttribute('tIns', CommonDrawing::pixelsToEmu($shape->getInsetTop()));
1141
1142 24
            if ($shape->getColumns() <> 1) {
1143
                $objWriter->writeAttribute('numCol', $shape->getColumns());
1144
            }
1145
1146
            // a:spAutoFit
1147 24
            $objWriter->startElement('a:' . $shape->getAutoFit());
1148 24
            if ($shape->getAutoFit() == RichText::AUTOFIT_NORMAL) {
1149 1
                if (!is_null($shape->getFontScale())) {
1150 1
                    $objWriter->writeAttribute('fontScale', (int)($shape->getFontScale() * 1000));
1151
                }
1152 1
                if (!is_null($shape->getLineSpaceReduction())) {
1153 1
                    $objWriter->writeAttribute('lnSpcReduction', (int)($shape->getLineSpaceReduction() * 1000));
1154
                }
1155
            }
1156
1157 24
            $objWriter->endElement();
1158
        }
1159 24
        $objWriter->endElement();
1160
1161
        // a:lstStyle
1162 24
        $objWriter->startElement('a:lstStyle');
1163 24
        $objWriter->endElement();
1164
1165
        // Write paragraphs
1166 24
        $this->writeParagraphs($objWriter, $shape->getParagraphs(), $shape->isPlaceholder());
1167
1168 24
        $objWriter->endElement();
1169
1170 24
        $objWriter->endElement();
1171 24
    }
1172
1173
    /**
1174
     * Write paragraphs
1175
     *
1176
     * @param  \PhpOffice\Common\XMLWriter           $objWriter  XML Writer
1177
     * @param  \PhpOffice\PhpPresentation\Shape\RichText\Paragraph[] $paragraphs
1178
     * @param  bool $bIsPlaceholder
1179
     * @throws \Exception
1180
     */
1181 35
    protected function writeParagraphs(XMLWriter $objWriter, $paragraphs, $bIsPlaceholder = false)
1182
    {
1183
        // Loop trough paragraphs
1184 35
        foreach ($paragraphs as $paragraph) {
1185
            // a:p
1186 35
            $objWriter->startElement('a:p');
1187
1188
            // a:pPr
1189 35
            if (!$bIsPlaceholder) {
1190 35
                $objWriter->startElement('a:pPr');
1191 35
                $objWriter->writeAttribute('algn', $paragraph->getAlignment()->getHorizontal());
1192 35
                $objWriter->writeAttribute('fontAlgn', $paragraph->getAlignment()->getVertical());
1193 35
                $objWriter->writeAttribute('marL', CommonDrawing::pixelsToEmu($paragraph->getAlignment()->getMarginLeft()));
1194 35
                $objWriter->writeAttribute('marR', CommonDrawing::pixelsToEmu($paragraph->getAlignment()->getMarginRight()));
1195 35
                $objWriter->writeAttribute('indent', CommonDrawing::pixelsToEmu($paragraph->getAlignment()->getIndent()));
1196 35
                $objWriter->writeAttribute('lvl', $paragraph->getAlignment()->getLevel());
1197
1198 35
                $objWriter->startElement('a:lnSpc');
1199 35
                $objWriter->startElement('a:spcPct');
1200 35
                $objWriter->writeAttribute('val', $paragraph->getLineSpacing() * 1000);
1201 35
                $objWriter->endElement();
1202 35
                $objWriter->endElement();
1203
1204
                // Bullet type specified?
1205 35
                if ($paragraph->getBulletStyle()->getBulletType() != Bullet::TYPE_NONE) {
1206
                    // Color
1207
                    // a:buClr must be before a:buFont (else PowerPoint crashes at launch)
1208 2
                    if ($paragraph->getBulletStyle()->getBulletColor() instanceof Color) {
1209 2
                        $objWriter->startElement('a:buClr');
1210 2
                        $this->writeColor($objWriter, $paragraph->getBulletStyle()->getBulletColor());
1211 2
                        $objWriter->endElement();
1212
                    }
1213
1214
                    // a:buFont
1215 2
                    $objWriter->startElement('a:buFont');
1216 2
                    $objWriter->writeAttribute('typeface', $paragraph->getBulletStyle()->getBulletFont());
1217 2
                    $objWriter->endElement();
1218
1219 2
                    if ($paragraph->getBulletStyle()->getBulletType() == Bullet::TYPE_BULLET) {
1220
                        // a:buChar
1221 1
                        $objWriter->startElement('a:buChar');
1222 1
                        $objWriter->writeAttribute('char', $paragraph->getBulletStyle()->getBulletChar());
1223 1
                        $objWriter->endElement();
1224 1
                    } elseif ($paragraph->getBulletStyle()->getBulletType() == Bullet::TYPE_NUMERIC) {
1225
                        // a:buAutoNum
1226 1
                        $objWriter->startElement('a:buAutoNum');
1227 1
                        $objWriter->writeAttribute('type', $paragraph->getBulletStyle()->getBulletNumericStyle());
1228 1
                        if ($paragraph->getBulletStyle()->getBulletNumericStartAt() != 1) {
1229 1
                            $objWriter->writeAttribute('startAt', $paragraph->getBulletStyle()->getBulletNumericStartAt());
1230
                        }
1231 1
                        $objWriter->endElement();
1232
                    }
1233
                }
1234
1235 35
                $objWriter->endElement();
1236
            }
1237
1238
            // Loop trough rich text elements
1239 35
            $elements = $paragraph->getRichTextElements();
1240 35
            foreach ($elements as $element) {
1241 30
                if ($element instanceof BreakElement) {
1242
                    // a:br
1243 1
                    $objWriter->writeElement('a:br', null);
1244 29
                } elseif ($element instanceof Run || $element instanceof TextElement) {
1245
                    // a:r
1246 29
                    $objWriter->startElement('a:r');
1247
1248
                    // a:rPr
1249 29
                    if ($element instanceof Run && !$bIsPlaceholder) {
1250
                        // a:rPr
1251 29
                        $objWriter->startElement('a:rPr');
1252
1253
                        // Lang
1254 29
                        $objWriter->writeAttribute('lang', ($element->getLanguage() ? $element->getLanguage() : 'en-US'));
1255
1256 29
                        $objWriter->writeAttributeIf($element->getFont()->isBold(), 'b', '1');
1257 29
                        $objWriter->writeAttributeIf($element->getFont()->isItalic(), 'i', '1');
1258 29
                        $objWriter->writeAttributeIf($element->getFont()->isStrikethrough(), 'strike', 'sngStrike');
1259
1260
                        // Size
1261 29
                        $objWriter->writeAttribute('sz', ($element->getFont()->getSize() * 100));
1262
1263
                        // Character spacing
1264 29
                        $objWriter->writeAttribute('spc', $element->getFont()->getCharacterSpacing());
1265
1266
                        // Underline
1267 29
                        $objWriter->writeAttribute('u', $element->getFont()->getUnderline());
1268
1269
                        // Superscript / subscript
1270 29
                        $objWriter->writeAttributeIf($element->getFont()->isSuperScript(), 'baseline', '30000');
1271 29
                        $objWriter->writeAttributeIf($element->getFont()->isSubScript(), 'baseline', '-25000');
1272
1273
                        // Color - a:solidFill
1274 29
                        $objWriter->startElement('a:solidFill');
1275 29
                        $this->writeColor($objWriter, $element->getFont()->getColor());
1276 29
                        $objWriter->endElement();
1277
1278
                        // Font - a:latin
1279 29
                        $objWriter->startElement('a:latin');
1280 29
                        $objWriter->writeAttribute('typeface', $element->getFont()->getName());
1281 29
                        $objWriter->endElement();
1282
1283
                        // a:hlinkClick
1284 29
                        $this->writeHyperlink($objWriter, $element);
1285
1286 29
                        $objWriter->endElement();
1287
                    }
1288
1289
                    // t
1290 29
                    $objWriter->startElement('a:t');
1291 29
                    $objWriter->writeCData(Text::controlCharacterPHP2OOXML($element->getText()));
1292 29
                    $objWriter->endElement();
1293
1294 30
                    $objWriter->endElement();
1295
                }
1296
            }
1297
1298 35
            $objWriter->endElement();
1299
        }
1300 35
    }
1301
1302
    /**
1303
     * Write Line Shape
1304
     *
1305
     * @param  \PhpOffice\Common\XMLWriter $objWriter XML Writer
1306
     * @param \PhpOffice\PhpPresentation\Shape\Line $shape
1307
     * @param  int $shapeId
1308
     */
1309 1
    protected function writeShapeLine(XMLWriter $objWriter, Line $shape, $shapeId)
1310
    {
1311
        // p:sp
1312 1
        $objWriter->startElement('p:cxnSp');
1313
1314
        // p:nvSpPr
1315 1
        $objWriter->startElement('p:nvCxnSpPr');
1316
1317
        // p:cNvPr
1318 1
        $objWriter->startElement('p:cNvPr');
1319 1
        $objWriter->writeAttribute('id', $shapeId);
1320 1
        $objWriter->writeAttribute('name', '');
1321
1322 1
        $objWriter->endElement();
1323
1324
        // p:cNvCxnSpPr
1325 1
        $objWriter->writeElement('p:cNvCxnSpPr', null);
1326
1327
        // p:nvPr
1328 1
        $objWriter->startElement('p:nvPr');
1329 1
        if ($shape->isPlaceholder()) {
1330
            $objWriter->startElement('p:ph');
1331
            $objWriter->writeAttribute('type', $shape->getPlaceholder()->getType());
1332
            $objWriter->endElement();
1333
        }
1334 1
        $objWriter->endElement();
1335
1336 1
        $objWriter->endElement();
1337
1338
        // p:spPr
1339 1
        $objWriter->startElement('p:spPr');
1340
1341
        // a:xfrm
1342 1
        $objWriter->startElement('a:xfrm');
1343
1344 1
        if ($shape->getWidth() >= 0 && $shape->getHeight() >= 0) {
1345
            // a:off
1346 1
            $objWriter->startElement('a:off');
1347 1
            $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($shape->getOffsetX()));
1348 1
            $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($shape->getOffsetY()));
1349 1
            $objWriter->endElement();
1350
1351
            // a:ext
1352 1
            $objWriter->startElement('a:ext');
1353 1
            $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu($shape->getWidth()));
1354 1
            $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu($shape->getHeight()));
1355 1
            $objWriter->endElement();
1356 1
        } elseif ($shape->getWidth() < 0 && $shape->getHeight() < 0) {
1357
            // a:off
1358 1
            $objWriter->startElement('a:off');
1359 1
            $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($shape->getOffsetX() + $shape->getWidth()));
1360 1
            $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($shape->getOffsetY() + $shape->getHeight()));
1361 1
            $objWriter->endElement();
1362
1363
            // a:ext
1364 1
            $objWriter->startElement('a:ext');
1365 1
            $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu(-$shape->getWidth()));
1366 1
            $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu(-$shape->getHeight()));
1367 1
            $objWriter->endElement();
1368 1
        } elseif ($shape->getHeight() < 0) {
1369 1
            $objWriter->writeAttribute('flipV', 1);
1370
1371
            // a:off
1372 1
            $objWriter->startElement('a:off');
1373 1
            $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($shape->getOffsetX()));
1374 1
            $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($shape->getOffsetY() + $shape->getHeight()));
1375 1
            $objWriter->endElement();
1376
1377
            // a:ext
1378 1
            $objWriter->startElement('a:ext');
1379 1
            $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu($shape->getWidth()));
1380 1
            $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu(-$shape->getHeight()));
1381 1
            $objWriter->endElement();
1382 1
        } elseif ($shape->getWidth() < 0) {
1383 1
            $objWriter->writeAttribute('flipV', 1);
1384
1385
            // a:off
1386 1
            $objWriter->startElement('a:off');
1387 1
            $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($shape->getOffsetX() + $shape->getWidth()));
1388 1
            $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($shape->getOffsetY()));
1389 1
            $objWriter->endElement();
1390
1391
            // a:ext
1392 1
            $objWriter->startElement('a:ext');
1393 1
            $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu(-$shape->getWidth()));
1394 1
            $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu($shape->getHeight()));
1395 1
            $objWriter->endElement();
1396
        }
1397
1398 1
        $objWriter->endElement();
1399
1400
        // a:prstGeom
1401 1
        $objWriter->startElement('a:prstGeom');
1402 1
        $objWriter->writeAttribute('prst', 'line');
1403 1
        $objWriter->endElement();
1404
1405 1
        if ($shape->getBorder()->getLineStyle() != Border::LINE_NONE) {
1406 1
            $this->writeBorder($objWriter, $shape->getBorder(), '');
1407
        }
1408
1409 1
        $objWriter->endElement();
1410
1411 1
        $objWriter->endElement();
1412 1
    }
1413
1414
    /**
1415
     * Write hyperlink
1416
     *
1417
     * @param \PhpOffice\Common\XMLWriter                               $objWriter XML Writer
1418
     * @param \PhpOffice\PhpPresentation\AbstractShape|\PhpOffice\PhpPresentation\Shape\RichText\TextElement $shape
1419
     */
1420 31
    protected function writeHyperlink(XMLWriter $objWriter, $shape)
1421
    {
1422 31
        if (!$shape->hasHyperlink()) {
1423 26
            return;
1424
        }
1425
        // a:hlinkClick
1426 5
        $objWriter->startElement('a:hlinkClick');
1427 5
        $objWriter->writeAttribute('r:id', $shape->getHyperlink()->relationId);
1428 5
        $objWriter->writeAttribute('tooltip', $shape->getHyperlink()->getTooltip());
1429 5
        if ($shape->getHyperlink()->isInternal()) {
1430 1
            $objWriter->writeAttribute('action', $shape->getHyperlink()->getUrl());
1431
        }
1432 5
        $objWriter->endElement();
1433 5
    }
1434
}
1435