Imagemagick.php
Go to the documentation of this file.
1<?php
11
22{
26 protected $command = '';
30 protected $executable;
34 protected $timeout = 0;
40 public function __construct($options = array())
41 {
42 parent::__construct($options);
43
44 $this->executable = isset($options['executable']) ? $options['executable'] : null;
45 $this->timeout = isset($options['timeout']) ? $options['timeout'] : 0;
46 }
47
59 protected function crop($width, $height, $x = 0, $y = 0)
60 {
61 if (!$this->bypassTest($width, $height, $x, $y)) {
62 // '+' for positive offset (the '-' is already there)
63 $x = ($x < 0) ? $x : '+' . $x;
64 $y = ($y < 0) ? $y : '+' . $y;
65
66 $this->command .= " -gravity NorthWest -crop {$width}x{$height}{$x}{$y}! -flatten";
67 $this->size = array($width, $height);
68 }
69 }
79 protected function resize($width, $height)
80 {
81 $newSize = $this->dimensions($width, $height);
82
83 if (!$this->bypassTest($newSize[0], $newSize[1])) {
84 $resizeAction = $this->getResizeAction($newSize[0], $newSize[1]);
85
86 $this->command .= " $resizeAction {$newSize[0]}x{$newSize[1]}!";
87
88 $this->size = $newSize;
89 }
90 }
100 protected function thumb($width, $height)
101 {
102 if (!$this->bypassTest($width, $height)) {
103 $resizeAction = $this->getResizeAction($width, $height);
104
105 $this->command .= " -gravity Center $resizeAction {$width}x{$height} -extent {$width}x{$height}";
106 $this->size = array($width, $height);
107 }
108 }
120 protected function thumbfill($width, $height, $centerX = 50, $centerY = 50)
121 {
122 if (!$this->bypassTest($width, $height)) {
123 $newSize = $this->dimensions($width, null);
124 $centerX = $centerX / -100 + 0.5;
125 $centerY = $centerY / -100 + 0.5;
126
127 if ($newSize[1] < $height) {
128 $newSize = $this->dimensions(null, $height);
129 $x = round(($width - $newSize[0]) * $centerX);
130 $y = 0;
131 } else {
132 $x = 0;
133 $y = round(($height - $newSize[1]) * $centerY);
134 }
135 $x = ($x < 0) ? $x : '+' . $x;
136 $y = ($y < 0) ? $y : '+' . $y;
137
138 $resizeAction = $this->getResizeAction($width, $height);
139
140 $this->command .= " -gravity Center $resizeAction {$width}x{$height}^ -extent {$width}x{$height}{$x}{$y}";
141 $this->size = array($width, $height);
142 }
143 }
144
150 protected function getImageSize()
151 {
152 $imageSize = false;
153 if (is_callable('getimagesize')) {
154 $imageSize = getimagesize($this->input);
155 }
156 if (!$imageSize) {
157 $pageNumber = $this->getPageNumber();
158 $identify = preg_replace('/convert$/', 'identify', $this->executable);
159 $command = "{$identify} -ping -format \"%wx%h\" " . escapeshellarg($this->input) . $pageNumber;
160 $escapedCommand = str_replace('!', '\!', escapeshellcmd($command));
161
162 exec($escapedCommand . ' 2>&1', $commandOutput, $returnStatus);
163 if ($returnStatus === 0) {
164 $imageSize = explode('x', $commandOutput[0]);
165 } else {
166 $this->unlock();
167
168 throw new \Depage\Graphics\Exceptions\Exception(implode("\n", $commandOutput));
169 }
170 }
171
172 return $imageSize;
173 }
174
184 public function render($input, $output = null)
185 {
186 parent::render($input, $output);
187
188 $this->command = '';
189 $this->processQueue();
190
191 if ($this->otherRender && file_exists($this->output)) {
192 // do nothing file is already generated
193 } else if (
194 $this->bypass
195 && $this->inputFormat == $this->outputFormat
196 ) {
197 $this->bypass();
198 } else {
199 $background = $this->getBackground();
200 $quality = $this->getQuality();
201 $optimize = $this->getOptimize();
202 $pageNumber = $this->getPageNumber();
203
204 $this->command = "{$this->executable} {$background} ( " . escapeshellarg($this->input) . "{$pageNumber}{$this->command}";
205 $this->command .= " ) -colorspace sRGB -flatten {$quality}{$optimize}";
206
207 $this->command .= " {$this->outputFormat}:" . escapeshellarg($this->output);
208
209 $this->execCommand();
210
211 if ($this->optimize) {
212 $this->optimizeImage($this->output);
213 }
214 }
215
216 parent::renderFinished();
217 }
218
226 protected function execCommand()
227 {
228 $command = str_replace('!', '\!', escapeshellcmd($this->command));
229
230 $descriptorspec = array(
231 0 => array("pipe", "r"), // stdin is a pipe that the child will read from
232 1 => array("pipe", "w"), // stdout is a pipe that the child will write to
233 2 => array("pipe", "w") // stderr is pipe that the child will write errors to
234 );
235 $process = proc_open("exec " . $command, $descriptorspec, $pipes);
236
237 // set pipes non blocking
238 stream_set_blocking($pipes[1], false);
239 stream_set_blocking($pipes[2], false);
240
241 $startTime = time();
242 $output = array(1 => "", 2 => "");
243 $terminated = false;
244
245 if (is_resource($process)) {
246 // read stdin and stderr
247 while(!feof($pipes[1]) && !feof($pipes[2])) {
248 for ($i = 1; $i < 3; $i++) {
249 $s = fgets($pipes[$i]);
250 $output[$i] .= $s;
251 }
252
253 usleep(10000);
254 if ($this->timeout > 0 && time() - $startTime > $this->timeout) {
255 // terminate process of takes longer than timeout
256 proc_terminate($process);
257 $terminated = true;
258 }
259 }
260
261 for ($i = 0; $i < 3; $i++) {
262 fclose($pipes[$i]);
263 }
264 $returnStatus = proc_close($process);
265 }
266
267 if ($terminated) {
268 $this->unlock();
269
270 throw new \Depage\Graphics\Exceptions\Exception("Conversion over timeout");
271 } else if ($returnStatus != 0) {
272 $this->unlock();
273
274 throw new \Depage\Graphics\Exceptions\Exception($output[2]);
275 }
276 }
277
283 protected function getBackground()
284 {
285 $background = "-size {$this->size[0]}x{$this->size[1]}";
286
287 if ($this->background[0] === '#') {
288 $background .= " -background {$this->background}";
289 } elseif ($this->background == 'checkerboard') {
290 $background .= " -background none pattern:checkerboard";
291 } else {
292 if ($this->outputFormat == 'jpg') {
293 $background .= " -background #FFF";
294 } else {
295 $background .= " -background none";
296 }
297 }
298
299 return $background;
300 }
306 protected function getQuality()
307 {
308 if (
309 $this->outputFormat == 'jpg'
310 || $this->outputFormat == 'png'
311 || $this->outputFormat == 'webp'
312 ) {
313 return '-quality ' . parent::getQuality();
314 } else {
315 return '';
316 }
317 }
323 protected function getOptimize()
324 {
325 $param = " -strip";
326
327 if ($this->outputFormat == 'jpg') {
328 $param .= " -interlace Plane";
329 } else if ($this->outputFormat == 'png') {
330 $param .= " -define png:format=png00";
331 } else if ($this->outputFormat == "webp" && $this->inputFormat == "png") {
332 $param .= " -define webp:lossless=true -define webp:image-hint=graph";
333 }
334
335 return $param;
336 }
345 protected function getResizeAction($width, $height)
346 {
347 if ($width <= 160 && $height <= 160) {
348 return "-thumbnail";
349 } else {
350 return "-resize";
351 }
352 }
359 public function getPageNumber()
360 {
361 if ($this->inputFormat == "pdf") {
362 return "[0]";
363 } else {
364 return "";
365 }
366 }
367}
368
369/* vim:set ft=php sw=4 sts=4 fdm=marker et : */
Main graphics class.
Definition Graphics.php:41
$background
Image background string.
Definition Graphics.php:73
$quality
Image quality string.
Definition Graphics.php:77
processQueue()
Process action queue.
Definition Graphics.php:299
bypassTest($width, $height, $x=0, $y=0)
Tests if action would change current image.
Definition Graphics.php:512
$input
Input filename.
Definition Graphics.php:45
$output
Output filename.
Definition Graphics.php:49
dimensions($width, $height)
Scales image dimensions.
Definition Graphics.php:278
optimizeImage($filename)
Opimizes final image through one of the optimization programs.
Definition Graphics.php:350
bypass()
Runs bypass (copies file)
Definition Graphics.php:540
$optimize
Optimize output images.
Definition Graphics.php:81
getBackground()
Generates background command.
thumbfill($width, $height, $centerX=50, $centerY=50)
Thumb action.
getQuality()
Generates quality command.
$executable
Imagemagick executable path.
$timeout
timeout after which the image conversion will be canceled
getImageSize()
Determine size of input image.
render($input, $output=null)
Main method for image handling.
$command
Imagemagick command string.
getResizeAction($width, $height)
Gets the resize action depending on target size.
resize($width, $height)
Resize action.
__construct($options=array())
graphics_graphicsmagick class constructor
crop($width, $height, $x=0, $y=0)
Crop action.
thumb($width, $height)
Thumb action.
getOptimize()
Generates optimization parameters.
execCommand()
Executes ImageMagick command.