PageRenderTime 133ms CodeModel.GetById 16ms app.highlight 107ms RepoModel.GetById 1ms app.codeStats 1ms

/src/FreeImage/Source/FreeImage/PluginBMP.cpp

https://bitbucket.org/cabalistic/ogredeps/
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}