ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
GetId3\Module\Graphic\Bmp Class Reference

GetId3() by James Heinrich info@.nosp@m.geti.nosp@m.d3.or.nosp@m.g //. More...

+ Inheritance diagram for GetId3\Module\Graphic\Bmp:
+ Collaboration diagram for GetId3\Module\Graphic\Bmp:

Public Member Functions

 analyze ()
 
 PlotBMP (&$BMPinfo)
 
 BMPcompressionWindowsLookup ($compressionid)
 @staticvar array $BMPcompressionWindowsLookup More...
 
 BMPcompressionOS2Lookup ($compressionid)
 @staticvar array $BMPcompressionOS2Lookup More...
 
- Public Member Functions inherited from GetId3\Handler\BaseHandler
 __construct (GetId3Core $getid3, $call_module=null)
 
 analyze ()
 Analyze from file pointer. More...
 
 AnalyzeString (&$string)
 Analyze from string instead. More...
 
 saveAttachment (&$ThisFileInfoIndex, $filename, $offset, $length)
 

Data Fields

 $ExtractPalette = false
 
 $ExtractData = false
 

Additional Inherited Members

- Protected Member Functions inherited from GetId3\Handler\BaseHandler
 ftell ()
 
 fread ($bytes)
 
 fseek ($bytes, $whence=SEEK_SET)
 
 feof ()
 
 isDependencyFor ($module)
 
 error ($text)
 
 warning ($text)
 
- Protected Attributes inherited from GetId3\Handler\BaseHandler
 $getid3
 
 $data_string_flag = false
 
 $data_string = ''
 
 $data_string_position = 0
 
 $data_string_length = 0
 

Detailed Description

GetId3() by James Heinrich info@.nosp@m.geti.nosp@m.d3.or.nosp@m.g //.

module for analyzing BMP Image files

Author
James Heinrich info@.nosp@m.geti.nosp@m.d3.or.nosp@m.g http://www.getid3.org

Definition at line 29 of file Bmp.php.

Member Function Documentation

◆ analyze()

GetId3\Module\Graphic\Bmp::analyze ( )
Returns
boolean

Reimplemented from GetId3\Handler\BaseHandler.

Definition at line 46 of file Bmp.php.

