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