Source for file ImageMagick.php

Documentation is available at ImageMagick.php

  1. 1: <?php
  2. 2:  
  3. 3: /**
  4. 4:  * Nette Framework
  5. 5:  *
  6. 6:  * Copyright (c) 2004, 2009 David Grudl (http://davidgrudl.com)
  7. 7:  *
  8. 8:  * This source file is subject to the "Nette license" that is bundled
  9. 9:  * with this package in the file license.txt.
  10. 10:  *
  11. 11:  * For more information please see http://nettephp.com
  12. 12:  *
  13. 13:  * @copyright  Copyright (c) 2004, 2009 David Grudl
  14. 14:  * @license    http://nettephp.com/license  Nette license
  15. 15:  * @link       http://nettephp.com
  16. 16:  * @category   Nette
  17. 17:  * @package    Nette
  18. 18:  */
  19. 19:  
  20. 20:  
  21. 21:  
  22. 22: require_once dirname(__FILE__'/Object.php';
  23. 23:  
  24. 24:  
  25. 25:  
  26. 26: /**
  27. 27:  * Manipulation with large images using ImageMagick.
  28. 28:  *
  29. 29:  * <code>
  30. 30:  * $image = Image::fromFile('bigphoto.jpg');
  31. 31:  * $image->resize(150, 100);
  32. 32:  * $image->sharpen();
  33. 33:  * $image->send();
  34. 34:  * </code>
  35. 35:  *
  36. 36:  * @author     David Grudl
  37. 37:  * @copyright  Copyright (c) 2004, 2009 David Grudl
  38. 38:  * @package    Nette
  39. 39:  */
  40. 40: class ImageMagick extends Image
  41. 41: {
  42. 42:     /** @var string  path to ImageMagick library */
  43. 43:     public static $path '';
  44. 44:  
  45. 45:     /** @var string */
  46. 46:     public static $tempDir;
  47. 47:  
  48. 48:     /** @var string */
  49. 49:     private $file;
  50. 50:  
  51. 51:     /** @var bool */
  52. 52:     private $isTemporary FALSE;
  53. 53:  
  54. 54:     /** @var int */
  55. 55:     private $width;
  56. 56:  
  57. 57:     /** @var int */
  58. 58:     private $height;
  59. 59:  
  60. 60:  
  61. 61:  
  62. 62:     /**
  63. 63:      * Wraps image file.
  64. 64:      * @param  string  detected image format
  65. 65:      * @param  string 
  66. 66:      */
  67. 67:     public function __construct($file$format NULL)
  68. 68:     {
  69. 69:         if (!is_file($file)) {
  70. 70:             throw new InvalidArgumentException('File not found.');
  71. 71:         }
  72. 72:         $format $this->setFile(realpath($file));
  73. 73:         if ($format === 'JPEG'$format self::JPEG;
  74. 74:         elseif ($format === 'PNG'$format self::PNG;
  75. 75:         elseif ($format === 'GIF'$format self::GIF;
  76. 76:     }
  77. 77:  
  78. 78:  
  79. 79:  
  80. 80:     /**
  81. 81:      * Returns image width.
  82. 82:      * @return int 
  83. 83:      */
  84. 84:     public function getWidth()
  85. 85:     {
  86. 86:         return $this->file === NULL parent::getWidth($this->width;
  87. 87:     }
  88. 88:  
  89. 89:  
  90. 90:  
  91. 91:     /**
  92. 92:      * Returns image height.
  93. 93:      * @return int 
  94. 94:      */
  95. 95:     public function getHeight()
  96. 96:     {
  97. 97:         return $this->file === NULL parent::getHeight($this->height;
  98. 98:     }
  99. 99:  
  100. 100:  
  101. 101:  
  102. 102:     /**
  103. 103:      * Returns image GD resource.
  104. 104:      * @return resource 
  105. 105:      */
  106. 106:     public function getImageResource()
  107. 107:     {
  108. 108:         if ($this->file !== NULL{
  109. 109:             if (!$this->isTemporary{
  110. 110:                 $this->execute("convert -strip %input %output"self::PNG);
  111. 111:             }
  112. 112:             $this->setImageResource(imagecreatefrompng($this->file));
  113. 113:             if ($this->isTemporary{
  114. 114:                 unlink($this->file);
  115. 115:             }
  116. 116:             $this->file NULL;
  117. 117:         }
  118. 118:  
  119. 119:         return parent::getImageResource();
  120. 120:     }
  121. 121:  
  122. 122:  
  123. 123:  
  124. 124:     /**
  125. 125:      * Resizes image.
  126. 126:      * @param  mixed  width in pixels or percent
  127. 127:      * @param  mixed  height in pixels or percent
  128. 128:      * @param  int    flags
  129. 129:      * @return ImageMagick  provides a fluent interface
  130. 130:      */
  131. 131:     public function resize($newWidth$newHeight$flags 0)
  132. 132:     {
  133. 133:         if ($this->file === NULL{
  134. 134:             return parent::resize($newWidth$newHeight$flags);
  135. 135:         }
  136. 136:  
  137. 137:         list($newWidth$newHeight$this->calculateSize($newWidth$newHeight$flags);
  138. 138:         $this->execute("convert -resize {$newWidth}x{$newHeight}! -strip %input %output"self::PNG);
  139. 139:         return $this;
  140. 140:     }
  141. 141:  
  142. 142:  
  143. 143:  
  144. 144:     /**
  145. 145:      * Crops image.
  146. 146:      * @param  int  x-coordinate
  147. 147:      * @param  int  y-coordinate
  148. 148:      * @param  int  width
  149. 149:      * @param  int  height
  150. 150:      * @return ImageMagick  provides a fluent interface
  151. 151:      */
  152. 152:     public function crop($left$top$width$height)
  153. 153:     {
  154. 154:         if ($this->file === NULL{
  155. 155:             return parent::crop($left$top$width$height);
  156. 156:         }
  157. 157:  
  158. 158:         $left max(0(int) $left);
  159. 159:         $top max(0(int) $top);
  160. 160:         $width min((int) $width$this->getWidth($left);
  161. 161:         $height min((int) $height$this->getHeight($top);
  162. 162:         $this->execute("convert -crop {$width}x{$height}+{$left}+{$top} -strip %input %output"self::PNG);
  163. 163:         return $this;
  164. 164:     }
  165. 165:  
  166. 166:  
  167. 167:  
  168. 168:     /**
  169. 169:      * Saves image to the file.
  170. 170:      * @param  string  filename
  171. 171:      * @param  int  quality 0..100 (for JPEG and PNG)
  172. 172:      * @param  int  optional image type
  173. 173:      * @return bool TRUE on success or FALSE on failure.
  174. 174:      */
  175. 175:     public function save($file NULL$quality NULL$type NULL)
  176. 176:     {
  177. 177:         if ($this->file === NULL{
  178. 178:             return parent::save($file$quality$type);
  179. 179:         }
  180. 180:  
  181. 181:         $quality $quality === NULL '' '-quality ' max(0min(100(int) $quality));
  182. 182:         if ($file === NULL{
  183. 183:             $this->execute("convert $quality -strip %input %output"$type === NULL self::PNG $type);
  184. 184:             readfile($this->file);
  185. 185:  
  186. 186:         else {
  187. 187:             $this->execute("convert $quality -strip %input %output"(string) $file);
  188. 188:         }
  189. 189:         return TRUE;
  190. 190:     }
  191. 191:  
  192. 192:  
  193. 193:  
  194. 194:     /**
  195. 195:      * Change and identify image file.
  196. 196:      * @param  string  filename
  197. 197:      * @return string  detected image format
  198. 198:      */
  199. 199:     private function setFile($file)
  200. 200:     {
  201. 201:         $this->file $file;
  202. 202:         $res $this->execute('identify -format "%w,%h,%m" ' escapeshellarg($this->file));
  203. 203:         if (!$res{
  204. 204:             throw new Exception("Unknown image type in file '$file' or ImageMagick not available.");
  205. 205:         }
  206. 206:         list($this->width$this->height$formatexplode(','$res3);
  207. 207:         return $format;
  208. 208:     }
  209. 209:  
  210. 210:  
  211. 211:  
  212. 212:     /**
  213. 213:      * Executes command.
  214. 214:      * @param  string  command
  215. 215:      * @param  string|bool process output?
  216. 216:      * @return string 
  217. 217:      */
  218. 218:     private function execute($command$output NULL)
  219. 219:     {
  220. 220:         $command str_replace('%input'escapeshellarg($this->file)$command);
  221. 221:         if ($output{
  222. 222:             $newFile is_string($output)
  223. 223:                 ? $output
  224. 224:                 : (self::$tempDir self::$tempDir dirname($this->file)) '/_tempimage' uniqid(image_type_to_extension($output);
  225. 225:             $command str_replace('%output'escapeshellarg($newFile)$command);
  226. 226:         }
  227. 227:  
  228. 228:         $lines array();
  229. 229:         exec(self::$path $command$lines$status)// $status: 0 - ok, 1 - error, 127 - command not found?
  230. 230:  
  231. 231:         if ($output{
  232. 232:             if ($status != 0{
  233. 233:                 throw new Exception("Unknown error while calling ImageMagick.");
  234. 234:             }
  235. 235:             if ($this->isTemporary{
  236. 236:                 unlink($this->file);
  237. 237:             }
  238. 238:             $this->setFile($newFile);
  239. 239:             $this->isTemporary !is_string($output);
  240. 240:         }
  241. 241:  
  242. 242:         return $lines $lines[0FALSE;
  243. 243:     }
  244. 244:  
  245. 245:  
  246. 246:  
  247. 247:     /**
  248. 248:      * Delete temporary files.
  249. 249:      * @return void 
  250. 250:      */
  251. 251:     public function __destruct()
  252. 252:     {
  253. 253:         if ($this->file !== NULL && $this->isTemporary{
  254. 254:             unlink($this->file);
  255. 255:         }
  256. 256:     }
  257. 257: