/src/FreeImage/Source/FreeImage/PluginBMP.cpp
C++ | 1480 lines | 987 code | 303 blank | 190 comment | 277 complexity | 992db755149e41de68b37e55c8d8b79b MD5 | raw file
1// ========================================================== 2// BMP Loader and Writer 3// 4// Design and implementation by 5// - Floris van den Berg (flvdberg@wxs.nl) 6// - Markus Loibl (markus.loibl@epost.de) 7// - Martin Weber (martweb@gmx.net) 8// - Hervé Drolon (drolon@infonie.fr) 9// - Michal Novotny (michal@etc.cz) 10// 11// This file is part of FreeImage 3 12// 13// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY 14// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES 15// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE 16// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED 17// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT 18// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY 19// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL 20// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER 21// THIS DISCLAIMER. 22// 23// Use at your own risk! 24// ========================================================== 25 26#include "FreeImage.h" 27#include "Utilities.h" 28 29// ---------------------------------------------------------- 30// Constants + headers 31// ---------------------------------------------------------- 32 33static const BYTE RLE_COMMAND = 0; 34static const BYTE RLE_ENDOFLINE = 0; 35static const BYTE RLE_ENDOFBITMAP = 1; 36static const BYTE RLE_DELTA = 2; 37 38static const BYTE BI_RGB = 0; 39static const BYTE BI_RLE8 = 1; 40static const BYTE BI_RLE4 = 2; 41static const BYTE BI_BITFIELDS = 3; 42 43// ---------------------------------------------------------- 44 45#ifdef _WIN32 46#pragma pack(push, 1) 47#else 48#pragma pack(1) 49#endif 50 51typedef struct tagBITMAPCOREHEADER { 52 DWORD bcSize; 53 WORD bcWidth; 54 WORD bcHeight; 55 WORD bcPlanes; 56 WORD bcBitCnt; 57} BITMAPCOREHEADER, *PBITMAPCOREHEADER; 58 59typedef struct tagBITMAPINFOOS2_1X_HEADER { 60 DWORD biSize; 61 WORD biWidth; 62 WORD biHeight; 63 WORD biPlanes; 64 WORD biBitCount; 65} BITMAPINFOOS2_1X_HEADER, *PBITMAPINFOOS2_1X_HEADER; 66 67typedef struct tagBITMAPFILEHEADER { 68 WORD bfType; 69 DWORD bfSize; 70 WORD bfReserved1; 71 WORD bfReserved2; 72 DWORD bfOffBits; 73} BITMAPFILEHEADER, *PBITMAPFILEHEADER; 74 75#ifdef _WIN32 76#pragma pack(pop) 77#else 78#pragma pack() 79#endif 80 81// ========================================================== 82// Plugin Interface 83// ========================================================== 84 85static int s_format_id; 86 87// ========================================================== 88// Internal functions 89// ========================================================== 90 91#ifdef FREEIMAGE_BIGENDIAN 92static void 93SwapInfoHeader(BITMAPINFOHEADER *header) { 94 SwapLong(&header->biSize); 95 SwapLong((DWORD *)&header->biWidth); 96 SwapLong((DWORD *)&header->biHeight); 97 SwapShort(&header->biPlanes); 98 SwapShort(&header->biBitCount); 99 SwapLong(&header->biCompression); 100 SwapLong(&header->biSizeImage); 101 SwapLong((DWORD *)&header->biXPelsPerMeter); 102 SwapLong((DWORD *)&header->biYPelsPerMeter); 103 SwapLong(&header->biClrUsed); 104 SwapLong(&header->biClrImportant); 105} 106 107static void 108SwapCoreHeader(BITMAPCOREHEADER *header) { 109 SwapLong(&header->bcSize); 110 SwapShort(&header->bcWidth); 111 SwapShort(&header->bcHeight); 112 SwapShort(&header->bcPlanes); 113 SwapShort(&header->bcBitCnt); 114} 115 116static void 117SwapOS21XHeader(BITMAPINFOOS2_1X_HEADER *header) { 118 SwapLong(&header->biSize); 119 SwapShort(&header->biWidth); 120 SwapShort(&header->biHeight); 121 SwapShort(&header->biPlanes); 122 SwapShort(&header->biBitCount); 123} 124 125static void 126SwapFileHeader(BITMAPFILEHEADER *header) { 127 SwapShort(&header->bfType); 128 SwapLong(&header->bfSize); 129 SwapShort(&header->bfReserved1); 130 SwapShort(&header->bfReserved2); 131 SwapLong(&header->bfOffBits); 132} 133#endif 134 135// -------------------------------------------------------------------------- 136 137/** 138Load uncompressed image pixels for 1-, 4-, 8-, 16-, 24- and 32-bit dib 139@param io FreeImage IO 140@param handle FreeImage IO handle 141@param dib Image to be loaded 142@param height Image height 143@param pitch Image pitch 144@param bit_count Image bit-depth (1-, 4-, 8-, 16-, 24- or 32-bit) 145@return Returns TRUE if successful, returns FALSE otherwise 146*/ 147static BOOL 148LoadPixelData(FreeImageIO *io, fi_handle handle, FIBITMAP *dib, int height, unsigned pitch, unsigned bit_count) { 149 unsigned count = 0; 150 151 // Load pixel data 152 // NB: height can be < 0 for BMP data 153 if (height > 0) { 154 count = io->read_proc((void *)FreeImage_GetBits(dib), height * pitch, 1, handle); 155 if(count != 1) { 156 return FALSE; 157 } 158 } else { 159 int positiveHeight = abs(height); 160 for (int c = 0; c < positiveHeight; ++c) { 161 count = io->read_proc((void *)FreeImage_GetScanLine(dib, positiveHeight - c - 1), pitch, 1, handle); 162 if(count != 1) { 163 return FALSE; 164 } 165 } 166 } 167 168 // swap as needed 169#ifdef FREEIMAGE_BIGENDIAN 170 if (bit_count == 16) { 171 for(unsigned y = 0; y < FreeImage_GetHeight(dib); y++) { 172 WORD *pixel = (WORD *)FreeImage_GetScanLine(dib, y); 173 for(unsigned x = 0; x < FreeImage_GetWidth(dib); x++) { 174 SwapShort(pixel); 175 pixel++; 176 } 177 } 178 } 179#endif 180#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB 181 if (bit_count == 24 || bit_count == 32) { 182 for(unsigned y = 0; y < FreeImage_GetHeight(dib); y++) { 183 BYTE *pixel = FreeImage_GetScanLine(dib, y); 184 for(unsigned x = 0; x < FreeImage_GetWidth(dib); x++) { 185 INPLACESWAP(pixel[0], pixel[2]); 186 pixel += (bit_count >> 3); 187 } 188 } 189 } 190#endif 191 192 return TRUE; 193} 194 195/** 196Load image pixels for 4-bit RLE compressed dib 197@param io FreeImage IO 198@param handle FreeImage IO handle 199@param width Image width 200@param height Image height 201@param dib Image to be loaded 202@return Returns TRUE if successful, returns FALSE otherwise 203*/ 204static BOOL 205LoadPixelDataRLE4(FreeImageIO *io, fi_handle handle, int width, int height, FIBITMAP *dib) { 206 int status_byte = 0; 207 BYTE second_byte = 0; 208 int bits = 0; 209 210 BYTE *pixels = NULL; // temporary 8-bit buffer 211 212 try { 213 height = abs(height); 214 215 pixels = (BYTE*)malloc(width * height * sizeof(BYTE)); 216 if(!pixels) throw(1); 217 memset(pixels, 0, width * height * sizeof(BYTE)); 218 219 BYTE *q = pixels; 220 BYTE *end = pixels + height * width; 221 222 for (int scanline = 0; scanline < height; ) { 223 if (q < pixels || q >= end) { 224 break; 225 } 226 if(io->read_proc(&status_byte, sizeof(BYTE), 1, handle) != 1) { 227 throw(1); 228 } 229 if (status_byte != 0) { 230 status_byte = (int)MIN((size_t)status_byte, (size_t)(end - q)); 231 // Encoded mode 232 if(io->read_proc(&second_byte, sizeof(BYTE), 1, handle) != 1) { 233 throw(1); 234 } 235 for (int i = 0; i < status_byte; i++) { 236 *q++=(BYTE)((i & 0x01) ? (second_byte & 0x0f) : ((second_byte >> 4) & 0x0f)); 237 } 238 bits += status_byte; 239 } 240 else { 241 // Escape mode 242 if(io->read_proc(&status_byte, sizeof(BYTE), 1, handle) != 1) { 243 throw(1); 244 } 245 switch (status_byte) { 246 case RLE_ENDOFLINE: 247 { 248 // End of line 249 bits = 0; 250 scanline++; 251 q = pixels + scanline*width; 252 } 253 break; 254 255 case RLE_ENDOFBITMAP: 256 // End of bitmap 257 q = end; 258 break; 259 260 case RLE_DELTA: 261 { 262 // read the delta values 263 264 BYTE delta_x = 0; 265 BYTE delta_y = 0; 266 267 if(io->read_proc(&delta_x, sizeof(BYTE), 1, handle) != 1) { 268 throw(1); 269 } 270 if(io->read_proc(&delta_y, sizeof(BYTE), 1, handle) != 1) { 271 throw(1); 272 } 273 274 // apply them 275 276 bits += delta_x; 277 scanline += delta_y; 278 q = pixels + scanline*width+bits; 279 } 280 break; 281 282 default: 283 { 284 // Absolute mode 285 status_byte = (int)MIN((size_t)status_byte, (size_t)(end - q)); 286 for (int i = 0; i < status_byte; i++) { 287 if ((i & 0x01) == 0) { 288 if(io->read_proc(&second_byte, sizeof(BYTE), 1, handle) != 1) { 289 throw(1); 290 } 291 } 292 *q++=(BYTE)((i & 0x01) ? (second_byte & 0x0f) : ((second_byte >> 4) & 0x0f)); 293 } 294 bits += status_byte; 295 // Read pad byte 296 if (((status_byte & 0x03) == 1) || ((status_byte & 0x03) == 2)) { 297 BYTE padding = 0; 298 if(io->read_proc(&padding, sizeof(BYTE), 1, handle) != 1) { 299 throw(1); 300 } 301 } 302 } 303 break; 304 } 305 } 306 } 307 308 { 309 // Convert to 4-bit 310 for(int y = 0; y < height; y++) { 311 const BYTE *src = (BYTE*)pixels + y * width; 312 BYTE *dst = FreeImage_GetScanLine(dib, y); 313 314 BOOL hinibble = TRUE; 315 316 for (int cols = 0; cols < width; cols++){ 317 if (hinibble) { 318 dst[cols >> 1] = (src[cols] << 4); 319 } else { 320 dst[cols >> 1] |= src[cols]; 321 } 322 323 hinibble = !hinibble; 324 } 325 } 326 } 327 328 free(pixels); 329 330 return TRUE; 331 332 } catch(int) { 333 if(pixels) free(pixels); 334 return FALSE; 335 } 336} 337 338/** 339Load image pixels for 8-bit RLE compressed dib 340@param io FreeImage IO 341@param handle FreeImage IO handle 342@param width Image width 343@param height Image height 344@param dib Image to be loaded 345@return Returns TRUE if successful, returns FALSE otherwise 346*/ 347static BOOL 348LoadPixelDataRLE8(FreeImageIO *io, fi_handle handle, int width, int height, FIBITMAP *dib) { 349 BYTE status_byte = 0; 350 BYTE second_byte = 0; 351 int scanline = 0; 352 int bits = 0; 353 354 for (;;) { 355 if( io->read_proc(&status_byte, sizeof(BYTE), 1, handle) != 1) { 356 return FALSE; 357 } 358 359 switch (status_byte) { 360 case RLE_COMMAND : 361 if(io->read_proc(&status_byte, sizeof(BYTE), 1, handle) != 1) { 362 return FALSE; 363 } 364 365 switch (status_byte) { 366 case RLE_ENDOFLINE : 367 bits = 0; 368 scanline++; 369 break; 370 371 case RLE_ENDOFBITMAP : 372 return TRUE; 373 374 case RLE_DELTA : 375 { 376 // read the delta values 377 378 BYTE delta_x = 0; 379 BYTE delta_y = 0; 380 381 if(io->read_proc(&delta_x, sizeof(BYTE), 1, handle) != 1) { 382 return FALSE; 383 } 384 if(io->read_proc(&delta_y, sizeof(BYTE), 1, handle) != 1) { 385 return FALSE; 386 } 387 388 // apply them 389 390 bits += delta_x; 391 scanline += delta_y; 392 393 break; 394 } 395 396 default : 397 { 398 if(scanline >= abs(height)) { 399 return TRUE; 400 } 401 402 int count = MIN((int)status_byte, width - bits); 403 404 BYTE *sline = FreeImage_GetScanLine(dib, scanline); 405 406 if(io->read_proc((void *)(sline + bits), sizeof(BYTE) * count, 1, handle) != 1) { 407 return FALSE; 408 } 409 410 // align run length to even number of bytes 411 412 if ((status_byte & 1) == 1) { 413 if(io->read_proc(&second_byte, sizeof(BYTE), 1, handle) != 1) { 414 return FALSE; 415 } 416 } 417 418 bits += status_byte; 419 420 break; 421 } 422 } 423 424 break; 425 426 default : 427 { 428 if(scanline >= abs(height)) { 429 return TRUE; 430 } 431 432 int count = MIN((int)status_byte, width - bits); 433 434 BYTE *sline = FreeImage_GetScanLine(dib, scanline); 435 436 if(io->read_proc(&second_byte, sizeof(BYTE), 1, handle) != 1) { 437 return FALSE; 438 } 439 440 for (int i = 0; i < count; i++) { 441 *(sline + bits) = second_byte; 442 443 bits++; 444 } 445 446 break; 447 } 448 } 449 } 450} 451 452// -------------------------------------------------------------------------- 453 454static FIBITMAP * 455LoadWindowsBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bits_offset) { 456 FIBITMAP *dib = NULL; 457 458 try { 459 BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS; 460 461 // load the info header 462 463 BITMAPINFOHEADER bih; 464 465 io->read_proc(&bih, sizeof(BITMAPINFOHEADER), 1, handle); 466#ifdef FREEIMAGE_BIGENDIAN 467 SwapInfoHeader(&bih); 468#endif 469 470 // keep some general information about the bitmap 471 472 unsigned used_colors = bih.biClrUsed; 473 int width = bih.biWidth; 474 int height = bih.biHeight; // WARNING: height can be < 0 => check each call using 'height' as a parameter 475 unsigned bit_count = bih.biBitCount; 476 unsigned compression = bih.biCompression; 477 unsigned pitch = CalculatePitch(CalculateLine(width, bit_count)); 478 479 switch (bit_count) { 480 case 1 : 481 case 4 : 482 case 8 : 483 { 484 if ((used_colors == 0) || (used_colors > CalculateUsedPaletteEntries(bit_count))) 485 used_colors = CalculateUsedPaletteEntries(bit_count); 486 487 // allocate enough memory to hold the bitmap (header, palette, pixels) and read the palette 488 489 dib = FreeImage_AllocateHeader(header_only, width, height, bit_count); 490 if (dib == NULL) { 491 throw FI_MSG_ERROR_DIB_MEMORY; 492 } 493 494 // set resolution information 495 FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter); 496 FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter); 497 498 // load the palette 499 500 io->read_proc(FreeImage_GetPalette(dib), used_colors * sizeof(RGBQUAD), 1, handle); 501#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB 502 RGBQUAD *pal = FreeImage_GetPalette(dib); 503 for(int i = 0; i < used_colors; i++) { 504 INPLACESWAP(pal[i].rgbRed, pal[i].rgbBlue); 505 } 506#endif 507 508 if(header_only) { 509 // header only mode 510 return dib; 511 } 512 513 // seek to the actual pixel data. 514 // this is needed because sometimes the palette is larger than the entries it contains predicts 515 516 if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * sizeof(RGBQUAD)))) 517 io->seek_proc(handle, bitmap_bits_offset, SEEK_SET); 518 519 // read the pixel data 520 521 switch (compression) { 522 case BI_RGB : 523 if( LoadPixelData(io, handle, dib, height, pitch, bit_count) ) { 524 return dib; 525 } else { 526 throw "Error encountered while decoding BMP data"; 527 } 528 break; 529 530 case BI_RLE4 : 531 if( LoadPixelDataRLE4(io, handle, width, height, dib) ) { 532 return dib; 533 } else { 534 throw "Error encountered while decoding RLE4 BMP data"; 535 } 536 break; 537 538 case BI_RLE8 : 539 if( LoadPixelDataRLE8(io, handle, width, height, dib) ) { 540 return dib; 541 } else { 542 throw "Error encountered while decoding RLE8 BMP data"; 543 } 544 break; 545 546 default : 547 throw FI_MSG_ERROR_UNSUPPORTED_COMPRESSION; 548 } 549 } 550 break; // 1-, 4-, 8-bit 551 552 case 16 : 553 { 554 if (bih.biCompression == BI_BITFIELDS) { 555 DWORD bitfields[3]; 556 557 io->read_proc(bitfields, 3 * sizeof(DWORD), 1, handle); 558 559 dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, bitfields[0], bitfields[1], bitfields[2]); 560 } else { 561 dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI16_555_RED_MASK, FI16_555_GREEN_MASK, FI16_555_BLUE_MASK); 562 } 563 564 if (dib == NULL) { 565 throw FI_MSG_ERROR_DIB_MEMORY; 566 } 567 568 // set resolution information 569 FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter); 570 FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter); 571 572 if(header_only) { 573 // header only mode 574 return dib; 575 } 576 577 // load pixel data and swap as needed if OS is Big Endian 578 579 if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER))) { 580 // seek to the actual pixel data 581 io->seek_proc(handle, bitmap_bits_offset, SEEK_SET); 582 } 583 584 LoadPixelData(io, handle, dib, height, pitch, bit_count); 585 586 return dib; 587 } 588 break; // 16-bit 589 590 case 24 : 591 case 32 : 592 { 593 if (bih.biCompression == BI_BITFIELDS) { 594 DWORD bitfields[3]; 595 596 io->read_proc(bitfields, 3 * sizeof(DWORD), 1, handle); 597 598 dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, bitfields[0], bitfields[1], bitfields[2]); 599 } else { 600 if( bit_count == 32 ) { 601 dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); 602 } else { 603 dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); 604 } 605 } 606 607 if (dib == NULL) { 608 throw FI_MSG_ERROR_DIB_MEMORY; 609 } 610 611 // set resolution information 612 FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter); 613 FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter); 614 615 if(header_only) { 616 // header only mode 617 return dib; 618 } 619 620 // Skip over the optional palette 621 // A 24 or 32 bit DIB may contain a palette for faster color reduction 622 623 if (FreeImage_GetColorsUsed(dib) > 0) { 624 io->seek_proc(handle, FreeImage_GetColorsUsed(dib) * sizeof(RGBQUAD), SEEK_CUR); 625 } else if ((bih.biCompression != BI_BITFIELDS) && (bitmap_bits_offset > sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER))) { 626 io->seek_proc(handle, bitmap_bits_offset, SEEK_SET); 627 } 628 629 // read in the bitmap bits 630 // load pixel data and swap as needed if OS is Big Endian 631 LoadPixelData(io, handle, dib, height, pitch, bit_count); 632 633 // check if the bitmap contains transparency, if so enable it in the header 634 635 FreeImage_SetTransparent(dib, (FreeImage_GetColorType(dib) == FIC_RGBALPHA)); 636 637 return dib; 638 } 639 break; // 24-, 32-bit 640 } 641 } catch(const char *message) { 642 if(dib) { 643 FreeImage_Unload(dib); 644 } 645 if(message) { 646 FreeImage_OutputMessageProc(s_format_id, message); 647 } 648 } 649 650 return NULL; 651} 652 653// -------------------------------------------------------------------------- 654 655static FIBITMAP * 656LoadOS22XBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bits_offset) { 657 FIBITMAP *dib = NULL; 658 659 try { 660 BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS; 661 662 // load the info header 663 664 BITMAPINFOHEADER bih; 665 666 io->read_proc(&bih, sizeof(BITMAPINFOHEADER), 1, handle); 667#ifdef FREEIMAGE_BIGENDIAN 668 SwapInfoHeader(&bih); 669#endif 670 671 // keep some general information about the bitmap 672 673 unsigned used_colors = bih.biClrUsed; 674 int width = bih.biWidth; 675 int height = bih.biHeight; // WARNING: height can be < 0 => check each read_proc using 'height' as a parameter 676 unsigned bit_count = bih.biBitCount; 677 unsigned compression = bih.biCompression; 678 unsigned pitch = CalculatePitch(CalculateLine(width, bit_count)); 679 680 switch (bit_count) { 681 case 1 : 682 case 4 : 683 case 8 : 684 { 685 if ((used_colors == 0) || (used_colors > CalculateUsedPaletteEntries(bit_count))) 686 used_colors = CalculateUsedPaletteEntries(bit_count); 687 688 // allocate enough memory to hold the bitmap (header, palette, pixels) and read the palette 689 690 dib = FreeImage_AllocateHeader(header_only, width, height, bit_count); 691 692 if (dib == NULL) { 693 throw FI_MSG_ERROR_DIB_MEMORY; 694 } 695 696 // set resolution information 697 FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter); 698 FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter); 699 700 // load the palette 701 // note that it may contain RGB or RGBA values : we will calculate this 702 unsigned pal_size = (bitmap_bits_offset - sizeof(BITMAPFILEHEADER) - bih.biSize) / used_colors; 703 704 io->seek_proc(handle, sizeof(BITMAPFILEHEADER) + bih.biSize, SEEK_SET); 705 706 RGBQUAD *pal = FreeImage_GetPalette(dib); 707 708 if(pal_size == 4) { 709 for (unsigned count = 0; count < used_colors; count++) { 710 FILE_BGRA bgra; 711 712 io->read_proc(&bgra, sizeof(FILE_BGRA), 1, handle); 713 714 pal[count].rgbRed = bgra.r; 715 pal[count].rgbGreen = bgra.g; 716 pal[count].rgbBlue = bgra.b; 717 } 718 } else if(pal_size == 3) { 719 for (unsigned count = 0; count < used_colors; count++) { 720 FILE_BGR bgr; 721 722 io->read_proc(&bgr, sizeof(FILE_BGR), 1, handle); 723 724 pal[count].rgbRed = bgr.r; 725 pal[count].rgbGreen = bgr.g; 726 pal[count].rgbBlue = bgr.b; 727 } 728 } 729 730 if(header_only) { 731 // header only mode 732 return dib; 733 } 734 735 // seek to the actual pixel data. 736 // this is needed because sometimes the palette is larger than the entries it contains predicts 737 738 if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3))) 739 io->seek_proc(handle, bitmap_bits_offset, SEEK_SET); 740 741 // read the pixel data 742 743 switch (compression) { 744 case BI_RGB : 745 // load pixel data 746 LoadPixelData(io, handle, dib, height, pitch, bit_count); 747 return dib; 748 749 case BI_RLE4 : 750 if( LoadPixelDataRLE4(io, handle, width, height, dib) ) { 751 return dib; 752 } else { 753 throw "Error encountered while decoding RLE4 BMP data"; 754 } 755 break; 756 757 case BI_RLE8 : 758 if( LoadPixelDataRLE8(io, handle, width, height, dib) ) { 759 return dib; 760 } else { 761 throw "Error encountered while decoding RLE8 BMP data"; 762 } 763 break; 764 765 default : 766 throw FI_MSG_ERROR_UNSUPPORTED_COMPRESSION; 767 } 768 } 769 770 case 16 : 771 { 772 if (bih.biCompression == 3) { 773 DWORD bitfields[3]; 774 775 io->read_proc(bitfields, 3 * sizeof(DWORD), 1, handle); 776 777 dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, bitfields[0], bitfields[1], bitfields[2]); 778 } else { 779 dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI16_555_RED_MASK, FI16_555_GREEN_MASK, FI16_555_BLUE_MASK); 780 } 781 782 if (dib == NULL) { 783 throw FI_MSG_ERROR_DIB_MEMORY; 784 } 785 786 // set resolution information 787 FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter); 788 FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter); 789 790 if(header_only) { 791 // header only mode 792 return dib; 793 } 794 795 if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3))) { 796 io->seek_proc(handle, bitmap_bits_offset, SEEK_SET); 797 } 798 799 // load pixel data and swap as needed if OS is Big Endian 800 LoadPixelData(io, handle, dib, height, pitch, bit_count); 801 802 return dib; 803 } 804 805 case 24 : 806 case 32 : 807 { 808 if( bit_count == 32 ) { 809 dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); 810 } else { 811 dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); 812 } 813 814 if (dib == NULL) { 815 throw FI_MSG_ERROR_DIB_MEMORY; 816 } 817 818 // set resolution information 819 FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter); 820 FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter); 821 822 if(header_only) { 823 // header only mode 824 return dib; 825 } 826 827 // Skip over the optional palette 828 // A 24 or 32 bit DIB may contain a palette for faster color reduction 829 830 if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3))) 831 io->seek_proc(handle, bitmap_bits_offset, SEEK_SET); 832 833 // read in the bitmap bits 834 // load pixel data and swap as needed if OS is Big Endian 835 LoadPixelData(io, handle, dib, height, pitch, bit_count); 836 837 // check if the bitmap contains transparency, if so enable it in the header 838 839 FreeImage_SetTransparent(dib, (FreeImage_GetColorType(dib) == FIC_RGBALPHA)); 840 841 return dib; 842 } 843 } 844 } catch(const char *message) { 845 if(dib) 846 FreeImage_Unload(dib); 847 848 FreeImage_OutputMessageProc(s_format_id, message); 849 } 850 851 return NULL; 852} 853 854// -------------------------------------------------------------------------- 855 856static FIBITMAP * 857LoadOS21XBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bits_offset) { 858 FIBITMAP *dib = NULL; 859 860 try { 861 BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS; 862 863 BITMAPINFOOS2_1X_HEADER bios2_1x; 864 865 io->read_proc(&bios2_1x, sizeof(BITMAPINFOOS2_1X_HEADER), 1, handle); 866#ifdef FREEIMAGE_BIGENDIAN 867 SwapOS21XHeader(&bios2_1x); 868#endif 869 // keep some general information about the bitmap 870 871 unsigned used_colors = 0; 872 unsigned width = bios2_1x.biWidth; 873 unsigned height = bios2_1x.biHeight; // WARNING: height can be < 0 => check each read_proc using 'height' as a parameter 874 unsigned bit_count = bios2_1x.biBitCount; 875 unsigned pitch = CalculatePitch(CalculateLine(width, bit_count)); 876 877 switch (bit_count) { 878 case 1 : 879 case 4 : 880 case 8 : 881 { 882 used_colors = CalculateUsedPaletteEntries(bit_count); 883 884 // allocate enough memory to hold the bitmap (header, palette, pixels) and read the palette 885 886 dib = FreeImage_AllocateHeader(header_only, width, height, bit_count); 887 888 if (dib == NULL) { 889 throw FI_MSG_ERROR_DIB_MEMORY; 890 } 891 892 // set resolution information to default values (72 dpi in english units) 893 FreeImage_SetDotsPerMeterX(dib, 2835); 894 FreeImage_SetDotsPerMeterY(dib, 2835); 895 896 // load the palette 897 898 RGBQUAD *pal = FreeImage_GetPalette(dib); 899 900 for (unsigned count = 0; count < used_colors; count++) { 901 FILE_BGR bgr; 902 903 io->read_proc(&bgr, sizeof(FILE_BGR), 1, handle); 904 905 pal[count].rgbRed = bgr.r; 906 pal[count].rgbGreen = bgr.g; 907 pal[count].rgbBlue = bgr.b; 908 } 909 910 if(header_only) { 911 // header only mode 912 return dib; 913 } 914 915 // Skip over the optional palette 916 // A 24 or 32 bit DIB may contain a palette for faster color reduction 917 918 io->seek_proc(handle, bitmap_bits_offset, SEEK_SET); 919 920 // read the pixel data 921 922 // load pixel data 923 LoadPixelData(io, handle, dib, height, pitch, bit_count); 924 925 return dib; 926 } 927 928 case 16 : 929 { 930 dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI16_555_RED_MASK, FI16_555_GREEN_MASK, FI16_555_BLUE_MASK); 931 932 if (dib == NULL) { 933 throw FI_MSG_ERROR_DIB_MEMORY; 934 } 935 936 // set resolution information to default values (72 dpi in english units) 937 FreeImage_SetDotsPerMeterX(dib, 2835); 938 FreeImage_SetDotsPerMeterY(dib, 2835); 939 940 if(header_only) { 941 // header only mode 942 return dib; 943 } 944 945 // load pixel data and swap as needed if OS is Big Endian 946 LoadPixelData(io, handle, dib, height, pitch, bit_count); 947 948 return dib; 949 } 950 951 case 24 : 952 case 32 : 953 { 954 if( bit_count == 32 ) { 955 dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); 956 } else { 957 dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); 958 } 959 960 if (dib == NULL) { 961 throw FI_MSG_ERROR_DIB_MEMORY; 962 } 963 964 // set resolution information to default values (72 dpi in english units) 965 FreeImage_SetDotsPerMeterX(dib, 2835); 966 FreeImage_SetDotsPerMeterY(dib, 2835); 967 968 if(header_only) { 969 // header only mode 970 return dib; 971 } 972 973 // Skip over the optional palette 974 // A 24 or 32 bit DIB may contain a palette for faster color reduction 975 976 // load pixel data and swap as needed if OS is Big Endian 977 LoadPixelData(io, handle, dib, height, pitch, bit_count); 978 979 // check if the bitmap contains transparency, if so enable it in the header 980 981 FreeImage_SetTransparent(dib, (FreeImage_GetColorType(dib) == FIC_RGBALPHA)); 982 983 return dib; 984 } 985 } 986 } catch(const char *message) { 987 if(dib) 988 FreeImage_Unload(dib); 989 990 FreeImage_OutputMessageProc(s_format_id, message); 991 } 992 993 return NULL; 994} 995 996// ========================================================== 997// Plugin Implementation 998// ========================================================== 999 1000static const char * DLL_CALLCONV 1001Format() { 1002 return "BMP"; 1003} 1004 1005static const char * DLL_CALLCONV 1006Description() { 1007 return "Windows or OS/2 Bitmap"; 1008} 1009 1010static const char * DLL_CALLCONV 1011Extension() { 1012 return "bmp"; 1013} 1014 1015static const char * DLL_CALLCONV 1016RegExpr() { 1017 return "^BM"; 1018} 1019 1020static const char * DLL_CALLCONV 1021MimeType() { 1022 return "image/bmp"; 1023} 1024 1025static BOOL DLL_CALLCONV 1026Validate(FreeImageIO *io, fi_handle handle) { 1027 BYTE bmp_signature1[] = { 0x42, 0x4D }; 1028 BYTE bmp_signature2[] = { 0x42, 0x41 }; 1029 BYTE signature[2] = { 0, 0 }; 1030 1031 io->read_proc(signature, 1, sizeof(bmp_signature1), handle); 1032 1033 if (memcmp(bmp_signature1, signature, sizeof(bmp_signature1)) == 0) 1034 return TRUE; 1035 1036 if (memcmp(bmp_signature2, signature, sizeof(bmp_signature2)) == 0) 1037 return TRUE; 1038 1039 return FALSE; 1040} 1041 1042static BOOL DLL_CALLCONV 1043SupportsExportDepth(int depth) { 1044 return ( 1045 (depth == 1) || 1046 (depth == 4) || 1047 (depth == 8) || 1048 (depth == 16) || 1049 (depth == 24) || 1050 (depth == 32) 1051 ); 1052} 1053 1054static BOOL DLL_CALLCONV 1055SupportsExportType(FREE_IMAGE_TYPE type) { 1056 return (type == FIT_BITMAP) ? TRUE : FALSE; 1057} 1058 1059static BOOL DLL_CALLCONV 1060SupportsNoPixels() { 1061 return TRUE; 1062} 1063 1064// ---------------------------------------------------------- 1065 1066static FIBITMAP * DLL_CALLCONV 1067Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { 1068 if (handle != NULL) { 1069 BITMAPFILEHEADER bitmapfileheader; 1070 DWORD type = 0; 1071 1072 // we use this offset value to make seemingly absolute seeks relative in the file 1073 1074 long offset_in_file = io->tell_proc(handle); 1075 1076 // read the fileheader 1077 1078 io->read_proc(&bitmapfileheader, sizeof(BITMAPFILEHEADER), 1, handle); 1079#ifdef FREEIMAGE_BIGENDIAN 1080 SwapFileHeader(&bitmapfileheader); 1081#endif 1082 1083 // check the signature 1084 1085 if((bitmapfileheader.bfType != 0x4D42) && (bitmapfileheader.bfType != 0x4142)) { 1086 FreeImage_OutputMessageProc(s_format_id, FI_MSG_ERROR_MAGIC_NUMBER); 1087 return NULL; 1088 } 1089 1090 // read the first byte of the infoheader 1091 1092 io->read_proc(&type, sizeof(DWORD), 1, handle); 1093 io->seek_proc(handle, 0 - (long)sizeof(DWORD), SEEK_CUR); 1094#ifdef FREEIMAGE_BIGENDIAN 1095 SwapLong(&type); 1096#endif 1097 1098 // call the appropriate load function for the found bitmap type 1099 1100 switch(type) { 1101 case 12: 1102 // OS/2 and also all Windows versions since Windows 3.0 1103 return LoadOS21XBMP(io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits); 1104 case 64: 1105 // OS/2 1106 return LoadOS22XBMP(io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits); 1107 case 40: 1108 // BITMAPINFOHEADER - all Windows versions since Windows 3.0 1109 return LoadWindowsBMP(io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits); 1110 case 52: 1111 // BITMAPV2INFOHEADER (undocumented) 1112 break; 1113 case 56: 1114 // BITMAPV3INFOHEADER (undocumented) 1115 break; 1116 case 108: 1117 // BITMAPV4HEADER - all Windows versions since Windows 95/NT4 (not supported) 1118 break; 1119 case 124: 1120 // BITMAPV5HEADER - Windows 98/2000 and newer (not supported) 1121 break; 1122 default: 1123 break; 1124 } 1125 1126 FreeImage_OutputMessageProc(s_format_id, "unknown bmp subtype with id %d", type); 1127 } 1128 1129 return NULL; 1130} 1131 1132// ---------------------------------------------------------- 1133 1134/** 1135Encode a 8-bit source buffer into a 8-bit target buffer using a RLE compression algorithm. 1136The size of the target buffer must be equal to the size of the source buffer. 1137On return, the function will return the real size of the target buffer, which should be less that or equal to the source buffer size. 1138@param target 8-bit Target buffer 1139@param source 8-bit Source buffer 1140@param size Source/Target input buffer size 1141@return Returns the target buffer size 1142*/ 1143static int 1144RLEEncodeLine(BYTE *target, BYTE *source, int size) { 1145 BYTE buffer[256]; 1146 int buffer_size = 0; 1147 int target_pos = 0; 1148 1149 for (int i = 0; i < size; ++i) { 1150 if ((i < size - 1) && (source[i] == source[i + 1])) { 1151 // find a solid block of same bytes 1152 1153 int j = i + 1; 1154 int jmax = 254 + i; 1155 1156 while ((j < size - 1) && (j < jmax) && (source[j] == source[j + 1])) 1157 ++j; 1158 1159 // if the block is larger than 3 bytes, use it 1160 // else put the data into the larger pool 1161 1162 if (((j - i) + 1) > 3) { 1163 // don't forget to write what we already have in the buffer 1164 1165 switch(buffer_size) { 1166 case 0 : 1167 break; 1168 1169 case RLE_DELTA : 1170 target[target_pos++] = 1; 1171 target[target_pos++] = buffer[0]; 1172 target[target_pos++] = 1; 1173 target[target_pos++] = buffer[1]; 1174 break; 1175 1176 case RLE_ENDOFBITMAP : 1177 target[target_pos++] = (BYTE)buffer_size; 1178 target[target_pos++] = buffer[0]; 1179 break; 1180 1181 default : 1182 target[target_pos++] = RLE_COMMAND; 1183 target[target_pos++] = (BYTE)buffer_size; 1184 memcpy(target + target_pos, buffer, buffer_size); 1185 1186 // prepare for next run 1187 1188 target_pos += buffer_size; 1189 1190 if ((buffer_size & 1) == 1) 1191 target_pos++; 1192 1193 break; 1194 } 1195 1196 // write the continuous data 1197 1198 target[target_pos++] = (BYTE)((j - i) + 1); 1199 target[target_pos++] = source[i]; 1200 1201 buffer_size = 0; 1202 } else { 1203 for (int k = 0; k < (j - i) + 1; ++k) { 1204 buffer[buffer_size++] = source[i + k]; 1205 1206 if (buffer_size == 254) { 1207 // write what we have 1208 1209 target[target_pos++] = RLE_COMMAND; 1210 target[target_pos++] = (BYTE)buffer_size; 1211 memcpy(target + target_pos, buffer, buffer_size); 1212 1213 // prepare for next run 1214 1215 target_pos += buffer_size; 1216 buffer_size = 0; 1217 } 1218 } 1219 } 1220 1221 i = j; 1222 } else { 1223 buffer[buffer_size++] = source[i]; 1224 } 1225 1226 // write the buffer if it's full 1227 1228 if (buffer_size == 254) { 1229 target[target_pos++] = RLE_COMMAND; 1230 target[target_pos++] = (BYTE)buffer_size; 1231 memcpy(target + target_pos, buffer, buffer_size); 1232 1233 // prepare for next run 1234 1235 target_pos += buffer_size; 1236 buffer_size = 0; 1237 } 1238 } 1239 1240 // write the last bytes 1241 1242 switch(buffer_size) { 1243 case 0 : 1244 break; 1245 1246 case RLE_DELTA : 1247 target[target_pos++] = 1; 1248 target[target_pos++] = buffer[0]; 1249 target[target_pos++] = 1; 1250 target[target_pos++] = buffer[1]; 1251 break; 1252 1253 case RLE_ENDOFBITMAP : 1254 target[target_pos++] = (BYTE)buffer_size; 1255 target[target_pos++] = buffer[0]; 1256 break; 1257 1258 default : 1259 target[target_pos++] = RLE_COMMAND; 1260 target[target_pos++] = (BYTE)buffer_size; 1261 memcpy(target + target_pos, buffer, buffer_size); 1262 1263 // prepare for next run 1264 1265 target_pos += buffer_size; 1266 1267 if ((buffer_size & 1) == 1) 1268 target_pos++; 1269 1270 break; 1271 } 1272 1273 // write the END_OF_LINE marker 1274 1275 target[target_pos++] = RLE_COMMAND; 1276 target[target_pos++] = RLE_ENDOFLINE; 1277 1278 // return the written size 1279 1280 return target_pos; 1281} 1282 1283static BOOL DLL_CALLCONV 1284Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) { 1285 if ((dib != NULL) && (handle != NULL)) { 1286 // write the file header 1287 1288 BITMAPFILEHEADER bitmapfileheader; 1289 bitmapfileheader.bfType = 0x4D42; 1290 bitmapfileheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + FreeImage_GetColorsUsed(dib) * sizeof(RGBQUAD); 1291 bitmapfileheader.bfSize = bitmapfileheader.bfOffBits + FreeImage_GetHeight(dib) * FreeImage_GetPitch(dib); 1292 bitmapfileheader.bfReserved1 = 0; 1293 bitmapfileheader.bfReserved2 = 0; 1294 1295 // take care of the bit fields data of any 1296 1297 bool bit_fields = (FreeImage_GetBPP(dib) == 16); 1298 1299 if (bit_fields) { 1300 bitmapfileheader.bfSize += 3 * sizeof(DWORD); 1301 bitmapfileheader.bfOffBits += 3 * sizeof(DWORD); 1302 } 1303 1304#ifdef FREEIMAGE_BIGENDIAN 1305 SwapFileHeader(&bitmapfileheader); 1306#endif 1307 if (io->write_proc(&bitmapfileheader, sizeof(BITMAPFILEHEADER), 1, handle) != 1) 1308 return FALSE; 1309 1310 // update the bitmap info header 1311 1312 BITMAPINFOHEADER bih; 1313 memcpy(&bih, FreeImage_GetInfoHeader(dib), sizeof(BITMAPINFOHEADER)); 1314 1315 if (bit_fields) 1316 bih.biCompression = BI_BITFIELDS; 1317 else if ((bih.biBitCount == 8) && (flags & BMP_SAVE_RLE)) 1318 bih.biCompression = BI_RLE8; 1319 else 1320 bih.biCompression = BI_RGB; 1321 1322 // write the bitmap info header 1323 1324#ifdef FREEIMAGE_BIGENDIAN 1325 SwapInfoHeader(&bih); 1326#endif 1327 if (io->write_proc(&bih, sizeof(BITMAPINFOHEADER), 1, handle) != 1) 1328 return FALSE; 1329 1330 // write the bit fields when we are dealing with a 16 bit BMP 1331 1332 if (bit_fields) { 1333 DWORD d; 1334 1335 d = FreeImage_GetRedMask(dib); 1336 1337 if (io->write_proc(&d, sizeof(DWORD), 1, handle) != 1) 1338 return FALSE; 1339 1340 d = FreeImage_GetGreenMask(dib); 1341 1342 if (io->write_proc(&d, sizeof(DWORD), 1, handle) != 1) 1343 return FALSE; 1344 1345 d = FreeImage_GetBlueMask(dib); 1346 1347 if (io->write_proc(&d, sizeof(DWORD), 1, handle) != 1) 1348 return FALSE; 1349 } 1350 1351 // write the palette 1352 1353 if (FreeImage_GetPalette(dib) != NULL) { 1354 RGBQUAD *pal = FreeImage_GetPalette(dib); 1355 FILE_BGRA bgra; 1356 for(unsigned i = 0; i < FreeImage_GetColorsUsed(dib); i++ ) { 1357 bgra.b = pal[i].rgbBlue; 1358 bgra.g = pal[i].rgbGreen; 1359 bgra.r = pal[i].rgbRed; 1360 bgra.a = pal[i].rgbReserved; 1361 if (io->write_proc(&bgra, sizeof(FILE_BGRA), 1, handle) != 1) 1362 return FALSE; 1363 } 1364 } 1365 1366 // write the bitmap data... if RLE compression is enable, use it 1367 1368 unsigned bpp = FreeImage_GetBPP(dib); 1369 if ((bpp == 8) && (flags & BMP_SAVE_RLE)) { 1370 BYTE *buffer = (BYTE*)malloc(FreeImage_GetPitch(dib) * 2 * sizeof(BYTE)); 1371 1372 for (DWORD i = 0; i < FreeImage_GetHeight(dib); ++i) { 1373 int size = RLEEncodeLine(buffer, FreeImage_GetScanLine(dib, i), FreeImage_GetLine(dib)); 1374 1375 if (io->write_proc(buffer, size, 1, handle) != 1) { 1376 free(buffer); 1377 return FALSE; 1378 } 1379 } 1380 1381 buffer[0] = RLE_COMMAND; 1382 buffer[1] = RLE_ENDOFBITMAP; 1383 1384 if (io->write_proc(buffer, 2, 1, handle) != 1) { 1385 free(buffer); 1386 return FALSE; 1387 } 1388 1389 free(buffer); 1390#ifdef FREEIMAGE_BIGENDIAN 1391 } else if (bpp == 16) { 1392 int padding = FreeImage_GetPitch(dib) - FreeImage_GetWidth(dib) * sizeof(WORD); 1393 WORD pad = 0; 1394 WORD pixel; 1395 for(unsigned y = 0; y < FreeImage_GetHeight(dib); y++) { 1396 BYTE *line = FreeImage_GetScanLine(dib, y); 1397 for(unsigned x = 0; x < FreeImage_GetWidth(dib); x++) { 1398 pixel = ((WORD *)line)[x]; 1399 SwapShort(&pixel); 1400 if (io->write_proc(&pixel, sizeof(WORD), 1, handle) != 1) 1401 return FALSE; 1402 } 1403 if(padding != 0) { 1404 if(io->write_proc(&pad, padding, 1, handle) != 1) { 1405 return FALSE; 1406 } 1407 } 1408 } 1409#endif 1410#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB 1411 } else if (bpp == 24) { 1412 int padding = FreeImage_GetPitch(dib) - FreeImage_GetWidth(dib) * sizeof(FILE_BGR); 1413 DWORD pad = 0; 1414 FILE_BGR bgr; 1415 for(unsigned y = 0; y < FreeImage_GetHeight(dib); y++) { 1416 BYTE *line = FreeImage_GetScanLine(dib, y); 1417 for(unsigned x = 0; x < FreeImage_GetWidth(dib); x++) { 1418 RGBTRIPLE *triple = ((RGBTRIPLE *)line)+x; 1419 bgr.b = triple->rgbtBlue; 1420 bgr.g = triple->rgbtGreen; 1421 bgr.r = triple->rgbtRed; 1422 if (io->write_proc(&bgr, sizeof(FILE_BGR), 1, handle) != 1) 1423 return FALSE; 1424 } 1425 if(padding != 0) { 1426 if(io->write_proc(&pad, padding, 1, handle) != 1) { 1427 return FALSE; 1428 } 1429 } 1430 } 1431 } else if (bpp == 32) { 1432 FILE_BGRA bgra; 1433 for(unsigned y = 0; y < FreeImage_GetHeight(dib); y++) { 1434 BYTE *line = FreeImage_GetScanLine(dib, y); 1435 for(unsigned x = 0; x < FreeImage_GetWidth(dib); x++) { 1436 RGBQUAD *quad = ((RGBQUAD *)line)+x; 1437 bgra.b = quad->rgbBlue; 1438 bgra.g = quad->rgbGreen; 1439 bgra.r = quad->rgbRed; 1440 bgra.a = quad->rgbReserved; 1441 if (io->write_proc(&bgra, sizeof(FILE_BGRA), 1, handle) != 1) 1442 return FALSE; 1443 } 1444 } 1445#endif 1446 } else if (io->write_proc(FreeImage_GetBits(dib), FreeImage_GetHeight(dib) * FreeImage_GetPitch(dib), 1, handle) != 1) { 1447 return FALSE; 1448 } 1449 1450 return TRUE; 1451 } else { 1452 return FALSE; 1453 } 1454} 1455 1456// ========================================================== 1457// Init 1458// ========================================================== 1459 1460void DLL_CALLCONV 1461InitBMP(Plugin *plugin, int format_id) { 1462 s_format_id = format_id; 1463 1464 plugin->format_proc = Format; 1465 plugin->description_proc = Description; 1466 plugin->extension_proc = Extension; 1467 plugin->regexpr_proc = RegExpr; 1468 plugin->open_proc = NULL; 1469 plugin->close_proc = NULL; 1470 plugin->pagecount_proc = NULL; 1471 plugin->pagecapability_proc = NULL; 1472 plugin->load_proc = Load; 1473 plugin->save_proc = Save; 1474 plugin->validate_proc = Validate; 1475 plugin->mime_proc = MimeType; 1476 plugin->supports_export_bpp_proc = SupportsExportDepth; 1477 plugin->supports_export_type_proc = SupportsExportType; 1478 plugin->supports_icc_profiles_proc = NULL; // not implemented yet; 1479 plugin->supports_no_pixels_proc = SupportsNoPixels; 1480}