23 {
24 $info = &$this->getid3->info;
25
26
27 $info[
'bmp'][
'header'][
'raw'] = array();
28 $thisfile_bmp = &
$info[
'bmp'];
29 $thisfile_bmp_header = &$thisfile_bmp['header'];
30 $thisfile_bmp_header_raw = &$thisfile_bmp_header['raw'];
31
32
33
34
35
36
37
38
39
41 $offset = 0;
42 $BMPheader = $this->
fread(14 + 40);
43
44 $thisfile_bmp_header_raw['identifier'] = substr($BMPheader, $offset, 2);
45 $offset += 2;
46
47 $magic = 'BM';
48 if ($thisfile_bmp_header_raw['identifier'] != $magic) {
50 unset(
$info[
'fileformat']);
52 return false;
53 }
54
56 $offset += 4;
58 $offset += 2;
60 $offset += 2;
62 $offset += 4;
64 $offset += 4;
65
66
67
70 if (($planes22 == 1) && ($planes26 != 1)) {
71 $thisfile_bmp['type_os'] = 'OS/2';
72 $thisfile_bmp['type_version'] = 1;
73 } elseif (($planes26 == 1) && ($planes22 != 1)) {
74 $thisfile_bmp['type_os'] = 'Windows';
75 $thisfile_bmp['type_version'] = 1;
76 } elseif ($thisfile_bmp_header_raw['header_size'] == 12) {
77 $thisfile_bmp['type_os'] = 'OS/2';
78 $thisfile_bmp['type_version'] = 1;
79 } elseif ($thisfile_bmp_header_raw['header_size'] == 40) {
80 $thisfile_bmp['type_os'] = 'Windows';
81 $thisfile_bmp['type_version'] = 1;
82 } elseif ($thisfile_bmp_header_raw['header_size'] == 84) {
83 $thisfile_bmp['type_os'] = 'Windows';
84 $thisfile_bmp['type_version'] = 4;
85 } elseif ($thisfile_bmp_header_raw['header_size'] == 100) {
86 $thisfile_bmp['type_os'] = 'Windows';
87 $thisfile_bmp['type_version'] = 5;
88 } else {
89 $this->
error(
'Unknown BMP subtype (or not a BMP file)');
90 unset(
$info[
'fileformat']);
92 return false;
93 }
94
95 $info[
'fileformat'] =
'bmp';
96 $info[
'video'][
'dataformat'] =
'bmp';
97 $info[
'video'][
'lossless'] =
true;
98 $info[
'video'][
'pixel_aspect_ratio'] = (float) 1;
99
100 if ($thisfile_bmp['type_os'] == 'OS/2') {
101
102
103
104
105
106
107
108
109
110
112 $offset += 2;
114 $offset += 2;
116 $offset += 2;
118 $offset += 2;
119
120 $info[
'video'][
'resolution_x'] = $thisfile_bmp_header_raw[
'width'];
121 $info[
'video'][
'resolution_y'] = $thisfile_bmp_header_raw[
'height'];
122 $info[
'video'][
'codec'] =
'BI_RGB '.$thisfile_bmp_header_raw[
'bits_per_pixel'].
'-bit';
123 $info[
'video'][
'bits_per_sample'] = $thisfile_bmp_header_raw[
'bits_per_pixel'];
124
125 if ($thisfile_bmp['type_version'] >= 2) {
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
142 $offset += 4;
144 $offset += 4;
146 $offset += 4;
148 $offset += 4;
150 $offset += 4;
152 $offset += 4;
154 $offset += 2;
156 $offset += 2;
158 $offset += 2;
160 $offset += 2;
162 $offset += 4;
164 $offset += 4;
166 $offset += 4;
168 $offset += 4;
169
171
172 $info[
'video'][
'codec'] = $thisfile_bmp_header[
'compression'].
' '.$thisfile_bmp_header_raw[
'bits_per_pixel'].
'-bit';
173 }
174
175 } elseif ($thisfile_bmp['type_os'] == 'Windows') {
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
196 $offset += 4;
198 $offset += 4;
200 $offset += 2;
202 $offset += 2;
204 $offset += 4;
206 $offset += 4;
208 $offset += 4;
210 $offset += 4;
212 $offset += 4;
214 $offset += 4;
215
217 $info[
'video'][
'resolution_x'] = $thisfile_bmp_header_raw[
'width'];
218 $info[
'video'][
'resolution_y'] = $thisfile_bmp_header_raw[
'height'];
219 $info[
'video'][
'codec'] = $thisfile_bmp_header[
'compression'].
' '.$thisfile_bmp_header_raw[
'bits_per_pixel'].
'-bit';
220 $info[
'video'][
'bits_per_sample'] = $thisfile_bmp_header_raw[
'bits_per_pixel'];
221
222 if (($thisfile_bmp['type_version'] >= 4) || ($thisfile_bmp_header_raw['compression'] == 3)) {
223
224 $BMPheader .= $this->
fread(44);
225
226
227
228
229
230
231
232
233
234
235
236
238 $offset += 4;
240 $offset += 4;
242 $offset += 4;
244 $offset += 4;
246 $offset += 4;
247 $thisfile_bmp_header_raw['ciexyz_red'] = substr($BMPheader, $offset, 4);
248 $offset += 4;
249 $thisfile_bmp_header_raw['ciexyz_green'] = substr($BMPheader, $offset, 4);
250 $offset += 4;
251 $thisfile_bmp_header_raw['ciexyz_blue'] = substr($BMPheader, $offset, 4);
252 $offset += 4;
254 $offset += 4;
256 $offset += 4;
258 $offset += 4;
259
263 }
264
265 if ($thisfile_bmp['type_version'] >= 5) {
266 $BMPheader .= $this->
fread(16);
267
268
269
270
271
272
273
275 $offset += 4;
277 $offset += 4;
279 $offset += 4;
281 $offset += 4;
282 }
283
284 } else {
285
286 $this->
error(
'Unknown BMP format in header.');
287 return false;
288
289 }
290
291
292 if ($this->ExtractPalette || $this->ExtractData) {
293 $PaletteEntries = 0;
294 if ($thisfile_bmp_header_raw['bits_per_pixel'] < 16) {
295 $PaletteEntries = pow(2, $thisfile_bmp_header_raw['bits_per_pixel']);
296 } elseif (isset($thisfile_bmp_header_raw['colors_used']) && ($thisfile_bmp_header_raw['colors_used'] > 0) && ($thisfile_bmp_header_raw['colors_used'] <= 256)) {
297 $PaletteEntries = $thisfile_bmp_header_raw['colors_used'];
298 }
299 if ($PaletteEntries > 0) {
300 $BMPpalette = $this->
fread(4 * $PaletteEntries);
301 $paletteoffset = 0;
302 for (
$i = 0;
$i < $PaletteEntries;
$i++) {
303
304
305
306
307
311 if (($thisfile_bmp['type_os'] == 'OS/2') && ($thisfile_bmp['type_version'] == 1)) {
312
313 } else {
314 $paletteoffset++;
315 }
317 }
318 }
319 }
320
321 if ($this->ExtractData) {
322 $this->
fseek($thisfile_bmp_header_raw[
'data_offset']);
323 $RowByteLength = ceil(($thisfile_bmp_header_raw['width'] * ($thisfile_bmp_header_raw['bits_per_pixel'] / 8)) / 4) * 4;
324 $BMPpixelData = $this->
fread($thisfile_bmp_header_raw[
'height'] * $RowByteLength);
325 $pixeldataoffset = 0;
326 $thisfile_bmp_header_raw['compression'] = (isset($thisfile_bmp_header_raw['compression']) ? $thisfile_bmp_header_raw['compression'] : '');
327 switch ($thisfile_bmp_header_raw['compression']) {
328
329 case 0:
330 switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
331 case 1:
332 for (
$row = ($thisfile_bmp_header_raw[
'height'] - 1);
$row >= 0;
$row--) {
333 for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) {
334 $paletteindexbyte = ord($BMPpixelData{$pixeldataoffset++});
335 for (
$i = 7;
$i >= 0;
$i--) {
336 $paletteindex = ($paletteindexbyte & (0x01 <<
$i)) >>
$i;
337 $thisfile_bmp[
'data'][
$row][$col] = $thisfile_bmp[
'palette'][$paletteindex];
338 $col++;
339 }
340 }
341 while (($pixeldataoffset % 4) != 0) {
342
343 $pixeldataoffset++;
344 }
345 }
346 break;
347
348 case 4:
349 for (
$row = ($thisfile_bmp_header_raw[
'height'] - 1);
$row >= 0;
$row--) {
350 for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) {
351 $paletteindexbyte = ord($BMPpixelData{$pixeldataoffset++});
352 for (
$i = 1;
$i >= 0;
$i--) {
353 $paletteindex = ($paletteindexbyte & (0x0F << (4 *
$i))) >> (4 *
$i);
354 $thisfile_bmp[
'data'][
$row][$col] = $thisfile_bmp[
'palette'][$paletteindex];
355 $col++;
356 }
357 }
358 while (($pixeldataoffset % 4) != 0) {
359
360 $pixeldataoffset++;
361 }
362 }
363 break;
364
365 case 8:
366 for (
$row = ($thisfile_bmp_header_raw[
'height'] - 1);
$row >= 0;
$row--) {
367 for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
368 $paletteindex = ord($BMPpixelData{$pixeldataoffset++});
369 $thisfile_bmp[
'data'][
$row][$col] = $thisfile_bmp[
'palette'][$paletteindex];
370 }
371 while (($pixeldataoffset % 4) != 0) {
372
373 $pixeldataoffset++;
374 }
375 }
376 break;
377
378 case 24:
379 for (
$row = ($thisfile_bmp_header_raw[
'height'] - 1);
$row >= 0;
$row--) {
380 for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
381 $thisfile_bmp[
'data'][
$row][$col] = (ord($BMPpixelData{$pixeldataoffset+2}) << 16) | (ord($BMPpixelData{$pixeldataoffset+1}) << 8) | ord($BMPpixelData{$pixeldataoffset});
382 $pixeldataoffset += 3;
383 }
384 while (($pixeldataoffset % 4) != 0) {
385
386 $pixeldataoffset++;
387 }
388 }
389 break;
390
391 case 32:
392 for (
$row = ($thisfile_bmp_header_raw[
'height'] - 1);
$row >= 0;
$row--) {
393 for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
394 $thisfile_bmp[
'data'][
$row][$col] = (ord($BMPpixelData{$pixeldataoffset+3}) << 24) | (ord($BMPpixelData{$pixeldataoffset+2}) << 16) | (ord($BMPpixelData{$pixeldataoffset+1}) << 8) | ord($BMPpixelData{$pixeldataoffset});
395 $pixeldataoffset += 4;
396 }
397 while (($pixeldataoffset % 4) != 0) {
398
399 $pixeldataoffset++;
400 }
401 }
402 break;
403
404 case 16:
405
406 break;
407
408 default:
409 $this->
error(
'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw[
'bits_per_pixel'].
') - cannot read pixel data');
410 break;
411 }
412 break;
413
414
415 case 1:
416 switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
417 case 8:
418 $pixelcounter = 0;
419 while ($pixeldataoffset < strlen($BMPpixelData)) {
422 if ($firstbyte == 0) {
423
424
425
426
427 switch ($secondbyte) {
428 case 0:
429
430
431 break;
432
433 case 1:
434
435 $pixeldataoffset = strlen($BMPpixelData);
436 break;
437
438 case 2:
439
440
441
444 $col = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement;
445 $row = ($thisfile_bmp_header_raw[
'height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw[
'width'])) - $rowincrement;
446 $pixelcounter = (
$row * $thisfile_bmp_header_raw[
'width']) + $col;
447 break;
448
449 default:
450
451
452
453
454 for (
$i = 0;
$i < $secondbyte;
$i++) {
456 $col = $pixelcounter % $thisfile_bmp_header_raw['width'];
457 $row = $thisfile_bmp_header_raw[
'height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw[
'width']);
458 $thisfile_bmp[
'data'][
$row][$col] = $thisfile_bmp[
'palette'][$paletteindex];
459 $pixelcounter++;
460 }
461 while (($pixeldataoffset % 2) != 0) {
462
463 $pixeldataoffset++;
464 }
465 break;
466 }
467
468 } else {
469
470
471
472 for (
$i = 0;
$i < $firstbyte;
$i++) {
473 $col = $pixelcounter % $thisfile_bmp_header_raw['width'];
474 $row = $thisfile_bmp_header_raw[
'height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw[
'width']);
475 $thisfile_bmp[
'data'][
$row][$col] = $thisfile_bmp[
'palette'][$secondbyte];
476 $pixelcounter++;
477 }
478
479 }
480 }
481 break;
482
483 default:
484 $this->
error(
'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw[
'bits_per_pixel'].
') - cannot read pixel data');
485 break;
486 }
487 break;
488
489
490
491 case 2:
492 switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
493 case 4:
494 $pixelcounter = 0;
495 while ($pixeldataoffset < strlen($BMPpixelData)) {
498 if ($firstbyte == 0) {
499
500
501
502
503 switch ($secondbyte) {
504 case 0:
505
506
507 break;
508
509 case 1:
510
511 $pixeldataoffset = strlen($BMPpixelData);
512 break;
513
514 case 2:
515
516
517
520 $col = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement;
521 $row = ($thisfile_bmp_header_raw[
'height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw[
'width'])) - $rowincrement;
522 $pixelcounter = (
$row * $thisfile_bmp_header_raw[
'width']) + $col;
523 break;
524
525 default:
526
527
528
529
530 unset($paletteindexes);
531 for (
$i = 0;
$i < ceil($secondbyte / 2);
$i++) {
533 $paletteindexes[] = ($paletteindexbyte & 0xF0) >> 4;
534 $paletteindexes[] = ($paletteindexbyte & 0x0F);
535 }
536 while (($pixeldataoffset % 2) != 0) {
537
538 $pixeldataoffset++;
539 }
540
541 foreach ($paletteindexes as $paletteindex) {
542 $col = $pixelcounter % $thisfile_bmp_header_raw['width'];
543 $row = $thisfile_bmp_header_raw[
'height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw[
'width']);
544 $thisfile_bmp[
'data'][
$row][$col] = $thisfile_bmp[
'palette'][$paletteindex];
545 $pixelcounter++;
546 }
547 break;
548 }
549
550 } else {
551
552
553
554
555
556
557
558
559 $paletteindexes[0] = ($secondbyte & 0xF0) >> 4;
560 $paletteindexes[1] = ($secondbyte & 0x0F);
561 for (
$i = 0;
$i < $firstbyte;
$i++) {
562 $col = $pixelcounter % $thisfile_bmp_header_raw['width'];
563 $row = $thisfile_bmp_header_raw[
'height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw[
'width']);
564 $thisfile_bmp[
'data'][
$row][$col] = $thisfile_bmp[
'palette'][$paletteindexes[(
$i % 2)]];
565 $pixelcounter++;
566 }
567
568 }
569 }
570 break;
571
572 default:
573 $this->
error(
'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw[
'bits_per_pixel'].
') - cannot read pixel data');
574 break;
575 }
576 break;
577
578
579 case 3:
580 switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
581 case 16:
582 case 32:
583 $redshift = 0;
584 $greenshift = 0;
585 $blueshift = 0;
586 while ((($thisfile_bmp_header_raw['red_mask'] >> $redshift) & 0x01) == 0) {
587 $redshift++;
588 }
589 while ((($thisfile_bmp_header_raw['green_mask'] >> $greenshift) & 0x01) == 0) {
590 $greenshift++;
591 }
592 while ((($thisfile_bmp_header_raw['blue_mask'] >> $blueshift) & 0x01) == 0) {
593 $blueshift++;
594 }
595 for (
$row = ($thisfile_bmp_header_raw[
'height'] - 1);
$row >= 0;
$row--) {
596 for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
598 $pixeldataoffset += $thisfile_bmp_header_raw['bits_per_pixel'] / 8;
599
600 $red = intval(round(((($pixelvalue & $thisfile_bmp_header_raw[
'red_mask']) >> $redshift) / ($thisfile_bmp_header_raw[
'red_mask'] >> $redshift)) * 255));
601 $green = intval(round(((($pixelvalue & $thisfile_bmp_header_raw[
'green_mask']) >> $greenshift) / ($thisfile_bmp_header_raw[
'green_mask'] >> $greenshift)) * 255));
602 $blue = intval(round(((($pixelvalue & $thisfile_bmp_header_raw[
'blue_mask']) >> $blueshift) / ($thisfile_bmp_header_raw[
'blue_mask'] >> $blueshift)) * 255));
604 }
605 while (($pixeldataoffset % 4) != 0) {
606
607 $pixeldataoffset++;
608 }
609 }
610 break;
611
612 default:
613 $this->
error(
'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw[
'bits_per_pixel'].
') - cannot read pixel data');
614 break;
615 }
616 break;
617
618
619 default:
620 $this->
error(
'Unknown/unhandled compression type value ('.$thisfile_bmp_header_raw[
'compression'].
') - cannot decompress pixel data');
621 break;
622 }
623 }
624
625 return true;
626 }
BMPcompressionOS2Lookup($compressionid)
BMPcompressionWindowsLookup($compressionid)
fseek($bytes, $whence=SEEK_SET)
static PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8')
static FixedPoint2_30($rawdata)
static LittleEndian2Int($byteword, $signed=false)