Completed
Pull Request — master (#140)
by
unknown
02:19
created

Pdf::fetchNumberPages()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace Spatie\PdfToImage;
4
5
use Imagick;
6
use Smalot\PdfParser\Parser;
7
use Spatie\PdfToImage\Exceptions\InvalidFormat;
8
use Spatie\PdfToImage\Exceptions\PageDoesNotExist;
9
use Spatie\PdfToImage\Exceptions\PdfDoesNotExist;
10
11
class Pdf
12
{
13
    protected $pdfFile;
14
15
    protected $resolution = 144;
16
17
    protected $outputFormat = 'jpg';
18
19
    protected $page = 1;
20
21
    public $imagick;
22
23
    protected $numberOfPages;
24
25
    protected $validOutputFormats = ['jpg', 'jpeg', 'png'];
26
27
    protected $layerMethod = Imagick::LAYERMETHOD_FLATTEN;
28
29
    protected $colorspace;
30
31
    protected $compressionQuality;
32
33
    public function __construct(string $pdfFile)
34
    {
35
        if (! file_exists($pdfFile)) {
36
            throw new PdfDoesNotExist("File `{$pdfFile}` does not exist");
37
        }
38
39
        $this->imagick = new Imagick();
40
41
        $this->numberOfPages = $this->fetchNumberPages($pdfFile);
42
43
        $this->pdfFile = $pdfFile;
44
    }
45
46
    public function fetchNumberPages(string $pdfFile)
47
    {
48
        $parser = new Parser();
49
50
        $document = $parser->parseFile($pdfFile);
51
52
        return count($document->getPages());
53
    }
54
55
    public function setResolution(int $resolution)
56
    {
57
        $this->resolution = $resolution;
58
59
        return $this;
60
    }
61
62
    public function setOutputFormat(string $outputFormat)
63
    {
64
        if (! $this->isValidOutputFormat($outputFormat)) {
65
            throw new InvalidFormat("Format {$outputFormat} is not supported");
66
        }
67
68
        $this->outputFormat = $outputFormat;
69
70
        return $this;
71
    }
72
73
    public function getOutputFormat(): string
74
    {
75
        return $this->outputFormat;
76
    }
77
78
    /**
79
     * Sets the layer method for Imagick::mergeImageLayers()
80
     * If int, should correspond to a predefined LAYERMETHOD constant.
81
     * If null, Imagick::mergeImageLayers() will not be called.
82
     *
83
     * @param int|null
84
     *
85
     * @return $this
86
     *
87
     * @throws \Spatie\PdfToImage\Exceptions\InvalidLayerMethod
88
     *
89
     * @see https://secure.php.net/manual/en/imagick.constants.php
90
     * @see Pdf::getImageData()
91
     */
92
    public function setLayerMethod(?int $layerMethod)
93
    {
94
        $this->layerMethod = $layerMethod;
95
96
        return $this;
97
    }
98
99
    public function isValidOutputFormat(string $outputFormat): bool
100
    {
101
        return in_array($outputFormat, $this->validOutputFormats);
102
    }
103
104
    public function setPage(int $page)
105
    {
106
        if ($page > $this->getNumberOfPages() || $page < 1) {
107
            throw new PageDoesNotExist("Page {$page} does not exist");
108
        }
109
110
        $this->page = $page;
111
112
        return $this;
113
    }
114
115
    public function getNumberOfPages(): int
116
    {
117
        return $this->numberOfPages;
118
    }
119
120
    public function saveImage(string $pathToImage): bool
121
    {
122
        if (is_dir($pathToImage)) {
123
            $pathToImage = rtrim($pathToImage, '\/').DIRECTORY_SEPARATOR.$this->page.'.'.$this->outputFormat;
124
        }
125
126
        $imageData = $this->getImageData($pathToImage);
127
128
        return file_put_contents($pathToImage, $imageData) !== false;
129
    }
130
131
    public function saveAllPagesAsImages(string $directory, string $prefix = ''): array
132
    {
133
        $numberOfPages = $this->getNumberOfPages();
134
135
        if ($numberOfPages === 0) {
136
            return [];
137
        }
138
139
        return array_map(function ($pageNumber) use ($directory, $prefix) {
140
            $this->setPage($pageNumber);
141
142
            $destination = "{$directory}/{$prefix}{$pageNumber}.{$this->outputFormat}";
143
144
            $this->saveImage($destination);
145
146
            return $destination;
147
        }, range(1, $numberOfPages));
148
    }
149
150
    public function getImageData(string $pathToImage): Imagick
151
    {
152
        /*
153
         * Reinitialize imagick because the target resolution must be set
154
         * before reading the actual image.
155
         */
156
        $this->imagick = new Imagick();
157
158
        $this->imagick->setResolution($this->resolution, $this->resolution);
159
160
        if ($this->colorspace !== null) {
161
            $this->imagick->setColorspace($this->colorspace);
162
        }
163
164
        if ($this->compressionQuality !== null) {
165
            $this->imagick->setCompressionQuality($this->compressionQuality);
166
        }
167
168
        if (filter_var($this->pdfFile, FILTER_VALIDATE_URL)) {
169
            return $this->getRemoteImageData($pathToImage);
170
        }
171
172
        $this->imagick->readImage(sprintf('%s[%s]', $this->pdfFile, $this->page - 1));
173
174
        if (is_int($this->layerMethod)) {
175
            $this->imagick = $this->imagick->mergeImageLayers($this->layerMethod);
176
        }
177
178
        $this->imagick->setFormat($this->determineOutputFormat($pathToImage));
179
180
        return $this->imagick;
181
    }
182
183
    public function setColorspace(int $colorspace)
184
    {
185
        $this->colorspace = $colorspace;
186
187
        return $this;
188
    }
189
190
    public function setCompressionQuality(int $compressionQuality)
191
    {
192
        $this->compressionQuality = $compressionQuality;
193
194
        return $this;
195
    }
196
197
    protected function getRemoteImageData(string $pathToImage): Imagick
198
    {
199
        $this->imagick->readImage($this->pdfFile);
200
201
        $this->imagick->setIteratorIndex($this->page - 1);
202
203
        if (is_int($this->layerMethod)) {
204
            $this->imagick = $this->imagick->mergeImageLayers($this->layerMethod);
205
        }
206
207
        $this->imagick->setFormat($this->determineOutputFormat($pathToImage));
208
209
        return $this->imagick;
210
    }
211
212
    protected function determineOutputFormat(string $pathToImage): string
213
    {
214
        $outputFormat = pathinfo($pathToImage, PATHINFO_EXTENSION);
215
216
        if ($this->outputFormat != '') {
217
            $outputFormat = $this->outputFormat;
218
        }
219
220
        $outputFormat = strtolower($outputFormat);
221
222
        if (! $this->isValidOutputFormat($outputFormat)) {
223
            $outputFormat = 'jpg';
224
        }
225
226
        return $outputFormat;
227
    }
228
}
229