PageRenderTime 56ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/x2engine/protected/extensions/image/drivers/Image_GD_Driver.php

https://gitlab.com/e0/X2CRM
PHP | 400 lines | 257 code | 66 blank | 77 comment | 29 complexity | a0eb0b52b04c7c1090bb0734ac8d5c36 MD5 | raw file
  1. <?php
  2. /**
  3. * GD Image Driver.
  4. *
  5. * $Id: GD.php 3769 2008-12-15 00:48:56Z zombor $
  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. {
  14. // A transparent PNG as a string
  15. protected static $blank_png;
  16. protected static $blank_png_width;
  17. protected static $blank_png_height;
  18. public function __construct()
  19. {
  20. // Make sure that GD2 is available
  21. if (!function_exists('gd_info'))
  22. throw new CException('Image component requires GD');
  23. // Get the GD information
  24. $info = gd_info();
  25. // Make sure that the GD2 is installed
  26. if (strpos($info['GD Version'], '2.') === FALSE)
  27. throw new CException('Image component requires GD v2');
  28. }
  29. public function process($image, $actions, $dir, $file, $render = FALSE)
  30. {
  31. // Set the "create" function
  32. switch ($image['type']) {
  33. case IMAGETYPE_JPEG:
  34. $create = 'imagecreatefromjpeg';
  35. $save = 'imagejpeg';
  36. break;
  37. case IMAGETYPE_GIF:
  38. $create = 'imagecreatefromgif';
  39. $save = 'imagegif';
  40. break;
  41. case IMAGETYPE_PNG:
  42. $create = 'imagecreatefrompng';
  43. $save = 'imagepng';
  44. break;
  45. }
  46. // Set the "save" function
  47. switch (strtolower(substr(strrchr($file, '.'), 1))) {
  48. case 'jpg':
  49. case 'jpeg':
  50. $save = 'imagejpeg';
  51. break;
  52. case 'gif':
  53. $save = 'imagegif';
  54. break;
  55. case 'png':
  56. $save = 'imagepng';
  57. break;
  58. }
  59. // Make sure the image type is supported for import
  60. if (empty($create) or !function_exists($create))
  61. throw new CException('image type not allowed');
  62. // Make sure the image type is supported for saving
  63. if (empty($save) or !function_exists($save))
  64. throw new CException('image type not allowed');
  65. // Load the image
  66. $this->image = $image;
  67. // Create the GD image resource
  68. $this->tmp_image = $create($image['file']);
  69. // Get the quality setting from the actions
  70. $quality = null;
  71. if (array_key_exists('quality', $actions)) {
  72. $quality = $actions['quality'];
  73. unset($actions['quality']);
  74. }
  75. if ($status = $this->execute($actions)) {
  76. // Prevent the alpha from being lost
  77. imagealphablending($this->tmp_image, true);
  78. imagesavealpha($this->tmp_image, true);
  79. switch ($save) {
  80. case 'imagejpeg':
  81. // Default the quality to 95
  82. ($quality === NULL) and $quality = 95;
  83. break;
  84. case 'imagegif':
  85. // Remove the quality setting, GIF doesn't use it
  86. unset($quality);
  87. break;
  88. case 'imagepng':
  89. // Always use a compression level of 9 for PNGs. This does not
  90. // affect quality, it only increases the level of compression!
  91. $quality = 9;
  92. break;
  93. }
  94. if ($render === false) {
  95. // Set the status to the save return value, saving with the quality requested
  96. $status = isset($quality)
  97. ? $save($this->tmp_image, $dir . $file, $quality)
  98. : $save($this->tmp_image, $dir . $file);
  99. } else {
  100. // Output the image directly to the browser
  101. switch ($save) {
  102. case 'imagejpeg':
  103. header('Content-Type: image/jpeg');
  104. break;
  105. case 'imagegif':
  106. header('Content-Type: image/gif');
  107. break;
  108. case 'imagepng':
  109. header('Content-Type: image/png');
  110. break;
  111. }
  112. $status = isset($quality)
  113. ? $save($this->tmp_image, NULL, $quality)
  114. : $save($this->tmp_image);
  115. }
  116. // Destroy the temporary image
  117. imagedestroy($this->tmp_image);
  118. }
  119. return $status;
  120. }
  121. public function flip($direction)
  122. {
  123. // Get the current width and height
  124. $width = imagesx($this->tmp_image);
  125. $height = imagesy($this->tmp_image);
  126. // Create the flipped image
  127. $flipped = $this->imagecreatetransparent($width, $height);
  128. $status = false;
  129. switch ($direction) {
  130. case Image::HORIZONTAL:
  131. for ($x = 0; $x < $width; $x++) {
  132. $status = imagecopy($flipped, $this->tmp_image, $x, 0, $width - $x - 1, 0, 1, $height);
  133. }
  134. break;
  135. case Image::VERTICAL:
  136. for ($y = 0; $y < $height; $y++) {
  137. $status = imagecopy($flipped, $this->tmp_image, 0, $y, 0, $height - $y - 1, $width, 1);
  138. }
  139. break;
  140. default:
  141. return true;
  142. }
  143. if ($status === true) {
  144. // Swap the new image for the old one
  145. imagedestroy($this->tmp_image);
  146. $this->tmp_image = $flipped;
  147. }
  148. return $status;
  149. }
  150. public function crop($properties)
  151. {
  152. // Sanitize the cropping settings
  153. $this->sanitize_geometry($properties);
  154. // Get the current width and height
  155. $width = imagesx($this->tmp_image);
  156. $height = imagesy($this->tmp_image);
  157. // Create the temporary image to copy to
  158. $img = $this->imagecreatetransparent($properties['width'], $properties['height']);
  159. // Execute the crop
  160. if ($status = imagecopyresampled($img, $this->tmp_image, 0, 0, $properties['left'], $properties['top'], $width, $height, $width, $height)) {
  161. // Swap the new image for the old one
  162. imagedestroy($this->tmp_image);
  163. $this->tmp_image = $img;
  164. }
  165. return $status;
  166. }
  167. public function resize($properties)
  168. {
  169. // Get the current width and height
  170. $width = imagesx($this->tmp_image);
  171. $height = imagesy($this->tmp_image);
  172. if (substr($properties['width'], -1) === '%') {
  173. // Recalculate the percentage to a pixel size
  174. $properties['width'] = round($width * (substr($properties['width'], 0, -1) / 100));
  175. }
  176. if (substr($properties['height'], -1) === '%') {
  177. // Recalculate the percentage to a pixel size
  178. $properties['height'] = round($height * (substr($properties['height'], 0, -1) / 100));
  179. }
  180. // Recalculate the width and height, if they are missing
  181. empty($properties['width']) and $properties['width'] = round($width * $properties['height'] / $height);
  182. empty($properties['height']) and $properties['height'] = round($height * $properties['width'] / $width);
  183. if ($properties['master'] === Image::AUTO) {
  184. // Change an automatic master dim to the correct type
  185. $properties['master'] = (($width / $properties['width']) > ($height / $properties['height']))
  186. ? Image::WIDTH
  187. : Image::HEIGHT;
  188. }
  189. if (empty($properties['height']) or $properties['master'] === Image::WIDTH) {
  190. // Recalculate the height based on the width
  191. $properties['height'] = round($height * $properties['width'] / $width);
  192. }
  193. if (empty($properties['width']) or $properties['master'] === Image::HEIGHT) {
  194. // Recalculate the width based on the height
  195. $properties['width'] = round($width * $properties['height'] / $height);
  196. }
  197. // Test if we can do a resize without resampling to speed up the final resize
  198. if ($properties['width'] > $width / 2 and $properties['height'] > $height / 2) {
  199. // Presize width and height
  200. $pre_width = $width;
  201. $pre_height = $height;
  202. // The maximum reduction is 10% greater than the final size
  203. $max_reduction_width = round($properties['width'] * 1.1);
  204. $max_reduction_height = round($properties['height'] * 1.1);
  205. // Reduce the size using an O(2n) algorithm, until it reaches the maximum reduction
  206. while ($pre_width / 2 > $max_reduction_width and $pre_height / 2 > $max_reduction_height) {
  207. $pre_width /= 2;
  208. $pre_height /= 2;
  209. }
  210. // Create the temporary image to copy to
  211. $img = $this->imagecreatetransparent($pre_width, $pre_height);
  212. if ($status = imagecopyresized($img, $this->tmp_image, 0, 0, 0, 0, $pre_width, $pre_height, $width, $height)) {
  213. // Swap the new image for the old one
  214. imagedestroy($this->tmp_image);
  215. $this->tmp_image = $img;
  216. }
  217. // Set the width and height to the presize
  218. $width = $pre_width;
  219. $height = $pre_height;
  220. }
  221. // Create the temporary image to copy to
  222. $img = $this->imagecreatetransparent($properties['width'], $properties['height']);
  223. // Execute the resize
  224. if ($status = imagecopyresampled($img, $this->tmp_image, 0, 0, 0, 0, $properties['width'], $properties['height'], $width, $height)) {
  225. // Swap the new image for the old one
  226. imagedestroy($this->tmp_image);
  227. $this->tmp_image = $img;
  228. }
  229. return $status;
  230. }
  231. public function rotate($amount)
  232. {
  233. // Use current image to rotate
  234. $img = $this->tmp_image;
  235. // White, with an alpha of 0
  236. $transparent = imagecolorallocatealpha($img, 255, 255, 255, 127);
  237. // Rotate, setting the transparent color
  238. $img = imagerotate($img, 360 - $amount, $transparent, -1);
  239. // Fill the background with the transparent "color"
  240. imagecolortransparent($img, $transparent);
  241. // Merge the images
  242. if ($status = imagecopymerge($this->tmp_image, $img, 0, 0, 0, 0, imagesx($this->tmp_image), imagesy($this->tmp_image), 100)) {
  243. // Prevent the alpha from being lost
  244. imagealphablending($img, true);
  245. imagesavealpha($img, true);
  246. // Swap the new image for the old one
  247. imagedestroy($this->tmp_image);
  248. $this->tmp_image = $img;
  249. }
  250. return $status;
  251. }
  252. public function sharpen($amount)
  253. {
  254. // Make sure that the sharpening function is available
  255. if (!function_exists('imageconvolution'))
  256. throw new CException('image unsupported method');
  257. // Amount should be in the range of 18-10
  258. $amount = round(abs(-18 + ($amount * 0.08)), 2);
  259. // Gaussian blur matrix
  260. $matrix = array
  261. (
  262. array(-1, -1, -1),
  263. array(-1, $amount, -1),
  264. array(-1, -1, -1),
  265. );
  266. // Perform the sharpen
  267. return imageconvolution($this->tmp_image, $matrix, $amount - 8, 0);
  268. }
  269. public function grayscale($unused)
  270. {
  271. return imagefilter($this->tmp_image, IMG_FILTER_GRAYSCALE);
  272. }
  273. public function colorize($params)
  274. {
  275. return imagefilter($this->tmp_image, IMG_FILTER_COLORIZE, $params['r'], $params['g'], $params['b'], $params['a']);
  276. }
  277. public function emboss($unused)
  278. {
  279. return imagefilter($this->tmp_image, IMG_FILTER_EMBOSS);
  280. }
  281. public function negate($unused)
  282. {
  283. return imagefilter($this->tmp_image, IMG_FILTER_NEGATE);
  284. }
  285. protected function properties()
  286. {
  287. return array(imagesx($this->tmp_image), imagesy($this->tmp_image));
  288. }
  289. /**
  290. * Returns an image with a transparent background. Used for rotating to
  291. * prevent unfilled backgrounds.
  292. *
  293. * @param integer image width
  294. * @param integer image height
  295. * @return resource
  296. */
  297. protected function imagecreatetransparent($width, $height)
  298. {
  299. if (self::$blank_png === NULL) {
  300. // Decode the blank PNG if it has not been done already
  301. self::$blank_png = imagecreatefromstring(base64_decode
  302. (
  303. 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29' .
  304. 'mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAADqSURBVHjaYvz//z/DYAYAAcTEMMgBQAANegcCBN' .
  305. 'CgdyBAAA16BwIE0KB3IEAADXoHAgTQoHcgQAANegcCBNCgdyBAAA16BwIE0KB3IEAADXoHAgTQoHcgQ' .
  306. 'AANegcCBNCgdyBAAA16BwIE0KB3IEAADXoHAgTQoHcgQAANegcCBNCgdyBAAA16BwIE0KB3IEAADXoH' .
  307. 'AgTQoHcgQAANegcCBNCgdyBAAA16BwIE0KB3IEAADXoHAgTQoHcgQAANegcCBNCgdyBAAA16BwIE0KB' .
  308. '3IEAADXoHAgTQoHcgQAANegcCBNCgdyBAgAEAMpcDTTQWJVEAAAAASUVORK5CYII='
  309. ));
  310. // Set the blank PNG width and height
  311. self::$blank_png_width = imagesx(self::$blank_png);
  312. self::$blank_png_height = imagesy(self::$blank_png);
  313. }
  314. $img = imagecreatetruecolor($width, $height);
  315. // Resize the blank image
  316. imagecopyresized($img, self::$blank_png, 0, 0, 0, 0, $width, $height, self::$blank_png_width, self::$blank_png_height);
  317. // Prevent the alpha from being lost
  318. imagealphablending($img, FALSE);
  319. imagesavealpha($img, TRUE);
  320. return $img;
  321. }
  322. public function watermark($params)
  323. {
  324. $path = $params['path'];
  325. $x = $params['x'];
  326. $y = $params['y'];
  327. imagealphablending($this->tmp_image, true);
  328. imagesavealpha($this->tmp_image, true);
  329. $mark = imagecreatefrompng($path);
  330. imagecopyresized($this->tmp_image, $mark, $x, $y, 0, 0, imagesx($mark), imagesy($mark), imagesx($mark), imagesy($mark));
  331. imagedestroy($mark);
  332. return $this->tmp_image;
  333. }
  334. } // End Image GD Driver