rlm@3
|
1 <?php
|
rlm@3
|
2 // +----------------------------------------------------------------------+
|
rlm@3
|
3 // | PHP version 5 |
|
rlm@3
|
4 // +----------------------------------------------------------------------+
|
rlm@3
|
5 // | Copyright (c) 2002-2006 James Heinrich, Allan Hansen |
|
rlm@3
|
6 // +----------------------------------------------------------------------+
|
rlm@3
|
7 // | This source file is subject to version 2 of the GPL license, |
|
rlm@3
|
8 // | that is bundled with this package in the file license.txt and is |
|
rlm@3
|
9 // | available through the world-wide-web at the following url: |
|
rlm@3
|
10 // | http://www.gnu.org/copyleft/gpl.html |
|
rlm@3
|
11 // +----------------------------------------------------------------------+
|
rlm@3
|
12 // | getID3() - http://getid3.sourceforge.net or http://www.getid3.org |
|
rlm@3
|
13 // +----------------------------------------------------------------------+
|
rlm@3
|
14 // | Authors: James Heinrich <infoØgetid3*org> |
|
rlm@3
|
15 // | Allan Hansen <ahØartemis*dk> |
|
rlm@3
|
16 // +----------------------------------------------------------------------+
|
rlm@3
|
17 // | module.graphic.bmp.php |
|
rlm@3
|
18 // | Module for analyzing BMP graphic files. |
|
rlm@3
|
19 // | dependencies: NONE |
|
rlm@3
|
20 // +----------------------------------------------------------------------+
|
rlm@3
|
21 //
|
rlm@3
|
22 // $Id: module.graphic.bmp.php,v 1.4 2006/11/02 10:48:02 ah Exp $
|
rlm@3
|
23
|
rlm@3
|
24
|
rlm@3
|
25
|
rlm@3
|
26 class getid3_bmp extends getid3_handler
|
rlm@3
|
27 {
|
rlm@3
|
28
|
rlm@3
|
29
|
rlm@3
|
30 public function Analyze() {
|
rlm@3
|
31
|
rlm@3
|
32 $getid3 = $this->getid3;
|
rlm@3
|
33
|
rlm@3
|
34 // BITMAPFILEHEADER [14 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_62uq.asp
|
rlm@3
|
35 // all versions
|
rlm@3
|
36 // WORD bfType;
|
rlm@3
|
37 // DWORD bfSize;
|
rlm@3
|
38 // WORD bfReserved1;
|
rlm@3
|
39 // WORD bfReserved2;
|
rlm@3
|
40 // DWORD bfOffBits;
|
rlm@3
|
41
|
rlm@3
|
42 // shortcuts
|
rlm@3
|
43 $getid3->info['bmp']['header']['raw'] = array ();
|
rlm@3
|
44 $info_bmp = &$getid3->info['bmp'];
|
rlm@3
|
45 $info_bmp_header = &$info_bmp['header'];
|
rlm@3
|
46 $info_bmp_header_raw = &$info_bmp_header['raw'];
|
rlm@3
|
47
|
rlm@3
|
48 fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET);
|
rlm@3
|
49 $bmp_header = fread($getid3->fp, 14 + 40);
|
rlm@3
|
50
|
rlm@3
|
51 // Magic bytes
|
rlm@3
|
52 $info_bmp_header_raw['identifier'] = 'BM';
|
rlm@3
|
53
|
rlm@3
|
54 getid3_lib::ReadSequence('LittleEndian2Int', $info_bmp_header_raw, $bmp_header, 2,
|
rlm@3
|
55 array (
|
rlm@3
|
56 'filesize' => 4,
|
rlm@3
|
57 'reserved1' => 2,
|
rlm@3
|
58 'reserved2' => 2,
|
rlm@3
|
59 'data_offset' => 4,
|
rlm@3
|
60 'header_size' => 4
|
rlm@3
|
61 )
|
rlm@3
|
62 );
|
rlm@3
|
63
|
rlm@3
|
64 // Check if the hardcoded-to-1 "planes" is at offset 22 or 26
|
rlm@3
|
65 $planes22 = getid3_lib::LittleEndian2Int(substr($bmp_header, 22, 2));
|
rlm@3
|
66 $planes26 = getid3_lib::LittleEndian2Int(substr($bmp_header, 26, 2));
|
rlm@3
|
67 if (($planes22 == 1) && ($planes26 != 1)) {
|
rlm@3
|
68 $info_bmp['type_os'] = 'OS/2';
|
rlm@3
|
69 $info_bmp['type_version'] = 1;
|
rlm@3
|
70 }
|
rlm@3
|
71 elseif (($planes26 == 1) && ($planes22 != 1)) {
|
rlm@3
|
72 $info_bmp['type_os'] = 'Windows';
|
rlm@3
|
73 $info_bmp['type_version'] = 1;
|
rlm@3
|
74 }
|
rlm@3
|
75 elseif ($info_bmp_header_raw['header_size'] == 12) {
|
rlm@3
|
76 $info_bmp['type_os'] = 'OS/2';
|
rlm@3
|
77 $info_bmp['type_version'] = 1;
|
rlm@3
|
78 }
|
rlm@3
|
79 elseif ($info_bmp_header_raw['header_size'] == 40) {
|
rlm@3
|
80 $info_bmp['type_os'] = 'Windows';
|
rlm@3
|
81 $info_bmp['type_version'] = 1;
|
rlm@3
|
82 }
|
rlm@3
|
83 elseif ($info_bmp_header_raw['header_size'] == 84) {
|
rlm@3
|
84 $info_bmp['type_os'] = 'Windows';
|
rlm@3
|
85 $info_bmp['type_version'] = 4;
|
rlm@3
|
86 }
|
rlm@3
|
87 elseif ($info_bmp_header_raw['header_size'] == 100) {
|
rlm@3
|
88 $info_bmp['type_os'] = 'Windows';
|
rlm@3
|
89 $info_bmp['type_version'] = 5;
|
rlm@3
|
90 }
|
rlm@3
|
91 else {
|
rlm@3
|
92 throw new getid3_exception('Unknown BMP subtype (or not a BMP file)');
|
rlm@3
|
93 }
|
rlm@3
|
94
|
rlm@3
|
95 $getid3->info['fileformat'] = 'bmp';
|
rlm@3
|
96 $getid3->info['video']['dataformat'] = 'bmp';
|
rlm@3
|
97 $getid3->info['video']['lossless'] = true;
|
rlm@3
|
98 $getid3->info['video']['pixel_aspect_ratio'] = (float)1;
|
rlm@3
|
99
|
rlm@3
|
100 if ($info_bmp['type_os'] == 'OS/2') {
|
rlm@3
|
101
|
rlm@3
|
102 // OS/2-format BMP
|
rlm@3
|
103 // http://netghost.narod.ru/gff/graphics/summary/os2bmp.htm
|
rlm@3
|
104
|
rlm@3
|
105 // DWORD Size; /* Size of this structure in bytes */
|
rlm@3
|
106 // DWORD Width; /* Bitmap width in pixels */
|
rlm@3
|
107 // DWORD Height; /* Bitmap height in pixel */
|
rlm@3
|
108 // WORD NumPlanes; /* Number of bit planes (color depth) */
|
rlm@3
|
109 // WORD BitsPerPixel; /* Number of bits per pixel per plane */
|
rlm@3
|
110
|
rlm@3
|
111 getid3_lib::ReadSequence('LittleEndian2Int', $info_bmp_header_raw, $bmp_header, 18,
|
rlm@3
|
112 array (
|
rlm@3
|
113 'width' => 2,
|
rlm@3
|
114 'height' => 2,
|
rlm@3
|
115 'planes' => 2,
|
rlm@3
|
116 'bits_per_pixel' => 2
|
rlm@3
|
117 )
|
rlm@3
|
118 );
|
rlm@3
|
119
|
rlm@3
|
120 $getid3->info['video']['resolution_x'] = $info_bmp_header_raw['width'];
|
rlm@3
|
121 $getid3->info['video']['resolution_y'] = $info_bmp_header_raw['height'];
|
rlm@3
|
122 $getid3->info['video']['codec'] = 'BI_RGB '.$info_bmp_header_raw['bits_per_pixel'].'-bit';
|
rlm@3
|
123 $getid3->info['video']['bits_per_sample'] = $info_bmp_header_raw['bits_per_pixel'];
|
rlm@3
|
124
|
rlm@3
|
125 if ($info_bmp['type_version'] >= 2) {
|
rlm@3
|
126 // DWORD Compression; /* Bitmap compression scheme */
|
rlm@3
|
127 // DWORD ImageDataSize; /* Size of bitmap data in bytes */
|
rlm@3
|
128 // DWORD XResolution; /* X resolution of display device */
|
rlm@3
|
129 // DWORD YResolution; /* Y resolution of display device */
|
rlm@3
|
130 // DWORD ColorsUsed; /* Number of color table indices used */
|
rlm@3
|
131 // DWORD ColorsImportant; /* Number of important color indices */
|
rlm@3
|
132 // WORD Units; /* Type of units used to measure resolution */
|
rlm@3
|
133 // WORD Reserved; /* Pad structure to 4-byte boundary */
|
rlm@3
|
134 // WORD Recording; /* Recording algorithm */
|
rlm@3
|
135 // WORD Rendering; /* Halftoning algorithm used */
|
rlm@3
|
136 // DWORD Size1; /* Reserved for halftoning algorithm use */
|
rlm@3
|
137 // DWORD Size2; /* Reserved for halftoning algorithm use */
|
rlm@3
|
138 // DWORD ColorEncoding; /* Color model used in bitmap */
|
rlm@3
|
139 // DWORD Identifier; /* Reserved for application use */
|
rlm@3
|
140
|
rlm@3
|
141 getid3_lib::ReadSequence('LittleEndian2Int', $info_bmp_header_raw, $bmp_header, 26,
|
rlm@3
|
142 array (
|
rlm@3
|
143 'compression' => 4,
|
rlm@3
|
144 'bmp_data_size' => 4,
|
rlm@3
|
145 'resolution_h' => 4,
|
rlm@3
|
146 'resolution_v' => 4,
|
rlm@3
|
147 'colors_used' => 4,
|
rlm@3
|
148 'colors_important' => 4,
|
rlm@3
|
149 'resolution_units' => 2,
|
rlm@3
|
150 'reserved1' => 2,
|
rlm@3
|
151 'recording' => 2,
|
rlm@3
|
152 'rendering' => 2,
|
rlm@3
|
153 'size1' => 4,
|
rlm@3
|
154 'size2' => 4,
|
rlm@3
|
155 'color_encoding' => 4,
|
rlm@3
|
156 'identifier' => 4
|
rlm@3
|
157 )
|
rlm@3
|
158 );
|
rlm@3
|
159
|
rlm@3
|
160 $info_bmp_header['compression'] = getid3_bmp::BMPcompressionOS2Lookup($info_bmp_header_raw['compression']);
|
rlm@3
|
161 $getid3->info['video']['codec'] = $info_bmp_header['compression'].' '.$info_bmp_header_raw['bits_per_pixel'].'-bit';
|
rlm@3
|
162 }
|
rlm@3
|
163
|
rlm@3
|
164 return true;
|
rlm@3
|
165 }
|
rlm@3
|
166
|
rlm@3
|
167
|
rlm@3
|
168 if ($info_bmp['type_os'] == 'Windows') {
|
rlm@3
|
169
|
rlm@3
|
170 // Windows-format BMP
|
rlm@3
|
171
|
rlm@3
|
172 // BITMAPINFOHEADER - [40 bytes] http://msdn.microsoft.com/library/en-us/gdi/bitmaps_1rw2.asp
|
rlm@3
|
173 // all versions
|
rlm@3
|
174 // DWORD biSize;
|
rlm@3
|
175 // LONG biWidth;
|
rlm@3
|
176 // LONG biHeight;
|
rlm@3
|
177 // WORD biPlanes;
|
rlm@3
|
178 // WORD biBitCount;
|
rlm@3
|
179 // DWORD biCompression;
|
rlm@3
|
180 // DWORD biSizeImage;
|
rlm@3
|
181 // LONG biXPelsPerMeter;
|
rlm@3
|
182 // LONG biYPelsPerMeter;
|
rlm@3
|
183 // DWORD biClrUsed;
|
rlm@3
|
184 // DWORD biClrImportant;
|
rlm@3
|
185
|
rlm@3
|
186 getid3_lib::ReadSequence('LittleEndian2Int', $info_bmp_header_raw, $bmp_header, 18,
|
rlm@3
|
187 array (
|
rlm@3
|
188 'width' => -4, //signed
|
rlm@3
|
189 'height' => -4, //signed
|
rlm@3
|
190 'planes' => 2,
|
rlm@3
|
191 'bits_per_pixel' => 2,
|
rlm@3
|
192 'compression' => 4,
|
rlm@3
|
193 'bmp_data_size' => 4,
|
rlm@3
|
194 'resolution_h' => -4, //signed
|
rlm@3
|
195 'resolution_v' => -4, //signed
|
rlm@3
|
196 'colors_used' => 4,
|
rlm@3
|
197 'colors_important' => 4
|
rlm@3
|
198 )
|
rlm@3
|
199 );
|
rlm@3
|
200 foreach (array ('width', 'height', 'resolution_h', 'resolution_v') as $key) {
|
rlm@3
|
201 $info_bmp_header_raw[$key] = getid3_lib::LittleEndian2Int($info_bmp_header_raw[$key], true);
|
rlm@3
|
202 }
|
rlm@3
|
203
|
rlm@3
|
204 $info_bmp_header['compression'] = getid3_bmp::BMPcompressionWindowsLookup($info_bmp_header_raw['compression']);
|
rlm@3
|
205 $getid3->info['video']['resolution_x'] = $info_bmp_header_raw['width'];
|
rlm@3
|
206 $getid3->info['video']['resolution_y'] = $info_bmp_header_raw['height'];
|
rlm@3
|
207 $getid3->info['video']['codec'] = $info_bmp_header['compression'].' '.$info_bmp_header_raw['bits_per_pixel'].'-bit';
|
rlm@3
|
208 $getid3->info['video']['bits_per_sample'] = $info_bmp_header_raw['bits_per_pixel'];
|
rlm@3
|
209
|
rlm@3
|
210 // should only be v4+, but BMPs with type_version==1 and BI_BITFIELDS compression have been seen
|
rlm@3
|
211 if (($info_bmp['type_version'] >= 4) || ($info_bmp_header_raw['compression'] == 3)) {
|
rlm@3
|
212
|
rlm@3
|
213
|
rlm@3
|
214 $bmp_header .= fread($getid3->fp, 44);
|
rlm@3
|
215
|
rlm@3
|
216 // BITMAPV4HEADER - [44 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_2k1e.asp
|
rlm@3
|
217 // Win95+, WinNT4.0+
|
rlm@3
|
218 // DWORD bV4RedMask;
|
rlm@3
|
219 // DWORD bV4GreenMask;
|
rlm@3
|
220 // DWORD bV4BlueMask;
|
rlm@3
|
221 // DWORD bV4AlphaMask;
|
rlm@3
|
222 // DWORD bV4CSType;
|
rlm@3
|
223 // CIEXYZTRIPLE bV4Endpoints;
|
rlm@3
|
224 // DWORD bV4GammaRed;
|
rlm@3
|
225 // DWORD bV4GammaGreen;
|
rlm@3
|
226 // DWORD bV4GammaBlue;
|
rlm@3
|
227
|
rlm@3
|
228 getid3_lib::ReadSequence('LittleEndian2Int', $info_bmp_header_raw, $bmp_header, 54,
|
rlm@3
|
229 array (
|
rlm@3
|
230 'red_mask' => 4,
|
rlm@3
|
231 'green_mask' => 4,
|
rlm@3
|
232 'blue_mask' => 4,
|
rlm@3
|
233 'alpha_mask' => 4,
|
rlm@3
|
234 'cs_type' => 4,
|
rlm@3
|
235 'ciexyz_red' => -4, //string
|
rlm@3
|
236 'ciexyz_green' => -4, //string
|
rlm@3
|
237 'ciexyz_blue' => -4, //string
|
rlm@3
|
238 'gamma_red' => 4,
|
rlm@3
|
239 'gamma_green' => 4,
|
rlm@3
|
240 'gamma_blue' => 4
|
rlm@3
|
241 )
|
rlm@3
|
242 );
|
rlm@3
|
243
|
rlm@3
|
244 $info_bmp_header['ciexyz_red'] = getid3_bmp::FixedPoint2_30(strrev($info_bmp_header_raw['ciexyz_red']));
|
rlm@3
|
245 $info_bmp_header['ciexyz_green'] = getid3_bmp::FixedPoint2_30(strrev($info_bmp_header_raw['ciexyz_green']));
|
rlm@3
|
246 $info_bmp_header['ciexyz_blue'] = getid3_bmp::FixedPoint2_30(strrev($info_bmp_header_raw['ciexyz_blue']));
|
rlm@3
|
247
|
rlm@3
|
248
|
rlm@3
|
249 if ($info_bmp['type_version'] >= 5) {
|
rlm@3
|
250 $bmp_header .= fread($getid3->fp, 16);
|
rlm@3
|
251
|
rlm@3
|
252 // BITMAPV5HEADER - [16 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_7c36.asp
|
rlm@3
|
253 // Win98+, Win2000+
|
rlm@3
|
254 // DWORD bV5Intent;
|
rlm@3
|
255 // DWORD bV5ProfileData;
|
rlm@3
|
256 // DWORD bV5ProfileSize;
|
rlm@3
|
257 // DWORD bV5Reserved;
|
rlm@3
|
258
|
rlm@3
|
259 getid3_lib::ReadSequence('LittleEndian2Int', $info_bmp_header_raw, $bmp_header, 98,
|
rlm@3
|
260 array (
|
rlm@3
|
261 'intent' => 4,
|
rlm@3
|
262 'profile_data_offset' => 4,
|
rlm@3
|
263 'profile_data_size' => 4,
|
rlm@3
|
264 'reserved3' => 4
|
rlm@3
|
265 )
|
rlm@3
|
266 );
|
rlm@3
|
267
|
rlm@3
|
268 }
|
rlm@3
|
269 }
|
rlm@3
|
270
|
rlm@3
|
271 return true;
|
rlm@3
|
272 }
|
rlm@3
|
273
|
rlm@3
|
274
|
rlm@3
|
275 throw new getid3_exception('Unknown BMP format in header.');
|
rlm@3
|
276
|
rlm@3
|
277 }
|
rlm@3
|
278
|
rlm@3
|
279
|
rlm@3
|
280
|
rlm@3
|
281 public static function BMPcompressionWindowsLookup($compression_id) {
|
rlm@3
|
282
|
rlm@3
|
283 static $lookup = array (
|
rlm@3
|
284 0 => 'BI_RGB',
|
rlm@3
|
285 1 => 'BI_RLE8',
|
rlm@3
|
286 2 => 'BI_RLE4',
|
rlm@3
|
287 3 => 'BI_BITFIELDS',
|
rlm@3
|
288 4 => 'BI_JPEG',
|
rlm@3
|
289 5 => 'BI_PNG'
|
rlm@3
|
290 );
|
rlm@3
|
291 return (isset($lookup[$compression_id]) ? $lookup[$compression_id] : 'invalid');
|
rlm@3
|
292 }
|
rlm@3
|
293
|
rlm@3
|
294
|
rlm@3
|
295
|
rlm@3
|
296 public static function BMPcompressionOS2Lookup($compression_id) {
|
rlm@3
|
297
|
rlm@3
|
298 static $lookup = array (
|
rlm@3
|
299 0 => 'BI_RGB',
|
rlm@3
|
300 1 => 'BI_RLE8',
|
rlm@3
|
301 2 => 'BI_RLE4',
|
rlm@3
|
302 3 => 'Huffman 1D',
|
rlm@3
|
303 4 => 'BI_RLE24',
|
rlm@3
|
304 );
|
rlm@3
|
305 return (isset($lookup[$compression_id]) ? $lookup[$compression_id] : 'invalid');
|
rlm@3
|
306 }
|
rlm@3
|
307
|
rlm@3
|
308
|
rlm@3
|
309 public static function FixedPoint2_30($raw_data) {
|
rlm@3
|
310
|
rlm@3
|
311 $binary_string = getid3_lib::BigEndian2Bin($raw_data);
|
rlm@3
|
312 return bindec(substr($binary_string, 0, 2)) + (float)(bindec(substr($binary_string, 2, 30)) / 1073741824); // pow(2, 30) = 1073741824
|
rlm@3
|
313 }
|
rlm@3
|
314
|
rlm@3
|
315
|
rlm@3
|
316 }
|
rlm@3
|
317
|
rlm@3
|
318
|
rlm@3
|
319 ?> |