PageRenderTime 27ms CodeModel.GetById 33ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://github.com/mihalyf/gallery3-contrib
PHP | 440 lines | 272 code | 73 blank | 95 comment | 29 complexity | f4e4b1931b9bcaee787a2d68c92b12fa MD5 | raw file
  1. <?php defined('SYSPATH') OR die('No direct access allowed.');
  2. /**
  3. * GD Image Driver.
  4. *
  5. * $Id: GD.php 4679 2009-11-10 01:45:52Z isaiah $
  6. *
  7. * @package Image
  8. * @author Kohana Team
  9. * @copyright (c) 2007-2009 Kohana Team
  10. * @license http://kohanaphp.com/license
  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('The Image library requires GD2. Please see http://php.net/gd_info for more information.');
  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('The Image library requires GD2. Please see http://php.net/gd_info for more information.');
  27. }
  28. public function process($image, $actions, $dir, $file, $render = FALSE, $background = NULL)
  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(substr(strrchr($file, '.'), 1)))
  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('The specified image, :type:, is not an allowed image type.', array(':type:' => $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('The specified image, :type:, is not an allowed image type.', array(':type:' => $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. if ($render === FALSE)
  91. {
  92. // Set the status to the save return value, saving with the quality requested
  93. $status = isset($quality) ? $save($this->tmp_image, $dir.$file, $quality) : $save($this->tmp_image, $dir.$file);
  94. }
  95. else
  96. {
  97. // Output the image directly to the browser
  98. switch ($save)
  99. {
  100. case 'imagejpeg':
  101. header('Content-Type: image/jpeg');
  102. break;
  103. case 'imagegif':
  104. header('Content-Type: image/gif');
  105. break;
  106. case 'imagepng':
  107. header('Content-Type: image/png');
  108. break;
  109. }
  110. $status = isset($quality) ? $save($this->tmp_image, NULL, $quality) : $save($this->tmp_image);
  111. }
  112. // Destroy the temporary image
  113. imagedestroy($this->tmp_image);
  114. }
  115. return $status;
  116. }
  117. public function flip($direction)
  118. {
  119. // Get the current width and height
  120. $width = imagesx($this->tmp_image);
  121. $height = imagesy($this->tmp_image);
  122. // Create the flipped image
  123. $flipped = $this->imagecreatetransparent($width, $height);
  124. if ($direction === Image::HORIZONTAL)
  125. {
  126. for ($x = 0; $x < $width; $x++)
  127. {
  128. $status = imagecopy($flipped, $this->tmp_image, $x, 0, $width - $x - 1, 0, 1, $height);
  129. }
  130. }
  131. elseif ($direction === Image::VERTICAL)
  132. {
  133. for ($y = 0; $y < $height; $y++)
  134. {
  135. $status = imagecopy($flipped, $this->tmp_image, 0, $y, 0, $height - $y - 1, $width, 1);
  136. }
  137. }
  138. else
  139. {
  140. // Do nothing
  141. return TRUE;
  142. }
  143. if ($status === TRUE)
  144. {
  145. // Swap the new image for the old one
  146. imagedestroy($this->tmp_image);
  147. $this->tmp_image = $flipped;
  148. }
  149. return $status;
  150. }
  151. public function crop($properties)
  152. {
  153. // Sanitize the cropping settings
  154. $this->sanitize_geometry($properties);
  155. // Get the current width and height
  156. $width = imagesx($this->tmp_image);
  157. $height = imagesy($this->tmp_image);
  158. // Create the temporary image to copy to
  159. $img = $this->imagecreatetransparent($properties['width'], $properties['height']);
  160. // Execute the crop
  161. if ($status = imagecopyresampled($img, $this->tmp_image, 0, 0, $properties['left'], $properties['top'], $width, $height, $width, $height))
  162. {
  163. // Swap the new image for the old one
  164. imagedestroy($this->tmp_image);
  165. $this->tmp_image = $img;
  166. }
  167. return $status;
  168. }
  169. public function resize($properties)
  170. {
  171. // Get the current width and height
  172. $width = imagesx($this->tmp_image);
  173. $height = imagesy($this->tmp_image);
  174. if (substr($properties['width'], -1) === '%')
  175. {
  176. // Recalculate the percentage to a pixel size
  177. $properties['width'] = round($width * (substr($properties['width'], 0, -1) / 100));
  178. }
  179. if (substr($properties['height'], -1) === '%')
  180. {
  181. // Recalculate the percentage to a pixel size
  182. $properties['height'] = round($height * (substr($properties['height'], 0, -1) / 100));
  183. }
  184. // Recalculate the width and height, if they are missing
  185. empty($properties['width']) and $properties['width'] = round($width * $properties['height'] / $height);
  186. empty($properties['height']) and $properties['height'] = round($height * $properties['width'] / $width);
  187. if ($properties['master'] === Image::AUTO)
  188. {
  189. // Change an automatic master dim to the correct type
  190. $properties['master'] = (($width / $properties['width']) > ($height / $properties['height'])) ? Image::WIDTH : Image::HEIGHT;
  191. }
  192. if (empty($properties['height']) OR $properties['master'] === Image::WIDTH)
  193. {
  194. // Recalculate the height based on the width
  195. $properties['height'] = round($height * $properties['width'] / $width);
  196. }
  197. if (empty($properties['width']) OR $properties['master'] === Image::HEIGHT)
  198. {
  199. // Recalculate the width based on the height
  200. $properties['width'] = round($width * $properties['height'] / $height);
  201. }
  202. // Test if we can do a resize without resampling to speed up the final resize
  203. if ($properties['width'] > $width / 2 AND $properties['height'] > $height / 2)
  204. {
  205. // Presize width and height
  206. $pre_width = $width;
  207. $pre_height = $height;
  208. // The maximum reduction is 10% greater than the final size
  209. $max_reduction_width = round($properties['width'] * 1.1);
  210. $max_reduction_height = round($properties['height'] * 1.1);
  211. // Reduce the size using an O(2n) algorithm, until it reaches the maximum reduction
  212. while ($pre_width / 2 > $max_reduction_width AND $pre_height / 2 > $max_reduction_height)
  213. {
  214. $pre_width /= 2;
  215. $pre_height /= 2;
  216. }
  217. // Create the temporary image to copy to
  218. $img = $this->imagecreatetransparent($pre_width, $pre_height);
  219. if ($status = imagecopyresized($img, $this->tmp_image, 0, 0, 0, 0, $pre_width, $pre_height, $width, $height))
  220. {
  221. // Swap the new image for the old one
  222. imagedestroy($this->tmp_image);
  223. $this->tmp_image = $img;
  224. }
  225. // Set the width and height to the presize
  226. $width = $pre_width;
  227. $height = $pre_height;
  228. }
  229. // Create the temporary image to copy to
  230. $img = $this->imagecreatetransparent($properties['width'], $properties['height']);
  231. // Execute the resize
  232. if ($status = imagecopyresampled($img, $this->tmp_image, 0, 0, 0, 0, $properties['width'], $properties['height'], $width, $height))
  233. {
  234. // Swap the new image for the old one
  235. imagedestroy($this->tmp_image);
  236. $this->tmp_image = $img;
  237. }
  238. return $status;
  239. }
  240. public function rotate($amount)
  241. {
  242. // Use current image to rotate
  243. $img = $this->tmp_image;
  244. // White, with an alpha of 0
  245. $transparent = imagecolorallocatealpha($img, 255, 255, 255, 127);
  246. // Rotate, setting the transparent color
  247. $img = imagerotate($img, 360 - $amount, $transparent, -1);
  248. // Fill the background with the transparent "color"
  249. imagecolortransparent($img, $transparent);
  250. // Merge the images
  251. if ($status = imagecopymerge($this->tmp_image, $img, 0, 0, 0, 0, imagesx($this->tmp_image), imagesy($this->tmp_image), 100))
  252. {
  253. // Prevent the alpha from being lost
  254. imagealphablending($img, TRUE);
  255. imagesavealpha($img, TRUE);
  256. // Swap the new image for the old one
  257. imagedestroy($this->tmp_image);
  258. $this->tmp_image = $img;
  259. }
  260. return $status;
  261. }
  262. public function sharpen($amount)
  263. {
  264. // Make sure that the sharpening function is available
  265. if ( ! function_exists('imageconvolution'))
  266. throw new Kohana_Exception('Your configured driver does not support the :method: image transformation.', array(':method:' => __FUNCTION__));
  267. // Amount should be in the range of 18-10
  268. $amount = round(abs(-18 + ($amount * 0.08)), 2);
  269. // Gaussian blur matrix
  270. $matrix = array
  271. (
  272. array(-1, -1, -1),
  273. array(-1, $amount, -1),
  274. array(-1, -1, -1),
  275. );
  276. // Perform the sharpen
  277. return imageconvolution($this->tmp_image, $matrix, $amount - 8, 0);
  278. }
  279. public function composite($properties)
  280. {
  281. switch($properties['mime'])
  282. {
  283. case "image/jpeg":
  284. $overlay_img = imagecreatefromjpeg($properties['overlay_file']);
  285. break;
  286. case "image/gif":
  287. $overlay_img = imagecreatefromgif($properties['overlay_file']);
  288. break;
  289. case "image/png":
  290. $overlay_img = imagecreatefrompng($properties['overlay_file']);
  291. break;
  292. }
  293. $this->imagecopymerge_alpha($this->tmp_image, $overlay_img, $properties['x'], $properties['y'], 0, 0, imagesx($overlay_img), imagesy($overlay_img), $properties['transparency']);
  294. imagedestroy($overlay_img);
  295. return TRUE;
  296. }
  297. /**
  298. * A replacement for php's imagecopymerge() function that supports the alpha channel
  299. * See php bug #23815: http://bugs.php.net/bug.php?id=23815
  300. *
  301. * @param resource $dst_im Destination image link resource
  302. * @param resource $src_im Source image link resource
  303. * @param integer $dst_x x-coordinate of destination point
  304. * @param integer $dst_y y-coordinate of destination point
  305. * @param integer $src_x x-coordinate of source point
  306. * @param integer $src_y y-coordinate of source point
  307. * @param integer $src_w Source width
  308. * @param integer $src_h Source height
  309. * @param integer $pct Transparency percent (0 to 100)
  310. */
  311. protected function imagecopymerge_alpha($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $pct)
  312. {
  313. // Create a new blank image the site of our source image
  314. $cut = imagecreatetruecolor($src_w, $src_h);
  315. // Copy the blank image into the destination image where the source goes
  316. imagecopy($cut, $dst_im, 0, 0, $dst_x, $dst_y, $src_w, $src_h);
  317. // Place the source image in the destination image
  318. imagecopy($cut, $src_im, 0, 0, $src_x, $src_y, $src_w, $src_h);
  319. imagecopymerge($dst_im, $cut, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $pct);
  320. }
  321. protected function properties()
  322. {
  323. return array(imagesx($this->tmp_image), imagesy($this->tmp_image));
  324. }
  325. /**
  326. * Returns an image with a transparent background. Used for rotating to
  327. * prevent unfilled backgrounds.
  328. *
  329. * @param integer image width
  330. * @param integer image height
  331. * @return resource
  332. */
  333. protected function imagecreatetransparent($width, $height)
  334. {
  335. if ($width < 1)
  336. {
  337. $width = 1;
  338. }
  339. if ($height < 1)
  340. {
  341. $height = 1;
  342. }
  343. if (self::$blank_png === NULL)
  344. {
  345. // Decode the blank PNG if it has not been done already
  346. self::$blank_png = imagecreatefromstring(base64_decode
  347. (
  348. 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29'.
  349. 'mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAADqSURBVHjaYvz//z/DYAYAAcTEMMgBQAANegcCBN'.
  350. 'CgdyBAAA16BwIE0KB3IEAADXoHAgTQoHcgQAANegcCBNCgdyBAAA16BwIE0KB3IEAADXoHAgTQoHcgQ'.
  351. 'AANegcCBNCgdyBAAA16BwIE0KB3IEAADXoHAgTQoHcgQAANegcCBNCgdyBAAA16BwIE0KB3IEAADXoH'.
  352. 'AgTQoHcgQAANegcCBNCgdyBAAA16BwIE0KB3IEAADXoHAgTQoHcgQAANegcCBNCgdyBAAA16BwIE0KB'.
  353. '3IEAADXoHAgTQoHcgQAANegcCBNCgdyBAgAEAMpcDTTQWJVEAAAAASUVORK5CYII='
  354. ));
  355. // Set the blank PNG width and height
  356. self::$blank_png_width = imagesx(self::$blank_png);
  357. self::$blank_png_height = imagesy(self::$blank_png);
  358. }
  359. $img = imagecreatetruecolor($width, $height);
  360. // Resize the blank image
  361. imagecopyresized($img, self::$blank_png, 0, 0, 0, 0, $width, $height, self::$blank_png_width, self::$blank_png_height);
  362. // Prevent the alpha from being lost
  363. imagealphablending($img, FALSE);
  364. imagesavealpha($img, TRUE);
  365. return $img;
  366. }
  367. } // End Image GD Driver