47 {
48 $info = &$this->getid3->info;
49
50 // shortcuts
51 $info['bmp']['header']['raw'] = array();
52 $thisfile_bmp = &$info['bmp'];
53 $thisfile_bmp_header = &$thisfile_bmp['header'];
54 $thisfile_bmp_header_raw = &$thisfile_bmp_header['raw'];
55
56 // BITMAPFILEHEADER [14 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_62uq.asp
57 // all versions
58 // WORD bfType;
59 // DWORD bfSize;
60 // WORD bfReserved1;
61 // WORD bfReserved2;
62 // DWORD bfOffBits;
63
64 fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
65 $offset = 0;
66 $BMPheader = fread($this->getid3->fp, 14 + 40);
67
68 $thisfile_bmp_header_raw['identifier'] = substr($BMPheader, $offset, 2);
69 $offset += 2;
70
71 $magic = 'BM';
72 if ($thisfile_bmp_header_raw['identifier'] != $magic) {
73 $info['error'][] = 'Expecting "'.Helper::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.Helper::PrintHexBytes($thisfile_bmp_header_raw['identifier']).'"';
74 unset($info['fileformat']);
75 unset($info['bmp']);
76
77 return false;
78 }
79
80 $thisfile_bmp_header_raw['filesize'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
81 $offset += 4;
82 $thisfile_bmp_header_raw['reserved1'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 2));
83 $offset += 2;
84 $thisfile_bmp_header_raw['reserved2'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 2));
85 $offset += 2;
86 $thisfile_bmp_header_raw['data_offset'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
87 $offset += 4;
88 $thisfile_bmp_header_raw['header_size'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
89 $offset += 4;
90
91 // check if the hardcoded-to-1 "planes" is at offset 22 or 26
92 $planes22 = Helper::LittleEndian2Int(substr($BMPheader, 22, 2));
93 $planes26 = Helper::LittleEndian2Int(substr($BMPheader, 26, 2));
94 if (($planes22 == 1) && ($planes26 != 1)) {
95 $thisfile_bmp['type_os'] = 'OS/2';
96 $thisfile_bmp['type_version'] = 1;
97 } elseif (($planes26 == 1) && ($planes22 != 1)) {
98 $thisfile_bmp['type_os'] = 'Windows';
99 $thisfile_bmp['type_version'] = 1;
100 } elseif ($thisfile_bmp_header_raw['header_size'] == 12) {
101 $thisfile_bmp['type_os'] = 'OS/2';
102 $thisfile_bmp['type_version'] = 1;
103 } elseif ($thisfile_bmp_header_raw['header_size'] == 40) {
104 $thisfile_bmp['type_os'] = 'Windows';
105 $thisfile_bmp['type_version'] = 1;
106 } elseif ($thisfile_bmp_header_raw['header_size'] == 84) {
107 $thisfile_bmp['type_os'] = 'Windows';
108 $thisfile_bmp['type_version'] = 4;
109 } elseif ($thisfile_bmp_header_raw['header_size'] == 100) {
110 $thisfile_bmp['type_os'] = 'Windows';
111 $thisfile_bmp['type_version'] = 5;
112 } else {
113 $info['error'][] = 'Unknown BMP subtype (or not a BMP file)';
114 unset($info['fileformat']);
115 unset($info['bmp']);
116
117 return false;
118 }
119
120 $info['fileformat'] = 'bmp';
121 $info['video']['dataformat'] = 'bmp';
122 $info['video']['lossless'] = true;
123 $info['video']['pixel_aspect_ratio'] = (float) 1;
124
125 if ($thisfile_bmp['type_os'] == 'OS/2') {
126
127 // OS/2-format BMP
128 // http://netghost.narod.ru/gff/graphics/summary/os2bmp.htm
129
130 // DWORD Size; /* Size of this structure in bytes */
131 // DWORD Width; /* Bitmap width in pixels */
132 // DWORD Height; /* Bitmap height in pixel */
133 // WORD NumPlanes; /* Number of bit planes (color depth) */
134 // WORD BitsPerPixel; /* Number of bits per pixel per plane */
135
136 $thisfile_bmp_header_raw['width'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 2));
137 $offset += 2;
138 $thisfile_bmp_header_raw['height'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 2));
139 $offset += 2;
140 $thisfile_bmp_header_raw['planes'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 2));
141 $offset += 2;
142 $thisfile_bmp_header_raw['bits_per_pixel'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 2));
143 $offset += 2;
144
145 $info['video']['resolution_x'] = $thisfile_bmp_header_raw['width'];
146 $info['video']['resolution_y'] = $thisfile_bmp_header_raw['height'];
147 $info['video']['codec'] = 'BI_RGB '.$thisfile_bmp_header_raw['bits_per_pixel'].'-bit';
148 $info['video']['bits_per_sample'] = $thisfile_bmp_header_raw['bits_per_pixel'];
149
150 if ($thisfile_bmp['type_version'] >= 2) {
151 // DWORD Compression; /* Bitmap compression scheme */
152 // DWORD ImageDataSize; /* Size of bitmap data in bytes */
153 // DWORD XResolution; /* X resolution of display device */
154 // DWORD YResolution; /* Y resolution of display device */
155 // DWORD ColorsUsed; /* Number of color table indices used */
156 // DWORD ColorsImportant; /* Number of important color indices */
157 // WORD Units; /* Type of units used to measure resolution */
158 // WORD Reserved; /* Pad structure to 4-byte boundary */
159 // WORD Recording; /* Recording algorithm */
160 // WORD Rendering; /* Halftoning algorithm used */
161 // DWORD Size1; /* Reserved for halftoning algorithm use */
162 // DWORD Size2; /* Reserved for halftoning algorithm use */
163 // DWORD ColorEncoding; /* Color model used in bitmap */
164 // DWORD Identifier; /* Reserved for application use */
165
166 $thisfile_bmp_header_raw['compression'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
167 $offset += 4;
168 $thisfile_bmp_header_raw['bmp_data_size'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
169 $offset += 4;
170 $thisfile_bmp_header_raw['resolution_h'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
171 $offset += 4;
172 $thisfile_bmp_header_raw['resolution_v'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
173 $offset += 4;
174 $thisfile_bmp_header_raw['colors_used'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
175 $offset += 4;
176 $thisfile_bmp_header_raw['colors_important'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
177 $offset += 4;
178 $thisfile_bmp_header_raw['resolution_units'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 2));
179 $offset += 2;
180 $thisfile_bmp_header_raw['reserved1'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 2));
181 $offset += 2;
182 $thisfile_bmp_header_raw['recording'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 2));
183 $offset += 2;
184 $thisfile_bmp_header_raw['rendering'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 2));
185 $offset += 2;
186 $thisfile_bmp_header_raw['size1'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
187 $offset += 4;
188 $thisfile_bmp_header_raw['size2'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
189 $offset += 4;
190 $thisfile_bmp_header_raw['color_encoding'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
191 $offset += 4;
192 $thisfile_bmp_header_raw['identifier'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
193 $offset += 4;
194
195 $thisfile_bmp_header['compression'] = $this->BMPcompressionOS2Lookup($thisfile_bmp_header_raw['compression']);
196
197 $info['video']['codec'] = $thisfile_bmp_header['compression'].' '.$thisfile_bmp_header_raw['bits_per_pixel'].'-bit';
198 }
199
200 } elseif ($thisfile_bmp['type_os'] == 'Windows') {
201
202 // Windows-format BMP
203
204 // BITMAPINFOHEADER - [40 bytes] http://msdn.microsoft.com/library/en-us/gdi/bitmaps_1rw2.asp
205 // all versions
206 // DWORD biSize;
207 // LONG biWidth;
208 // LONG biHeight;
209 // WORD biPlanes;
210 // WORD biBitCount;
211 // DWORD biCompression;
212 // DWORD biSizeImage;
213 // LONG biXPelsPerMeter;
214 // LONG biYPelsPerMeter;
215 // DWORD biClrUsed;
216 // DWORD biClrImportant;
217
218 // possibly integrate this section and module.audio-video.riff.php::ParseBITMAPINFOHEADER() ?
219
220 $thisfile_bmp_header_raw['width'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4), true);
221 $offset += 4;
222 $thisfile_bmp_header_raw['height'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4), true);
223 $offset += 4;
224 $thisfile_bmp_header_raw['planes'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 2));
225 $offset += 2;
226 $thisfile_bmp_header_raw['bits_per_pixel'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 2));
227 $offset += 2;
228 $thisfile_bmp_header_raw['compression'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
229 $offset += 4;
230 $thisfile_bmp_header_raw['bmp_data_size'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
231 $offset += 4;
232 $thisfile_bmp_header_raw['resolution_h'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4), true);
233 $offset += 4;
234 $thisfile_bmp_header_raw['resolution_v'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4), true);
235 $offset += 4;
236 $thisfile_bmp_header_raw['colors_used'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
237 $offset += 4;
238 $thisfile_bmp_header_raw['colors_important'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
239 $offset += 4;
240
241 $thisfile_bmp_header['compression'] = $this->BMPcompressionWindowsLookup($thisfile_bmp_header_raw['compression']);
242 $info['video']['resolution_x'] = $thisfile_bmp_header_raw['width'];
243 $info['video']['resolution_y'] = $thisfile_bmp_header_raw['height'];
244 $info['video']['codec'] = $thisfile_bmp_header['compression'].' '.$thisfile_bmp_header_raw['bits_per_pixel'].'-bit';
245 $info['video']['bits_per_sample'] = $thisfile_bmp_header_raw['bits_per_pixel'];
246
247 if (($thisfile_bmp['type_version'] >= 4) || ($thisfile_bmp_header_raw['compression'] == 3)) {
248 // should only be v4+, but BMPs with type_version==1 and BI_BITFIELDS compression have been seen
249 $BMPheader .= fread($this->getid3->fp, 44);
250
251 // BITMAPV4HEADER - [44 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_2k1e.asp
252 // Win95+, WinNT4.0+
253 // DWORD bV4RedMask;
254 // DWORD bV4GreenMask;
255 // DWORD bV4BlueMask;
256 // DWORD bV4AlphaMask;
257 // DWORD bV4CSType;
258 // CIEXYZTRIPLE bV4Endpoints;
259 // DWORD bV4GammaRed;
260 // DWORD bV4GammaGreen;
261 // DWORD bV4GammaBlue;
262 $thisfile_bmp_header_raw['red_mask'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
263 $offset += 4;
264 $thisfile_bmp_header_raw['green_mask'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
265 $offset += 4;
266 $thisfile_bmp_header_raw['blue_mask'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
267 $offset += 4;
268 $thisfile_bmp_header_raw['alpha_mask'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
269 $offset += 4;
270 $thisfile_bmp_header_raw['cs_type'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
271 $offset += 4;
272 $thisfile_bmp_header_raw['ciexyz_red'] = substr($BMPheader, $offset, 4);
273 $offset += 4;
274 $thisfile_bmp_header_raw['ciexyz_green'] = substr($BMPheader, $offset, 4);
275 $offset += 4;
276 $thisfile_bmp_header_raw['ciexyz_blue'] = substr($BMPheader, $offset, 4);
277 $offset += 4;
278 $thisfile_bmp_header_raw['gamma_red'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
279 $offset += 4;
280 $thisfile_bmp_header_raw['gamma_green'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
281 $offset += 4;
282 $thisfile_bmp_header_raw['gamma_blue'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
283 $offset += 4;
284
285 $thisfile_bmp_header['ciexyz_red'] = Helper::FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_red']));
286 $thisfile_bmp_header['ciexyz_green'] = Helper::FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_green']));
287 $thisfile_bmp_header['ciexyz_blue'] = Helper::FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_blue']));
288 }
289
290 if ($thisfile_bmp['type_version'] >= 5) {
291 $BMPheader .= fread($this->getid3->fp, 16);
292
293 // BITMAPV5HEADER - [16 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_7c36.asp
294 // Win98+, Win2000+
295 // DWORD bV5Intent;
296 // DWORD bV5ProfileData;
297 // DWORD bV5ProfileSize;
298 // DWORD bV5Reserved;
299 $thisfile_bmp_header_raw['intent'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
300 $offset += 4;
301 $thisfile_bmp_header_raw['profile_data_offset'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
302 $offset += 4;
303 $thisfile_bmp_header_raw['profile_data_size'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
304 $offset += 4;
305 $thisfile_bmp_header_raw['reserved3'] = Helper::LittleEndian2Int(substr($BMPheader, $offset, 4));
306 $offset += 4;
307 }
308
309 } else {
310
311 $info['error'][] = 'Unknown BMP format in header.';
312
313 return false;
314
315 }
316
317 if ($this->ExtractPalette || $this->ExtractData) {
318 $PaletteEntries = 0;
319 if ($thisfile_bmp_header_raw['bits_per_pixel'] < 16) {
320 $PaletteEntries = pow(2, $thisfile_bmp_header_raw['bits_per_pixel']);
321 } elseif (isset($thisfile_bmp_header_raw['colors_used']) && ($thisfile_bmp_header_raw['colors_used'] > 0) && ($thisfile_bmp_header_raw['colors_used'] <= 256)) {
322 $PaletteEntries = $thisfile_bmp_header_raw['colors_used'];
323 }
324 if ($PaletteEntries > 0) {
325 $BMPpalette = fread($this->getid3->fp, 4 * $PaletteEntries);
326 $paletteoffset = 0;
327 for ($i = 0; $i < $PaletteEntries; $i++) {
328 // RGBQUAD - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_5f8y.asp
329 // BYTE rgbBlue;
330 // BYTE rgbGreen;
331 // BYTE rgbRed;
332 // BYTE rgbReserved;
333 $blue = Helper::LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1));
334 $green = Helper::LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1));
335 $red = Helper::LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1));
336 if (($thisfile_bmp['type_os'] == 'OS/2') && ($thisfile_bmp['type_version'] == 1)) {
337 // no padding byte
338 } else {
339 $paletteoffset++; // padding byte
340 }
341 $thisfile_bmp['palette'][$i] = (($red << 16) | ($green << 8) | $blue);
342 }
343 }
344 }
345
346 if ($this->ExtractData) {
347 fseek($this->getid3->fp, $thisfile_bmp_header_raw['data_offset'], SEEK_SET);
348 $RowByteLength = ceil(($thisfile_bmp_header_raw['width'] * ($thisfile_bmp_header_raw['bits_per_pixel'] / 8)) / 4) * 4; // round up to nearest DWORD boundry
349 $BMPpixelData = fread($this->getid3->fp, $thisfile_bmp_header_raw['height'] * $RowByteLength);
350 $pixeldataoffset = 0;
351 $thisfile_bmp_header_raw['compression'] = (isset($thisfile_bmp_header_raw['compression']) ? $thisfile_bmp_header_raw['compression'] : '');
352 switch ($thisfile_bmp_header_raw['compression']) {
353
354 case 0: // BI_RGB
355 switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
356 case 1:
357 for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
358 for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) {
359 $paletteindexbyte = ord($BMPpixelData{$pixeldataoffset++});
360 for ($i = 7; $i >= 0; $i--) {
361 $paletteindex = ($paletteindexbyte & (0x01 << $i)) >> $i;
362 $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
363 $col++;
364 }
365 }
366 while (($pixeldataoffset % 4) != 0) {
367 // lines are padded to nearest DWORD
368 $pixeldataoffset++;
369 }
370 }
371 break;
372
373 case 4:
374 for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
375 for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) {
376 $paletteindexbyte = ord($BMPpixelData{$pixeldataoffset++});
377 for ($i = 1; $i >= 0; $i--) {
378 $paletteindex = ($paletteindexbyte & (0x0F << (4 * $i))) >> (4 * $i);
379 $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
380 $col++;
381 }
382 }
383 while (($pixeldataoffset % 4) != 0) {
384 // lines are padded to nearest DWORD
385 $pixeldataoffset++;
386 }
387 }
388 break;
389
390 case 8:
391 for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
392 for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
393 $paletteindex = ord($BMPpixelData{$pixeldataoffset++});
394 $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
395 }
396 while (($pixeldataoffset % 4) != 0) {
397 // lines are padded to nearest DWORD
398 $pixeldataoffset++;
399 }
400 }
401 break;
402
403 case 24:
404 for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
405 for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
406 $thisfile_bmp['data'][$row][$col] = (ord($BMPpixelData{$pixeldataoffset+2}) << 16) | (ord($BMPpixelData{$pixeldataoffset+1}) << 8) | ord($BMPpixelData{$pixeldataoffset});
407 $pixeldataoffset += 3;
408 }
409 while (($pixeldataoffset % 4) != 0) {
410 // lines are padded to nearest DWORD
411 $pixeldataoffset++;
412 }
413 }
414 break;
415
416 case 32:
417 for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
418 for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
419 $thisfile_bmp['data'][$row][$col] = (ord($BMPpixelData{$pixeldataoffset+3}) << 24) | (ord($BMPpixelData{$pixeldataoffset+2}) << 16) | (ord($BMPpixelData{$pixeldataoffset+1}) << 8) | ord($BMPpixelData{$pixeldataoffset});
420 $pixeldataoffset += 4;
421 }
422 while (($pixeldataoffset % 4) != 0) {
423 // lines are padded to nearest DWORD
424 $pixeldataoffset++;
425 }
426 }
427 break;
428
429 case 16:
430 // ?
431 break;
432
433 default:
434 $info['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data';
435 break;
436 }
437 break;
438
439 case 1: // BI_RLE8 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp
440 switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
441 case 8:
442 $pixelcounter = 0;
443 while ($pixeldataoffset < strlen($BMPpixelData)) {
444 $firstbyte = Helper::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
445 $secondbyte = Helper::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
446 if ($firstbyte == 0) {
447
448 // escaped/absolute mode - the first byte of the pair can be set to zero to
449 // indicate an escape character that denotes the end of a line, the end of
450 // a bitmap, or a delta, depending on the value of the second byte.
451 switch ($secondbyte) {
452 case 0:
453 // end of line
454 // no need for special processing, just ignore
455 break;
456
457 case 1:
458 // end of bitmap
459 $pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case
460 break;
461
462 case 2:
463 // delta - The 2 bytes following the escape contain unsigned values
464 // indicating the horizontal and vertical offsets of the next pixel
465 // from the current position.
466 $colincrement = Helper::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
467 $rowincrement = Helper::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
468 $col = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement;
469 $row = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement;
470 $pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col;
471 break;
472
473 default:
474 // In absolute mode, the first byte is zero and the second byte is a
475 // value in the range 03H through FFH. The second byte represents the
476 // number of bytes that follow, each of which contains the color index
477 // of a single pixel. Each run must be aligned on a word boundary.
478 for ($i = 0; $i < $secondbyte; $i++) {
479 $paletteindex = Helper::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
480 $col = $pixelcounter % $thisfile_bmp_header_raw['width'];
481 $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']);
482 $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
483 $pixelcounter++;
484 }
485 while (($pixeldataoffset % 2) != 0) {
486 // Each run must be aligned on a word boundary.
487 $pixeldataoffset++;
488 }
489 break;
490 }
491
492 } else {
493
494 // encoded mode - the first byte specifies the number of consecutive pixels
495 // to be drawn using the color index contained in the second byte.
496 for ($i = 0; $i < $firstbyte; $i++) {
497 $col = $pixelcounter % $thisfile_bmp_header_raw['width'];
498 $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']);
499 $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$secondbyte];
500 $pixelcounter++;
501 }
502
503 }
504 }
505 break;
506
507 default:
508 $info['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data';
509 break;
510 }
511 break;
512
513 case 2: // BI_RLE4 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp
514 switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
515 case 4:
516 $pixelcounter = 0;
517 while ($pixeldataoffset < strlen($BMPpixelData)) {
518 $firstbyte = Helper::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
519 $secondbyte = Helper::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
520 if ($firstbyte == 0) {
521
522 // escaped/absolute mode - the first byte of the pair can be set to zero to
523 // indicate an escape character that denotes the end of a line, the end of
524 // a bitmap, or a delta, depending on the value of the second byte.
525 switch ($secondbyte) {
526 case 0:
527 // end of line
528 // no need for special processing, just ignore
529 break;
530
531 case 1:
532 // end of bitmap
533 $pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case
534 break;
535
536 case 2:
537 // delta - The 2 bytes following the escape contain unsigned values
538 // indicating the horizontal and vertical offsets of the next pixel
539 // from the current position.
540 $colincrement = Helper::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
541 $rowincrement = Helper::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
542 $col = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement;
543 $row = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement;
544 $pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col;
545 break;
546
547 default:
548 // In absolute mode, the first byte is zero. The second byte contains the number
549 // of color indexes that follow. Subsequent bytes contain color indexes in their
550 // high- and low-order 4 bits, one color index for each pixel. In absolute mode,
551 // each run must be aligned on a word boundary.
552 unset($paletteindexes);
553 for ($i = 0; $i < ceil($secondbyte / 2); $i++) {
554 $paletteindexbyte = Helper::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
555 $paletteindexes[] = ($paletteindexbyte & 0xF0) >> 4;
556 $paletteindexes[] = ($paletteindexbyte & 0x0F);
557 }
558 while (($pixeldataoffset % 2) != 0) {
559 // Each run must be aligned on a word boundary.
560 $pixeldataoffset++;
561 }
562
563 foreach ($paletteindexes as $paletteindex) {
564 $col = $pixelcounter % $thisfile_bmp_header_raw['width'];
565 $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']);
566 $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
567 $pixelcounter++;
568 }
569 break;
570 }
571
572 } else {
573
574 // encoded mode - the first byte of the pair contains the number of pixels to be
575 // drawn using the color indexes in the second byte. The second byte contains two
576 // color indexes, one in its high-order 4 bits and one in its low-order 4 bits.
577 // The first of the pixels is drawn using the color specified by the high-order
578 // 4 bits, the second is drawn using the color in the low-order 4 bits, the third
579 // is drawn using the color in the high-order 4 bits, and so on, until all the
580 // pixels specified by the first byte have been drawn.
581 $paletteindexes[0] = ($secondbyte & 0xF0) >> 4;
582 $paletteindexes[1] = ($secondbyte & 0x0F);
583 for ($i = 0; $i < $firstbyte; $i++) {
584 $col = $pixelcounter % $thisfile_bmp_header_raw['width'];
585 $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']);
586 $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindexes[($i % 2)]];
587 $pixelcounter++;
588 }
589
590 }
591 }
592 break;
593
594 default:
595 $info['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data';
596 break;
597 }
598 break;
599
600 case 3: // BI_BITFIELDS
601 switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
602 case 16:
603 case 32:
604 $redshift = 0;
605 $greenshift = 0;
606 $blueshift = 0;
607 while ((($thisfile_bmp_header_raw['red_mask'] >> $redshift) & 0x01) == 0) {
608 $redshift++;
609 }
610 while ((($thisfile_bmp_header_raw['green_mask'] >> $greenshift) & 0x01) == 0) {
611 $greenshift++;
612 }
613 while ((($thisfile_bmp_header_raw['blue_mask'] >> $blueshift) & 0x01) == 0) {
614 $blueshift++;
615 }
616 for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
617 for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
618 $pixelvalue = Helper::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset, $thisfile_bmp_header_raw['bits_per_pixel'] / 8));
619 $pixeldataoffset += $thisfile_bmp_header_raw['bits_per_pixel'] / 8;
620
621 $red = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['red_mask']) >> $redshift) / ($thisfile_bmp_header_raw['red_mask'] >> $redshift)) * 255));
622 $green = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['green_mask']) >> $greenshift) / ($thisfile_bmp_header_raw['green_mask'] >> $greenshift)) * 255));
623 $blue = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['blue_mask']) >> $blueshift) / ($thisfile_bmp_header_raw['blue_mask'] >> $blueshift)) * 255));
624 $thisfile_bmp['data'][$row][$col] = (($red << 16) | ($green << 8) | ($blue));
625 }
626 while (($pixeldataoffset % 4) != 0) {
627 // lines are padded to nearest DWORD
628 $pixeldataoffset++;
629 }
630 }
631 break;
632
633 default:
634 $info['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data';
635 break;
636 }
637 break;
638
639 default: // unhandled compression type
640 $info['error'][] = 'Unknown/unhandled compression type value ('.$thisfile_bmp_header_raw['compression'].') - cannot decompress pixel data';
641 break;
642 }
643 }
644
645 return true;
646 }
fseek($bytes, $whence=SEEK_SET)
static LittleEndian2Int($byteword, $signed=false)
Definition: Helper.php:413
static PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8')
Definition: Helper.php:36
static FixedPoint2_30($rawdata)
Definition: Helper.php:709
BMPcompressionOS2Lookup($compressionid)
@staticvar array $BMPcompressionOS2Lookup
Definition: Bmp.php:719
BMPcompressionWindowsLookup($compressionid)
@staticvar array $BMPcompressionWindowsLookup
Definition: Bmp.php:699
$red
Definition: example_030.php:80
$green
Definition: example_030.php:83
$blue
Definition: example_030.php:81
$info
Definition: example_052.php:80

