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

/concrete/core/helpers/image.php

https://bitbucket.org/selfeky/xclusivescardwebsite
PHP | 290 lines | 170 code | 33 blank | 87 comment | 58 complexity | 752286f25a40dfe7d497d462a48356d7 MD5 | raw file
  1. <?php
  2. /**
  3. * @package Helpers
  4. * @category Concrete
  5. * @author Andrew Embler <andrew@concrete5.org>
  6. * @copyright Copyright (c) 2003-2008 Concrete5. (http://www.concrete5.org)
  7. * @license http://www.concrete5.org/license/ MIT License
  8. */
  9. /**
  10. * Functions useful for working with images.
  11. * @package Helpers
  12. * @category Concrete
  13. * @author Andrew Embler <andrew@concrete5.org>
  14. * @copyright Copyright (c) 2003-2008 Concrete5. (http://www.concrete5.org)
  15. * @license http://www.concrete5.org/license/ MIT License
  16. * Now includes cropping functionality (thanks to Jordan Lev and Kirk Roberts)
  17. */
  18. defined('C5_EXECUTE') or die("Access Denied.");
  19. class Concrete5_Helper_Image {
  20. public $jpegCompression = 80;
  21. /**
  22. * Resets the compression level to the system default
  23. * This method is automatically run when Loader::helper invokes this class
  24. * @return void
  25. */
  26. function reset() {
  27. $this->jpegCompression = $this->defaultJpegCompression();
  28. }
  29. /**
  30. * Returns the default system value for JPEG image compression
  31. * @return int from 1-100
  32. */
  33. public function defaultJpegCompression(){
  34. return defined('AL_THUMBNAIL_JPEG_COMPRESSION') ? AL_THUMBNAIL_JPEG_COMPRESSION : 80;
  35. }
  36. /**
  37. * Overrides the default or defined JPEG compression level per instance
  38. * of the image helper. This allows for a single-use for a particularly
  39. * low or high compression value. Passing a non-integer value will reset
  40. * to the default system setting (DEFINE or 80)
  41. * @param int $level the level of compression
  42. * @return self
  43. */
  44. public function setJpegCompression($level) {
  45. if (is_int($level)) {
  46. $this->jpegCompression = min(max($level, 0), 100);
  47. } else {
  48. $this->reset();
  49. }
  50. return $this;
  51. }
  52. /**
  53. * Creates a new image given an original path, a new path, a target width and height.
  54. * Optionally crops image to exactly match given width and height.
  55. * @params string $originalPath, string $newpath, int $width, int $height, bool $crop
  56. * @return void
  57. */
  58. public function create($originalPath, $newPath, $width, $height, $crop = false) {
  59. // first, we grab the original image. We shouldn't ever get to this function unless the image is valid
  60. $imageSize = @getimagesize($originalPath);
  61. $oWidth = $imageSize[0];
  62. $oHeight = $imageSize[1];
  63. $finalWidth = 0; //For cropping, this is really "scale to width before chopping extra height"
  64. $finalHeight = 0; //For cropping, this is really "scale to height before chopping extra width"
  65. $do_crop_x = false;
  66. $do_crop_y = false;
  67. $crop_src_x = 0;
  68. $crop_src_y = 0;
  69. // first, if what we're uploading is actually smaller than width and height, we do nothing
  70. if ($oWidth < $width && $oHeight < $height) {
  71. $finalWidth = $oWidth;
  72. $finalHeight = $oHeight;
  73. $width = $oWidth;
  74. $height = $oHeight;
  75. } else if ($crop && ($height >= $oHeight && $width <= $oWidth)) {
  76. //crop to width only -- don't scale anything
  77. $finalWidth = $oWidth;
  78. $finalHeight = $oHeight;
  79. $height = $oHeight;
  80. $do_crop_x = true;
  81. } else if ($crop && ($width >= $oWidth && $height <= $oHeight)) {
  82. //crop to height only -- don't scale anything
  83. $finalHeight = $oHeight;
  84. $finalWidth = $oWidth;
  85. $width = $oWidth;
  86. $do_crop_y = true;
  87. } else {
  88. // otherwise, we do some complicated stuff
  89. // first, we divide original width and height by new width and height, and find which difference is greater
  90. $wDiff = $oWidth / $width;
  91. $hDiff = ($height != 0 ? $oHeight / $height : 0);
  92. if (!$crop && ($wDiff > $hDiff)) {
  93. //no cropping, just resize down based on target width
  94. $finalWidth = $width;
  95. $finalHeight = ($wDiff != 0 ? $oHeight / $wDiff : 0);
  96. } else if (!$crop) {
  97. //no cropping, just resize down based on target height
  98. $finalWidth = ($hDiff != 0 ? $oWidth / $hDiff : 0);
  99. $finalHeight = $height;
  100. } else if ($crop && ($wDiff > $hDiff)) {
  101. //resize down to target height, THEN crop off extra width
  102. $finalWidth = ($hDiff != 0 ? $oWidth / $hDiff : 0);
  103. $finalHeight = $height;
  104. $do_crop_x = true;
  105. } else if ($crop) {
  106. //resize down to target width, THEN crop off extra height
  107. $finalWidth = $width;
  108. $finalHeight = ($wDiff != 0 ? $oHeight / $wDiff : 0);
  109. $do_crop_y = true;
  110. }
  111. }
  112. //Calculate cropping to center image
  113. if ($do_crop_x) {
  114. /*
  115. //Get half the difference between scaled width and target width,
  116. // and crop by starting the copy that many pixels over from the left side of the source (scaled) image.
  117. $nudge = ($width / 10); //I have *no* idea why the width isn't centering exactly -- this seems to fix it though.
  118. $crop_src_x = ($finalWidth / 2.00) - ($width / 2.00) + $nudge;
  119. */
  120. $crop_src_x = round(($oWidth - ($width * $oHeight / $height)) * 0.5);
  121. }
  122. if ($do_crop_y) {
  123. /*
  124. //Calculate cropping...
  125. //Get half the difference between scaled height and target height,
  126. // and crop by starting the copy that many pixels down from the top of the source (scaled) image.
  127. $crop_src_y = ($finalHeight / 2.00) - ($height / 2.00);
  128. */
  129. $crop_src_y = round(($oHeight - ($height * $oWidth / $width)) * 0.5);
  130. }
  131. //create "canvas" to put new resized and/or cropped image into
  132. if ($crop) {
  133. $image = @imageCreateTrueColor($width, $height);
  134. } else {
  135. $image = @imageCreateTrueColor($finalWidth, $finalHeight);
  136. }
  137. $im = false;
  138. switch($imageSize[2]) {
  139. case IMAGETYPE_GIF:
  140. $im = @imageCreateFromGIF($originalPath);
  141. break;
  142. case IMAGETYPE_JPEG:
  143. $im = @imageCreateFromJPEG($originalPath);
  144. break;
  145. case IMAGETYPE_PNG:
  146. $im = @imageCreateFromPNG($originalPath);
  147. break;
  148. }
  149. if ($im) {
  150. // Better transparency - thanks for the ideas and some code from mediumexposure.com
  151. if (($imageSize[2] == IMAGETYPE_GIF) || ($imageSize[2] == IMAGETYPE_PNG)) {
  152. $trnprt_indx = imagecolortransparent($im);
  153. // If we have a specific transparent color
  154. if ($trnprt_indx >= 0 && $trnprt_indx < imagecolorstotal($im)) {
  155. // Get the original image's transparent color's RGB values
  156. $trnprt_color = imagecolorsforindex($im, $trnprt_indx);
  157. // Allocate the same color in the new image resource
  158. $trnprt_indx = imagecolorallocate($image, $trnprt_color['red'], $trnprt_color['green'], $trnprt_color['blue']);
  159. // Completely fill the background of the new image with allocated color.
  160. imagefill($image, 0, 0, $trnprt_indx);
  161. // Set the background color for new image to transparent
  162. imagecolortransparent($image, $trnprt_indx);
  163. } else if ($imageSize[2] == IMAGETYPE_PNG) {
  164. // Turn off transparency blending (temporarily)
  165. imagealphablending($image, false);
  166. // Create a new transparent color for image
  167. $color = imagecolorallocatealpha($image, 0, 0, 0, 127);
  168. // Completely fill the background of the new image with allocated color.
  169. imagefill($image, 0, 0, $color);
  170. // Restore transparency blending
  171. imagesavealpha($image, true);
  172. }
  173. }
  174. $res = @imageCopyResampled($image, $im, 0, 0, $crop_src_x, $crop_src_y, $finalWidth, $finalHeight, $oWidth, $oHeight);
  175. if ($res) {
  176. switch($imageSize[2]) {
  177. case IMAGETYPE_GIF:
  178. $res2 = imageGIF($image, $newPath);
  179. break;
  180. case IMAGETYPE_JPEG:
  181. $res2 = imageJPEG($image, $newPath, $this->jpegCompression);
  182. break;
  183. case IMAGETYPE_PNG:
  184. $res2 = imagePNG($image, $newPath);
  185. break;
  186. }
  187. }
  188. }
  189. @chmod($newPath, FILE_PERMISSIONS_MODE);
  190. }
  191. /**
  192. * Returns a path to the specified item, resized and/or cropped to meet max width and height. $obj can either be
  193. * a string (path) or a file object.
  194. * Returns an object with the following properties: src, width, height
  195. * @param mixed $obj
  196. * @param int $maxWidth
  197. * @param int $maxHeight
  198. * @param bool $crop
  199. */
  200. public function getThumbnail($obj, $maxWidth, $maxHeight, $crop = false) {
  201. $fID = false;
  202. if ($obj instanceof File) {
  203. $path = $obj->getPath();
  204. $fID = $obj->getFileID();
  205. } else {
  206. $path = $obj;
  207. }
  208. $fh = Loader::helper('file');
  209. $prefix = $this->jpegCompression . ':'; // Add prefix for compression level to serve the properly compressed images
  210. $prefix .= ($crop ? 'cropped:' : ''); // Name cropped images different from resized images so they don't get mixed up in the cache
  211. if (file_exists($path) && $fID) {
  212. $filename = md5($prefix . $path . ':' . $maxWidth . ':' . $maxHeight . ':' . filemtime($path)) . '_f' . $fID . '.' . $fh->getExtension($path);
  213. } else if (file_exists($path)){
  214. $filename = md5($prefix . $path . ':' . $maxWidth . ':' . $maxHeight . ':' . filemtime($path)) . '.' . $fh->getExtension($path);
  215. } else if ($fID){
  216. // This may be redundant - don't know it can actually ever occur
  217. $filename = md5($prefix . $path . ':' . $maxWidth . ':' . $maxHeight . ':') . '_f' . $fID . '.' . $fh->getExtension($path);
  218. } else {
  219. $filename = md5($prefix . $path . ':' . $maxWidth . ':' . $maxHeight . ':') . '.' . $fh->getExtension($path);
  220. }
  221. if (!file_exists(DIR_FILES_CACHE . '/' . $filename)) {
  222. // create image there
  223. $this->create($path, DIR_FILES_CACHE . '/' . $filename, $maxWidth, $maxHeight, $crop);
  224. }
  225. $src = REL_DIR_FILES_CACHE . '/' . $filename;
  226. $abspath = DIR_FILES_CACHE . '/' . $filename;
  227. $thumb = new stdClass;
  228. if (isset($abspath) && file_exists($abspath)) {
  229. $thumb->src = $src;
  230. $dimensions = getimagesize($abspath);
  231. $thumb->width = $dimensions[0];
  232. $thumb->height = $dimensions[1];
  233. return $thumb;
  234. }
  235. }
  236. /**
  237. * Runs getThumbnail on the path, and then prints it out as an XHTML image
  238. */
  239. public function outputThumbnail($obj, $maxWidth, $maxHeight, $alt = null, $return = false, $crop = false) {
  240. $thumb = $this->getThumbnail($obj, $maxWidth, $maxHeight, $crop);
  241. $html = '<img class="ccm-output-thumbnail" alt="' . $alt . '" src="' . $thumb->src . '" width="' . $thumb->width . '" height="' . $thumb->height . '" />';
  242. if ($return) {
  243. return $html;
  244. } else {
  245. print $html;
  246. }
  247. }
  248. public function output($obj, $alt = null, $return = false) {
  249. $s = @getimagesize($obj->getPath());
  250. $html = '<img class="ccm-output-image" alt="' . $alt . '" src="' . $obj->getRelativePath() . '" width="' . $s[0] . '" height="' . $s[1] . '" />';
  251. if ($return) {
  252. return $html;
  253. } else {
  254. print $html;
  255. }
  256. }
  257. }