depage-graphics
Loading...
Searching...
No Matches
Graphics.php
Go to the documentation of this file.
1<?php
2
14
15namespace Depage\Graphics;
16
22function autoload($class)
23{
24 if (strpos($class, __NAMESPACE__ . '\\') == 0) {
25 $class = str_replace('\\', '/', str_replace(__NAMESPACE__ . '\\', '', $class));
26 $file = __DIR__ . '/' . $class . '.php';
27
28 if (file_exists($file)) {
29 require_once($file);
30 }
31 }
32}
33
34spl_autoload_register(__NAMESPACE__ . '\autoload');
35
42{
46 protected $input;
50 protected $output;
54 protected $format;
58 protected $outputLockFp = null;
62 protected $otherRender = false;
66 protected $queue = array();
70 protected $size = array();
74 protected $background;
78 protected $quality = '';
82 protected $optimize;
86 protected $optimizers;
90 protected $limits = [];
94 protected $inputFormat;
98 protected $outputFormat;
102 protected $bypass = true;
106 private $oldIgnoreUserAbort = false;
116 public static function factory($options = array())
117 {
118 $extension = (isset($options['extension'])) ? $options['extension'] : 'gd';
119
120 if ($extension == 'imagick' && extension_loaded('imagick')) {
121 return new Providers\Imagick($options);
122 } elseif ($extension == 'im' || $extension == 'imagemagick') {
123 if (isset($options['executable'])) {
124 return new Providers\Imagemagick($options);
125 } else {
126 $executable = Graphics::which('convert');
127 if ($executable == null) {
128 trigger_error("Cannot find ImageMagick, falling back to GD", E_USER_WARNING);
129 } else {
130 $options['executable'] = $executable;
131
132 return new Providers\Imagemagick($options);
133 }
134 }
135 } elseif ($extension == 'gm' || $extension == 'graphicsmagick') {
136 if (isset($options['executable'])) {
137 return new Providers\Graphicsmagick($options);
138 } else {
139 $executable = Graphics::which('gm');
140 if ($executable == null) {
141 trigger_error("Cannot find GraphicsMagick, falling back to GD", E_USER_WARNING);
142 } else {
143 $options['executable'] = $executable;
144
145 return new Providers\Graphicsmagick($options);
146 }
147 }
148 }
149
150 return new Providers\Gd($options);
151 }
152
157 public function __construct($options = array())
158 {
159 $this->background = (isset($options['background'])) ? $options['background'] : 'transparent';
160 $this->quality = (isset($options['quality'])) ? intval($options['quality']) : null;
161 $this->format = (isset($options['format'])) ? $options['format'] : null;
162 $this->optimize = (isset($options['optimize'])) ? $options['optimize'] : false;
163 $this->optimizers = (isset($options['optimizers'])) ? $options['optimizers'] : [];
164 $this->limits = (isset($options['limits'])) ? $options['limits'] : [
165 'memory' => "64MiB",
166 'map' => "128MiB",
167 ];
168 if (isset($this->limits['memory'])) {
169 putenv("MAGICK_MEMORY_LIMIT=" . $this->limits['memory']);
170 putenv("MAGICK_LIMIT_MEMORY=" . $this->limits['memory']);
171 }
172 if (isset($this->limits['map'])) {
173 putenv("MAGICK_MAP_LIMIT=" . $this->limits['map']);
174 putenv("MAGICK_LIMIT_MAP=" . $this->limits['map']);
175 }
176 }
177
184 public function canRead($ext)
185 {
186 return in_array($ext, ['jpg', 'jpeg', 'png', 'gif', 'webp']);
187 }
188
194 public function canWrite($ext)
195 {
196 return in_array($ext, ['png']);
197 return in_array($ext, ['jpg', 'jpeg', 'png', 'gif', 'webp']);
198 }
199
208 public function addBackground($background)
209 {
210 $this->background = $background;
211
212 return $this;
213 }
214
225 public function addCrop($width, $height, $x = 0, $y = 0)
226 {
227 $this->queue[] = array('crop', func_get_args());
228
229 return $this;
230 }
231
240 public function addResize($width, $height)
241 {
242 $this->queue[] = array('resize', func_get_args());
243
244 return $this;
245 }
246
255 public function addThumb($width, $height)
256 {
257 $this->queue[] = array('thumb', func_get_args());
258
259 return $this;
260 }
261
272 public function addThumbfill($width, $height, $centerX = 50, $centerY = 50)
273 {
274 $this->queue[] = array('thumbfill', func_get_args());
275
276 return $this;
277 }
278
287 protected function escapeNumber($number)
288 {
289 return (is_numeric($number)) ? intval($number) : null;
290 }
291
301 protected function dimensions($width, $height)
302 {
303 if (!is_numeric($width) && !is_numeric($height)) {
304 $width = null;
305 $height = null;
306 } elseif (!is_numeric($height)) {
307 $height = round(($this->size[1] / $this->size[0]) * $width);
308 } elseif (!is_numeric($width)) {
309 $width = round(($this->size[0] / $this->size[1]) * $height);
310 }
311
312 return [$width, $height];
313 }
314
322 protected function processQueue()
323 {
324 foreach ($this->queue as $task) {
325 $action = $task[0];
326 $arguments = array_map(array($this, 'escapeNumber'), $task[1]);
327
328 call_user_func_array(array($this, $action), $arguments);
329 }
330 }
331
340 public function render($input, $output = null)
341 {
342 if (!file_exists($input)) {
343 throw new Exceptions\FileNotFound();
344 }
345
346 $this->input = $input;
347 $this->output = ($output == null) ? $input : $output;
348 $this->inputFormat = $this->obtainFormat($this->input);
349 $this->outputFormat = ($this->format == null) ? $this->obtainFormat($this->output) : $this->format;
350 $this->size = $this->getImageSize();
351 $this->otherRender = false;
352
353 $this->lock();
354
355 $this->oldIgnoreUserAbort = ignore_user_abort();
356 ignore_user_abort(true);
357 }
358
363 public function renderFinished()
364 {
365 ignore_user_abort($this->oldIgnoreUserAbort);
366
367 $this->unlock();
368 }
369
375 public function optimizeImage($filename)
376 {
377 if (!file_exists($filename)) {
378 return false;
379 }
380
381 $optimizer = new Optimizers\Optimizer($this->optimizers);
382 $success = $optimizer->optimize($filename);
383
384 return $success;
385 }
386
391 protected function lock()
392 {
393 // set lock
394 $this->outputLockFp = fopen($this->output . ".lock", 'w');
395 $locked = flock($this->outputLockFp, LOCK_EX | LOCK_NB, $wouldblock);
396
397 if (!$locked && $wouldblock) {
398 $this->otherRender = true;
399 flock($this->outputLockFp, LOCK_EX);
400 }
401 }
402
407 protected function unlock()
408 {
409 // release lock
410 if (isset($this->outputLockFp)) {
411 flock($this->outputLockFp, LOCK_UN);
412 unlink($this->output . ".lock");
413
414 $this->outputLockFp = null;
415 }
416 }
417
424 protected function obtainFormat($fileName)
425 {
426 $parts = explode('.', $fileName);
427 $extension = strtolower(end($parts));
428
429 if ($extension == 'jpeg') {
430 $extension = 'jpg';
431 } elseif (
432 $extension != 'jpg'
433 && $extension != 'png'
434 && $extension != 'gif'
435 ) {
436 if (is_callable('getimagesize') && file_exists($fileName)) {
437 $info = getimagesize($fileName);
438 if (isset($info[2])) {
439 $format = $info[2];
440
441 if ($format == 1) {
442 $extension = 'gif';
443 } elseif ($format == 2) {
444 $extension = 'jpg';
445 } elseif ($format == 3) {
446 $extension = 'png';
447 }
448 }
449 }
450 }
451
452 return $extension;
453 }
454
463 public static function which($binary)
464 {
465 exec('which ' . $binary, $commandOutput, $returnStatus);
466 if ($returnStatus === 0) {
467 return $commandOutput[0];
468 } else {
469 return null;
470 }
471 }
472
476 public function setQuality($quality)
477 {
478 $this->quality = $quality;
479 }
480
488 protected function getQuality()
489 {
490 if ($this->outputFormat == 'jpg') {
491 if (
492 is_numeric($this->quality)
493 && $this->quality >= 0
494 && $this->quality <= 100
495 ) {
497 } else {
498 $quality = 85;
499 }
500 } elseif ($this->outputFormat == "webp") {
501 if (
502 is_numeric($this->quality)
503 && $this->quality >= 0
504 && $this->quality <= 100
505 ) {
507 } else {
508 $quality = 75;
509 }
510 } elseif ($this->outputFormat == 'png') {
511 if (
512 is_numeric($this->quality)
513 && $this->quality >= 0
514 && $this->quality <= 95
515 && $this->quality % 10 <= 5
516 ) {
517 $quality = sprintf("%02d", $this->quality);
518 } else {
519 $quality = 95;
520 }
521 } else {
522 $quality = intval($this->quality);
523 }
524
525 return (string) $quality;
526 }
527
533 public function getPageNumber()
534 {
535 if ($this->inputFormat == "pdf") {
536 return "[0]";
537 } else {
538 return "";
539 }
540 }
541
551 protected function bypassTest($width, $height, $x = 0, $y = 0)
552 {
553 if (
554 ($width !== null && $width < 1)
555 || ($height !== null && $height < 1)
556 || ($width == null && $height == null)
557 ) {
558 $this->unlock();
559
560 throw new Exceptions\Exception('Invalid image size.');
561 }
562
563 $bypass = (
564 $width == $this->size[0]
565 && $height == $this->size[1]
566 && $x == 0
567 && $y == 0
568 );
569
570 $this->bypass = $this->bypass && $bypass;
571
572 return $bypass;
573 }
574
579 protected function bypass()
580 {
581 if ($this->input != $this->output) {
582 copy($this->input, $this->output);
583 }
584 }
585}
586
587/* 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:42
$background
Image background string.
Definition Graphics.php:74
$quality
Image quality string.
Definition Graphics.php:78
canWrite($ext)
Checks if extension supports writing file type.
Definition Graphics.php:194
addThumbfill($width, $height, $centerX=50, $centerY=50)
Adds thumb-fill action.
Definition Graphics.php:272
$format
Output format.
Definition Graphics.php:54
processQueue()
Process action queue.
Definition Graphics.php:322
bypassTest($width, $height, $x=0, $y=0)
Tests if action would change current image.
Definition Graphics.php:551
$inputFormat
Input image format.
Definition Graphics.php:94
getQuality()
Returns quality-index for current image format.
Definition Graphics.php:488
addThumb($width, $height)
Adds thumb action.
Definition Graphics.php:255
$queue
Action queue array.
Definition Graphics.php:66
$input
Input filename.
Definition Graphics.php:46
$otherRender
otherRender is set to true if another render process has already locked file
Definition Graphics.php:62
$output
Output filename.
Definition Graphics.php:50
getPageNumber()
getPageNumber
Definition Graphics.php:533
canRead($ext)
Checks if extension support reading file type.
Definition Graphics.php:184
render($input, $output=null)
Main method for image handling.
Definition Graphics.php:340
$limits
limits (mainly for imagemagick and graphicsmagick)
Definition Graphics.php:90
static factory($options=array())
graphics object factory
Definition Graphics.php:116
__construct($options=array())
graphics class constructor
Definition Graphics.php:157
addCrop($width, $height, $x=0, $y=0)
Adds crop action.
Definition Graphics.php:225
$outputFormat
Output image format.
Definition Graphics.php:98
setQuality($quality)
Sets quality parameter.
Definition Graphics.php:476
dimensions($width, $height)
Scales image dimensions.
Definition Graphics.php:301
optimizeImage($filename)
Opimizes final image through one of the optimization programs.
Definition Graphics.php:375
obtainFormat($fileName)
Determines image format from file extension.
Definition Graphics.php:424
$optimizers
List of optimizer binaries.
Definition Graphics.php:86
static which($binary)
Executes "which" command.
Definition Graphics.php:463
$bypass
Process bypass bool.
Definition Graphics.php:102
renderFinished()
Called after rendering has finished.
Definition Graphics.php:363
addBackground($background)
Background "action".
Definition Graphics.php:208
addResize($width, $height)
Adds resize action.
Definition Graphics.php:240
bypass()
Runs bypass (copies file)
Definition Graphics.php:579
escapeNumber($number)
Validates integers.
Definition Graphics.php:287
$size
Image size array(width, height)
Definition Graphics.php:70
$optimize
Optimize output images.
Definition Graphics.php:82
PHP GD extension interface.
Definition Gd.php:19
Imagick Class Imagick.
Definition Imagick.php:20
autoload($class)
PHP autoloader.
Definition Graphics.php:22