PageRenderTime 48ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/etc/apps/webmail/program/lib/Roundcube/rcube_image.php

https://github.com/raiman264/zpanelx
PHP | 321 lines | 205 code | 46 blank | 70 comment | 75 complexity | 10808c2b3a07ccca32b3da5becc11ee2 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-3.0, LGPL-2.1, CC-BY-SA-4.0, GPL-3.0
  1. <?php
  2. /*
  3. +-----------------------------------------------------------------------+
  4. | This file is part of the Roundcube Webmail client |
  5. | Copyright (C) 2005-2012, The Roundcube Dev Team |
  6. | Copyright (C) 2011-2012, Kolab Systems AG |
  7. | |
  8. | Licensed under the GNU General Public License version 3 or |
  9. | any later version with exceptions for skins & plugins. |
  10. | See the README file for a full license statement. |
  11. | |
  12. | PURPOSE: |
  13. | Image resizer and converter |
  14. +-----------------------------------------------------------------------+
  15. | Author: Thomas Bruederli <roundcube@gmail.com> |
  16. | Author: Aleksander Machniak <alec@alec.pl> |
  17. +-----------------------------------------------------------------------+
  18. */
  19. /**
  20. * Image resizer and converter
  21. *
  22. * @package Framework
  23. * @subpackage Utils
  24. */
  25. class rcube_image
  26. {
  27. private $image_file;
  28. const TYPE_GIF = 1;
  29. const TYPE_JPG = 2;
  30. const TYPE_PNG = 3;
  31. const TYPE_TIF = 4;
  32. public static $extensions = array(
  33. self::TYPE_GIF => 'gif',
  34. self::TYPE_JPG => 'jpg',
  35. self::TYPE_PNG => 'png',
  36. self::TYPE_TIF => 'tif',
  37. );
  38. function __construct($filename)
  39. {
  40. $this->image_file = $filename;
  41. }
  42. /**
  43. * Get image properties.
  44. *
  45. * @return mixed Hash array with image props like type, width, height
  46. */
  47. public function props()
  48. {
  49. // use GD extension
  50. if (function_exists('getimagesize') && ($imsize = @getimagesize($this->image_file))) {
  51. $width = $imsize[0];
  52. $height = $imsize[1];
  53. $gd_type = $imsize['2'];
  54. $type = image_type_to_extension($imsize['2'], false);
  55. }
  56. // use ImageMagick
  57. if (!$type && ($data = $this->identify())) {
  58. list($type, $width, $height) = $data;
  59. }
  60. if ($type) {
  61. return array(
  62. 'type' => $type,
  63. 'gd_type' => $gd_type,
  64. 'width' => $width,
  65. 'height' => $height,
  66. );
  67. }
  68. }
  69. /**
  70. * Resize image to a given size. Use only to shrink an image.
  71. * If an image is smaller than specified size it will be not resized.
  72. *
  73. * @param int $size Max width/height size
  74. * @param string $filename Output filename
  75. * @param boolean $browser_compat Convert to image type displayable by any browser
  76. *
  77. * @return mixed Output type on success, False on failure
  78. */
  79. public function resize($size, $filename = null, $browser_compat = false)
  80. {
  81. $result = false;
  82. $rcube = rcube::get_instance();
  83. $convert = $rcube->config->get('im_convert_path', false);
  84. $props = $this->props();
  85. if (empty($props)) {
  86. return false;
  87. }
  88. if (!$filename) {
  89. $filename = $this->image_file;
  90. }
  91. // use Imagemagick
  92. if ($convert) {
  93. $p['out'] = $filename;
  94. $p['in'] = $this->image_file;
  95. $type = $props['type'];
  96. if (!$type && ($data = $this->identify())) {
  97. $type = $data[0];
  98. }
  99. $type = strtr($type, array("jpeg" => "jpg", "tiff" => "tif", "ps" => "eps", "ept" => "eps"));
  100. $p['intype'] = $type;
  101. // convert to an image format every browser can display
  102. if ($browser_compat && !in_array($type, array('jpg','gif','png'))) {
  103. $type = 'jpg';
  104. }
  105. // If only one dimension is greater than the limit convert doesn't
  106. // work as expected, we need to calculate new dimensions
  107. $scale = $size / max($props['width'], $props['height']);
  108. // if file is smaller than the limit, we do nothing
  109. // but copy original file to destination file
  110. if ($scale >= 1 && $p['intype'] == $type) {
  111. $result = ($this->image_file == $filename || copy($this->image_file, $filename)) ? '' : false;
  112. }
  113. else {
  114. if ($scale >= 1) {
  115. $width = $props['width'];
  116. $height = $props['height'];
  117. }
  118. else {
  119. $width = intval($props['width'] * $scale);
  120. $height = intval($props['height'] * $scale);
  121. }
  122. $valid_types = "bmp,eps,gif,jp2,jpg,png,svg,tif";
  123. $p += array(
  124. 'type' => $type,
  125. 'quality' => 75,
  126. 'size' => $width . 'x' . $height,
  127. );
  128. if (in_array($type, explode(',', $valid_types))) { // Valid type?
  129. $result = rcube::exec($convert . ' 2>&1 -flatten -auto-orient -colorspace sRGB -strip'
  130. . ' -quality {quality} -resize {size} {intype}:{in} {type}:{out}', $p);
  131. }
  132. }
  133. if ($result === '') {
  134. @chmod($filename, 0600);
  135. return $type;
  136. }
  137. }
  138. // use GD extension
  139. if ($props['gd_type']) {
  140. if ($props['gd_type'] == IMAGETYPE_JPEG && function_exists('imagecreatefromjpeg')) {
  141. $image = imagecreatefromjpeg($this->image_file);
  142. $type = 'jpg';
  143. }
  144. else if($props['gd_type'] == IMAGETYPE_GIF && function_exists('imagecreatefromgif')) {
  145. $image = imagecreatefromgif($this->image_file);
  146. $type = 'gid';
  147. }
  148. else if($props['gd_type'] == IMAGETYPE_PNG && function_exists('imagecreatefrompng')) {
  149. $image = imagecreatefrompng($this->image_file);
  150. $type = 'png';
  151. }
  152. else {
  153. // @TODO: print error to the log?
  154. return false;
  155. }
  156. if ($image === false) {
  157. return false;
  158. }
  159. $scale = $size / max($props['width'], $props['height']);
  160. // Imagemagick resize is implemented in shrinking mode (see -resize argument above)
  161. // we do the same here, if an image is smaller than specified size
  162. // we do nothing but copy original file to destination file
  163. if ($scale >= 1) {
  164. $result = $this->image_file == $filename || copy($this->image_file, $filename);
  165. }
  166. else {
  167. $width = intval($props['width'] * $scale);
  168. $height = intval($props['height'] * $scale);
  169. $new_image = imagecreatetruecolor($width, $height);
  170. // Fix transparency of gif/png image
  171. if ($props['gd_type'] != IMAGETYPE_JPEG) {
  172. imagealphablending($new_image, false);
  173. imagesavealpha($new_image, true);
  174. $transparent = imagecolorallocatealpha($new_image, 255, 255, 255, 127);
  175. imagefilledrectangle($new_image, 0, 0, $width, $height, $transparent);
  176. }
  177. imagecopyresampled($new_image, $image, 0, 0, 0, 0, $width, $height, $props['width'], $props['height']);
  178. $image = $new_image;
  179. if ($props['gd_type'] == IMAGETYPE_JPEG) {
  180. $result = imagejpeg($image, $filename, 75);
  181. }
  182. elseif($props['gd_type'] == IMAGETYPE_GIF) {
  183. $result = imagegif($image, $filename);
  184. }
  185. elseif($props['gd_type'] == IMAGETYPE_PNG) {
  186. $result = imagepng($image, $filename, 6, PNG_ALL_FILTERS);
  187. }
  188. }
  189. if ($result) {
  190. @chmod($filename, 0600);
  191. return $type;
  192. }
  193. }
  194. // @TODO: print error to the log?
  195. return false;
  196. }
  197. /**
  198. * Convert image to a given type
  199. *
  200. * @param int $type Destination file type (see class constants)
  201. * @param string $filename Output filename (if empty, original file will be used
  202. * and filename extension will be modified)
  203. *
  204. * @return bool True on success, False on failure
  205. */
  206. public function convert($type, $filename = null)
  207. {
  208. $rcube = rcube::get_instance();
  209. $convert = $rcube->config->get('im_convert_path', false);
  210. if (!$filename) {
  211. $filename = $this->image_file;
  212. // modify extension
  213. if ($extension = self::$extensions[$type]) {
  214. $filename = preg_replace('/\.[^.]+$/', '', $filename) . '.' . $extension;
  215. }
  216. }
  217. // use ImageMagick
  218. if ($convert) {
  219. $p['in'] = $this->image_file;
  220. $p['out'] = $filename;
  221. $p['type'] = self::$extensions[$type];
  222. $result = rcube::exec($convert . ' 2>&1 -colorspace sRGB -strip -quality 75 {in} {type}:{out}', $p);
  223. if ($result === '') {
  224. @chmod($filename, 0600);
  225. return true;
  226. }
  227. }
  228. // use GD extension (TIFF isn't supported)
  229. $props = $this->props();
  230. if ($props['gd_type']) {
  231. if ($props['gd_type'] == IMAGETYPE_JPEG && function_exists('imagecreatefromjpeg')) {
  232. $image = imagecreatefromjpeg($this->image_file);
  233. }
  234. else if ($props['gd_type'] == IMAGETYPE_GIF && function_exists('imagecreatefromgif')) {
  235. $image = imagecreatefromgif($this->image_file);
  236. }
  237. else if ($props['gd_type'] == IMAGETYPE_PNG && function_exists('imagecreatefrompng')) {
  238. $image = imagecreatefrompng($this->image_file);
  239. }
  240. else {
  241. // @TODO: print error to the log?
  242. return false;
  243. }
  244. if ($type == self::TYPE_JPG) {
  245. $result = imagejpeg($image, $filename, 75);
  246. }
  247. else if ($type == self::TYPE_GIF) {
  248. $result = imagegif($image, $filename);
  249. }
  250. else if ($type == self::TYPE_PNG) {
  251. $result = imagepng($image, $filename, 6, PNG_ALL_FILTERS);
  252. }
  253. if ($result) {
  254. @chmod($filename, 0600);
  255. return true;
  256. }
  257. }
  258. // @TODO: print error to the log?
  259. return false;
  260. }
  261. /**
  262. * Identify command handler.
  263. */
  264. private function identify()
  265. {
  266. $rcube = rcube::get_instance();
  267. if ($cmd = $rcube->config->get('im_identify_path')) {
  268. $args = array('in' => $this->image_file, 'format' => "%m %[fx:w] %[fx:h]");
  269. $id = rcube::exec($cmd. ' 2>/dev/null -format {format} {in}', $args);
  270. if ($id) {
  271. return explode(' ', strtolower($id));
  272. }
  273. }
  274. }
  275. }