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