References $blue, $green, $info, $red, $row, GetId3\Module\Graphic\Bmp\BMPcompressionOS2Lookup(), GetId3\Module\Graphic\Bmp\BMPcompressionWindowsLookup(), GetId3\Lib\Helper\FixedPoint2_30(), GetId3\Handler\BaseHandler\fread(), GetId3\Handler\BaseHandler\fseek(), GetId3\Lib\Helper\LittleEndian2Int(), and GetId3\Lib\Helper\PrintHexBytes().

+ Here is the call graph for this function:

◆ BMPcompressionOS2Lookup()

GetId3\Module\Graphic\Bmp::BMPcompressionOS2Lookup (   $compressionid)

@staticvar array $BMPcompressionOS2Lookup

Parameters
type$compressionid
Returns
type

Definition at line 719 of file Bmp.php.

720 {
721 static $BMPcompressionOS2Lookup = array(
722 0 => 'BI_RGB',
723 1 => 'BI_RLE8',
724 2 => 'BI_RLE4',
725 3 => 'Huffman 1D',
726 4 => 'BI_RLE24',
727 );
728
729 return (isset($BMPcompressionOS2Lookup[$compressionid]) ? $BMPcompressionOS2Lookup[$compressionid] : 'invalid');
730 }

Referenced by GetId3\Module\Graphic\Bmp\analyze().

