Graphics.php
Go to the documentation of this file.
1<?php
14namespace Depage\Graphics;
15
21function autoload($class)
22{
23 if (strpos($class, __NAMESPACE__ . '\\') == 0) {
24 $class = str_replace('\\', '/', str_replace(__NAMESPACE__ . '\\', '', $class));
25 $file = __DIR__ . '/' . $class . '.php';
26
27 if (file_exists($file)) {
28 require_once($file);
29 }
30 }
31}
32
33spl_autoload_register(__NAMESPACE__ . '\autoload');
34
41{
45 protected $input;
49 protected $output;
53 protected $format;
57 protected $outputLockFp = null;
61 protected $otherRender = false;
65 protected $queue = array();
69 protected $size = array();
73 protected $background;
77 protected $quality = '';
81 protected $optimize;
85 protected $optimizers;
89 protected $limits = [];
93 protected $inputFormat;
97 protected $outputFormat;
101 protected $bypass = true;
105 private $oldIgnoreUserAbort = false;
115 public static function factory($options = array())
116 {
117 $extension = (isset($options['extension'])) ? $options['extension'] : 'gd';
118
119 if ($extension == 'imagick' && extension_loaded('imagick')) {
120 return new Providers\Imagick($options);
121 } elseif ($extension == 'im' || $extension == 'imagemagick') {
122 if (isset($options['executable'])) {
123 return new Providers\Imagemagick($options);
124 } else {
125 $executable = Graphics::which('convert');
126 if ($executable == null) {
127 trigger_error("Cannot find ImageMagick, falling back to GD", E_USER_WARNING);
128 } else {
129 $options['executable'] = $executable;
130
131 return new Providers\Imagemagick($options);
132 }
133 }
134 } elseif ($extension == 'gm' || $extension == 'graphicsmagick') {
135 if (isset($options['executable'])) {
136 return new Providers\Graphicsmagick($options);
137 } else {
138 $executable = Graphics::which('gm');
139 if ($executable == null) {
140 trigger_error("Cannot find GraphicsMagick, falling back to GD", E_USER_WARNING);
141 } else {
142 $options['executable'] = $executable;
143
144 return new Providers\Graphicsmagick($options);
145 }
146 }
147 }
148
149 return new Providers\Gd($options);
150 }
156 public function __construct($options = array())
157 {
158 $this->background = (isset($options['background'])) ? $options['background'] : 'transparent';
159 $this->quality = (isset($options['quality'])) ? intval($options['quality']) : null;
160 $this->format = (isset($options['format'])) ? $options['format'] : null;
161 $this->optimize = (isset($options['optimize'])) ? $options['optimize'] : false;
162 $this->optimizers = (isset($options['optimizers'])) ? $options['optimizers'] : [];
163 $this->limits = (isset($options['limits'])) ? $options['limits'] : [
164 'memory' => "64MiB",
165 'map' => "128MiB",
166 ];
167 if (isset($this->limits['memory'])) {
168 putenv("MAGICK_MEMORY_LIMIT=" . $this->limits['memory']);
169 putenv("MAGICK_LIMIT_MEMORY=" . $this->limits['memory']);
170 }
171 if (isset($this->limits['map'])) {
172 putenv("MAGICK_MAP_LIMIT=" . $this->limits['map']);
173 putenv("MAGICK_LIMIT_MAP=" . $this->limits['map']);
174 }
175 }
176
185 public function addBackground($background)
186 {
187 $this->background = $background;
188
189 return $this;
190 }
202 public function addCrop($width, $height, $x = 0, $y = 0)
203 {
204 $this->queue[] = array('crop', func_get_args());
205
206 return $this;
207 }
217 public function addResize($width, $height)
218 {
219 $this->queue[] = array('resize', func_get_args());
220
221 return $this;
222 }
232 public function addThumb($width, $height)
233 {
234 $this->queue[] = array('thumb', func_get_args());
235
236 return $this;
237 }
249 public function addThumbfill($width, $height, $centerX = 50, $centerY = 50)
250 {
251 $this->queue[] = array('thumbfill', func_get_args());
252
253 return $this;
254 }
255
264 protected function escapeNumber($number)
265 {
266 return (is_numeric($number)) ? intval($number) : null;
267 }
278 protected function dimensions($width, $height)
279 {
280 if (!is_numeric($width) && !is_numeric($height)) {
281 $width = null;
282 $height = null;
283 } elseif (!is_numeric($height)) {
284 $height = round(($this->size[1] / $this->size[0]) * $width);
285 } elseif (!is_numeric($width)) {
286 $width = round(($this->size[0] / $this->size[1]) * $height);
287 }
288
289 return array($width, $height);
290 }
291
299 protected function processQueue()
300 {
301 foreach ($this->queue as $task) {
302 $action = $task[0];
303 $arguments = array_map(array($this, 'escapeNumber'), $task[1]);
304
305 call_user_func_array(array($this, $action), $arguments);
306 }
307 }
317 public function render($input, $output = null)
318 {
319 if (!file_exists($input)) throw new Exceptions\FileNotFound();
320
321 $this->input = $input;
322 $this->output = ($output == null) ? $input : $output;
323 $this->inputFormat = $this->obtainFormat($this->input);
324 $this->outputFormat = ($this->format == null) ? $this->obtainFormat($this->output) : $this->format;
325 $this->size = $this->getImageSize();
326 $this->otherRender = false;
327
328 $this->lock();
329
330 $this->oldIgnoreUserAbort = ignore_user_abort();
331 ignore_user_abort(true);
332 }
338 public function renderFinished()
339 {
340 ignore_user_abort($this->oldIgnoreUserAbort);
341
342 $this->unlock();
343 }
350 public function optimizeImage($filename)
351 {
352 if (!file_exists($filename)) {
353 return false;
354 }
355
356 $optimizer = new Optimizers\Optimizer($this->optimizers);
357 $success = $optimizer->optimize($filename);
358
359 return $success;
360 }
366 protected function lock()
367 {
368 // set lock
369 $this->outputLockFp = fopen($this->output . ".lock", 'w');
370 $locked = flock($this->outputLockFp, LOCK_EX | LOCK_NB, $wouldblock);
371
372 if (!$locked && $wouldblock) {
373 $this->otherRender = true;
374 flock($this->outputLockFp, LOCK_EX);
375 }
376 }
382 protected function unlock()
383 {
384 // release lock
385 if (isset($this->outputLockFp)) {
386 flock($this->outputLockFp, LOCK_UN);
387 unlink($this->output . ".lock");
388
389 $this->outputLockFp = null;
390 }
391 }
392
399 protected function obtainFormat($fileName)
400 {
401 $parts = explode('.', $fileName);
402 $extension = strtolower(end($parts));
403
404 if ($extension == 'jpeg') {
405 $extension = 'jpg';
406 } elseif (
407 $extension != 'jpg'
408 && $extension != 'png'
409 && $extension != 'gif'
410 ) {
411 if (is_callable('getimagesize') && file_exists($fileName)) {
412 $info = getimagesize($fileName);
413 if (isset($info[2])) {
414 $format = $info[2];
415
416 if ($format == 1) {
417 $extension = 'gif';
418 } elseif ($format == 2) {
419 $extension = 'jpg';
420 } elseif ($format == 3) {
421 $extension = 'png';
422 }
423 }
424 }
425 }
426
427 return $extension;
428 }
429
438 public static function which($binary)
439 {
440 exec('which ' . $binary, $commandOutput, $returnStatus);
441 if ($returnStatus === 0) {
442 return $commandOutput[0];
443 } else {
444 return null;
445 }
446 }
447
451 public function setQuality($quality)
452 {
453 $this->quality = $quality;
454 }
463 protected function getQuality()
464 {
465 if ($this->outputFormat == 'jpg') {
466 if (
467 is_numeric($this->quality)
468 && $this->quality >= 0
469 && $this->quality <= 100
470 ) {
472 } else {
473 $quality = 85;
474 }
475 } elseif ($this->outputFormat == "webp") {
476 if (
477 is_numeric($this->quality)
478 && $this->quality >= 0
479 && $this->quality <= 100
480 ) {
482 } else {
483 $quality = 75;
484 }
485 } elseif ($this->outputFormat == 'png') {
486 if (
487 is_numeric($this->quality)
488 && $this->quality >= 0
489 && $this->quality <= 95
490 && $this->quality % 10 <= 5
491 ) {
492 $quality = sprintf("%02d", $this->quality);
493 } else {
494 $quality = 95;
495 }
496 } else {
497 $quality = intval($this->quality);
498 }
499
500 return (string) $quality;
501 }
502
512 protected function bypassTest($width, $height, $x = 0, $y = 0)
513 {
514 if (
515 ($width !== null && $width < 1)
516 || ($height !== null && $height < 1)
517 || ($width == null && $height == null)
518 ) {
519 $this->unlock();
520
521 throw new Exceptions\Exception('Invalid image size.');
522 }
523
524 $bypass = (
525 $width == $this->size[0]
526 && $height == $this->size[1]
527 && $x == 0
528 && $y == 0
529 );
530
531 $this->bypass = $this->bypass && $bypass;
532
533 return $bypass;
534 }
540 protected function bypass()
541 {
542 if ($this->input != $this->output) {
543 copy($this->input, $this->output);
544 }
545 }
546}
547
548/* vim:set ft=php sw=4 sts=4 fdm=marker et : */
general graphics related exception class
Definition Exception.php:17
Input file not found exception.
Main graphics class.
Definition Graphics.php:41
$background
Image background string.
Definition Graphics.php:73
$quality
Image quality string.
Definition Graphics.php:77
addThumbfill($width, $height, $centerX=50, $centerY=50)
Adds thumb-fill action.
Definition Graphics.php:249
$format
Output format.
Definition Graphics.php:53
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
$inputFormat
Input image format.
Definition Graphics.php:93
getQuality()
Returns quality-index for current image format.
Definition Graphics.php:463
addThumb($width, $height)
Adds thumb action.
Definition Graphics.php:232
$queue
Action queue array.
Definition Graphics.php:65
$input
Input filename.
Definition Graphics.php:45
$otherRender
otherRender is set to true if another render process has already locked file
Definition Graphics.php:61
$output
Output filename.
Definition Graphics.php:49
render($input, $output=null)
Main method for image handling.
Definition Graphics.php:317
$limits
limits (mainly for imagemagick and graphicsmagick)
Definition Graphics.php:89
static factory($options=array())
graphics object factory
Definition Graphics.php:115
__construct($options=array())
graphics class constructor
Definition Graphics.php:156
addCrop($width, $height, $x=0, $y=0)
Adds crop action.
Definition Graphics.php:202
$outputFormat
Output image format.
Definition Graphics.php:97
setQuality($quality)
Sets quality parameter.
Definition Graphics.php:451
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
obtainFormat($fileName)
Determines image format from file extension.
Definition Graphics.php:399
$optimizers
List of optimizer binaries.
Definition Graphics.php:85
static which($binary)
Executes "which" command.
Definition Graphics.php:438
$bypass
Process bypass bool.
Definition Graphics.php:101
renderFinished()
Called after rendering has finished.
Definition Graphics.php:338
addBackground($background)
Background "action".
Definition Graphics.php:185
addResize($width, $height)
Adds resize action.
Definition Graphics.php:217
bypass()
Runs bypass (copies file)
Definition Graphics.php:540
escapeNumber($number)
Validates integers.
Definition Graphics.php:264
$size
Image size array(width, height)
Definition Graphics.php:69
$optimize
Optimize output images.
Definition Graphics.php:81
PHP GD extension interface.
Definition Gd.php:19
Imagick Class Imagick.
Definition Imagick.php:19
autoload($class)
PHP autoloader.
Definition Graphics.php:21