## Apache Zeta Components Manual :: File Source for imagemagick_base.php

## Source for file imagemagick_base.php

Documentation is available at imagemagick_base.php

1. <?php
2. /**
3. * This file contains the ezcImageImagemagickBaseHandler class.
4. *
5. * Licensed to the Apache Software Foundation (ASF) under one
6. * or more contributor license agreements. See the NOTICE file
7. * distributed with this work for additional information
8. * regarding copyright ownership. The ASF licenses this file
9. * to you under the Apache License, Version 2.0 (the
10. * "License"); you may not use this file except in compliance
11. * with the License. You may obtain a copy of the License at
12. *
13. * http://www.apache.org/licenses/LICENSE-2.0
14. *
15. * Unless required by applicable law or agreed to in writing,
16. * software distributed under the License is distributed on an
17. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18. * KIND, either express or implied. See the License for the
19. * specific language governing permissions and limitations
20. * under the License.
21. *
22. * @package ImageConversion
23. * @version //autogentag//
24. * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
25. * @filesource
26. */
29. /**
30. * ezcImageHandler implementation for ImageMagick.
31. * This class only implements the base funtionality of handling images with
32. * ImageMagick. If you want to manipulate images using ImageMagick in your
33. * application, you should use the {@link ezcImageImagemagickHandler}.
34. *
35. * You can use this base class to implement your own filter set on basis of
36. * ImageMagick, but you can also use {@link ezcImageImagemagickHandler} for
37. * this and profit from its already implemented filters.
38. *
39. * @see ezcImageConverter
40. * @see ezcImageHandler
41. *
42. * @package ImageConversion
43. * @version //autogentag//
44. */
45. class ezcImageImagemagickBaseHandler extends ezcImageMethodcallHandler
46. {
47. /**
48. * Path to the convert binary.
49. *
50. * @var string
51. */
52. private $binary;
54. /**
55. * Map of MIME types to convert tags.
56. *
57. * @var array(string=>string)
58. */
59. private $tagMap = array();
61. /**
62. * Filter options per reference.
63. *
64. * @var array(string=>array)
65. */
66. private $filterOptions = array();
68. /**
69. * Composite image setting per reference.
70. *
71. * @var array(string=>bool)
72. */
73. private $compositeImages = array();
75. /**
76. * Create a new image handler.
77. * Creates an image handler. This should never be done directly,
78. * but only through the manager for configuration reasons. One can
79. * get a direct reference through manager afterwards.
80. *
81. * This handler has an option 'binary' available, which allows you to
82. * explicitly set the path to your ImageMagicks "convert" binary (this
83. * may be necessary on Windows, since there may be an obscure "convert.exe"
84. * in the $PATH variable available, which has nothing to do with
85. * ImageMagick).
86. *
87. * @throws ezcImageHandlerNotAvailableException
88. * If the ImageMagick binary is not found.
89. *
90. * @param ezcImageHandlerSettings $settings Settings for the handler.
91. */
92. public function __construct ( ezcImageHandlerSettings $settings )
93. {
94. // Check for ImageMagick
95. $this->checkImageMagick( $settings );
96. $this->determineTypes();
97. parent::__construct( $settings );
98. }
100. /**
101. * Load an image file.
102. * Loads an image file and returns a reference to it.
103. *
104. * @param string $file File to load.
105. * @param string $mime The MIME type of the file.
106. *
107. * @return string Reference to the file in this handler.
108. *
109. * @see ezcImageAnalyzer
110. *
111. * @throws ezcBaseFileNotFoundException
112. * If the desired file does not exist.
113. * @throws ezcImageMimeTypeUnsupportedException
114. * If the desired file has a not recognized type.
115. * @throws ezcImageFileNameInvalidException
116. * If an invalid character (", ', $) is found in the file name.
117. */
118. public function load ( $file, $mime = null )
119. {
120. $this->checkFileName( $file );
121. $ref = $this->loadCommon( $file, $mime );
123. // Atomic file operation
124. $fileTmp = tempnam ( dirname ( $file ) . DIRECTORY_SEPARATOR, '.' . basename ( $file ) );
125. copy ( $file, $fileTmp );
127. $this->setReferenceData( $ref, $fileTmp, 'resource' );
128. return $ref;
129. }
131. /**
132. * Save an image file.
133. * Saves a given open file. Can optionally save to a new file name.
134. *
135. * @see ezcImageHandler::load()
136. *
137. * @param string $image File reference created through load().
138. * @param string $newFile Filename to save the image to.
139. * @param string $mime New MIME type, if differs from initial one.
140. * @param ezcImageSaveOptions $options Save options.
141. * @return void
142. *
143. * @throws ezcBaseFilePermissionException
144. * If the desired file exists and is not writeable.
145. * @throws ezcImageMimeTypeUnsupportedException
146. * If the desired MIME type is not recognized.
147. * @throws ezcImageFileNameInvalidException
148. * If an invalid character (", ', $) is found in the file name.
149. */
150. public function save ( $image, $newFile = null, $mime = null, ezcImageSaveOptions $options = null )
151. {
152. if ( $options === null )
153. {
154. $options = new ezcImageSaveOptions ();
155. }
157. if ( $newFile !== null )
158. {
159. $this->checkFileName( $newFile );
160. }
162. // Check is transparency must be converted
163. if ( $this->needsTransparencyConversion( $this->getReferenceData( $image, 'mime' ), $mime ) && $options->transparencyReplacementColor !== null )
164. {
165. $this-> addFilterOption ( $image, '-background', $this-> colorArrayToString ( $options->transparencyReplacementColor ) );
166. $this-> addFilterOption ( $image, '-flatten' );
167. }
169. $this->saveCommon( $image, $newFile, $mime );
171. switch ( $this->getReferenceData( $image, 'mime' ) )
172. {
173. case "image/jpeg":
174. if ( $options->quality !== null )
175. {
176. $this-> addFilterOption ( $image, "-quality", $options->quality );
177. }
178. break;
179. case "image/png":
180. if ( $options->compression !== null )
181. {
182. // ImageMagick uses qualtiy options here and incorporates filter options
183. $this-> addFilterOption ( $image, "-quality", $options->compression * 10 );
184. }
185. break;
186. }
188. // Prepare ImageMagick command
189. // Here we need a work around, because older ImageMagick versions do not
190. // support this option order
192. if ( isset( $this->compositeImages[$image] ) )
193. {
194. $command = $this->binary . ' ' .
195. ( isset( $this->filterOptions[$image] ) ? implode ( ' ', $this->filterOptions[$image] ) : '' ) . ' ' .
196. escapeshellarg ( $this->getReferenceData( $image, 'resource' ) ) . ' ' .
197. implode ( ' ', $this->compositeImages[$image] ) . ' ' .
198. escapeshellarg ( $this->tagMap[$this->getReferenceData( $image, 'mime' )] . ':' . $this->getReferenceData( $image, 'resource' ) );
199. }
200. else
201. {
202. $command = $this->binary . ' ' .
203. escapeshellarg ( $this->getReferenceData( $image, 'resource' ) ) . ' ' .
204. ( isset( $this->filterOptions[$image] ) ? implode ( ' ', $this->filterOptions[$image] ) : '' ) . ' ' .
205. escapeshellarg ( $this->tagMap[$this->getReferenceData( $image, 'mime' )] . ':' . $this->getReferenceData( $image, 'resource' ) );
206. }
209. // Prepare to run ImageMagick command
210. $descriptors = array(
211. array( 'pipe', 'r' ),
212. array( 'pipe', 'w' ),
213. array( 'pipe', 'w' ),
214. );
216. // Open ImageMagick process
217. $imageProcess = proc_open ( $command, $descriptors, $pipes );
218. // Close STDIN pipe
219. fclose ( $pipes[0] );
221. $errorString = '';
222. $outputString = '';
223. // Read STDERR
224. do
225. {
226. $outputString .= rtrim ( fgets ( $pipes[1], 1024 ), "\n" );
227. $errorString .= rtrim ( fgets ( $pipes[2], 1024 ), "\n" );
228. } while ( ! feof ( $pipes[2] ) );
230. // Wait for process to terminate and store return value
231. $status = proc_get_status ( $imageProcess );
232. while ( $status['running'] !== false )
233. {
234. // Sleep 1/100 second to wait for convert to exit
235. usleep ( 10000 );
236. $status = proc_get_status ( $imageProcess );
237. }
238. $return = proc_close ( $imageProcess );
240. // Process potential errors
241. // Exit code may be messed up with -1, especially on Windoze
242. if ( ( $status['exitcode'] != 0 && $status['exitcode'] != -1 ) || strlen ( $errorString ) > 0 )
243. {
244. throw new ezcImageFileNotProcessableException (
245. $this->getReferenceData( $image, 'resource' ),
246. "The command '{$command}' resulted in an error ({$status['exitcode']}): '{$errorString}'. Output: '{$outputString}'"
247. );
248. }
249. // Finish atomic file operation
250. copy ( $this->getReferenceData( $image, 'resource' ), $this->getReferenceData( $image, 'file' ) );
251. }
253. /**
254. * Returns a string representation of the given color array.
255. *
256. * ImageConversion uses arrays to represent color values, in the format:
257. * <code>
258. * array(
259. * 255,
260. * 0,
261. * 0,
262. * )
263. * </code>
264. * This array represents the color red.
265. *
266. * This method takes such a color array and converts it into a string
267. * representation usable by the convert binary. For the above examle it
268. * would be '#FF0000'.
269. *
270. * @param array $color
271. * @return void
272. *
273. * @throws ezcBaseValueException
274. * if one of the color values in the array is invalid (not integer,
275. * smaller than 0 or larger than 255).
276. */
277. protected function colorArrayToString ( array $color )
278. {
279. $colorString = '#';
280. $i = 0;
281. foreach ( $color as $id => $colorVal )
282. {
283. if ( $i++ > 2 )
284. {
285. break;
286. }
287. if ( ! is_int ( $colorVal ) || $colorVal < 0 || $colorVal > 255 )
288. {
289. throw new ezcBaseValueException ( "color[$id]", $color[$id], 'int > 0 and < 256' );
290. }
291. $colorString .= sprintf ( '%02x', $colorVal );
292. }
293. return $colorString;
294. }
296. /**
297. * Close the file referenced by $image.
298. * Frees the image reference. You should call close() before.
299. *
300. * @see ezcImageHandler::load()
301. * @see ezcImageHandler::save()
302. * @param string $image The image reference.
303. */
304. public function close ( $image )
305. {
306. unlink ( $this->getReferenceData( $image, 'resource' ) );
307. $this->setReferenceData( $image, false, 'resource' );
308. $this->closeCommon( $image );
309. }
311. /**
312. * Add a filter option to a given reference
313. *
314. * @param string $reference The reference to add a filter for.
315. * @param string $name The option name.
316. * @param string $parameter The option parameter.
317. * @return void
318. */
319. protected function addFilterOption ( $reference, $name, $parameter = null )
320. {
321. $this->filterOptions[$reference][] = $name . ( $parameter !== null ? ' ' . escapeshellarg ( $parameter ) : '' );
322. }
324. /**
325. * Add an image to composite with the given reference.
326. *
327. * @param string $reference The reference to add an image to
328. * @param string $file The file to composite with the image.
329. * @return void
330. */
331. protected function addCompositeImage ( $reference, $file )
332. {
333. $this->compositeImages[$reference][] = $file;
334. }
336. /**
337. * Determines the supported input/output types supported by handler.
338. * Set's various attributes to reflect the MIME types this handler is
339. * capable to process.
340. *
341. * @return void
342. *
343. * @apichange Faulty MIME type "image/svg" will be removed and replaced by
344. * correct MIME type image/svg+xml.
345. */
346. private function determineTypes()
347. {
348. $tagMap = array(
349. 'application/pcl' => 'PCL',
350. 'application/pdf' => 'PDF',
351. 'application/postscript' => 'PS',
352. 'application/vnd.palm' => 'PDB',
353. 'application/x-icb' => 'ICB',
354. 'application/x-mif' => 'MIFF',
355. 'image/bmp' => 'BMP3',
356. 'image/dcx' => 'DCX',
357. 'image/g3fax' => 'G3',
358. 'image/gif' => 'GIF',
359. 'image/jng' => 'JNG',
360. 'image/jpeg' => 'JPG',
361. 'image/pbm' => 'PBM',
362. 'image/pcd' => 'PCD',
363. 'image/pict' => 'PCT',
364. 'image/pjpeg' => 'PJPEG',
365. 'image/png' => 'PNG',
366. 'image/ras' => 'RAS',
367. 'image/sgi' => 'SGI',
368. 'image/svg+xml' => 'SVG',
369. // Left over for BC reasons
370. 'image/svg' => 'SVG',
371. 'image/tga' => 'TGA',
372. 'image/tiff' => 'TIF',
373. 'image/vda' => 'VDA',
374. 'image/vnd.wap.wbmp' => 'WBMP',
375. 'image/vst' => 'VST',
376. 'image/x-fits' => 'FITS',
377. 'image/x-otb' => 'OTB',
378. 'image/x-palm' => 'PALM',
379. 'image/x-pcx' => 'PCX',
380. 'image/x-pgm' => 'PGM',
381. 'image/psd' => 'PSD',
382. 'image/x-ppm' => 'PPM',
383. 'image/x-ptiff' => 'PTIF',
384. 'image/x-viff' => 'VIFF',
385. 'image/x-xbitmap' => 'XPM',
386. 'image/x-xv' => 'P7',
387. 'image/xpm' => 'PICON',
388. 'image/xwd' => 'XWD',
389. 'text/plain' => 'TXT',
390. 'video/mng' => 'MNG',
391. 'video/mpeg' => 'MPEG',
392. 'video/mpeg2' => 'M2V',
393. );
394. $types = array_keys ( $tagMap );
395. $this->inputTypes = $types;
396. $this->outputTypes = $types;
397. $this->tagMap = $tagMap;
398. }
400. /**
401. * Checks for ImageMagick on the system.
402. *
403. * @param ezcImageHandlerSettings $settings The settings object of the current handler instance.
404. * @return void
405. *
406. * @throws ezcImageHandlerNotAvailableException
407. * If the ImageMagick binary is not found.
408. */
409. private function checkImageMagick( ezcImageHandlerSettings $settings )
410. {
411. if ( !isset( $settings->options['binary'] ) )
412. {
413. $this->binary = ezcBaseFeatures :: getImageConvertExecutable ();
414. }
415. else if ( file_exists ( $settings->options['binary'] ) )
416. {
417. $this->binary = $settings->options['binary'];
418. }
420. if ( $this->binary === null )
421. {
422. throw new ezcImageHandlerNotAvailableException (
423. 'ezcImageImagemagickHandler',
424. 'ImageMagick not installed or not available in PATH variable.'
425. );
426. }
428. // Prepare to run ImageMagick command
429. $descriptors = array(
430. array( 'pipe', 'r' ),
431. array( 'pipe', 'w' ),
432. array( 'pipe', 'w' ),
433. );
435. // Open ImageMagick process
436. $imageProcess = proc_open ( $this->binary, $descriptors, $pipes );
438. // Close STDIN pipe
439. fclose ( $pipes[0] );
441. $outputString = '';
442. // Read STDOUT
443. do
444. {
445. $outputString .= rtrim ( fgets ( $pipes[1], 1024 ), "\n" );
446. } while ( ! feof ( $pipes[1] ) );
448. $errorString = '';
449. // Read STDERR
450. do
451. {
452. $errorString .= rtrim ( fgets ( $pipes[2], 1024 ), "\n" );
453. } while ( ! feof ( $pipes[2] ) );
455. // Wait for process to terminate and store return value
456. $return = proc_close ( $imageProcess );
458. // Process potential errors
459. if ( strlen ( $errorString ) > 0 || strpos ( $outputString, 'ImageMagick' ) === false )
460. {
461. throw new ezcImageHandlerNotAvailableException ( 'ezcImageImagemagickHandler', 'ImageMagick not installed or not available in PATH variable.' );
462. }
463. }
465. /**
466. * Creates default settings for the handler and returns it.
467. * The reference name will be set to 'ImageMagick'.
468. *
469. * @return ezcImageHandlerSettings
470. */
471. static public function defaultSettings ()
472. {
473. return new ezcImageHandlerSettings ( 'ImageMagick', 'ezcImageImagemagickHandler' );
474. }
475. }
477. ?>

Documentation generated by phpDocumentor 1.4.3