+ Here is the caller graph for this function:

◆ BMPcompressionWindowsLookup()

GetId3\Module\Graphic\Bmp::BMPcompressionWindowsLookup (   $compressionid)

@staticvar array $BMPcompressionWindowsLookup

Parameters
type$compressionid
Returns
type

Definition at line 699 of file Bmp.php.

700 {
701 static $BMPcompressionWindowsLookup = array(
702 0 => 'BI_RGB',
703 1 => 'BI_RLE8',
704 2 => 'BI_RLE4',
705 3 => 'BI_BITFIELDS',
706 4 => 'BI_JPEG',
707 5 => 'BI_PNG'
708 );
709
710 return (isset($BMPcompressionWindowsLookup[$compressionid]) ? $BMPcompressionWindowsLookup[$compressionid] : 'invalid');
711 }

Referenced by GetId3\Module\Graphic\Bmp\analyze().

+ Here is the caller graph for this function:

◆ PlotBMP()

GetId3\Module\Graphic\Bmp::PlotBMP ( $BMPinfo)
Parameters
type$BMPinfo
Returns
boolean

Definition at line 653 of file Bmp.php.

654 {
655 $starttime = time();
656 if (!isset($BMPinfo['bmp']['data']) || !is_array($BMPinfo['bmp']['data'])) {
657 echo 'ERROR: no pixel data<BR>';
658
659 return false;
660 }
661 set_time_limit(intval(round($BMPinfo['resolution_x'] * $BMPinfo['resolution_y'] / 10000)));
662 if ($im = ImageCreateTrueColor($BMPinfo['resolution_x'], $BMPinfo['resolution_y'])) {
663 for ($row = 0; $row < $BMPinfo['resolution_y']; $row++) {
664 for ($col = 0; $col < $BMPinfo['resolution_x']; $col++) {
665 if (isset($BMPinfo['bmp']['data'][$row][$col])) {
666 $red = ($BMPinfo['bmp']['data'][$row][$col] & 0x00FF0000) >> 16;
667 $green = ($BMPinfo['bmp']['data'][$row][$col] & 0x0000FF00) >> 8;
668 $blue = ($BMPinfo['bmp']['data'][$row][$col] & 0x000000FF);
669 $pixelcolor = ImageColorAllocate($im, $red, $green, $blue);
670 ImageSetPixel($im, $col, $row, $pixelcolor);
671 } else {
672 //echo 'ERROR: no data for pixel '.$row.' x '.$col.'<BR>';
673 //return false;
674 }
675 }
676 }
677 if (headers_sent()) {
678 echo 'plotted '.($BMPinfo['resolution_x'] * $BMPinfo['resolution_y']).' pixels in '.(time() - $starttime).' seconds<BR>';
679 ImageDestroy($im);
680 exit;
681 } else {
682 header('Content-type: image/png');
683 ImagePNG($im);
684 ImageDestroy($im);
685
686 return true;
687 }
688 }
689
690 return false;
691 }

References $blue, $green, $red, $row, and exit.

Field Documentation

◆ $ExtractData

GetId3\Module\Graphic\Bmp::$ExtractData = false

Definition at line 40 of file Bmp.php.

◆ $ExtractPalette

GetId3\Module\Graphic\Bmp::$ExtractPalette = false

Definition at line 35 of file Bmp.php.


The documentation for this class was generated from the following file: