Completed
Pull Request — develop (#186)
by
unknown
07:55
created

ODPresentation::getDrawingHashTable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
/**
3
 * This file is part of PHPPresentation - A pure PHP library for reading and writing
4
 * presentations documents.
5
 *
6
 * PHPPresentation is free software distributed under the terms of the GNU Lesser
7
 * General Public License version 3 as published by the Free Software Foundation.
8
 *
9
 * For the full copyright and license information, please read the LICENSE
10
 * file that was distributed with this source code. For the full list of
11
 * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors.
12
 *
13
 * @link        https://github.com/PHPOffice/PHPPresentation
14
 * @copyright   2009-2015 PHPPresentation contributors
15
 * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
16
 */
17
18
namespace PhpOffice\PhpPresentation\Writer;
19
20
use PhpOffice\PhpPresentation\HashTable;
21
use PhpOffice\PhpPresentation\PhpPresentation;
22
use PhpOffice\PhpPresentation\Shape\Drawing as ShapeDrawing;
23
use PhpOffice\PhpPresentation\Shape\MemoryDrawing;
24
use PhpOffice\PhpPresentation\Slide\Background\Image;
25
use PhpOffice\PhpPresentation\Writer\ODPresentation\Content;
26
use PhpOffice\PhpPresentation\Writer\ODPresentation\Drawing;
27
use PhpOffice\PhpPresentation\Writer\ODPresentation\Manifest;
28
use PhpOffice\PhpPresentation\Writer\ODPresentation\Meta;
29
use PhpOffice\PhpPresentation\Writer\ODPresentation\Mimetype;
30
use PhpOffice\PhpPresentation\Writer\ODPresentation\ObjectsChart;
31
use PhpOffice\PhpPresentation\Writer\ODPresentation\Styles;
32
use PhpOffice\PhpPresentation\Shape\AbstractDrawing;
33
34
/**
35
 * ODPresentation writer
36
 */
37
class ODPresentation implements WriterInterface
38
{
39
    /**
40
    * Private PhpPresentation
41
    *
42
    * @var \PhpOffice\PhpPresentation\PhpPresentation
43
    */
44
    private $presentation;
45
46
    /**
47
    * Private writer parts
48
    *
49
    * @var \PhpOffice\PhpPresentation\Writer\ODPresentation\AbstractPart[]
50
    */
51
    private $writerParts;
52
53
    /**
54
     * Private unique hashtable
55
     *
56
     * @var \PhpOffice\PhpPresentation\HashTable
57
     */
58
    private $drawingHashTable;
59
60
    /**
61
     * @var \PhpOffice\PhpPresentation\Shape\Chart[]
62
     */
63
    public $chartArray = array();
64
65
    /**
66
    * Use disk caching where possible?
67
    *
68
    * @var boolean
69
    */
70
    private $useDiskCaching = false;
71
72
    /**
73
     * Disk caching directory
74
     *
75
     * @var string
76
     */
77
    private $diskCachingDirectory;
78
79
    /**
80
     * Create a new \PhpOffice\PhpPresentation\Writer\ODPresentation
81
     *
82
     * @param PhpPresentation $pPhpPresentation
83
     */
84 50
    public function __construct(PhpPresentation $pPhpPresentation = null)
85
    {
86
        // Assign PhpPresentation
87 50
        $this->setPhpPresentation($pPhpPresentation);
88
89
        // Set up disk caching location
90 50
        $this->diskCachingDirectory = './';
91
92
        // Initialise writer parts
93 50
        $this->writerParts['content']  = new Content();
94 50
        $this->writerParts['manifest'] = new Manifest();
95 50
        $this->writerParts['meta']     = new Meta();
96 50
        $this->writerParts['mimetype'] = new Mimetype();
97 50
        $this->writerParts['styles']   = new Styles();
98 50
        $this->writerParts['charts']   = new ObjectsChart();
99 50
        $this->writerParts['drawing']  = new Drawing();
100
101
        // Assign parent WriterInterface
102 50
        foreach ($this->writerParts as $writer) {
103 50
            $writer->setParentWriter($this);
104
        }
105
106
        // Set HashTable variables
107 50
        $this->drawingHashTable            = new HashTable();
108 50
    }
109
110
    /**
111
     * Save PhpPresentation to file
112
     *
113
     * @param  string    $pFilename
114
     * @throws \Exception
115
     */
116 44
    public function save($pFilename)
117
    {
118 44
        if (empty($pFilename)) {
119 1
            throw new \Exception("Filename is empty");
120
        }
121 43
        if (!is_null($this->presentation)) {
122
            // If $pFilename is php://output or php://stdout, make it a temporary file...
123 43
            $originalFilename = $pFilename;
124 43
            if (strtolower($pFilename) == 'php://output' || strtolower($pFilename) == 'php://stdout') {
125
                $pFilename = @tempnam('./', 'phppttmp');
126
                if ($pFilename == '') {
127
                    $pFilename = $originalFilename;
128
                }
129
            }
130
131 43
            $writerPartChart = $this->getWriterPart('charts');
132 43
            if (!$writerPartChart instanceof ObjectsChart) {
133
                throw new \Exception('The $parentWriter is not an instance of \PhpOffice\PhpPresentation\Writer\ODPresentation\ObjectsChart');
134
            }
135 43
            $writerPartContent = $this->getWriterPart('content');
136 43
            if (!$writerPartContent instanceof Content) {
137
                throw new \Exception('The $parentWriter is not an instance of \PhpOffice\PhpPresentation\Writer\ODPresentation\Content');
138
            }
139 43
            $writerPartDrawing = $this->getWriterPart('Drawing');
140 43
            if (!$writerPartDrawing instanceof Drawing) {
141
                throw new \Exception('The $parentWriter is not an instance of \PhpOffice\PhpPresentation\Writer\ODPresentation\Drawing');
142
            }
143 43
            $writerPartManifest = $this->getWriterPart('manifest');
144 43
            if (!$writerPartManifest instanceof Manifest) {
145
                throw new \Exception('The $parentWriter is not an instance of \PhpOffice\PhpPresentation\Writer\ODPresentation\Manifest');
146
            }
147 43
            $writerPartMeta = $this->getWriterPart('meta');
148 43
            if (!$writerPartMeta instanceof Meta) {
149
                throw new \Exception('The $parentWriter is not an instance of \PhpOffice\PhpPresentation\Writer\ODPresentation\Meta');
150
            }
151 43
            $writerPartMimetype = $this->getWriterPart('mimetype');
152 43
            if (!$writerPartMimetype instanceof Mimetype) {
153
                throw new \Exception('The $parentWriter is not an instance of \PhpOffice\PhpPresentation\Writer\ODPresentation\Mimetype');
154
            }
155 43
            $writerPartStyles = $this->getWriterPart('styles');
156 43
            if (!$writerPartStyles instanceof Styles) {
157
                throw new \Exception('The $parentWriter is not an instance of \PhpOffice\PhpPresentation\Writer\ODPresentation\Styles');
158
            }
159
160
            // Create drawing dictionary
161 43
            $this->drawingHashTable->addFromSource($writerPartDrawing->allDrawings($this->presentation));
162
163
            // Create new ZIP file and open it for writing
164 43
            $objZip = new \ZipArchive();
165
166
            // Try opening the ZIP file
167 43
            if ($objZip->open($pFilename, \ZIPARCHIVE::OVERWRITE) !== true) {
168
                if ($objZip->open($pFilename, \ZIPARCHIVE::CREATE) !== true) {
169
                    throw new \Exception("Could not open " . $pFilename . " for writing.");
170
                }
171
            }
172
173
            // Add mimetype to ZIP file
174
            //@todo Not in ZIPARCHIVE::CM_STORE mode
175 43
            $objZip->addFromString('mimetype', $writerPartMimetype->writePart());
176
177
            // Add content.xml to ZIP file
178 43
            $objZip->addFromString('content.xml', $writerPartContent->writePart($this->presentation));
179
180
            // Add meta.xml to ZIP file
181 43
            $objZip->addFromString('meta.xml', $writerPartMeta->writePart($this->presentation));
182
183
            // Add styles.xml to ZIP file
184 43
            $objZip->addFromString('styles.xml', $writerPartStyles->writePart($this->presentation));
185
186
            // Add META-INF/manifest.xml
187 43
            $objZip->addFromString('META-INF/manifest.xml', $writerPartManifest->writePart());
188
            
189
            // Add Thumbnail
190 43
            if ($this->presentation->getPresentationProperties()->getThumbnailPath()) {
191 1
                $pathThumbnail = $this->presentation->getPresentationProperties()->getThumbnailPath();
192
                // Size : 128x128 pixel
193
                // PNG : 8bit, non-interlaced with full alpha transparency
194 1
                $gdImage = imagecreatefromstring(file_get_contents($pathThumbnail));
195 1
                if ($gdImage) {
196 1
                    list($width, $height) = getimagesize($pathThumbnail);
197
                    
198 1
                    $gdRender = imagecreatetruecolor(128, 128);
199 1
                    $colorBgAlpha = imagecolorallocatealpha($gdRender, 0, 0, 0, 127);
200 1
                    imagecolortransparent($gdRender, $colorBgAlpha);
201 1
                    imagefill($gdRender, 0, 0, $colorBgAlpha);
202 1
                    imagecopyresampled($gdRender, $gdImage, 0, 0, 0, 0, 128, 128, $width, $height);
203 1
                    imagetruecolortopalette($gdRender, false, 255);
204 1
                    imagesavealpha($gdRender, true);
205
                    
206 1
                    ob_start();
207 1
                    imagepng($gdRender);
208 1
                    $imageContents = ob_get_contents();
209 1
                    ob_end_clean();
210
                    
211 1
                    imagedestroy($gdRender);
212 1
                    imagedestroy($gdImage);
213
214 1
                    $objZip->addFromString('Thumbnails/thumbnail.png', $imageContents);
215
                }
216
            }
217
218
            // Add charts
219 43
            foreach ($this->chartArray as $keyChart => $shapeChart) {
220 15
                $arrayFile = $writerPartChart->writePart($shapeChart);
221 14
                foreach ($arrayFile as $file => $content) {
222 14
                    if (!empty($content)) {
223 14
                        $objZip->addFromString('Object '.$keyChart.'/' . $file, $content);
224
                    }
225
                }
226
            }
227
            
228
            // Add media
229 42
            $arrMedia = array();
230 42
            for ($i = 0; $i < $this->getDrawingHashTable()->count(); ++$i) {
231 18
                $shape = $this->getDrawingHashTable()->getByIndex($i);
232 18
                if (!($shape instanceof AbstractDrawing)) {
233
                    throw new \Exception('The $parentWriter is not an instance of \PhpOffice\PhpPresentation\Shape\AbstractDrawing');
234
                }
235 18
                if ($shape instanceof ShapeDrawing) {
236 4
                    if (!in_array(md5($shape->getPath()), $arrMedia)) {
237 4
                        $arrMedia[] = md5($shape->getPath());
238
239 4
                        $imagePath = $shape->getPath();
240
241 4
                        if (strpos($imagePath, 'zip://') !== false) {
242
                            $imagePath = substr($imagePath, 6);
243
                            $imagePathSplitted = explode('#', $imagePath);
244
245
                            $imageZip = new \ZipArchive();
246
                            $imageZip->open($imagePathSplitted[0]);
247
                            $imageContents = $imageZip->getFromName($imagePathSplitted[1]);
248
                            $imageZip->close();
249
                            unset($imageZip);
250
                        } else {
251 4
                            $imageContents = file_get_contents($imagePath);
252
                        }
253
254 4
                        $objZip->addFromString('Pictures/' . md5($shape->getPath()).'.'.$shape->getExtension(), $imageContents);
255
                    }
256
                } elseif ($shape instanceof MemoryDrawing) {
257 1
                    if (!in_array(str_replace(' ', '_', $shape->getIndexedFilename()), $arrMedia)) {
258 1
                        $arrMedia[] = str_replace(' ', '_', $shape->getIndexedFilename());
259 1
                        ob_start();
260 1
                            call_user_func($shape->getRenderingFunction(), $shape->getImageResource());
261 1
                            $imageContents = ob_get_contents();
262 1
                        ob_end_clean();
263
264 1
                        $objZip->addFromString('Pictures/' . str_replace(' ', '_', $shape->getIndexedFilename()), $imageContents);
265
                    }
266
                }
267
            }
268
269 42
            foreach ($this->presentation->getAllSlides() as $keySlide => $oSlide) {
270
                // Add background image slide
271 42
                $oBkgImage = $oSlide->getBackground();
272 42
                if ($oBkgImage instanceof Image) {
273 42
                    $objZip->addFromString('Pictures/'.$oBkgImage->getIndexedFilename($keySlide), file_get_contents($oBkgImage->getPath()));
274
                }
275
            }
276
277
            // Close file
278 42
            if ($objZip->close() === false) {
279
                throw new \Exception("Could not close zip file $pFilename.");
280
            }
281
282
            // If a temporary file was used, copy it to the correct file stream
283 42
            if ($originalFilename != $pFilename) {
284
                if (copy($pFilename, $originalFilename) === false) {
285
                    throw new \Exception("Could not copy temporary zip file $pFilename to $originalFilename.");
286
                }
287
                if (@unlink($pFilename) === false) {
288 42
                    throw new \Exception('The file '.$pFilename.' could not be deleted.');
289
                }
290
            }
291
        } else {
292
            throw new \Exception("PhpPresentation object unassigned.");
293
        }
294 42
    }
295
296
    /**
297
     * Get PhpPresentation object
298
     *
299
     * @return PhpPresentation
300
     * @throws \Exception
301
     */
302 45
    public function getPhpPresentation()
303
    {
304 45
        if (!is_null($this->presentation)) {
305 44
            return $this->presentation;
306
        } else {
307 1
            throw new \Exception("No PhpPresentation assigned.");
308
        }
309
    }
310
311
    /**
312
     * Get PhpPresentation object
313
     *
314
     * @param  PhpPresentation                       $pPhpPresentation PhpPresentation object
315
     * @throws \Exception
316
     * @return \PhpOffice\PhpPresentation\Writer\ODPresentation
317
     */
318 50
    public function setPhpPresentation(PhpPresentation $pPhpPresentation = null)
319
    {
320 50
        $this->presentation = $pPhpPresentation;
321
322 50
        return $this;
323
    }
324
325
    /**
326
     * Get drawing hash table
327
     *
328
     * @return \PhpOffice\PhpPresentation\HashTable
329
     */
330 44
    public function getDrawingHashTable()
331
    {
332 44
        return $this->drawingHashTable;
333
    }
334
335
    /**
336
     * Get writer part
337
     *
338
     * @param  string                                         $pPartName Writer part name
339
     * @return \PhpOffice\PhpPresentation\Writer\ODPresentation\AbstractPart
340
     */
341 45
    public function getWriterPart($pPartName = '')
342
    {
343 45
        if ($pPartName != '' && isset($this->writerParts[strtolower($pPartName)])) {
344 44
            return $this->writerParts[strtolower($pPartName)];
345
        } else {
346 1
            return null;
347
        }
348
    }
349
350
    /**
351
     * Get use disk caching where possible?
352
     *
353
     * @return boolean
354
     */
355 45
    public function hasDiskCaching()
356
    {
357 45
        return $this->useDiskCaching;
358
    }
359
360
    /**
361
     * Set use disk caching where possible?
362
     *
363
     * @param  boolean $pValue
364
     * @param  string $pDirectory Disk caching directory
365
     * @throws \Exception
366
     * @return \PhpOffice\PhpPresentation\Writer\ODPresentation
367
     */
368 3
    public function setUseDiskCaching($pValue = false, $pDirectory = null)
369
    {
370 3
        $this->useDiskCaching = $pValue;
371
372 3
        if (!is_null($pDirectory)) {
373 2
            if (is_dir($pDirectory)) {
374 1
                $this->diskCachingDirectory = $pDirectory;
375
            } else {
376 1
                throw new \Exception("Directory does not exist: $pDirectory");
377
            }
378
        }
379
380 2
        return $this;
381
    }
382
383
    /**
384
     * Get disk caching directory
385
     *
386
     * @return string
387
     */
388 3
    public function getDiskCachingDirectory()
389
    {
390 3
        return $this->diskCachingDirectory;
391
    }
392
}
393