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

## Source for file php.php

Documentation is available at php.php

1. <?php
2. /**
3. * File containing the ezcImageAnalyzerPhpHandler 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 ImageAnalysis
23. * @version //autogentag//
24. * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
25. * @filesource
26. */
28. /**
29. * Class to retrieve information about a given image file.
30. * This handler implements image analyzation using direct PHP functionality,
31. * mainly the {@link getimagesize()} function and, if available, the EXIF
32. * extension {@link exif_read_data()}. The driver is capable of determining
33. * the type the following file formats:
34. *
35. * - GIF
36. * - JPG
37. * - PNG
38. * - SWF
39. * - SWC
40. * - PSD
41. * - TIFF
42. * - BMP
43. * - IFF
44. * - JP2
45. * - JPX
46. * - JB2
47. * - JPC
48. * - XBM
49. * - WBMP
50. *
51. * The driver determines the MIME type of these images (using the
52. * {@link ezcImageAnalyzerPhpHandler::analyzeType()} method). The width,
53. * height and size of the given image are always available after analyzing a
54. * file, if the file in general can be analyzed
55. * {@link ezcImageAnalyzerPhpHandler::canAnalyze()}.
56. *
57. * For JPEG and TIFF images this driver will try to read in information using
58. * the EXIF extension in PHP and fills in the following properties of the
59. * {@link ezcImageAnalyzerData} struct, returned by the
60. * {@link ezcImageAnalyzerPhpHandler::analyzeImage()} method:
61. * - exif
62. * - isColor
63. * - comment
64. * - copyright
65. * - date
66. * - hasThumbnail
67. * - isAnimated
68. *
69. * For GIF (also animated) it finds information by scanning the file manually
70. * and fills in the following properties of the
71. * {@link ezcImageAnalyzerData} struct, returned by the
72. * {@link ezcImageAnalyzerPhpHandler::analyzeImage()} method:
73. * - mode
74. * - transparencyType
75. * - comment
76. * - commentList
77. * - colorCount
78. * - isAnimated
79. *
80. * @package ImageAnalysis
81. * @version //autogentag//
82. */
83. class ezcImageAnalyzerPhpHandler extends ezcImageAnalyzerHandler
84. {
85. /**
86. * Analyzes the image type.
87. *
88. * This method analyzes image data to determine the MIME type. This method
89. * returns the MIME type of the file to analyze in lowercase letters (e.g.
90. * "image/jpeg") or false, if the images MIME type could not be determined.
91. *
92. * For a list of image types this handler will be able to analyze, see
93. * {@link ezcImageAnalyzerPhpHandler}.
94. *
95. * @param string $file The file to analyze.
96. * @return string|boolThe MIME type if analyzation suceeded or false.
97. */
98. public function analyzeType ( $file )
99. {
100. $data = getimagesize ( $file );
101. if ( $data === false )
102. {
103. return false;
104. }
105. return image_type_to_mime_type ( $data[2] );
106. }
108. /**
109. * Analyze the image for detailed information.
110. *
111. * This may return various information about the image, depending on it's
112. * type. All information is collected in the struct
113. * {@link ezcImageAnalyzerData}. At least the
114. * {@link ezcImageAnalyzerData::$mime} attribute is always available, if the
115. * image type can be analyzed at all. Additionally this handler will always
116. * set the {@link ezcImageAnalyzerData::$width},
117. * {@link ezcImageAnalyzerData::$height} and
118. * {@link ezcImageAnalyzerData::$size} attributes. For detailes information
119. * on the additional data returned, see {@link ezcImageAnalyzerPhpHandler}.
120. *
121. * @throws ezcImageAnalyzerFileNotProcessableException
122. * If image file can not be processed.
123. * @param string $file The file to analyze.
124. * @return ezcImageAnalyzerData
125. */
126. public function analyzeImage ( $file )
127. {
128. $data = getimagesize ( $file );
129. if ( $data === false )
130. {
131. throw new ezcImageAnalyzerFileNotProcessableException (
132. $file,
133. 'getimagesize() returned false.'
134. );
135. }
137. $dataStruct = new ezcImageAnalyzerData ();
138. $dataStruct->width = $data[0];
139. $dataStruct->height = $data[1];
140. $dataStruct->mime = image_type_to_mime_type ( $data[2] );
141. $dataStruct->size = filesize ( $file );
143. if ( ( $dataStruct->mime === 'image/jpeg' || $dataStruct->mime === 'image/tiff' )
144. && ezcBaseFeatures :: hasFunction ( 'exif_read_data')
145. )
146. {
147. $this->analyzeExif( $file, $dataStruct );
148. }
149. elseif ( $dataStruct->mime === 'image/gif' )
150. {
151. $this->analyzeGif( $file, $dataStruct );
152. }
154. return $dataStruct;
155. }
157. /**
158. * Returns if the handler can analyze a given MIME type.
159. *
160. * This method returns if the driver is capable of analyzing a given MIME
161. * type. This method should be called before trying to actually analyze an
162. * image using the drivers {@link self::analyzeImage()} method.
163. *
164. * @param string $mime The MIME type to check for.
165. * @return bool True if the handler is able to analyze the MIME type.
166. */
167. public function canAnalyze ( $mime )
168. {
169. switch ( $mime )
170. {
171. case 'image/gif':
172. case 'image/jpeg':
173. case 'image/png':
174. case 'image/psd':
175. case 'image/bmp':
176. case 'image/tiff':
177. case 'image/tiff':
178. case 'image/jp2':
179. case 'application/x-shockwave-flash':
180. case 'image/iff':
181. case 'image/vnd.wap.wbmp':
182. case 'image/xbm':
183. return true;
184. }
185. return false;
186. }
188. /**
189. * Checks wether the GD handler is available on the system.
190. *
191. * Returns if PHP's {@link getimagesize()} function is available.
192. *
193. * @return bool True is the handler is available.
194. */
195. public function isAvailable ()
196. {
197. return ezcBaseFeatures :: hasFunction ( 'getimagesize' );
198. }
200. /**
201. * Analyze EXIF enabled file format for EXIF data entries.
202. *
203. * The image file is analyzed by calling exif_read_data and placing the
204. * result in self::exif. In addition it fills in extra properties from
205. * the EXIF data for easy and uniform access.
206. *
207. * @param string $file The file to analyze.
208. * @param ezcImageAnalyzerData $dataStruct The data struct to fill.
209. * @return ezcImageAnalyzerData The filled data struct.
210. */
211. private function analyzeExif( $file, ezcImageAnalyzerData $dataStruct )
212. {
213. $dataStruct->exif = exif_read_data ( $file, "COMPUTED,FILE", true, false );
215. // Section "COMPUTED"
216. if ( isset( $dataStruct->exif['COMPUTED']['Width'] ) && isset( $dataStruct->exif['COMPUTED']['Height'] ) )
217. {
218. $dataStruct->width = $dataStruct->exif['COMPUTED']['Width'];
219. $dataStruct->height = $dataStruct->exif['COMPUTED']['Height'];
220. }
221. if ( isset( $dataStruct->exif['COMPUTED']['IsColor'] ) )
222. {
223. $dataStruct->isColor = $dataStruct->exif['COMPUTED']['IsColor'] == 1;
224. }
225. if ( isset( $dataStruct->exif['COMPUTED']['UserComment'] ) )
226. {
227. $dataStruct->comment = $dataStruct->exif['COMPUTED']['UserComment'];
228. $dataStruct->commentList = array( $dataStruct->comment );
229. }
230. if ( isset( $dataStruct->exif['COMPUTED']['Copyright'] ) )
231. {
232. $dataStruct->copyright = $dataStruct->exif['COMPUTED']['Copyright'];
233. }
235. // Section THUMBNAIL
236. $dataStruct->hasThumbnail = isset( $dataStruct->exif['THUMBNAIL'] );
238. // Section "FILE"
239. if ( isset( $dataStruct->exif['FILE']['FileSize'] ) )
240. {
241. $dataStruct->size = $dataStruct->exif['FILE']['FileSize'];
242. }
243. if ( isset( $dataStruct->exif['FILE']['FileDateTime'] ) )
244. {
245. $dataStruct->date = $dataStruct->exif['FILE']['FileDateTime'];
246. }
248. // EXIF based image are never animated.
249. $dataStruct->isAnimated = false;
251. return $dataStruct;
252. }
254. /**
255. * Analyze GIF files for detailed information.
256. *
257. * The GIF file is analyzed by scanning for frame entries, if more than one
258. * is found it is assumed to be animated.
259. * It also extracts other information such as image width and height, color
260. * count, image mode, transparency type and comments.
261. *
262. * @throws ezcBaseFileIoException
263. * If image file could not be read.
264. * @throws ezcImageAnalyzerFileNotProcessableException
265. * If image file can not be processed.
266. * @param string $file The file to analyze.
267. * @param ezcImageAnalyzerData $dataStruct The data struct to fill.
268. * @return ezcImageAnalyzerData The filled data struct.
269. */
270. private function analyzeGif( $file, ezcImageAnalyzerData $dataStruct )
271. {
272. if ( ( $fp = fopen ( $file, 'rb' ) ) === false )
273. {
274. throw new ezcBaseFileIoException ( $file, ezcBaseFileException ::READ );
275. }
277. // Read GIF header
278. $magic = fread ( $fp, 6 );
279. $offset = 6;
280. if ( $magic != 'GIF87a' &&
281. $magic != 'GIF89a' )
282. {
283. throw new ezcImageAnalyzerFileNotProcessableException ( $file, 'Not a valid GIF image file' );
284. }
286. $info = array();
288. $version = substr ( $magic, 3 );
289. $frames = 0;
290. // Gifs are always indexed
291. $dataStruct->mode = self::MODE_INDEXED;
292. $dataStruct->commentList = array();
293. $dataStruct->transparencyType = self::TRANSPARENCY_OPAQUE;
295. // Read Logical Screen Descriptor
296. $data = unpack ( "v1width/v1height/C1bitfield/C1index/C1ration", fread ( $fp, 7 ) );
297. $offset += 7;
299. $lsdFields = $data['bitfield'];
300. $globalColorCount = 0;
301. $globalColorTableSize = 0;
302. if ( $lsdFields >> 7 )
303. {
304. // Extract 3 bits for color count
305. $globalColorCount = ( 1 << ( ( $lsdFields & 0x07 ) + 1) );
306. // Each color entry is RGB ie. 3 bytes
307. $globalColorTableSize = $globalColorCount * 3;
308. }
310. $dataStruct->colorCount = $globalColorCount;
311. $dataStruct->width = $data['width'];
312. $dataStruct->height = $data['height'];
314. if ( $globalColorTableSize )
315. {
316. // Skip the color table, we don't need the data
317. fseek ( $fp, $globalColorTableSize, SEEK_CUR );
318. $offset += $globalColorTableSize;
319. }
321. $done = false;
322. // Iterate over all blocks and extract information
323. while ( !$done )
324. {
325. $data = fread ( $fp, 1 );
326. $offset += 1;
327. $blockType = ord ( $data[0] );
329. if ( $blockType == 0x21 ) // Extension Introducer
330. {
331. $data .= fread ( $fp, 1 );
332. $offset += 1;
333. $extensionLabel = ord ( $data[1] );
335. if ( $extensionLabel == 0xf9 ) // Graphical Control Extension
336. {
337. $data = unpack ( "C1blocksize/C1bitfield/v1delay/C1index/C1term", fread ( $fp, 5 + 1 ) );
338. $gceFlags = $data['bitfield'];//ord( $data[1] );
339. // $animationTimer is currently not in use.
340. /* $animationTimer = $data['delay']; */
342. // Check bit 0
343. if ( $gceFlags & 0x01 )
344. {
345. $dataStruct->transparencyType = self::TRANSPARENCY_TRANSPARENT;
346. }
347. $offset += 5 + 1;
348. }
349. else if ( $extensionLabel == 0xff ) // Application Extension
350. {
351. $data = fread ( $fp, 12 );
352. $offset += 12;
354. $dataBlockDone = false;
355. while ( !$dataBlockDone )
356. {
357. $data = unpack ( "C1blocksize", fread ( $fp, 1 ) );
358. $offset += 1;
359. $blockBytes = $data['blocksize'];
361. if ( $blockBytes )
362. {
363. // Skip application data, we don't need the data
364. fseek ( $fp, $blockBytes, SEEK_CUR );
365. $offset += $blockBytes;
366. }
367. else
368. {
369. $dataBlockDone = true;
370. }
371. }
372. }
373. else if ( $extensionLabel == 0xfe ) // Comment Extension
374. {
375. $commentBlockDone = false;
376. $comment = false;
378. while ( !$commentBlockDone )
379. {
380. $data = unpack ( "C1blocksize", fread ( $fp, 1 ) );
381. $offset += 1;
382. $blockBytes = $data['blocksize'];
384. if ( $blockBytes )
385. {
386. // Append current block to comment
387. $data = fread ( $fp, $blockBytes );
388. $comment .= $data;
389. $offset += $blockBytes;
390. }
391. else
392. {
393. $commentBlockDone = true;
394. }
395. }
396. if ( $comment )
397. {
398. if ( $dataStruct->comment === null )
399. {
400. $dataStruct->comment = $comment;
401. }
402. $dataStruct->commentList[] = $comment;
403. }
404. }
405. else
406. {
407. throw new ezcImageAnalyzerFileNotProcessableException ( $file, "Invalid extension label 0x" . hexdec ( $extensionLabel ) . " in GIF image." );
408. }
409. }
410. else if ( $blockType == 0x2c ) // Image Descriptor
411. {
412. ++$frames;
413. $data .= fread ( $fp, 9 );
414. $data = unpack ( "C1separator/v1leftpos/v1toppos/v1width/v1height/C1bitfield", $data );
415. $localColorTableSize = 0;
416. $localColorCount = 0;
417. $idFields = $data['bitfield'];
418. if ( $idFields >> 7 ) // Local Color Table
419. {
420. // Extract 3 bits for color count
421. $localColorCount = ( 1 << ( ( $idFields & 0x07 ) + 1) );
422. // Each color entry is RGB ie. 3 bytes
423. $localColorTableSize = $localColorCount * 3;
424. }
425. if ( $localColorCount > $globalColorCount )
426. {
427. $dataStruct->colorCount = $localColorCount;
428. }
430. if ( $localColorTableSize )
431. {
432. // Skip the color table, we don't need the data
433. fseek ( $fp, $localColorTableSize, SEEK_CUR );
434. $offset += $localColorTableSize;
435. }
437. $lzwCodeSize = fread ( $fp, 1 ); // LZW Minimum Code Size, currently unused
438. $offset += 1;
440. $dataBlockDone = false;
441. while ( !$dataBlockDone )
442. {
443. $data = unpack ( "C1blocksize", fread ( $fp, 1 ) );
444. $offset += 1;
445. $blockBytes = $data['blocksize'];
447. if ( $blockBytes )
448. {
449. // Skip image data, we don't need the data
450. fseek ( $fp, $blockBytes, SEEK_CUR );
451. $offset += $blockBytes;
452. }
453. else
454. {
455. $dataBlockDone = true;
456. }
457. }
458. }
459. else if ( $blockType == 0x3b ) // Trailer, end of stream
460. {
461. $done = true;
462. }
463. else
464. {
465. throw new ezcImageAnalyzerFileNotProcessableException ( $file, "Invalid block type 0x" . hexdec ( $blockType ) . " in GIF image." );
466. }
467. if ( feof ( $fp ) )
468. {
469. break;
470. }
471. }
472. $dataStruct->isAnimated = $frames > 1;
474. return $dataStruct;
475. }
476. }
477. ?>

Documentation generated by phpDocumentor 1.4.3