Graphics.php
Go to the documentation of this file.
1 <?php
14 namespace Depage\Graphics;
15 
21 function 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 
33 spl_autoload_register(__NAMESPACE__ . '\autoload');
34 
40 class Graphics
41 {
45  protected $input;
49  protected $output;
53  protected $outputLockFp = null;
57  protected $otherRender = false;
61  protected $queue = array();
65  protected $size = array();
69  protected $background;
73  protected $quality = '';
77  protected $optimize;
81  protected $optimizers;
85  protected $inputFormat;
89  protected $outputFormat;
93  protected $bypass = true;
97  private $oldIgnoreUserAbort = false;
107  public static function factory($options = array())
108  {
109  $extension = (isset($options['extension'])) ? $options['extension'] : 'gd';
110 
111  if ($extension == 'im' || $extension == 'imagemagick') {
112  if (isset($options['executable'])) {
113  return new Providers\Imagemagick($options);
114  } else {
115  $executable = Graphics::which('convert');
116  if ($executable == null) {
117  trigger_error("Cannot find ImageMagick, falling back to GD", E_USER_WARNING);
118  } else {
119  $options['executable'] = $executable;
120 
121  return new Providers\Imagemagick($options);
122  }
123  }
124  } elseif ($extension == 'gm' || $extension == 'graphicsmagick') {
125  if (isset($options['executable'])) {
126  return new Providers\Graphicsmagick($options);
127  } else {
128  $executable = Graphics::which('gm');
129  if ($executable == null) {
130  trigger_error("Cannot find GraphicsMagick, falling back to GD", E_USER_WARNING);
131  } else {
132  $options['executable'] = $executable;
133 
134  return new Providers\Graphicsmagick($options);
135  }
136  }
137  }
138 
139  return new Providers\Gd($options);
140  }
146  public function __construct($options = array())
147  {
148  $this->background = (isset($options['background'])) ? $options['background'] : 'transparent';
149  $this->quality = (isset($options['quality'])) ? intval($options['quality']) : null;
150  $this->format = (isset($options['format'])) ? $options['format'] : null;
151  $this->optimize = (isset($options['optimize'])) ? $options['optimize'] : false;
152  $this->optimizers = (isset($options['optimizers'])) ? $options['optimizers'] : array();
153  }
154 
163  public function addBackground($background)
164  {
165  $this->background = $background;
166 
167  return $this;
168  }
180  public function addCrop($width, $height, $x = 0, $y = 0)
181  {
182  $this->queue[] = array('crop', func_get_args());
183 
184  return $this;
185  }
195  public function addResize($width, $height)
196  {
197  $this->queue[] = array('resize', func_get_args());
198 
199  return $this;
200  }
210  public function addThumb($width, $height)
211  {
212  $this->queue[] = array('thumb', func_get_args());
213 
214  return $this;
215  }
225  public function addThumbfill($width, $height)
226  {
227  $this->queue[] = array('thumbfill', func_get_args());
228 
229  return $this;
230  }
231 
240  protected function escapeNumber($number)
241  {
242  return (is_numeric($number)) ? intval($number) : null;
243  }
254  protected function dimensions($width, $height)
255  {
256  if (!is_numeric($width) && !is_numeric($height)) {
257  $width = null;
258  $height = null;
259  } elseif (!is_numeric($height)) {
260  $height = round(($this->size[1] / $this->size[0]) * $width);
261  } elseif (!is_numeric($width)) {
262  $width = round(($this->size[0] / $this->size[1]) * $height);
263  }
264 
265  return array($width, $height);
266  }
267 
275  protected function processQueue()
276  {
277  foreach ($this->queue as $task) {
278  $action = $task[0];
279  $arguments = array_map(array($this, 'escapeNumber'), $task[1]);
280 
281  call_user_func_array(array($this, $action), $arguments);
282  }
283  }
293  public function render($input, $output = null)
294  {
295  if (!file_exists($input)) throw new Exceptions\FileNotFound();
296 
297  $this->input = $input;
298  $this->output = ($output == null) ? $input : $output;
299  $this->inputFormat = $this->obtainFormat($this->input);
300  $this->outputFormat = ($this->format == null) ? $this->obtainFormat($this->output) : $this->format;
301  $this->size = $this->getImageSize();
302  $this->otherRender = false;
303 
304  $this->lock();
305 
306  $this->oldIgnoreUserAbort = ignore_user_abort();
307  ignore_user_abort(true);
308  }
314  public function renderFinished()
315  {
316  ignore_user_abort($this->oldIgnoreUserAbort);
317 
318  $this->unlock();
319  }
326  public function optimizeImage($filename)
327  {
328  if (!file_exists($filename)) {
329  return false;
330  }
331 
332  $optimizer = new Optimizers\Optimizer($this->optimizers);
333  $success = $optimizer->optimize($filename);
334 
335  return $success;
336  }
342  protected function lock()
343  {
344  // set lock
345  $this->outputLockFp = fopen($this->output . ".lock", 'w');
346  $locked = flock($this->outputLockFp, LOCK_EX | LOCK_NB, $wouldblock);
347 
348  if (!$locked && $wouldblock) {
349  $this->otherRender = true;
350  flock($this->outputLockFp, LOCK_EX);
351  }
352  }
358  protected function unlock()
359  {
360  // release lock
361  if (isset($this->outputLockFp)) {
362  flock($this->outputLockFp, LOCK_UN);
363  unlink($this->output . ".lock");
364  }
365  }
366 
373  protected function obtainFormat($fileName)
374  {
375  $parts = explode('.', $fileName);
376  $extension = strtolower(end($parts));
377 
378  if ($extension == 'jpeg') {
379  $extension = 'jpg';
380  } elseif (
381  $extension != 'jpg'
382  && $extension != 'png'
383  && $extension != 'gif'
384  ) {
385  if (is_callable('getimagesize') && file_exists($fileName)) {
386  $info = getimagesize($fileName);
387  if (isset($info[2])) {
388  $format = $info[2];
389 
390  if ($format == 1) {
391  $extension = 'gif';
392  } elseif ($format == 2) {
393  $extension = 'jpg';
394  } elseif ($format == 3) {
395  $extension = 'png';
396  }
397  }
398  }
399  }
400 
401  return $extension;
402  }
403 
412  public static function which($binary)
413  {
414  exec('which ' . $binary, $commandOutput, $returnStatus);
415  if ($returnStatus === 0) {
416  return $commandOutput[0];
417  } else {
418  return null;
419  }
420  }
421 
425  public function setQuality($quality)
426  {
427  $this->quality = $quality;
428  }
437  protected function getQuality()
438  {
439  if ($this->outputFormat == 'jpg') {
440  if (
441  is_numeric($this->quality)
442  && $this->quality >= 0
443  && $this->quality <= 100
444  ) {
446  } else {
447  $quality = 85;
448  }
449  } elseif ($this->outputFormat == 'png') {
450  if (
451  is_numeric($this->quality)
452  && $this->quality >= 0
453  && $this->quality <= 95
454  && $this->quality % 10 <= 5
455  ) {
456  $quality = sprintf("%02d", $this->quality);
457  } else {
458  $quality = 95;
459  }
460  } else {
461  $quality = intval($this->quality);
462  }
463 
464  return (string) $quality;
465  }
466 
476  protected function bypassTest($width, $height, $x = 0, $y = 0)
477  {
478  if (
479  ($width !== null && $width < 1)
480  || ($height !== null && $height < 1)
481  || ($width == null && $height == null)
482  ) {
483  $this->unlock();
484 
485  throw new Exceptions\Exception('Invalid image size.');
486  }
487 
488  $bypass = (
489  $width == $this->size[0]
490  && $height == $this->size[1]
491  && $x == 0
492  && $y == 0
493  );
494 
495  $this->bypass = $this->bypass && $bypass;
496 
497  return $bypass;
498  }
504  protected function bypass()
505  {
506  if ($this->input != $this->output) {
507  copy($this->input, $this->output);
508  }
509  }
510 }
511 
512 /* vim:set ft=php sw=4 sts=4 fdm=marker et : */
static factory($options=array())
graphics object factory
Definition: Graphics.php:107
addResize($width, $height)
Adds resize action.
Definition: Graphics.php:195
$inputFormat
Input image format.
Definition: Graphics.php:85
addBackground($background)
Background "action".
Definition: Graphics.php:163
addThumbfill($width, $height)
Adds thumb-fill action.
Definition: Graphics.php:225
$optimize
Optimize output images.
Definition: Graphics.php:77
GraphicsMagick interface.
general graphics related exception class
Definition: Exception.php:17
$background
Image background string.
Definition: Graphics.php:69
$quality
Image quality string.
Definition: Graphics.php:73
addThumb($width, $height)
Adds thumb action.
Definition: Graphics.php:210
ImageMagick interface.
Definition: Imagemagick.php:22
$outputFormat
Output image format.
Definition: Graphics.php:89
$outputLockFp
Definition: Graphics.php:53
PHP GD extension interface.
Definition: Gd.php:19
render($input, $output=null)
Main method for image handling.
Definition: Graphics.php:293
__construct($options=array())
graphics class constructor
Definition: Graphics.php:146
setQuality($quality)
Sets quality parameter.
Definition: Graphics.php:425
lock()
lock
Definition: Graphics.php:342
autoload($class)
PHP autoloader.
Definition: Graphics.php:21
bypass()
Runs bypass (copies file)
Definition: Graphics.php:504
optimizeImage($filename)
Opimizes final image through one of the optimization programs.
Definition: Graphics.php:326
processQueue()
Process action queue.
Definition: Graphics.php:275
$size
Image size array(width, height)
Definition: Graphics.php:65
$bypass
Process bypass bool.
Definition: Graphics.php:93
escapeNumber($number)
Validates integers.
Definition: Graphics.php:240
unlock()
unlock
Definition: Graphics.php:358
$input
Input filename.
Definition: Graphics.php:45
dimensions($width, $height)
Scales image dimensions.
Definition: Graphics.php:254
$queue
Action queue array.
Definition: Graphics.php:61
$otherRender
otherRender is set to true if another render process has already locked file
Definition: Graphics.php:57
Input file not found exception.
Definition: Optimizer.php:6
renderFinished()
Called after rendering has finished.
Definition: Graphics.php:314
obtainFormat($fileName)
Determines image format from file extension.
Definition: Graphics.php:373
getQuality()
Returns quality-index for current image format.
Definition: Graphics.php:437
addCrop($width, $height, $x=0, $y=0)
Adds crop action.
Definition: Graphics.php:180
static which($binary)
Executes "which" command.
Definition: Graphics.php:412
$output
Output filename.
Definition: Graphics.php:49
$optimizers
List of optimizer binaries.
Definition: Graphics.php:81
bypassTest($width, $height, $x=0, $y=0)
Tests if action would change current image.
Definition: Graphics.php:476
Main graphics class.
Definition: Graphics.php:41