10 defined(
'JPATH_PLATFORM') or die;
31 const SCALE_INSIDE = 2;
37 const SCALE_OUTSIDE = 3;
49 const CROP_RESIZE = 5;
67 protected $path = null;
73 protected static $formats = array();
83 public function __construct($source = null)
86 if (!extension_loaded(
'gd'))
90 throw new RuntimeException(
'The GD extension for PHP is not available.');
96 if (!isset(self::$formats[IMAGETYPE_JPEG]))
99 self::$formats[IMAGETYPE_JPEG] = ($info[
'JPEG Support']) ?
true :
false;
100 self::$formats[IMAGETYPE_PNG] = ($info[
'PNG Support']) ?
true :
false;
101 self::$formats[IMAGETYPE_GIF] = ($info[
'GIF Read Support']) ?
true :
false;
105 if (is_resource($source) && (get_resource_type($source) ==
'gd'))
107 $this->handle = &$source;
109 elseif (!empty($source) && is_string($source))
112 $this->loadFile($source);
129 public static function getImageFileProperties($path)
132 if (!file_exists($path))
134 throw new InvalidArgumentException(
'The image file does not exist.');
138 $info = getimagesize($path);
143 throw new RuntimeException(
'Unable to get properties for the image.');
149 $properties = (object) array(
151 'height' => $info[1],
153 'attributes' => $info[3],
154 'bits' => isset($info[
'bits']) ? $info[
'bits'] : null,
155 'channels' => isset($info[
'channels']) ? $info[
'channels'] : null,
156 'mime' => $info[
'mime']
175 public function generateThumbs($thumbSizes, $creationMethod = self::SCALE_INSIDE)
178 if (!$this->isLoaded())
180 throw new LogicException(
'No valid image was loaded.');
184 if (!is_array($thumbSizes))
186 $thumbSizes = array($thumbSizes);
190 $generated = array();
192 if (!empty($thumbSizes))
194 foreach ($thumbSizes as $thumbSize)
197 $size = explode(
'x', strtolower($thumbSize));
199 if (count($size) != 2)
201 throw new InvalidArgumentException(
'Invalid thumb size received: ' . $thumbSize);
204 $thumbWidth = $size[0];
205 $thumbHeight = $size[1];
207 switch ($creationMethod)
211 $thumb = $this->crop($thumbWidth, $thumbHeight, null, null,
true);
216 $thumb = $this->cropResize($thumbWidth, $thumbHeight,
true);
220 $thumb = $this->resize($thumbWidth, $thumbHeight,
true, $creationMethod);
225 $generated[] = $thumb;
246 public function createThumbs($thumbSizes, $creationMethod = self::SCALE_INSIDE, $thumbsFolder = null)
249 if (!$this->isLoaded())
251 throw new LogicException(
'No valid image was loaded.');
255 if (is_null($thumbsFolder))
257 $thumbsFolder = dirname($this->getPath()) .
'/thumbs';
261 if (!is_dir($thumbsFolder) && (!is_dir(dirname($thumbsFolder)) || !@mkdir($thumbsFolder)))
263 throw new InvalidArgumentException(
'Folder does not exist and cannot be created: ' . $thumbsFolder);
267 $thumbsCreated = array();
269 if ($thumbs = $this->generateThumbs($thumbSizes, $creationMethod))
272 $imgProperties = self::getImageFileProperties($this->getPath());
274 foreach ($thumbs as $thumb)
277 $thumbWidth = $thumb->getWidth();
278 $thumbHeight = $thumb->getHeight();
281 $filename = pathinfo($this->getPath(), PATHINFO_FILENAME);
282 $fileExtension = pathinfo($this->getPath(), PATHINFO_EXTENSION);
283 $thumbFileName = $filename .
'_' . $thumbWidth .
'x' . $thumbHeight .
'.' . $fileExtension;
286 $thumbFileName = $thumbsFolder .
'/' . $thumbFileName;
288 if ($thumb->toFile($thumbFileName, $imgProperties->type))
291 $thumb->path = $thumbFileName;
292 $thumbsCreated[] = $thumb;
297 return $thumbsCreated;
315 public function crop($width, $height, $left = null, $top = null, $createNew =
true)
318 if (!$this->isLoaded())
320 throw new LogicException(
'No valid image was loaded.');
324 $width = $this->sanitizeWidth($width, $height);
327 $height = $this->sanitizeHeight($height, $width);
332 $left = round(($this->getWidth() - $width) / 2);
337 $top = round(($this->getHeight() - $height) / 2);
341 $left = $this->sanitizeOffset($left);
344 $top = $this->sanitizeOffset($top);
347 $handle = imagecreatetruecolor($width, $height);
350 imagealphablending($handle,
false);
351 imagesavealpha($handle,
true);
353 if ($this->isTransparent())
356 $rgba = imageColorsForIndex($this->handle, imagecolortransparent($this->handle));
357 $color = imageColorAllocate($this->handle, $rgba[
'red'], $rgba[
'green'], $rgba[
'blue']);
360 imagecolortransparent($handle, $color);
361 imagefill($handle, 0, 0, $color);
363 imagecopyresized($handle, $this->handle, 0, 0, $left, $top, $width, $height, $width, $height);
367 imagecopyresampled($handle, $this->handle, 0, 0, $left, $top, $width, $height, $width, $height);
374 $new =
new JImage($handle);
386 $this->handle = $handle;
404 public function filter($type, array $options = array())
407 if (!$this->isLoaded())
409 throw new LogicException(
'No valid image was loaded.');
413 $filter = $this->getFilterInstance($type);
416 $filter->execute($options);
429 public function getHeight()
432 if (!$this->isLoaded())
434 throw new LogicException(
'No valid image was loaded.');
437 return imagesy($this->handle);
448 public function getWidth()
451 if (!$this->isLoaded())
453 throw new LogicException(
'No valid image was loaded.');
456 return imagesx($this->handle);
466 public function getPath()
478 public function isLoaded()
481 if (!is_resource($this->handle) || (get_resource_type($this->handle) !=
'gd'))
497 public function isTransparent()
500 if (!$this->isLoaded())
502 throw new LogicException(
'No valid image was loaded.');
505 return (imagecolortransparent($this->handle) >= 0);
519 public function loadFile($path)
525 if (!file_exists($path))
527 throw new InvalidArgumentException(
'The image file does not exist.');
531 $properties = self::getImageFileProperties($path);
534 switch ($properties->mime)
538 if (empty(self::$formats[IMAGETYPE_GIF]))
542 throw new RuntimeException(
'Attempting to load an image of unsupported type GIF.');
548 $handle = imagecreatefromgif($path);
550 if (!is_resource($handle))
553 throw new RuntimeException(
'Unable to process GIF image.');
558 $this->handle = $handle;
563 if (empty(self::$formats[IMAGETYPE_JPEG]))
567 throw new RuntimeException(
'Attempting to load an image of unsupported type JPG.');
573 $handle = imagecreatefromjpeg($path);
575 if (!is_resource($handle))
578 throw new RuntimeException(
'Unable to process JPG image.');
583 $this->handle = $handle;
588 if (empty(self::$formats[IMAGETYPE_PNG]))
592 throw new RuntimeException(
'Attempting to load an image of unsupported type PNG.');
598 $handle = imagecreatefrompng($path);
600 if (!is_resource($handle))
603 throw new RuntimeException(
'Unable to process PNG image.');
608 $this->handle = $handle;
611 if (!$this->isTransparent())
614 $transparency = imagecolorallocatealpha($handle, 0, 0, 0, 127);
616 imagecolortransparent($handle, $transparency);
622 JLog::add(
'Attempting to load an image of unsupported type: ' . $properties->mime,
JLog::ERROR);
623 throw new InvalidArgumentException(
'Attempting to load an image of unsupported type: ' . $properties->mime);
645 public function resize($width, $height, $createNew =
true, $scaleMethod = self::SCALE_INSIDE)
648 if (!$this->isLoaded())
650 throw new LogicException(
'No valid image was loaded.');
654 $width = $this->sanitizeWidth($width, $height);
657 $height = $this->sanitizeHeight($height, $width);
660 $dimensions = $this->prepareDimensions($width, $height, $scaleMethod);
663 $offset =
new stdClass;
664 $offset->x = $offset->y = 0;
667 if ($scaleMethod == self::SCALE_FIT)
670 $offset->x = round(($width - $dimensions->width) / 2);
671 $offset->y = round(($height - $dimensions->height) / 2);
673 $handle = imagecreatetruecolor($width, $height);
676 if (!$this->isTransparent())
678 $transparency = imagecolorAllocateAlpha($this->handle, 0, 0, 0, 127);
679 imagecolorTransparent($this->handle, $transparency);
684 $handle = imagecreatetruecolor($dimensions->width, $dimensions->height);
688 imagealphablending($handle,
false);
689 imagesavealpha($handle,
true);
691 if ($this->isTransparent())
694 $rgba = imageColorsForIndex($this->handle, imagecolortransparent($this->handle));
695 $color = imageColorAllocateAlpha($this->handle, $rgba[
'red'], $rgba[
'green'], $rgba[
'blue'], $rgba[
'alpha']);
698 imagecolortransparent($handle, $color);
699 imagefill($handle, 0, 0, $color);
701 imagecopyresized($handle, $this->handle, $offset->x, $offset->y, 0, 0, $dimensions->width, $dimensions->height, $this->getWidth(), $this->getHeight());
705 imagecopyresampled($handle, $this->handle, $offset->x, $offset->y, 0, 0, $dimensions->width, $dimensions->height, $this->getWidth(), $this->getHeight());
712 $new =
new JImage($handle);
724 $this->handle = $handle;
742 public function cropResize($width, $height, $createNew =
true)
744 $width = $this->sanitizeWidth($width, $height);
745 $height = $this->sanitizeHeight($height, $width);
747 if (($this->getWidth() / $width) < ($this->getHeight() / $height))
749 $this->resize($width, 0,
false);
753 $this->resize(0, $height,
false);
756 return $this->crop($width, $height, null, null, $createNew);
772 public function rotate($angle, $background = -1, $createNew =
true)
775 if (!$this->isLoaded())
777 throw new LogicException(
'No valid image was loaded.');
781 $angle = (float) $angle;
784 $handle = imagecreatetruecolor($this->getWidth(), $this->getHeight());
787 imagealphablending($handle,
false);
788 imagesavealpha($handle,
true);
791 imagecopy($handle, $this->handle, 0, 0, 0, 0, $this->getWidth(), $this->getHeight());
794 $handle = imagerotate($handle, $angle, $background);
800 $new =
new JImage($handle);
812 $this->handle = $handle;
831 public function toFile($path, $type = IMAGETYPE_JPEG, array $options = array())
834 if (!$this->isLoaded())
836 throw new LogicException(
'No valid image was loaded.');
842 return imagegif($this->handle, $path);
846 return imagepng($this->handle, $path, (array_key_exists(
'quality', $options)) ? $options[
'quality'] : 0);
851 return imagejpeg($this->handle, $path, (array_key_exists(
'quality', $options)) ? $options[
'quality'] : 100);
865 protected function getFilterInstance($type)
868 $type = strtolower(preg_replace(
'#[^A-Z0-9_]#i',
'', $type));
871 $className =
'JImageFilter' . ucfirst($type);
873 if (!class_exists($className))
876 throw new RuntimeException(
'The ' . ucfirst($type) .
' image filter is not available.');
880 $instance =
new $className($this->handle);
887 throw new RuntimeException(
'The ' . ucfirst($type) .
' image filter is not valid.');
907 protected function prepareDimensions($width, $height, $scaleMethod)
910 $dimensions =
new stdClass;
912 switch ($scaleMethod)
914 case self::SCALE_FILL:
915 $dimensions->width = (int) round($width);
916 $dimensions->height = (int) round($height);
919 case self::SCALE_INSIDE:
920 case self::SCALE_OUTSIDE:
921 case self::SCALE_FIT:
922 $rx = ($width > 0) ? ($this->getWidth() / $width) : 0;
923 $ry = ($height > 0) ? ($this->getHeight() / $height) : 0;
925 if ($scaleMethod != self::SCALE_OUTSIDE)
927 $ratio = max($rx, $ry);
931 $ratio = min($rx, $ry);
934 $dimensions->width = (int) round($this->getWidth() / $ratio);
935 $dimensions->height = (int) round($this->getHeight() / $ratio);
939 throw new InvalidArgumentException(
'Invalid scale method.');
956 protected function sanitizeHeight($height, $width)
959 $height = ($height === null) ? $width : $height;
962 if (preg_match(
'/^[0-9]+(\.[0-9]+)?\%$/', $height))
964 $height = (int) round($this->getHeight() * (float) str_replace(
'%',
'', $height) / 100);
969 $height = (int) round((
float) $height);
984 protected function sanitizeOffset($offset)
986 return (
int) round((
float) $offset);
999 protected function sanitizeWidth($width, $height)
1002 $width = ($width === null) ? $height : $width;
1005 if (preg_match(
'/^[0-9]+(\.[0-9]+)?\%$/', $width))
1007 $width = (int) round($this->getWidth() * (float) str_replace(
'%',
'', $width) / 100);
1012 $width = (int) round((
float) $width);
1026 public function destroy()
1028 if ($this->isLoaded())
1030 return imagedestroy($this->handle);
1043 public function __destruct()