Completed
Pull Request — master (#96)
by
unknown
01:21
created

Pdf   B

Complexity

Total Complexity 36

Size/Duplication

Total Lines 375
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 4
Bugs 1 Features 0
Metric Value
wmc 36
c 4
b 1
f 0
lcom 1
cbo 7
dl 0
loc 375
rs 8.8

17 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 20 4
A setResolution() 0 6 1
A setOutputFormat() 0 10 2
A getOutputFormat() 0 4 1
A setLayerMethod() 0 13 3
A isValidOutputFormat() 0 4 1
A setPage() 0 10 2
A getNumberOfPages() 0 4 1
A saveImage() 0 16 3
A saveAllPagesAsImages() 0 21 2
B getImageData() 0 28 4
A setColorspace() 0 6 1
A setCompressionQuality() 0 6 1
A determineOutputFormat() 0 16 3
B fetchRemoteFile() 0 30 3
A deleteTempFile() 0 10 2
A clear() 0 8 2
1
<?php
2
3
namespace Spatie\PdfToImage;
4
5
use Imagick;
6
use Spatie\PdfToImage\Exceptions\InvalidFormat;
7
use Spatie\PdfToImage\Exceptions\PdfDoesNotExist;
8
use Spatie\PdfToImage\Exceptions\PageDoesNotExist;
9
use Spatie\PdfToImage\Exceptions\InvalidLayerMethod;
10
use Spatie\PdfToImage\Exceptions\TempFileDoesNotExist;
11
use Spatie\PdfToImage\Exceptions\TempPathNotWritable;
12
use Spatie\PdfToImage\Exceptions\RemoteFileFetchFailed;
13
14
class Pdf
15
{
16
    protected $pdfFile;
17
18
    protected $resolution = 144;
19
20
    protected $outputFormat = 'jpg';
21
22
    protected $page = 1;
23
24
    public $imagick;
25
26
    protected $numberOfPages;
27
28
    protected $validOutputFormats = ['jpg', 'jpeg', 'png'];
29
30
    protected $layerMethod = Imagick::LAYERMETHOD_FLATTEN;
31
32
    protected $colorspace;
33
34
    protected $compressionQuality;
35
36
    protected $isRemoteFile = false;
37
38
    /**
39
     * @param string $pdfFile The path or url to the pdffile.
40
     *
41
     * @throws \Spatie\PdfToImage\Exceptions\PdfDoesNotExist
42
     */
43
    public function __construct($pdfFile)
44
    {
45
        if (! filter_var($pdfFile, FILTER_VALIDATE_URL) && ! file_exists($pdfFile)) {
46
            throw new PdfDoesNotExist();
47
        }       
48
49
        if (filter_var($pdfFile, FILTER_VALIDATE_URL)) {
50
            $this->pdfFile = $this->fetchRemoteFile($pdfFile);
51
52
            $this->isRemoteFile = true;
53
        } else {
54
            $this->pdfFile = $pdfFile;
55
        }
56
57
        $this->imagick = new Imagick();
58
59
        $this->imagick->pingImage($this->pdfFile);
60
61
        $this->numberOfPages = $this->imagick->getNumberImages();
62
    }
63
64
    /**
65
     * Set the raster resolution.
66
     *
67
     * @param int $resolution
68
     *
69
     * @return $this
70
     */
71
    public function setResolution($resolution)
72
    {
73
        $this->resolution = $resolution;
74
75
        return $this;
76
    }
77
78
    /**
79
     * Set the output format.
80
     *
81
     * @param string $outputFormat
82
     *
83
     * @return $this
84
     *
85
     * @throws \Spatie\PdfToImage\Exceptions\InvalidFormat
86
     */
87
    public function setOutputFormat($outputFormat)
88
    {
89
        if (! $this->isValidOutputFormat($outputFormat)) {
90
            throw new InvalidFormat("Format {$outputFormat} is not supported");
91
        }
92
93
        $this->outputFormat = $outputFormat;
94
95
        return $this;
96
    }
97
98
    /**
99
     * Get the output format.
100
     *
101
     * @return string
102
     */
103
    public function getOutputFormat()
104
    {
105
        return $this->outputFormat;
106
    }
107
108
    /**
109
     * Sets the layer method for Imagick::mergeImageLayers()
110
     * If int, should correspond to a predefined LAYERMETHOD constant.
111
     * If null, Imagick::mergeImageLayers() will not be called.
112
     *
113
     * @param int|null
114
     *
115
     * @return $this
116
     *
117
     * @throws \Spatie\PdfToImage\Exceptions\InvalidLayerMethod
118
     *
119
     * @see https://secure.php.net/manual/en/imagick.constants.php
120
     * @see Pdf::getImageData()
121
     */
122
    public function setLayerMethod($layerMethod)
123
    {
124
        if (
125
            is_int($layerMethod) === false &&
126
            is_null($layerMethod) === false
127
        ) {
128
            throw new InvalidLayerMethod('LayerMethod must be an integer or null');
129
        }
130
131
        $this->layerMethod = $layerMethod;
132
133
        return $this;
134
    }
135
136
    /**
137
     * Determine if the given format is a valid output format.
138
     *
139
     * @param $outputFormat
140
     *
141
     * @return bool
142
     */
143
    public function isValidOutputFormat($outputFormat)
144
    {
145
        return in_array($outputFormat, $this->validOutputFormats);
146
    }
147
148
    /**
149
     * Set the page number that should be rendered.
150
     *
151
     * @param int $page
152
     *
153
     * @return $this
154
     *
155
     * @throws \Spatie\PdfToImage\Exceptions\PageDoesNotExist
156
     */
157
    public function setPage($page)
158
    {
159
        if ($page > $this->getNumberOfPages()) {
160
            throw new PageDoesNotExist("Page {$page} does not exist");
161
        }
162
163
        $this->page = $page;
164
165
        return $this;
166
    }
167
168
    /**
169
     * Get the number of pages in the pdf file.
170
     *
171
     * @return int
172
     */
173
    public function getNumberOfPages()
174
    {
175
        return $this->numberOfPages;
176
    }
177
178
    /**
179
     * Save the image to the given path.
180
     *
181
     * @param string $pathToImage
182
     * @param bool $clear 
183
     *
184
     * @return bool
185
     */
186
    public function saveImage($pathToImage, $clear = true)
187
    {
188
        if (is_dir($pathToImage)) {
189
            $pathToImage = rtrim($pathToImage, '\/').DIRECTORY_SEPARATOR.$this->page.'.'.$this->outputFormat;
190
        }
191
192
        $imageData = $this->getImageData($pathToImage);
193
194
        $status = file_put_contents($pathToImage, $imageData) !== false;
195
        
196
        if ($clear) {
197
            $this->clear();
198
        }        
199
200
        return $status;
201
    }
202
203
    /**
204
     * Save the file as images to the given directory.
205
     *
206
     * @param string $directory
207
     * @param string $prefix
208
     *
209
     * @return array $files the paths to the created images
210
     */
211
    public function saveAllPagesAsImages($directory, $prefix = '')
212
    {
213
        
214
        $numberOfPages = $this->getNumberOfPages();
215
216
        if ($numberOfPages === 0) {
217
            return [];
218
        }
219
220
        return array_map(function ($pageNumber) use ($directory, $prefix) {
221
            $this->setPage($pageNumber);
222
223
            $destination = "{$directory}/{$prefix}{$pageNumber}.{$this->outputFormat}";
224
225
            $this->saveImage($destination, false);
226
227
            return $destination;
228
        }, range(1, $numberOfPages));
229
230
        $this->clear();
0 ignored issues
show
Unused Code introduced by
$this->clear(); does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
231
    }
232
233
    /**
234
     * Return raw image data.
235
     *
236
     * @param string $pathToImage
237
     *
238
     * @return \Imagick
239
     */
240
    public function getImageData($pathToImage)
241
    {
242
        /*
243
         * Reinitialize imagick because the target resolution must be set
244
         * before reading the actual image.
245
         */
246
        $this->imagick = new Imagick();
247
248
        $this->imagick->setResolution($this->resolution, $this->resolution);
249
250
        if ($this->colorspace !== null) {
251
            $this->imagick->setColorspace($this->colorspace);
252
        }
253
254
        if ($this->compressionQuality !== null) {
255
            $this->imagick->setCompressionQuality($this->compressionQuality);
256
        }
257
258
        $this->imagick->readImage(sprintf('%s[%s]', $this->pdfFile, $this->page - 1));
259
260
        if (is_int($this->layerMethod)) {
261
            $this->imagick = $this->imagick->mergeImageLayers($this->layerMethod);
262
        }
263
264
        $this->imagick->setFormat($this->determineOutputFormat($pathToImage));
265
266
        return $this->imagick;
267
    }
268
269
    /**
270
     * @param int $colorspace
271
     *
272
     * @return $this
273
     */
274
    public function setColorspace(int $colorspace)
275
    {
276
        $this->colorspace = $colorspace;
277
278
        return $this;
279
    }
280
281
    /**
282
     * @param int $compressionQuality
283
     *
284
     * @return $this
285
     */
286
    public function setCompressionQuality(int $compressionQuality)
287
    {
288
        $this->compressionQuality = $compressionQuality;
289
290
        return $this;
291
    }   
292
293
    /**
294
     * Determine in which format the image must be rendered.
295
     *
296
     * @param $pathToImage
297
     *
298
     * @return string
299
     */
300
    protected function determineOutputFormat($pathToImage)
301
    {
302
        $outputFormat = pathinfo($pathToImage, PATHINFO_EXTENSION);
303
304
        if ($this->outputFormat != '') {
305
            $outputFormat = $this->outputFormat;
306
        }
307
308
        $outputFormat = strtolower($outputFormat);
309
310
        if (! $this->isValidOutputFormat($outputFormat)) {
311
            $outputFormat = 'jpg';
312
        }
313
314
        return $outputFormat;
315
    }
316
317
    /**
318
     * Fetch remote file and save temporary on image dir.
319
     * 
320
     * @throws \Spatie\PdfToImage\Exceptions\TempPathNotWritable
321
     * @throws \Spatie\PdfToImage\Exceptions\RemoteFileFetchFailed
322
     * 
323
     * @return string
324
     */
325
    protected function fetchRemoteFile($source)
326
    {
327
        $pathToTemp = tempnam(sys_get_temp_dir(), 'pdf');
328
329
        if (!is_writable($pathToTemp)) {
330
            throw new TempPathNotWritable();
331
        }
332
333
        $remote = curl_init($source);
334
335
        $local = fopen($pathToTemp, 'w');
336
        
337
        curl_setopt($remote, CURLOPT_FILE, $local);
338
        
339
        curl_setopt($remote, CURLOPT_TIMEOUT, 60);
340
341
        curl_setopt($remote, CURLOPT_FOLLOWLOCATION, true);
342
343
        curl_exec($remote);
344
345
        if (curl_error($remote)) {
346
            throw new RemoteFileFetchFailed("Remote file fetch failed. Error ".curl_error($remote));
347
        }
348
        
349
        curl_close($remote);
350
        
351
        fclose($local);
352
353
        return $pathToTemp;
354
    }
355
356
    /**
357
     * Delete Temporary pdf file.
358
     *
359
     * @throws \Spatie\PdfToImage\Exceptions\TempFileDoesNotExist
360
     * 
361
     * @return bool
362
     */
363
    protected function deleteTempFile()
364
    {
365
        $tempPath = $this->pdfFile;
366
367
        if (!file_exists($tempPath)) {
368
            throw new TempFileDoesNotExist("Temporary file {$tempPath} does not exist");
369
        }
370
371
        return unlink($tempPath);
372
    }
373
374
    /**
375
     * Remove temp file and clear Imagick object
376
     *
377
     * @return bool
378
     */
379
    protected function clear()
380
    {
381
        if ($this->isRemoteFile) {
382
            $this->deleteTempFile();
383
        }
384
385
        return $this->imagick->clear();
386
    }
387
388
}
389