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)
 array $BMPcompressionWindowsLookup More...
 
 BMPcompressionOS2Lookup ($compressionid)
 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

Definition at line 46 of file Bmp.php.

References $blue, $green, $info, $red, $row, array, 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().

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  }
static PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8')
Definition: Helper.php:36
$blue
Definition: example_030.php:81
static FixedPoint2_30($rawdata)
Definition: Helper.php:709
fseek($bytes, $whence=SEEK_SET)
$info
Definition: example_052.php:80
$red
Definition: example_030.php:80
$green
Definition: example_030.php:83
Create styles array
The data for the language used.
BMPcompressionOS2Lookup($compressionid)
array $BMPcompressionOS2Lookup
Definition: Bmp.php:719
static LittleEndian2Int($byteword, $signed=false)
Definition: Helper.php:413
BMPcompressionWindowsLookup($compressionid)
array $BMPcompressionWindowsLookup
Definition: Bmp.php:699
+ Here is the call graph for this function:

◆ BMPcompressionOS2Lookup()

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

array $BMPcompressionOS2Lookup

Parameters
type$compressionid
Returns
type

Definition at line 719 of file Bmp.php.

References array.

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

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  }
Create styles array
The data for the language used.
+ Here is the caller graph for this function:

◆ BMPcompressionWindowsLookup()

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

array $BMPcompressionWindowsLookup

Parameters
type$compressionid
Returns
type

Definition at line 699 of file Bmp.php.

References array.

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

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  }
Create styles array
The data for the language used.
+ 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.

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

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  }
$blue
Definition: example_030.php:81
$red
Definition: example_030.php:80
$green
Definition: example_030.php:83
Add a drawing to the header
Definition: 04printing.php:69
Add data(end) time
Method that wraps PHPs time in order to allow simulations with the workflow.

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: