PageRenderTime 33ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/system/libraries/drivers/Image/GD.php

https://github.com/lmorchard/friendfeedarchiver
PHP | 325 lines | 200 code | 55 blank | 70 comment | 22 complexity | e95165e6cbd9f5e6ec277ebab11c4666 MD5 | raw file
  1. <?php defined('SYSPATH') or die('No direct script access.');
  2. /**
  3. * GD Image Driver.
  4. *
  5. * $Id: GD.php 2711 2008-05-28 22:37:22Z Shadowhand $
  6. *
  7. * @package Image
  8. * @author Kohana Team
  9. * @copyright (c) 2007-2008 Kohana Team
  10. * @license http://kohanaphp.com/license.html
  11. */
  12. class Image_GD_Driver extends Image_Driver {
  13. // A transparent PNG as a string
  14. protected static $blank_png;
  15. protected static $blank_png_width;
  16. protected static $blank_png_height;
  17. public function __construct()
  18. {
  19. // Make sure that GD2 is available
  20. if ( ! function_exists('gd_info'))
  21. throw new Kohana_Exception('image.gd.requires_v2');
  22. // Get the GD information
  23. $info = gd_info();
  24. // Make sure that the GD2 is installed
  25. if (strpos($info['GD Version'], '2.') === FALSE)
  26. throw new Kohana_Exception('image.gd.requires_v2');
  27. }
  28. public function process($image, $actions, $dir, $file)
  29. {
  30. // Set the "create" function
  31. switch ($image['type'])
  32. {
  33. case IMAGETYPE_JPEG:
  34. $create = 'imagecreatefromjpeg';
  35. break;
  36. case IMAGETYPE_GIF:
  37. $create = 'imagecreatefromgif';
  38. break;
  39. case IMAGETYPE_PNG:
  40. $create = 'imagecreatefrompng';
  41. break;
  42. }
  43. // Set the "save" function
  44. switch (strtolower(file::extension($file)))
  45. {
  46. case 'jpg':
  47. case 'jpeg':
  48. $save = 'imagejpeg';
  49. break;
  50. case 'gif':
  51. $save = 'imagegif';
  52. break;
  53. case 'png':
  54. $save = 'imagepng';
  55. break;
  56. }
  57. // Make sure the image type is supported for import
  58. if (empty($create) OR ! function_exists($create))
  59. throw new Kohana_Exception('image.type_not_allowed', $image['file']);
  60. // Make sure the image type is supported for saving
  61. if (empty($save) OR ! function_exists($save))
  62. throw new Kohana_Exception('image.type_not_allowed', $dir.$file);
  63. // Load the image
  64. $this->image = $image;
  65. // Create the GD image resource
  66. $this->tmp_image = $create($image['file']);
  67. // Get the quality setting from the actions
  68. $quality = arr::remove('quality', $actions);
  69. if ($status = $this->execute($actions))
  70. {
  71. // Prevent the alpha from being lost
  72. imagealphablending($this->tmp_image, TRUE);
  73. imagesavealpha($this->tmp_image, TRUE);
  74. switch ($save)
  75. {
  76. case 'imagejpeg':
  77. // Default the quality to 95
  78. ($quality === NULL) and $quality = 95;
  79. break;
  80. case 'imagegif':
  81. // Remove the quality setting, GIF doesn't use it
  82. unset($quality);
  83. break;
  84. case 'imagepng':
  85. // Always use a compression level of 9 for PNGs. This does not
  86. // affect quality, it only increases the level of compression!
  87. $quality = 9;
  88. break;
  89. }
  90. // Set the status to the save return value, saving with the quality reques
  91. $status = isset($quality) ? $save($this->tmp_image, $dir.$file, $quality) : $save($this->tmp_image, $dir.$file);
  92. // Destroy the temporary image
  93. imagedestroy($this->tmp_image);
  94. }
  95. return $status;
  96. }
  97. public function flip($direction)
  98. {
  99. // Get the current width and height
  100. $width = imagesx($this->tmp_image);
  101. $height = imagesy($this->tmp_image);
  102. // Create the flipped image
  103. $flipped = $this->imagecreatetransparent($width, $height);
  104. if ($direction === Image::HORIZONTAL)
  105. {
  106. for ($x = 0; $x < $width; $x++)
  107. {
  108. $status = imagecopy($flipped, $this->tmp_image, $x, 0, $width - $x - 1, 0, 1, $height);
  109. }
  110. }
  111. elseif ($direction === Image::VERTICAL)
  112. {
  113. for ($y = 0; $y < $height; $y++)
  114. {
  115. $status = imagecopy($flipped, $this->tmp_image, 0, $y, 0, $height - $y - 1, $width, 1);
  116. }
  117. }
  118. else
  119. {
  120. // Do nothing
  121. return TRUE;
  122. }
  123. if ($status === TRUE)
  124. {
  125. // Swap the new image for the old one
  126. imagedestroy($this->tmp_image);
  127. $this->tmp_image = $flipped;
  128. }
  129. return $status;
  130. }
  131. public function crop($properties)
  132. {
  133. // Sanitize the cropping settings
  134. $this->sanitize_geometry($properties);
  135. // Get the current width and height
  136. $width = imagesx($this->tmp_image);
  137. $height = imagesy($this->tmp_image);
  138. // Create the temporary image to copy to
  139. $img = $this->imagecreatetransparent($properties['width'], $properties['height']);
  140. // Execute the crop
  141. if ($status = imagecopyresampled($img, $this->tmp_image, 0, 0, $properties['left'], $properties['top'], $width, $height, $width, $height))
  142. {
  143. // Swap the new image for the old one
  144. imagedestroy($this->tmp_image);
  145. $this->tmp_image = $img;
  146. }
  147. return $status;
  148. }
  149. public function resize($properties)
  150. {
  151. // Get the current width and height
  152. $width = imagesx($this->tmp_image);
  153. $height = imagesy($this->tmp_image);
  154. if (substr($properties['width'], -1) === '%')
  155. {
  156. // Recalculate the percentage to a pixel size
  157. $properties['width'] = round($width * (substr($properties['width'], 0, -1) / 100));
  158. }
  159. if (substr($properties['height'], -1) === '%')
  160. {
  161. // Recalculate the percentage to a pixel size
  162. $properties['height'] = round($height * (substr($properties['height'], 0, -1) / 100));
  163. }
  164. if ($properties['master'] === Image::AUTO)
  165. {
  166. // Change an automatic master dim to the correct type
  167. $properties['master'] = ($width > $height) ? Image::WIDTH : Image::HEIGHT;
  168. }
  169. // Recalculate the width and height, if they are missing
  170. empty($properties['width']) and $properties['width'] = round($width * $properties['height'] / $height);
  171. empty($properties['height']) and $properties['height'] = round($height * $properties['width'] / $width);
  172. if (empty($properties['height']) OR $properties['master'] === Image::WIDTH)
  173. {
  174. // Recalculate the height based on the width
  175. $properties['height'] = round($height * $properties['width'] / $width);
  176. }
  177. if (empty($properties['width']) OR $properties['master'] === Image::HEIGHT)
  178. {
  179. // Recalculate the width based on the height
  180. $properties['width'] = round($width * $properties['height'] / $height);
  181. }
  182. // Create the temporary image to copy to
  183. $img = $this->imagecreatetransparent($properties['width'], $properties['height']);
  184. // Execute the resize
  185. if ($status = imagecopyresampled($img, $this->tmp_image, 0, 0, 0, 0, $properties['width'], $properties['height'], $width, $height))
  186. {
  187. // Swap the new image for the old one
  188. imagedestroy($this->tmp_image);
  189. $this->tmp_image = $img;
  190. }
  191. return $status;
  192. }
  193. public function rotate($amount)
  194. {
  195. // Use current image to rotate
  196. $img = $this->tmp_image;
  197. // White, with an alpha of 0
  198. $transparent = imagecolorallocatealpha($img, 255, 255, 255, 127);
  199. // Rotate, setting the transparent color
  200. $img = imagerotate($img, 360 - $amount, $transparent, -1);
  201. // Fill the background with the transparent "color"
  202. imagecolortransparent($img, $transparent);
  203. // Merge the images
  204. if ($status = imagecopymerge($this->tmp_image, $img, 0, 0, 0, 0, imagesx($this->tmp_image), imagesy($this->tmp_image), 100))
  205. {
  206. // Prevent the alpha from being lost
  207. imagealphablending($img, TRUE);
  208. imagesavealpha($img, TRUE);
  209. // Swap the new image for the old one
  210. imagedestroy($this->tmp_image);
  211. $this->tmp_image = $img;
  212. }
  213. return $status;
  214. }
  215. public function sharpen($amount)
  216. {
  217. // Make sure that the sharpening function is available
  218. if ( ! function_exists('imageconvolution'))
  219. throw new Kohana_Exception('image.unsupported_method', __FUNCTION__);
  220. // Amount should be in the range of 18-10
  221. $amount = round(abs(-18 + ($amount * 0.08)), 2);
  222. // Gaussian blur matrix
  223. $matrix = array
  224. (
  225. array(-1, -1, -1),
  226. array(-1, $amount, -1),
  227. array(-1, -1, -1)
  228. );
  229. // Perform the sharpen
  230. return imageconvolution($this->tmp_image, $matrix, $amount - 8, 0);
  231. }
  232. protected function properties()
  233. {
  234. return array(imagesx($this->tmp_image), imagesy($this->tmp_image));
  235. }
  236. /**
  237. * Returns an image with a transparent background. Used for rotating to
  238. * prevent unfilled backgrounds.
  239. *
  240. * @param integer image width
  241. * @param integer image height
  242. * @return resource
  243. */
  244. protected function imagecreatetransparent($width, $height)
  245. {
  246. if (self::$blank_png === NULL)
  247. {
  248. // Decode the blank PNG if it has not been done already
  249. self::$blank_png = imagecreatefromstring(base64_decode
  250. (
  251. 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29'.
  252. 'mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAADqSURBVHjaYvz//z/DYAYAAcTEMMgBQAANegcCBN'.
  253. 'CgdyBAAA16BwIE0KB3IEAADXoHAgTQoHcgQAANegcCBNCgdyBAAA16BwIE0KB3IEAADXoHAgTQoHcgQ'.
  254. 'AANegcCBNCgdyBAAA16BwIE0KB3IEAADXoHAgTQoHcgQAANegcCBNCgdyBAAA16BwIE0KB3IEAADXoH'.
  255. 'AgTQoHcgQAANegcCBNCgdyBAAA16BwIE0KB3IEAADXoHAgTQoHcgQAANegcCBNCgdyBAAA16BwIE0KB'.
  256. '3IEAADXoHAgTQoHcgQAANegcCBNCgdyBAgAEAMpcDTTQWJVEAAAAASUVORK5CYII='
  257. ));
  258. // Set the blank PNG width and height
  259. self::$blank_png_width = imagesx(self::$blank_png);
  260. self::$blank_png_height = imagesy(self::$blank_png);
  261. }
  262. $img = imagecreatetruecolor($width, $height);
  263. // Resize the blank image
  264. imagecopyresized($img, self::$blank_png, 0, 0, 0, 0, $width, $height, self::$blank_png_width, self::$blank_png_height);
  265. // Prevent the alpha from being lost
  266. imagealphablending($img, FALSE);
  267. imagesavealpha($img, TRUE);
  268. return $img;
  269. }
  270. } // End Image GD Driver