PageRenderTime 49ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/image/classes/kohana/image/imagick.php

https://bitbucket.org/sapphiriq/assets-example
PHP | 334 lines | 186 code | 66 blank | 82 comment | 15 complexity | f2e00a45bd3267cbfb596bb770915ddd MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php defined('SYSPATH') or die('No direct script access.');
  2. /**
  3. * Support for image manipulation using [Imagick](http://php.net/Imagick).
  4. *
  5. * @package Kohana/Image
  6. * @category Drivers
  7. * @author Tamas Mihalik tamas.mihalik@gmail.com
  8. * @copyright (c) 2009-2010 Kohana Team
  9. * @license http://kohanaphp.com/license.html
  10. */
  11. class Kohana_Image_Imagick extends Image {
  12. /**
  13. * @var Imagick image magick object
  14. */
  15. protected $im;
  16. /**
  17. * Checks if ImageMagick is enabled.
  18. *
  19. * @throws Kohana_Exception
  20. * @return boolean
  21. */
  22. public static function check()
  23. {
  24. if ( ! extension_loaded('imagick'))
  25. {
  26. throw new Kohana_Exception('Imagick is not installed, or the extension is not loaded');
  27. }
  28. return Image_Imagick::$_checked = TRUE;
  29. }
  30. /**
  31. * Runs [Image_Imagick::check] and loads the image.
  32. *
  33. * @return void
  34. * @throws Kohana_Exception
  35. */
  36. public function __construct($file)
  37. {
  38. if ( ! Image_Imagick::$_checked)
  39. {
  40. // Run the install check
  41. Image_Imagick::check();
  42. }
  43. parent::__construct($file);
  44. $this->im = new Imagick;
  45. $this->im->readImage($file);
  46. if ( ! $this->im->getImageAlphaChannel())
  47. {
  48. // Force the image to have an alpha channel
  49. $this->im->setImageAlphaChannel(Imagick::ALPHACHANNEL_SET);
  50. }
  51. }
  52. /**
  53. * Destroys the loaded image to free up resources.
  54. *
  55. * @return void
  56. */
  57. public function __destruct()
  58. {
  59. $this->im->clear();
  60. $this->im->destroy();
  61. }
  62. protected function _do_resize($width, $height)
  63. {
  64. if ($this->im->scaleImage($width, $height))
  65. {
  66. // Reset the width and height
  67. $this->width = $this->im->getImageWidth();
  68. $this->height = $this->im->getImageHeight();
  69. return TRUE;
  70. }
  71. return FALSE;
  72. }
  73. protected function _do_crop($width, $height, $offset_x, $offset_y)
  74. {
  75. if ($this->im->cropImage($width, $height, $offset_x, $offset_y))
  76. {
  77. // Reset the width and height
  78. $this->width = $this->im->getImageWidth();
  79. $this->height = $this->im->getImageHeight();
  80. // Trim off hidden areas
  81. $this->im->setImagePage($this->width, $this->height, 0, 0);
  82. return TRUE;
  83. }
  84. return FALSE;
  85. }
  86. protected function _do_rotate($degrees)
  87. {
  88. if ($this->im->rotateImage(new ImagickPixel('transparent'), $degrees))
  89. {
  90. // Reset the width and height
  91. $this->width = $this->im->getImageWidth();
  92. $this->height = $this->im->getImageHeight();
  93. // Trim off hidden areas
  94. $this->im->setImagePage($this->width, $this->height, 0, 0);
  95. return TRUE;
  96. }
  97. return FALSE;
  98. }
  99. protected function _do_flip($direction)
  100. {
  101. if ($direction === Image::HORIZONTAL)
  102. {
  103. return $this->im->flopImage();
  104. }
  105. else
  106. {
  107. return $this->im->flipImage();
  108. }
  109. }
  110. protected function _do_sharpen($amount)
  111. {
  112. //IM not support $amount under 5 (0.15)
  113. $amount = ($amount < 5) ? 5 : $amount;
  114. // Amount should be in the range of 0.0 to 3.0
  115. $amount = ($amount * 3.0) / 100;
  116. return $this->im->sharpenImage(0, $amount);
  117. }
  118. protected function _do_reflection($height, $opacity, $fade_in)
  119. {
  120. // Clone the current image and flip it for reflection
  121. $reflection = $this->im->clone();
  122. $reflection->flipImage();
  123. // Crop the reflection to the selected height
  124. $reflection->cropImage($this->width, $height, 0, 0);
  125. $reflection->setImagePage($this->width, $height, 0, 0);
  126. // Select the fade direction
  127. $direction = array('transparent', 'black');
  128. if ($fade_in)
  129. {
  130. // Change the direction of the fade
  131. $direction = array_reverse($direction);
  132. }
  133. // Create a gradient for fading
  134. $fade = new Imagick;
  135. $fade->newPseudoImage($reflection->getImageWidth(), $reflection->getImageHeight(), vsprintf('gradient:%s-%s', $direction));
  136. // Apply the fade alpha channel to the reflection
  137. $reflection->compositeImage($fade, Imagick::COMPOSITE_DSTOUT, 0, 0);
  138. // NOTE: Using setImageOpacity will destroy alpha channels!
  139. $reflection->evaluateImage(Imagick::EVALUATE_MULTIPLY, $opacity / 100, Imagick::CHANNEL_ALPHA);
  140. // Create a new container to hold the image and reflection
  141. $image = new Imagick;
  142. $image->newImage($this->width, $this->height + $height, new ImagickPixel);
  143. // Force the image to have an alpha channel
  144. $image->setImageAlphaChannel(Imagick::ALPHACHANNEL_SET);
  145. // Force the background color to be transparent
  146. // $image->setImageBackgroundColor(new ImagickPixel('transparent'));
  147. // Match the colorspace between the two images before compositing
  148. $image->setColorspace($this->im->getColorspace());
  149. // Place the image and reflection into the container
  150. if ($image->compositeImage($this->im, Imagick::COMPOSITE_SRC, 0, 0)
  151. AND $image->compositeImage($reflection, Imagick::COMPOSITE_OVER, 0, $this->height))
  152. {
  153. // Replace the current image with the reflected image
  154. $this->im = $image;
  155. // Reset the width and height
  156. $this->width = $this->im->getImageWidth();
  157. $this->height = $this->im->getImageHeight();
  158. return TRUE;
  159. }
  160. return FALSE;
  161. }
  162. protected function _do_watermark(Image $image, $offset_x, $offset_y, $opacity)
  163. {
  164. // Convert the Image intance into an Imagick instance
  165. $watermark = new Imagick;
  166. $watermark->readImageBlob($image->render(), $image->file);
  167. if ($watermark->getImageAlphaChannel() !== Imagick::ALPHACHANNEL_ACTIVATE)
  168. {
  169. // Force the image to have an alpha channel
  170. $watermark->setImageAlphaChannel(Imagick::ALPHACHANNEL_OPAQUE);
  171. }
  172. if ($opacity < 100)
  173. {
  174. // NOTE: Using setImageOpacity will destroy current alpha channels!
  175. $watermark->evaluateImage(Imagick::EVALUATE_MULTIPLY, $opacity / 100, Imagick::CHANNEL_ALPHA);
  176. }
  177. // Match the colorspace between the two images before compositing
  178. // $watermark->setColorspace($this->im->getColorspace());
  179. // Apply the watermark to the image
  180. return $this->im->compositeImage($watermark, Imagick::COMPOSITE_DISSOLVE, $offset_x, $offset_y);
  181. }
  182. protected function _do_background($r, $g, $b, $opacity)
  183. {
  184. // Create a RGB color for the background
  185. $color = sprintf('rgb(%d, %d, %d)', $r, $g, $b);
  186. // Create a new image for the background
  187. $background = new Imagick;
  188. $background->newImage($this->width, $this->height, new ImagickPixel($color));
  189. if ( ! $background->getImageAlphaChannel())
  190. {
  191. // Force the image to have an alpha channel
  192. $background->setImageAlphaChannel(Imagick::ALPHACHANNEL_SET);
  193. }
  194. // Clear the background image
  195. $background->setImageBackgroundColor(new ImagickPixel('transparent'));
  196. // NOTE: Using setImageOpacity will destroy current alpha channels!
  197. $background->evaluateImage(Imagick::EVALUATE_MULTIPLY, $opacity / 100, Imagick::CHANNEL_ALPHA);
  198. // Match the colorspace between the two images before compositing
  199. $background->setColorspace($this->im->getColorspace());
  200. if ($background->compositeImage($this->im, Imagick::COMPOSITE_DISSOLVE, 0, 0))
  201. {
  202. // Replace the current image with the new image
  203. $this->im = $background;
  204. return TRUE;
  205. }
  206. return FALSE;
  207. }
  208. protected function _do_save($file, $quality)
  209. {
  210. // Get the image format and type
  211. list($format, $type) = $this->_get_imagetype(pathinfo($file, PATHINFO_EXTENSION));
  212. // Set the output image type
  213. $this->im->setFormat($format);
  214. // Set the output quality
  215. $this->im->setImageCompressionQuality($quality);
  216. if ($this->im->writeImage($file))
  217. {
  218. // Reset the image type and mime type
  219. $this->type = $type;
  220. $this->mime = image_type_to_mime_type($type);
  221. return TRUE;
  222. }
  223. return FALSE;
  224. }
  225. protected function _do_render($type, $quality)
  226. {
  227. // Get the image format and type
  228. list($format, $type) = $this->_get_imagetype($type);
  229. // Set the output image type
  230. $this->im->setFormat($format);
  231. // Set the output quality
  232. $this->im->setImageCompressionQuality($quality);
  233. // Reset the image type and mime type
  234. $this->type = $type;
  235. $this->mime = image_type_to_mime_type($type);
  236. return (string) $this->im;
  237. }
  238. /**
  239. * Get the image type and format for an extension.
  240. *
  241. * @param string image extension: png, jpg, etc
  242. * @return string IMAGETYPE_* constant
  243. * @throws Kohana_Exception
  244. */
  245. protected function _get_imagetype($extension)
  246. {
  247. // Normalize the extension to a format
  248. $format = strtolower($extension);
  249. switch ($format)
  250. {
  251. case 'jpg':
  252. case 'jpeg':
  253. $type = IMAGETYPE_JPEG;
  254. break;
  255. case 'gif':
  256. $type = IMAGETYPE_GIF;
  257. break;
  258. case 'png':
  259. $type = IMAGETYPE_PNG;
  260. break;
  261. default:
  262. throw new Kohana_Exception('Installed ImageMagick does not support :type images',
  263. array(':type' => $extension));
  264. break;
  265. }
  266. return array($format, $type);
  267. }
  268. } // End Kohana_Image_Imagick