1 // ==========================================================
2 // FreeImage implementation
3 //
4 // Design and implementation by
5 // - Floris van den Berg (flvdberg@wxs.nl)
6 // - Herv� Drolon (drolon@infonie.fr)
7 // - Detlev Vendt (detlev.vendt@brillit.de)
8 // - Petr Supina (psup@centrum.cz)
9 // - Carsten Klein (c.klein@datagis.com)
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 #ifdef _MSC_VER
28 #pragma warning (disable : 4786) // identifier was truncated to 'number' characters
29 #endif
30 
31 #include <stdlib.h>
32 #if defined(_WIN32) || defined(_WIN64) || defined(__MINGW32__)
33 #include <malloc.h>
34 #endif // _WIN32 || _WIN64 || __MINGW32__
35 
36 #include "FreeImage.h"
37 #include "FreeImageIO.h"
38 #include "Utilities.h"
39 #include "MapIntrospector.h"
40 
41 #include "../Metadata/FreeImageTag.h"
42 
43 /**
44 Constants for the BITMAPINFOHEADER::biCompression field
45 BI_RGB:
46 The bitmap is in uncompressed red green blue (RGB) format that is not compressed and does not use color masks.
47 BI_BITFIELDS:
48 The bitmap is not compressed and the color table consists of three DWORD color masks that specify the red, green, and blue components,
49 respectively, of each pixel. This is valid when used with 16 and 32-bits per pixel bitmaps.
50 */
51 #ifndef _WINGDI_
52 #define BI_RGB       0L
53 #define BI_BITFIELDS 3L
54 #endif // _WINGDI_
55 
56 // ----------------------------------------------------------
57 //  Metadata definitions
58 // ----------------------------------------------------------
59 
60 /** helper for map<key, value> where value is a pointer to a FreeImage tag */
61 typedef std::map<std::string, FITAG*> TAGMAP;
62 
63 /** helper for map<FREE_IMAGE_MDMODEL, TAGMAP*> */
64 typedef std::map<int, TAGMAP*> METADATAMAP;
65 
66 /** helper for metadata iterator */
FI_STRUCT(METADATAHEADER)67 FI_STRUCT (METADATAHEADER) {
68 	long pos;		//! current position when iterating the map
69 	TAGMAP *tagmap;	//! pointer to the tag map
70 };
71 
72 // ----------------------------------------------------------
73 //  FIBITMAP definition
74 // ----------------------------------------------------------
75 
76 /**
77 FreeImage header structure
78 */
FI_STRUCT(FREEIMAGEHEADER)79 FI_STRUCT (FREEIMAGEHEADER) {
80 	/** data type - bitmap, array of long, double, complex, etc */
81 	FREE_IMAGE_TYPE type;
82 
83 	/** background color used for RGB transparency */
84 	RGBQUAD bkgnd_color;
85 
86 	/**@name transparency management */
87 	//@{
88 	/**
89 	why another table ? for easy transparency table retrieval !
90 	transparency could be stored in the palette, which is better
91 	overall, but it requires quite some changes and it will render
92 	FreeImage_GetTransparencyTable obsolete in its current form;
93 	*/
94 	BYTE transparent_table[256];
95 	/** number of transparent colors */
96 	int  transparency_count;
97 	/** TRUE if the image is transparent */
98 	BOOL transparent;
99 	//@}
100 
101 	/** space to hold ICC profile */
102 	FIICCPROFILE iccProfile;
103 
104 	/** contains a list of metadata models attached to the bitmap */
105 	METADATAMAP *metadata;
106 
107 	/** FALSE if the FIBITMAP only contains the header and no pixel data */
108 	BOOL has_pixels;
109 
110 	/** optionally contains a thumbnail attached to the bitmap */
111 	FIBITMAP *thumbnail;
112 
113 	/**@name external pixel buffer management */
114 	//@{
115 	/** pointer to user provided pixels, NULL otherwise */
116 	BYTE *external_bits;
117 	/** user provided pitch, 0 otherwise */
118 	unsigned external_pitch;
119 	//@}
120 
121 	//BYTE filler[1];			 // fill to 32-bit alignment
122 };
123 
124 // ----------------------------------------------------------
125 //  FREEIMAGERGBMASKS definition
126 // ----------------------------------------------------------
127 
128 /**
129 RGB mask structure - mainly used for 16-bit RGB555 / RGB 565 FIBITMAP
130 */
FI_STRUCT(FREEIMAGERGBMASKS)131 FI_STRUCT (FREEIMAGERGBMASKS) {
132 	unsigned red_mask;		//! bit layout of the red components
133 	unsigned green_mask;	//! bit layout of the green components
134 	unsigned blue_mask;		//! bit layout of the blue components
135 };
136 
137 // ----------------------------------------------------------
138 //  Memory allocation on a specified alignment boundary
139 // ----------------------------------------------------------
140 
141 #if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__)
142 
FreeImage_Aligned_Malloc(size_t amount,size_t alignment)143 void* FreeImage_Aligned_Malloc(size_t amount, size_t alignment) {
144 	assert(alignment == FIBITMAP_ALIGNMENT);
145 	return _aligned_malloc(amount, alignment);
146 }
147 
FreeImage_Aligned_Free(void * mem)148 void FreeImage_Aligned_Free(void* mem) {
149 	_aligned_free(mem);
150 }
151 
152 #elif defined (__MINGW32__)
153 
FreeImage_Aligned_Malloc(size_t amount,size_t alignment)154 void* FreeImage_Aligned_Malloc(size_t amount, size_t alignment) {
155 	assert(alignment == FIBITMAP_ALIGNMENT);
156 	return __mingw_aligned_malloc (amount, alignment);
157 }
158 
FreeImage_Aligned_Free(void * mem)159 void FreeImage_Aligned_Free(void* mem) {
160 	__mingw_aligned_free (mem);
161 }
162 
163 #else
164 
FreeImage_Aligned_Malloc(size_t amount,size_t alignment)165 void* FreeImage_Aligned_Malloc(size_t amount, size_t alignment) {
166 	assert(alignment == FIBITMAP_ALIGNMENT);
167 	/*
168 	In some rare situations, the malloc routines can return misaligned memory.
169 	The routine FreeImage_Aligned_Malloc allocates a bit more memory to do
170 	aligned writes.  Normally, it *should* allocate "alignment" extra memory and then writes
171 	one dword back the true pointer.  But if the memory manager returns a
172 	misaligned block that is less than a dword from the next alignment,
173 	then the writing back one dword will corrupt memory.
174 
175 	For example, suppose that alignment is 16 and malloc returns the address 0xFFFF.
176 
177 	16 - 0xFFFF % 16 + 0xFFFF = 16 - 15 + 0xFFFF = 0x10000.
178 
179 	Now, you subtract one dword from that and write and that will corrupt memory.
180 
181 	That's why the code below allocates *two* alignments instead of one.
182 	*/
183 	void* mem_real = malloc(amount + 2 * alignment);
184 	if(!mem_real) return NULL;
185 	char* mem_align = (char*)((unsigned long)(2 * alignment - (unsigned long)mem_real % (unsigned long)alignment) + (unsigned long)mem_real);
186 	*((long*)mem_align - 1) = (long)mem_real;
187 	return mem_align;
188 }
189 
FreeImage_Aligned_Free(void * mem)190 void FreeImage_Aligned_Free(void* mem) {
191 	free((void*)*((long*)mem - 1));
192 }
193 
194 #endif // _WIN32 || _WIN64
195 
196 // ----------------------------------------------------------
197 //  FIBITMAP memory management
198 // ----------------------------------------------------------
199 
200 /**
201 Calculate the size of a FreeImage image.
202 Align the palette and the pixels on a FIBITMAP_ALIGNMENT bytes alignment boundary.
203 This function includes a protection against malicious images, based on a KISS integer overflow detection mechanism.
204 
205 @param header_only If TRUE, calculate a 'header only' FIBITMAP size, otherwise calculate a full FIBITMAP size
206 @param width Image width
207 @param height Image height
208 @param bpp Number of bits-per-pixel
209 @param need_masks We only store the masks (and allocate memory for them) for 16-bit images of type FIT_BITMAP
210 @return Returns a size in BYTE units
211 @see FreeImage_AllocateBitmap
212 */
213 static size_t
FreeImage_GetInternalImageSize(BOOL header_only,unsigned width,unsigned height,unsigned bpp,BOOL need_masks)214 FreeImage_GetInternalImageSize(BOOL header_only, unsigned width, unsigned height, unsigned bpp, BOOL need_masks) {
215 	size_t dib_size = sizeof(FREEIMAGEHEADER);
216 	dib_size += (dib_size % FIBITMAP_ALIGNMENT ? FIBITMAP_ALIGNMENT - dib_size % FIBITMAP_ALIGNMENT : 0);
217 	dib_size += FIBITMAP_ALIGNMENT - sizeof(BITMAPINFOHEADER) % FIBITMAP_ALIGNMENT;
218 	dib_size += sizeof(BITMAPINFOHEADER);
219 	// palette is aligned on a 16 bytes boundary
220 	dib_size += sizeof(RGBQUAD) * CalculateUsedPaletteEntries(bpp);
221 	// we both add palette size and masks size if need_masks is true, since CalculateUsedPaletteEntries
222 	// always returns 0 if need_masks is true (which is only true for 16 bit images).
223 	dib_size += need_masks ? sizeof(DWORD) * 3 : 0;
224 	dib_size += (dib_size % FIBITMAP_ALIGNMENT ? FIBITMAP_ALIGNMENT - dib_size % FIBITMAP_ALIGNMENT : 0);
225 
226 	if(!header_only) {
227 		const size_t header_size = dib_size;
228 
229 		// pixels are aligned on a 16 bytes boundary
230 		dib_size += (size_t)CalculatePitch(CalculateLine(width, bpp)) * (size_t)height;
231 
232 		// check for possible malloc overflow using a KISS integer overflow detection mechanism
233 		{
234 			const double dPitch = floor( ((double)bpp * width + 31.0) / 32.0 ) * 4.0;
235 			const double dImageSize = (double)header_size + dPitch * height;
236 			if(dImageSize != (double)dib_size) {
237 				// here, we are sure to encounter a malloc overflow: try to avoid it ...
238 				return 0;
239 			}
240 
241 			/*
242 			The following constant take into account the additionnal memory used by
243 			aligned malloc functions as well as debug malloc functions.
244 			It is supposed here that using a (8 * FIBITMAP_ALIGNMENT) risk margin will be enough
245 			for the target compiler.
246 			*/
247 			const double FIBITMAP_MAX_MEMORY = (double)((size_t)-1) - 8 * FIBITMAP_ALIGNMENT;
248 
249 			if(dImageSize > FIBITMAP_MAX_MEMORY) {
250 				// avoid possible overflow inside C allocation functions
251 				return 0;
252 			}
253 		}
254 	}
255 
256 	return dib_size;
257 }
258 
259 /**
260 Helper for 16-bit FIT_BITMAP
261 Returns a pointer to the bitmap's red-, green- and blue masks.
262 @param dib The bitmap to obtain masks from.
263 @return Returns a pointer to the bitmap's red-, green- and blue masks
264 or NULL, if no masks are present (e.g. for 24 bit images).
265 */
266 static FREEIMAGERGBMASKS *
FreeImage_GetRGBMasks(FIBITMAP * dib)267 FreeImage_GetRGBMasks(FIBITMAP *dib) {
268 	return FreeImage_HasRGBMasks(dib) ? (FREEIMAGERGBMASKS *)(((BYTE *)FreeImage_GetInfoHeader(dib)) + sizeof(BITMAPINFOHEADER)) : NULL;
269 }
270 
271 /**
272 Internal FIBITMAP allocation.
273 
274 This function accepts (ext_bits, ext_pitch) arguments. If these are provided the FIBITMAP
275 will be allocated as "header only", but bits and pitch will be stored within the FREEIMAGEHEADER
276 and the resulting FIBITMAP will have pixels, i.e. HasPixels() will return TRUE.
277 - GetBits() and GetPitch return the correct values - either offsets or the stored values (user-provided bits and pitch).
278 - Clone() creates a new FIBITMAP with copy of the user pixel data.
279 - Unload's implementation does not need to change - it just release a "header only" dib.
280 Note that when using external data, the data does not need to have the same alignment as the default 4-byte alignment.
281 This enables the possibility to access buffers with, for instance, stricter alignment,
282 like the ones used in low-level APIs like OpenCL or intrinsics.
283 
284 @param header_only If TRUE, allocate a 'header only' FIBITMAP, otherwise allocate a full FIBITMAP
285 @param ext_bits Pointer to external user's pixel buffer if using wrapped buffer, NULL otherwise
286 @param ext_pitch Pointer to external user's pixel buffer pitch if using wrapped buffer, 0 otherwise
287 @param type Image type
288 @param width Image width
289 @param height Image height
290 @param bpp Number of bits per pixel
291 @param red_mask Image red mask
292 @param green_mask Image green mask
293 @param blue_mask Image blue mask
294 @return Returns the allocated FIBITMAP if successful, returns NULL otherwise
295 */
296 static FIBITMAP *
FreeImage_AllocateBitmap(BOOL header_only,BYTE * ext_bits,unsigned ext_pitch,FREE_IMAGE_TYPE type,int width,int height,int bpp,unsigned red_mask,unsigned green_mask,unsigned blue_mask)297 FreeImage_AllocateBitmap(BOOL header_only, BYTE *ext_bits, unsigned ext_pitch, FREE_IMAGE_TYPE type, int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) {
298 
299 	// check input variables
300 	width = abs(width);
301 	height = abs(height);
302 	if(!((width > 0) && (height > 0))) {
303 		return NULL;
304 	}
305 	if(ext_bits) {
306 		if(ext_pitch == 0) {
307 			return NULL;
308 		}
309 		assert(header_only == FALSE);
310 	}
311 
312 	// we only store the masks (and allocate memory for them) for 16-bit images of type FIT_BITMAP
313 	BOOL need_masks = FALSE;
314 
315 	// check pixel bit depth
316 	switch(type) {
317 		case FIT_BITMAP:
318 			switch(bpp) {
319 				case 1:
320 				case 4:
321 				case 8:
322 					break;
323 				case 16:
324 					need_masks = TRUE;
325 					break;
326 				case 24:
327 				case 32:
328 					break;
329 				default:
330 					bpp = 8;
331 					break;
332 			}
333 			break;
334 		case FIT_UINT16:
335 			bpp = 8 * sizeof(unsigned short);
336 			break;
337 		case FIT_INT16:
338 			bpp = 8 * sizeof(short);
339 			break;
340 		case FIT_UINT32:
341 			bpp = 8 * sizeof(DWORD);
342 			break;
343 		case FIT_INT32:
344 			bpp = 8 * sizeof(LONG);
345 			break;
346 		case FIT_FLOAT:
347 			bpp = 8 * sizeof(float);
348 			break;
349 		case FIT_DOUBLE:
350 			bpp = 8 * sizeof(double);
351 			break;
352 		case FIT_COMPLEX:
353 			bpp = 8 * sizeof(FICOMPLEX);
354 			break;
355 		case FIT_RGB16:
356 			bpp = 8 * sizeof(FIRGB16);
357 			break;
358 		case FIT_RGBA16:
359 			bpp = 8 * sizeof(FIRGBA16);
360 			break;
361 		case FIT_RGBF:
362 			bpp = 8 * sizeof(FIRGBF);
363 			break;
364 		case FIT_RGBAF:
365 			bpp = 8 * sizeof(FIRGBAF);
366 			break;
367 		default:
368 			return NULL;
369 	}
370 
371 	FIBITMAP *bitmap = (FIBITMAP *)malloc(sizeof(FIBITMAP));
372 
373 	if (bitmap != NULL) {
374 
375 		// calculate the size of a FreeImage image
376 		// align the palette and the pixels on a FIBITMAP_ALIGNMENT bytes alignment boundary
377 		// palette is aligned on a 16 bytes boundary
378 		// pixels are aligned on a 16 bytes boundary
379 
380 		// when using a user provided pixel buffer, force a 'header only' allocation
381 
382 		size_t dib_size = FreeImage_GetInternalImageSize(header_only || ext_bits, width, height, bpp, need_masks);
383 
384 		if(dib_size == 0) {
385 			// memory allocation will fail (probably a malloc overflow)
386 			free(bitmap);
387 			return NULL;
388 		}
389 
390 		bitmap->data = (BYTE *)FreeImage_Aligned_Malloc(dib_size * sizeof(BYTE), FIBITMAP_ALIGNMENT);
391 
392 		if (bitmap->data != NULL) {
393 			memset(bitmap->data, 0, dib_size);
394 
395 			// write out the FREEIMAGEHEADER
396 
397 			FREEIMAGEHEADER *fih = (FREEIMAGEHEADER *)bitmap->data;
398 
399 			fih->type = type;
400 
401 			memset(&fih->bkgnd_color, 0, sizeof(RGBQUAD));
402 
403 			fih->transparent = FALSE;
404 			fih->transparency_count = 0;
405 			memset(fih->transparent_table, 0xff, 256);
406 
407 			fih->has_pixels = header_only ? FALSE : TRUE;
408 
409 			// initialize FIICCPROFILE link
410 
411 			FIICCPROFILE *iccProfile = FreeImage_GetICCProfile(bitmap);
412 			iccProfile->size = 0;
413 			iccProfile->data = 0;
414 			iccProfile->flags = 0;
415 
416 			// initialize metadata models list
417 
418 			fih->metadata = new(std::nothrow) METADATAMAP;
419 
420 			// initialize attached thumbnail
421 
422 			fih->thumbnail = NULL;
423 
424 			// store a pointer to user provided pixel buffer (if any)
425 
426 			fih->external_bits = ext_bits;
427 			fih->external_pitch = ext_pitch;
428 
429 			// write out the BITMAPINFOHEADER
430 
431 			BITMAPINFOHEADER *bih   = FreeImage_GetInfoHeader(bitmap);
432 			bih->biSize             = sizeof(BITMAPINFOHEADER);
433 			bih->biWidth            = width;
434 			bih->biHeight           = height;
435 			bih->biPlanes           = 1;
436 			bih->biCompression      = need_masks ? BI_BITFIELDS : BI_RGB;
437 			bih->biBitCount         = (WORD)bpp;
438 			bih->biClrUsed          = CalculateUsedPaletteEntries(bpp);
439 			bih->biClrImportant     = bih->biClrUsed;
440 			bih->biXPelsPerMeter	= 2835;	// 72 dpi
441 			bih->biYPelsPerMeter	= 2835;	// 72 dpi
442 
443 			if(bpp == 8) {
444 				// build a default greyscale palette (very useful for image processing)
445 				RGBQUAD *pal = FreeImage_GetPalette(bitmap);
446 				for(int i = 0; i < 256; i++) {
447 					pal[i].rgbRed	= (BYTE)i;
448 					pal[i].rgbGreen = (BYTE)i;
449 					pal[i].rgbBlue	= (BYTE)i;
450 				}
451 			}
452 
453 			// just setting the masks (only if needed) just like the palette.
454 			if (need_masks) {
455 				FREEIMAGERGBMASKS *masks = FreeImage_GetRGBMasks(bitmap);
456 				masks->red_mask = red_mask;
457 				masks->green_mask = green_mask;
458 				masks->blue_mask = blue_mask;
459 			}
460 
461 			return bitmap;
462 		}
463 
464 		free(bitmap);
465 	}
466 
467 	return NULL;
468 }
469 
470 FIBITMAP * DLL_CALLCONV
FreeImage_AllocateHeaderForBits(BYTE * ext_bits,unsigned ext_pitch,FREE_IMAGE_TYPE type,int width,int height,int bpp,unsigned red_mask,unsigned green_mask,unsigned blue_mask)471 FreeImage_AllocateHeaderForBits(BYTE *ext_bits, unsigned ext_pitch, FREE_IMAGE_TYPE type, int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) {
472 	return FreeImage_AllocateBitmap(FALSE, ext_bits, ext_pitch, type, width, height, bpp, red_mask, green_mask, blue_mask);
473 }
474 
475 FIBITMAP * DLL_CALLCONV
FreeImage_AllocateHeaderT(BOOL header_only,FREE_IMAGE_TYPE type,int width,int height,int bpp,unsigned red_mask,unsigned green_mask,unsigned blue_mask)476 FreeImage_AllocateHeaderT(BOOL header_only, FREE_IMAGE_TYPE type, int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) {
477 	return FreeImage_AllocateBitmap(header_only, NULL, 0, type, width, height, bpp, red_mask, green_mask, blue_mask);
478 }
479 
480 FIBITMAP * DLL_CALLCONV
FreeImage_AllocateHeader(BOOL header_only,int width,int height,int bpp,unsigned red_mask,unsigned green_mask,unsigned blue_mask)481 FreeImage_AllocateHeader(BOOL header_only, int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) {
482 	return FreeImage_AllocateBitmap(header_only, NULL, 0, FIT_BITMAP, width, height, bpp, red_mask, green_mask, blue_mask);
483 }
484 
485 FIBITMAP * DLL_CALLCONV
FreeImage_Allocate(int width,int height,int bpp,unsigned red_mask,unsigned green_mask,unsigned blue_mask)486 FreeImage_Allocate(int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) {
487 	return FreeImage_AllocateBitmap(FALSE, NULL, 0, FIT_BITMAP, width, height, bpp, red_mask, green_mask, blue_mask);
488 }
489 
490 FIBITMAP * DLL_CALLCONV
FreeImage_AllocateT(FREE_IMAGE_TYPE type,int width,int height,int bpp,unsigned red_mask,unsigned green_mask,unsigned blue_mask)491 FreeImage_AllocateT(FREE_IMAGE_TYPE type, int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) {
492 	return FreeImage_AllocateBitmap(FALSE, NULL, 0, type, width, height, bpp, red_mask, green_mask, blue_mask);
493 }
494 
495 void DLL_CALLCONV
FreeImage_Unload(FIBITMAP * dib)496 FreeImage_Unload(FIBITMAP *dib) {
497 	if (NULL != dib) {
498 		if (NULL != dib->data) {
499 			// delete possible icc profile ...
500 			if (FreeImage_GetICCProfile(dib)->data) {
501 				free(FreeImage_GetICCProfile(dib)->data);
502 			}
503 
504 			// delete metadata models
505 			METADATAMAP *metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
506 
507 			for(METADATAMAP::iterator i = (*metadata).begin(); i != (*metadata).end(); i++) {
508 				TAGMAP *tagmap = (*i).second;
509 
510 				if(tagmap) {
511 					for(TAGMAP::iterator j = tagmap->begin(); j != tagmap->end(); j++) {
512 						FITAG *tag = (*j).second;
513 						FreeImage_DeleteTag(tag);
514 					}
515 
516 					delete tagmap;
517 				}
518 			}
519 
520 			delete metadata;
521 
522 			// delete embedded thumbnail
523 			FreeImage_Unload(FreeImage_GetThumbnail(dib));
524 
525 			// delete bitmap ...
526 			FreeImage_Aligned_Free(dib->data);
527 		}
528 
529 		free(dib);		// ... and the wrapper
530 	}
531 }
532 
533 // ----------------------------------------------------------
534 
535 FIBITMAP * DLL_CALLCONV
FreeImage_Clone(FIBITMAP * dib)536 FreeImage_Clone(FIBITMAP *dib) {
537 	if(!dib) {
538 		return NULL;
539 	}
540 
541 	FREE_IMAGE_TYPE type = FreeImage_GetImageType(dib);
542 	unsigned width	= FreeImage_GetWidth(dib);
543 	unsigned height	= FreeImage_GetHeight(dib);
544 	unsigned bpp	= FreeImage_GetBPP(dib);
545 
546 	// if the FIBITMAP is a wrapper to a user provided pixel buffer, get a pointer to this buffer
547 	const BYTE *ext_bits = ((FREEIMAGEHEADER *)dib->data)->external_bits;
548 
549 	// check for pixel availability ...
550 	BOOL header_only = FreeImage_HasPixels(dib) ? FALSE : TRUE;
551 
552 	// check whether this image has masks defined ...
553 	BOOL need_masks = (bpp == 16 && type == FIT_BITMAP) ? TRUE : FALSE;
554 
555 	// allocate a new dib
556 	FIBITMAP *new_dib = FreeImage_AllocateHeaderT(header_only, type, width, height, bpp,
557 			FreeImage_GetRedMask(dib), FreeImage_GetGreenMask(dib), FreeImage_GetBlueMask(dib));
558 
559 	if (new_dib) {
560 		// save ICC profile links
561 		FIICCPROFILE *src_iccProfile = FreeImage_GetICCProfile(dib);
562 		FIICCPROFILE *dst_iccProfile = FreeImage_GetICCProfile(new_dib);
563 
564 		// save metadata links
565 		METADATAMAP *src_metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
566 		METADATAMAP *dst_metadata = ((FREEIMAGEHEADER *)new_dib->data)->metadata;
567 
568 		// calculate the size of the dst image
569 		// align the palette and the pixels on a FIBITMAP_ALIGNMENT bytes alignment boundary
570 		// palette is aligned on a 16 bytes boundary
571 		// pixels are aligned on a 16 bytes boundary
572 
573 		// when using a user provided pixel buffer, force a 'header only' calculation
574 
575 		size_t dib_size = FreeImage_GetInternalImageSize(header_only || ext_bits, width, height, bpp, need_masks);
576 
577 		// copy the bitmap + internal pointers (remember to restore new_dib internal pointers later)
578 		memcpy(new_dib->data, dib->data, dib_size);
579 
580 		// reset ICC profile link for new_dib
581 		memset(dst_iccProfile, 0, sizeof(FIICCPROFILE));
582 
583 		// restore metadata link for new_dib
584 		((FREEIMAGEHEADER *)new_dib->data)->metadata = dst_metadata;
585 
586 		// reset thumbnail link for new_dib
587 		((FREEIMAGEHEADER *)new_dib->data)->thumbnail = NULL;
588 
589 		// reset external wrapped buffer link for new_dib
590 		((FREEIMAGEHEADER *)new_dib->data)->external_bits = NULL;
591 		((FREEIMAGEHEADER *)new_dib->data)->external_pitch = 0;
592 
593 		// copy possible ICC profile
594 		FreeImage_CreateICCProfile(new_dib, src_iccProfile->data, src_iccProfile->size);
595 		dst_iccProfile->flags = src_iccProfile->flags;
596 
597 		// copy metadata models
598 		for(METADATAMAP::iterator i = (*src_metadata).begin(); i != (*src_metadata).end(); i++) {
599 			int model = (*i).first;
600 			TAGMAP *src_tagmap = (*i).second;
601 
602 			if(src_tagmap) {
603 				// create a metadata model
604 				TAGMAP *dst_tagmap = new(std::nothrow) TAGMAP();
605 
606 				if(dst_tagmap) {
607 					// fill the model
608 					for(TAGMAP::iterator j = src_tagmap->begin(); j != src_tagmap->end(); j++) {
609 						std::string dst_key = (*j).first;
610 						FITAG *dst_tag = FreeImage_CloneTag( (*j).second );
611 
612 						// assign key and tag value
613 						(*dst_tagmap)[dst_key] = dst_tag;
614 					}
615 
616 					// assign model and tagmap
617 					(*dst_metadata)[model] = dst_tagmap;
618 				}
619 			}
620 		}
621 
622 		// copy the thumbnail
623 		FreeImage_SetThumbnail(new_dib, FreeImage_GetThumbnail(dib));
624 
625 		// copy user provided pixel buffer (if any)
626 		if(ext_bits) {
627 			const unsigned pitch = FreeImage_GetPitch(dib);
628 			const unsigned linesize = FreeImage_GetLine(dib);
629 			for(unsigned y = 0; y < height; y++) {
630 				memcpy(FreeImage_GetScanLine(new_dib, y), ext_bits, linesize);
631 				ext_bits += pitch;
632 			}
633 		}
634 
635 		return new_dib;
636 	}
637 
638 	return NULL;
639 }
640 
641 // ----------------------------------------------------------
642 
643 BYTE * DLL_CALLCONV
FreeImage_GetBits(FIBITMAP * dib)644 FreeImage_GetBits(FIBITMAP *dib) {
645 	if(!FreeImage_HasPixels(dib)) {
646 		return NULL;
647 	}
648 
649 	if(((FREEIMAGEHEADER *)dib->data)->external_bits) {
650 		return ((FREEIMAGEHEADER *)dib->data)->external_bits;
651 	}
652 
653 	// returns the pixels aligned on a FIBITMAP_ALIGNMENT bytes alignment boundary
654 	size_t lp = (size_t)FreeImage_GetInfoHeader(dib);
655 	lp += sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * FreeImage_GetColorsUsed(dib);
656 	lp += FreeImage_HasRGBMasks(dib) ? sizeof(DWORD) * 3 : 0;
657 	lp += (lp % FIBITMAP_ALIGNMENT ? FIBITMAP_ALIGNMENT - lp % FIBITMAP_ALIGNMENT : 0);
658 	return (BYTE *)lp;
659 }
660 
661 // ----------------------------------------------------------
662 //  DIB information functions
663 // ----------------------------------------------------------
664 
665 FIBITMAP* DLL_CALLCONV
FreeImage_GetThumbnail(FIBITMAP * dib)666 FreeImage_GetThumbnail(FIBITMAP *dib) {
667 	return (dib != NULL) ? ((FREEIMAGEHEADER *)dib->data)->thumbnail : NULL;
668 }
669 
670 BOOL DLL_CALLCONV
FreeImage_SetThumbnail(FIBITMAP * dib,FIBITMAP * thumbnail)671 FreeImage_SetThumbnail(FIBITMAP *dib, FIBITMAP *thumbnail) {
672 	if(dib == NULL) {
673 		return FALSE;
674 	}
675 	FIBITMAP *currentThumbnail = ((FREEIMAGEHEADER *)dib->data)->thumbnail;
676 	if(currentThumbnail == thumbnail) {
677 		return TRUE;
678 	}
679 	FreeImage_Unload(currentThumbnail);
680 
681 	((FREEIMAGEHEADER *)dib->data)->thumbnail = FreeImage_HasPixels(thumbnail) ? FreeImage_Clone(thumbnail) : NULL;
682 
683 	return TRUE;
684 }
685 
686 // ----------------------------------------------------------
687 
688 FREE_IMAGE_COLOR_TYPE DLL_CALLCONV
FreeImage_GetColorType(FIBITMAP * dib)689 FreeImage_GetColorType(FIBITMAP *dib) {
690 	RGBQUAD *rgb;
691 
692 	const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
693 
694 	// special bitmap type
695 	if(image_type != FIT_BITMAP) {
696 		switch(image_type) {
697 			case FIT_UINT16:
698 			{
699 				// 16-bit greyscale TIF can be either FIC_MINISBLACK (the most common case) or FIC_MINISWHITE
700 				// you can check this using EXIF_MAIN metadata
701 				FITAG *photometricTag = NULL;
702 				if(FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, "PhotometricInterpretation", &photometricTag)) {
703 					const short *value = (short*)FreeImage_GetTagValue(photometricTag);
704 					// PHOTOMETRIC_MINISWHITE = 0 => min value is white
705 					// PHOTOMETRIC_MINISBLACK = 1 => min value is black
706 					return (*value == 0) ? FIC_MINISWHITE : FIC_MINISBLACK;
707 				}
708 				return FIC_MINISBLACK;
709 			}
710 			break;
711 
712 			case FIT_RGB16:
713 			case FIT_RGBF:
714 				return FIC_RGB;
715 
716 			case FIT_RGBA16:
717 			case FIT_RGBAF:
718 				return (((FreeImage_GetICCProfile(dib)->flags) & FIICC_COLOR_IS_CMYK) == FIICC_COLOR_IS_CMYK) ? FIC_CMYK : FIC_RGBALPHA;
719 		}
720 
721 		return FIC_MINISBLACK;
722 	}
723 
724 	// standard image type
725 	switch (FreeImage_GetBPP(dib)) {
726 		case 1:
727 		{
728 			rgb = FreeImage_GetPalette(dib);
729 
730 			if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0)) {
731 				rgb++;
732 
733 				if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255)) {
734 					return FIC_MINISBLACK;
735 				}
736 			}
737 
738 			if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255)) {
739 				rgb++;
740 
741 				if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0)) {
742 					return FIC_MINISWHITE;
743 				}
744 			}
745 
746 			return FIC_PALETTE;
747 		}
748 
749 		case 4:
750 		case 8:	// Check if the DIB has a color or a greyscale palette
751 		{
752 			int ncolors = FreeImage_GetColorsUsed(dib);
753 		    int minisblack = 1;
754 			rgb = FreeImage_GetPalette(dib);
755 
756 			for (int i = 0; i < ncolors; i++) {
757 				if ((rgb->rgbRed != rgb->rgbGreen) || (rgb->rgbRed != rgb->rgbBlue)) {
758 					return FIC_PALETTE;
759 				}
760 
761 				// The DIB has a color palette if the greyscale isn't a linear ramp
762 				// Take care of reversed grey images
763 				if (rgb->rgbRed != i) {
764 					if ((ncolors-i-1) != rgb->rgbRed) {
765 						return FIC_PALETTE;
766 					} else {
767 						minisblack = 0;
768 					}
769 				}
770 
771 				rgb++;
772 			}
773 
774 			return minisblack ? FIC_MINISBLACK : FIC_MINISWHITE;
775 		}
776 
777 		case 16:
778 		case 24:
779 			return FIC_RGB;
780 
781 		case 32:
782 		{
783 			if (((FreeImage_GetICCProfile(dib)->flags) & FIICC_COLOR_IS_CMYK) == FIICC_COLOR_IS_CMYK) {
784 				return FIC_CMYK;
785 			}
786 
787 			if( FreeImage_HasPixels(dib) ) {
788 				// check for fully opaque alpha layer
789 				for (unsigned y = 0; y < FreeImage_GetHeight(dib); y++) {
790 					rgb = (RGBQUAD *)FreeImage_GetScanLine(dib, y);
791 
792 					for (unsigned x = 0; x < FreeImage_GetWidth(dib); x++) {
793 						if (rgb[x].rgbReserved != 0xFF) {
794 							return FIC_RGBALPHA;
795 						}
796 					}
797 				}
798 				return FIC_RGB;
799 			}
800 
801 			return FIC_RGBALPHA;
802 		}
803 
804 		default :
805 			return FIC_MINISBLACK;
806 	}
807 }
808 
809 // ----------------------------------------------------------
810 
811 FREE_IMAGE_TYPE DLL_CALLCONV
FreeImage_GetImageType(FIBITMAP * dib)812 FreeImage_GetImageType(FIBITMAP *dib) {
813 	return (dib != NULL) ? ((FREEIMAGEHEADER *)dib->data)->type : FIT_UNKNOWN;
814 }
815 
816 // ----------------------------------------------------------
817 
818 BOOL DLL_CALLCONV
FreeImage_HasPixels(FIBITMAP * dib)819 FreeImage_HasPixels(FIBITMAP *dib) {
820 	return (dib != NULL) ? ((FREEIMAGEHEADER *)dib->data)->has_pixels : FALSE;
821 }
822 
823 // ----------------------------------------------------------
824 
825 BOOL DLL_CALLCONV
FreeImage_HasRGBMasks(FIBITMAP * dib)826 FreeImage_HasRGBMasks(FIBITMAP *dib) {
827 	return dib && FreeImage_GetInfoHeader(dib)->biCompression == BI_BITFIELDS;
828 }
829 
830 unsigned DLL_CALLCONV
FreeImage_GetRedMask(FIBITMAP * dib)831 FreeImage_GetRedMask(FIBITMAP *dib) {
832 	FREEIMAGERGBMASKS *masks = NULL;
833 	FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
834 	switch(image_type) {
835 		case FIT_BITMAP:
836 			// check for 16-bit RGB (565 or 555)
837 			masks = FreeImage_GetRGBMasks(dib);
838 			if (masks) {
839 				return masks->red_mask;
840 			}
841 			return FreeImage_GetBPP(dib) >= 24 ? FI_RGBA_RED_MASK : 0;
842 		default:
843 			return 0;
844 	}
845 }
846 
847 unsigned DLL_CALLCONV
FreeImage_GetGreenMask(FIBITMAP * dib)848 FreeImage_GetGreenMask(FIBITMAP *dib) {
849 	FREEIMAGERGBMASKS *masks = NULL;
850 	FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
851 	switch(image_type) {
852 		case FIT_BITMAP:
853 			// check for 16-bit RGB (565 or 555)
854 			masks = FreeImage_GetRGBMasks(dib);
855 			if (masks) {
856 				return masks->green_mask;
857 			}
858 			return FreeImage_GetBPP(dib) >= 24 ? FI_RGBA_GREEN_MASK : 0;
859 		default:
860 			return 0;
861 	}
862 }
863 
864 unsigned DLL_CALLCONV
FreeImage_GetBlueMask(FIBITMAP * dib)865 FreeImage_GetBlueMask(FIBITMAP *dib) {
866 	FREEIMAGERGBMASKS *masks = NULL;
867 	FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
868 	switch(image_type) {
869 		case FIT_BITMAP:
870 			// check for 16-bit RGB (565 or 555)
871 			masks = FreeImage_GetRGBMasks(dib);
872 			if (masks) {
873 				return masks->blue_mask;
874 			}
875 			return FreeImage_GetBPP(dib) >= 24 ? FI_RGBA_BLUE_MASK : 0;
876 		default:
877 			return 0;
878 	}
879 }
880 
881 // ----------------------------------------------------------
882 
883 BOOL DLL_CALLCONV
FreeImage_HasBackgroundColor(FIBITMAP * dib)884 FreeImage_HasBackgroundColor(FIBITMAP *dib) {
885 	if(dib) {
886 		RGBQUAD *bkgnd_color = &((FREEIMAGEHEADER *)dib->data)->bkgnd_color;
887 		return (bkgnd_color->rgbReserved != 0) ? TRUE : FALSE;
888 	}
889 	return FALSE;
890 }
891 
892 BOOL DLL_CALLCONV
FreeImage_GetBackgroundColor(FIBITMAP * dib,RGBQUAD * bkcolor)893 FreeImage_GetBackgroundColor(FIBITMAP *dib, RGBQUAD *bkcolor) {
894 	if(dib && bkcolor) {
895 		if(FreeImage_HasBackgroundColor(dib)) {
896 			// get the background color
897 			RGBQUAD *bkgnd_color = &((FREEIMAGEHEADER *)dib->data)->bkgnd_color;
898 			memcpy(bkcolor, bkgnd_color, sizeof(RGBQUAD));
899 			// get the background index
900 			if(FreeImage_GetBPP(dib) == 8) {
901 				RGBQUAD *pal = FreeImage_GetPalette(dib);
902 				for(unsigned i = 0; i < FreeImage_GetColorsUsed(dib); i++) {
903 					if(bkgnd_color->rgbRed == pal[i].rgbRed) {
904 						if(bkgnd_color->rgbGreen == pal[i].rgbGreen) {
905 							if(bkgnd_color->rgbBlue == pal[i].rgbBlue) {
906 								bkcolor->rgbReserved = (BYTE)i;
907 								return TRUE;
908 							}
909 						}
910 					}
911 				}
912 			}
913 
914 			bkcolor->rgbReserved = 0;
915 
916 			return TRUE;
917 		}
918 	}
919 
920 	return FALSE;
921 }
922 
923 BOOL DLL_CALLCONV
FreeImage_SetBackgroundColor(FIBITMAP * dib,RGBQUAD * bkcolor)924 FreeImage_SetBackgroundColor(FIBITMAP *dib, RGBQUAD *bkcolor) {
925 	if(dib) {
926 		RGBQUAD *bkgnd_color = &((FREEIMAGEHEADER *)dib->data)->bkgnd_color;
927 		if(bkcolor) {
928 			// set the background color
929 			memcpy(bkgnd_color, bkcolor, sizeof(RGBQUAD));
930 			// enable the file background color
931 			bkgnd_color->rgbReserved = 1;
932 		} else {
933 			// clear and disable the file background color
934 			memset(bkgnd_color, 0, sizeof(RGBQUAD));
935 		}
936 		return TRUE;
937 	}
938 
939 	return FALSE;
940 }
941 
942 // ----------------------------------------------------------
943 
944 BOOL DLL_CALLCONV
FreeImage_IsTransparent(FIBITMAP * dib)945 FreeImage_IsTransparent(FIBITMAP *dib) {
946 	if(dib) {
947 		FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
948 		switch(image_type) {
949 			case FIT_BITMAP:
950 				if(FreeImage_GetBPP(dib) == 32) {
951 					if(FreeImage_GetColorType(dib) == FIC_RGBALPHA) {
952 						return TRUE;
953 					}
954 				} else {
955 					return ((FREEIMAGEHEADER *)dib->data)->transparent ? TRUE : FALSE;
956 				}
957 				break;
958 			case FIT_RGBA16:
959 			case FIT_RGBAF:
960 				return (((FreeImage_GetICCProfile(dib)->flags) & FIICC_COLOR_IS_CMYK) == FIICC_COLOR_IS_CMYK) ? FALSE : TRUE;
961 			default:
962 				break;
963 		}
964 	}
965 	return FALSE;
966 }
967 
968 BYTE * DLL_CALLCONV
FreeImage_GetTransparencyTable(FIBITMAP * dib)969 FreeImage_GetTransparencyTable(FIBITMAP *dib) {
970 	return dib ? ((FREEIMAGEHEADER *)dib->data)->transparent_table : NULL;
971 }
972 
973 void DLL_CALLCONV
FreeImage_SetTransparent(FIBITMAP * dib,BOOL enabled)974 FreeImage_SetTransparent(FIBITMAP *dib, BOOL enabled) {
975 	if (dib) {
976 		if ((FreeImage_GetBPP(dib) <= 8) || (FreeImage_GetBPP(dib) == 32)) {
977 			((FREEIMAGEHEADER *)dib->data)->transparent = enabled;
978 		} else {
979 			((FREEIMAGEHEADER *)dib->data)->transparent = FALSE;
980 		}
981 	}
982 }
983 
984 unsigned DLL_CALLCONV
FreeImage_GetTransparencyCount(FIBITMAP * dib)985 FreeImage_GetTransparencyCount(FIBITMAP *dib) {
986 	return dib ? ((FREEIMAGEHEADER *)dib->data)->transparency_count : 0;
987 }
988 
989 void DLL_CALLCONV
FreeImage_SetTransparencyTable(FIBITMAP * dib,BYTE * table,int count)990 FreeImage_SetTransparencyTable(FIBITMAP *dib, BYTE *table, int count) {
991 	if (dib) {
992 		count = MAX(0, MIN(count, 256));
993 		if (FreeImage_GetBPP(dib) <= 8) {
994 			((FREEIMAGEHEADER *)dib->data)->transparent = (count > 0) ? TRUE : FALSE;
995 			((FREEIMAGEHEADER *)dib->data)->transparency_count = count;
996 
997 			if (table) {
998 				memcpy(((FREEIMAGEHEADER *)dib->data)->transparent_table, table, count);
999 			} else {
1000 				memset(((FREEIMAGEHEADER *)dib->data)->transparent_table, 0xff, count);
1001 			}
1002 		}
1003 	}
1004 }
1005 
1006 /** @brief Sets the index of the palette entry to be used as transparent color
1007  for the image specified. Does nothing on high color images.
1008 
1009  This method sets the index of the palette entry to be used as single transparent
1010  color for the image specified. This works on palletised images only and does
1011  nothing for high color images.
1012 
1013  Although it is possible for palletised images to have more than one transparent
1014  color, this method sets the palette entry specified as the single transparent
1015  color for the image. All other colors will be set to be non-transparent by this
1016  method.
1017 
1018  As with FreeImage_SetTransparencyTable(), this method also sets the image's
1019  transparency property to TRUE (as it is set and obtained by
1020  FreeImage_SetTransparent() and FreeImage_IsTransparent() respectively) for
1021  palletised images.
1022 
1023  @param dib Input image, whose transparent color is to be set.
1024  @param index The index of the palette entry to be set as transparent color.
1025  */
1026 void DLL_CALLCONV
FreeImage_SetTransparentIndex(FIBITMAP * dib,int index)1027 FreeImage_SetTransparentIndex(FIBITMAP *dib, int index) {
1028 	if (dib) {
1029 		int count = FreeImage_GetColorsUsed(dib);
1030 		if (count) {
1031 			BYTE *new_tt = (BYTE *)malloc(count * sizeof(BYTE));
1032 			memset(new_tt, 0xFF, count);
1033 			if ((index >= 0) && (index < count)) {
1034 				new_tt[index] = 0x00;
1035 			}
1036 			FreeImage_SetTransparencyTable(dib, new_tt, count);
1037 			free(new_tt);
1038 		}
1039 	}
1040 }
1041 
1042 /** @brief Returns the palette entry used as transparent color for the image
1043  specified. Works for palletised images only and returns -1 for high color
1044  images or if the image has no color set to be transparent.
1045 
1046  Although it is possible for palletised images to have more than one transparent
1047  color, this function always returns the index of the first palette entry, set
1048  to be transparent.
1049 
1050  @param dib Input image, whose transparent color is to be returned.
1051  @return Returns the index of the palette entry used as transparent color for
1052  the image specified or -1 if there is no transparent color found (e.g. the image
1053  is a high color image).
1054  */
1055 int DLL_CALLCONV
FreeImage_GetTransparentIndex(FIBITMAP * dib)1056 FreeImage_GetTransparentIndex(FIBITMAP *dib) {
1057 	int count = FreeImage_GetTransparencyCount(dib);
1058 	BYTE *tt = FreeImage_GetTransparencyTable(dib);
1059 	for (int i = 0; i < count; i++) {
1060 		if (tt[i] == 0) {
1061 			return i;
1062 		}
1063 	}
1064 	return -1;
1065 }
1066 
1067 // ----------------------------------------------------------
1068 
1069 FIICCPROFILE * DLL_CALLCONV
FreeImage_GetICCProfile(FIBITMAP * dib)1070 FreeImage_GetICCProfile(FIBITMAP *dib) {
1071 	FIICCPROFILE *profile = (dib) ? (FIICCPROFILE *)&((FREEIMAGEHEADER *)dib->data)->iccProfile : NULL;
1072 	return profile;
1073 }
1074 
1075 FIICCPROFILE * DLL_CALLCONV
FreeImage_CreateICCProfile(FIBITMAP * dib,void * data,long size)1076 FreeImage_CreateICCProfile(FIBITMAP *dib, void *data, long size) {
1077 	// clear the profile but preserve profile->flags
1078 	FreeImage_DestroyICCProfile(dib);
1079 	// create the new profile
1080 	FIICCPROFILE *profile = FreeImage_GetICCProfile(dib);
1081 	if(size && profile) {
1082 		profile->data = malloc(size);
1083 		if(profile->data) {
1084 			memcpy(profile->data, data, profile->size = size);
1085 		}
1086 	}
1087 	return profile;
1088 }
1089 
1090 void DLL_CALLCONV
FreeImage_DestroyICCProfile(FIBITMAP * dib)1091 FreeImage_DestroyICCProfile(FIBITMAP *dib) {
1092 	FIICCPROFILE *profile = FreeImage_GetICCProfile(dib);
1093 	if(profile) {
1094 		if (profile->data) {
1095 			free (profile->data);
1096 		}
1097 		// clear the profile but preserve profile->flags
1098 		profile->data = NULL;
1099 		profile->size = 0;
1100 	}
1101 
1102 	// destroy also Exif-Main ICC profile
1103 	FreeImage_SetMetadata(FIMD_EXIF_MAIN, dib, "InterColorProfile", NULL);
1104 }
1105 
1106 // ----------------------------------------------------------
1107 
1108 unsigned DLL_CALLCONV
FreeImage_GetWidth(FIBITMAP * dib)1109 FreeImage_GetWidth(FIBITMAP *dib) {
1110 	return dib ? FreeImage_GetInfoHeader(dib)->biWidth : 0;
1111 }
1112 
1113 unsigned DLL_CALLCONV
FreeImage_GetHeight(FIBITMAP * dib)1114 FreeImage_GetHeight(FIBITMAP *dib) {
1115 	return (dib) ? FreeImage_GetInfoHeader(dib)->biHeight : 0;
1116 }
1117 
1118 unsigned DLL_CALLCONV
FreeImage_GetBPP(FIBITMAP * dib)1119 FreeImage_GetBPP(FIBITMAP *dib) {
1120 	return dib ? FreeImage_GetInfoHeader(dib)->biBitCount : 0;
1121 }
1122 
1123 unsigned DLL_CALLCONV
FreeImage_GetLine(FIBITMAP * dib)1124 FreeImage_GetLine(FIBITMAP *dib) {
1125 	return dib ? ((FreeImage_GetWidth(dib) * FreeImage_GetBPP(dib)) + 7) / 8 : 0;
1126 }
1127 
1128 unsigned DLL_CALLCONV
FreeImage_GetPitch(FIBITMAP * dib)1129 FreeImage_GetPitch(FIBITMAP *dib) {
1130 	if(dib) {
1131 		FREEIMAGEHEADER *fih = (FREEIMAGEHEADER *)dib->data;
1132 		return fih->external_bits ? fih->external_pitch : (FreeImage_GetLine(dib) + 3 & ~3);
1133 	}
1134 	return 0;
1135 }
1136 
1137 unsigned DLL_CALLCONV
FreeImage_GetColorsUsed(FIBITMAP * dib)1138 FreeImage_GetColorsUsed(FIBITMAP *dib) {
1139 	return dib ? FreeImage_GetInfoHeader(dib)->biClrUsed : 0;
1140 }
1141 
1142 unsigned DLL_CALLCONV
FreeImage_GetDIBSize(FIBITMAP * dib)1143 FreeImage_GetDIBSize(FIBITMAP *dib) {
1144 	return (dib) ? sizeof(BITMAPINFOHEADER) + (FreeImage_GetColorsUsed(dib) * sizeof(RGBQUAD)) + (FreeImage_GetPitch(dib) * FreeImage_GetHeight(dib)) : 0;
1145 }
1146 
1147 RGBQUAD * DLL_CALLCONV
FreeImage_GetPalette(FIBITMAP * dib)1148 FreeImage_GetPalette(FIBITMAP *dib) {
1149 	return (dib && FreeImage_GetBPP(dib) < 16) ? (RGBQUAD *)(((BYTE *)FreeImage_GetInfoHeader(dib)) + sizeof(BITMAPINFOHEADER)) : NULL;
1150 }
1151 
1152 unsigned DLL_CALLCONV
FreeImage_GetDotsPerMeterX(FIBITMAP * dib)1153 FreeImage_GetDotsPerMeterX(FIBITMAP *dib) {
1154 	return (dib) ? FreeImage_GetInfoHeader(dib)->biXPelsPerMeter : 0;
1155 }
1156 
1157 unsigned DLL_CALLCONV
FreeImage_GetDotsPerMeterY(FIBITMAP * dib)1158 FreeImage_GetDotsPerMeterY(FIBITMAP *dib) {
1159 	return (dib) ? FreeImage_GetInfoHeader(dib)->biYPelsPerMeter : 0;
1160 }
1161 
1162 void DLL_CALLCONV
FreeImage_SetDotsPerMeterX(FIBITMAP * dib,unsigned res)1163 FreeImage_SetDotsPerMeterX(FIBITMAP *dib, unsigned res) {
1164 	if(dib) {
1165 		FreeImage_GetInfoHeader(dib)->biXPelsPerMeter = res;
1166 	}
1167 }
1168 
1169 void DLL_CALLCONV
FreeImage_SetDotsPerMeterY(FIBITMAP * dib,unsigned res)1170 FreeImage_SetDotsPerMeterY(FIBITMAP *dib, unsigned res) {
1171 	if(dib) {
1172 		FreeImage_GetInfoHeader(dib)->biYPelsPerMeter = res;
1173 	}
1174 }
1175 
1176 BITMAPINFOHEADER * DLL_CALLCONV
FreeImage_GetInfoHeader(FIBITMAP * dib)1177 FreeImage_GetInfoHeader(FIBITMAP *dib) {
1178 	if(!dib) {
1179 		return NULL;
1180 	}
1181 	size_t lp = (size_t)dib->data + sizeof(FREEIMAGEHEADER);
1182 	lp += (lp % FIBITMAP_ALIGNMENT ? FIBITMAP_ALIGNMENT - lp % FIBITMAP_ALIGNMENT : 0);
1183 	lp += FIBITMAP_ALIGNMENT - sizeof(BITMAPINFOHEADER) % FIBITMAP_ALIGNMENT;
1184 	return (BITMAPINFOHEADER *)lp;
1185 }
1186 
1187 BITMAPINFO * DLL_CALLCONV
FreeImage_GetInfo(FIBITMAP * dib)1188 FreeImage_GetInfo(FIBITMAP *dib) {
1189 	return (BITMAPINFO *)FreeImage_GetInfoHeader(dib);
1190 }
1191 
1192 // ----------------------------------------------------------
1193 //  Metadata routines
1194 // ----------------------------------------------------------
1195 
1196 FIMETADATA * DLL_CALLCONV
FreeImage_FindFirstMetadata(FREE_IMAGE_MDMODEL model,FIBITMAP * dib,FITAG ** tag)1197 FreeImage_FindFirstMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, FITAG **tag) {
1198 	if(!dib) {
1199 		return NULL;
1200 	}
1201 
1202 	// get the metadata model
1203 	METADATAMAP *metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
1204 	TAGMAP *tagmap = NULL;
1205 	if( (*metadata).find(model) != (*metadata).end() ) {
1206 		tagmap = (*metadata)[model];
1207 	}
1208 	if(tagmap) {
1209 		// allocate a handle
1210 		FIMETADATA 	*handle = (FIMETADATA *)malloc(sizeof(FIMETADATA));
1211 		if(handle) {
1212 			// calculate the size of a METADATAHEADER
1213 			const size_t header_size = sizeof(METADATAHEADER);
1214 
1215 			handle->data = (BYTE *)malloc(header_size);
1216 
1217 			if(handle->data) {
1218 				memset(handle->data, 0, header_size);
1219 
1220 				// write out the METADATAHEADER
1221 				METADATAHEADER *mdh = (METADATAHEADER *)handle->data;
1222 
1223 				mdh->pos = 1;
1224 				mdh->tagmap = tagmap;
1225 
1226 				// get the first element
1227 				TAGMAP::iterator i = tagmap->begin();
1228 				*tag = (*i).second;
1229 
1230 				return handle;
1231 			}
1232 
1233 			free(handle);
1234 		}
1235 	}
1236 
1237 	return NULL;
1238 }
1239 
1240 BOOL DLL_CALLCONV
FreeImage_FindNextMetadata(FIMETADATA * mdhandle,FITAG ** tag)1241 FreeImage_FindNextMetadata(FIMETADATA *mdhandle, FITAG **tag) {
1242 	if(!mdhandle) {
1243 		return FALSE;
1244 	}
1245 
1246 	METADATAHEADER *mdh = (METADATAHEADER *)mdhandle->data;
1247 	TAGMAP *tagmap = mdh->tagmap;
1248 
1249 	int current_pos = mdh->pos;
1250 	int mapsize     = (int)tagmap->size();
1251 
1252 	if(current_pos < mapsize) {
1253 		// get the tag element at position pos
1254 		int count = 0;
1255 
1256 		for(TAGMAP::iterator i = tagmap->begin(); i != tagmap->end(); i++) {
1257 			if(count == current_pos) {
1258 				*tag = (*i).second;
1259 				mdh->pos++;
1260 				break;
1261 			}
1262 			count++;
1263 		}
1264 
1265 		return TRUE;
1266 	}
1267 
1268 	return FALSE;
1269 }
1270 
1271 void DLL_CALLCONV
FreeImage_FindCloseMetadata(FIMETADATA * mdhandle)1272 FreeImage_FindCloseMetadata(FIMETADATA *mdhandle) {
1273 	if (NULL != mdhandle) {	// delete the handle
1274 		if (NULL != mdhandle->data) {
1275 			free(mdhandle->data);
1276 		}
1277 		free(mdhandle);		// ... and the wrapper
1278 	}
1279 }
1280 
1281 
1282 // ----------------------------------------------------------
1283 
1284 BOOL DLL_CALLCONV
FreeImage_CloneMetadata(FIBITMAP * dst,FIBITMAP * src)1285 FreeImage_CloneMetadata(FIBITMAP *dst, FIBITMAP *src) {
1286 	if(!src || !dst) {
1287 		return FALSE;
1288 	}
1289 
1290 	// get metadata links
1291 	METADATAMAP *src_metadata = ((FREEIMAGEHEADER *)src->data)->metadata;
1292 	METADATAMAP *dst_metadata = ((FREEIMAGEHEADER *)dst->data)->metadata;
1293 
1294 	// copy metadata models, *except* the FIMD_ANIMATION model
1295 	for(METADATAMAP::iterator i = (*src_metadata).begin(); i != (*src_metadata).end(); i++) {
1296 		int model = (*i).first;
1297 		if(model == (int)FIMD_ANIMATION) {
1298 			continue;
1299 		}
1300 		TAGMAP *src_tagmap = (*i).second;
1301 
1302 		if(src_tagmap) {
1303 			if( dst_metadata->find(model) != dst_metadata->end() ) {
1304 				// destroy dst model
1305 				FreeImage_SetMetadata((FREE_IMAGE_MDMODEL)model, dst, NULL, NULL);
1306 			}
1307 
1308 			// create a metadata model
1309 			TAGMAP *dst_tagmap = new(std::nothrow) TAGMAP();
1310 
1311 			if(dst_tagmap) {
1312 				// fill the model
1313 				for(TAGMAP::iterator j = src_tagmap->begin(); j != src_tagmap->end(); j++) {
1314 					std::string dst_key = (*j).first;
1315 					FITAG *dst_tag = FreeImage_CloneTag( (*j).second );
1316 
1317 					// assign key and tag value
1318 					(*dst_tagmap)[dst_key] = dst_tag;
1319 				}
1320 
1321 				// assign model and tagmap
1322 				(*dst_metadata)[model] = dst_tagmap;
1323 			}
1324 		}
1325 	}
1326 
1327 	// clone resolution
1328 	FreeImage_SetDotsPerMeterX(dst, FreeImage_GetDotsPerMeterX(src));
1329 	FreeImage_SetDotsPerMeterY(dst, FreeImage_GetDotsPerMeterY(src));
1330 
1331 	return TRUE;
1332 }
1333 
1334 // ----------------------------------------------------------
1335 
1336 BOOL DLL_CALLCONV
FreeImage_SetMetadata(FREE_IMAGE_MDMODEL model,FIBITMAP * dib,const char * key,FITAG * tag)1337 FreeImage_SetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, FITAG *tag) {
1338 	if(!dib) {
1339 		return FALSE;
1340 	}
1341 
1342 	TAGMAP *tagmap = NULL;
1343 
1344 	// get the metadata model
1345 	METADATAMAP *metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
1346 	METADATAMAP::iterator model_iterator = metadata->find(model);
1347 	if (model_iterator != metadata->end()) {
1348 		tagmap = model_iterator->second;
1349 	}
1350 
1351 	if(key != NULL) {
1352 
1353 		if ((tag == NULL) && !tagmap) {
1354 			// remove a tag from an unknown tagmap, nothing to do
1355 			return TRUE;
1356 		}
1357 
1358 		if(!tagmap) {
1359 			// this model, doesn't exist: create it
1360 			tagmap = new(std::nothrow) TAGMAP();
1361 			(*metadata)[model] = tagmap;
1362 		}
1363 
1364 		if(tag) {
1365 			// first check the tag
1366 			if(FreeImage_GetTagKey(tag) == NULL) {
1367 				FreeImage_SetTagKey(tag, key);
1368 			} else if(strcmp(key, FreeImage_GetTagKey(tag)) != 0) {
1369 				// set the tag key
1370 				FreeImage_SetTagKey(tag, key);
1371 			}
1372 			if(FreeImage_GetTagCount(tag) * FreeImage_TagDataWidth(FreeImage_GetTagType(tag)) != FreeImage_GetTagLength(tag)) {
1373 				FreeImage_OutputMessageProc(FIF_UNKNOWN, "Invalid data count for tag '%s'", key);
1374 				return FALSE;
1375 			}
1376 
1377 			// fill the tag ID if possible and if it's needed
1378 			TagLib& tag_lib = TagLib::instance();
1379 			switch(model) {
1380 				case FIMD_IPTC:
1381 				{
1382 					int id = tag_lib.getTagID(TagLib::IPTC, key);
1383 					/*
1384 					if(id == -1) {
1385 						FreeImage_OutputMessageProc(FIF_UNKNOWN, "IPTC: Invalid key '%s'", key);
1386 					}
1387 					*/
1388 					FreeImage_SetTagID(tag, (WORD)id);
1389 				}
1390 				break;
1391 
1392 				default:
1393 					break;
1394 			}
1395 
1396 			// delete existing tag
1397 			FITAG *old_tag = (*tagmap)[key];
1398 			if(old_tag) {
1399 				FreeImage_DeleteTag(old_tag);
1400 			}
1401 
1402 			// create a new tag
1403 			(*tagmap)[key] = FreeImage_CloneTag(tag);
1404 		}
1405 		else {
1406 			// delete existing tag
1407 			TAGMAP::iterator i = tagmap->find(key);
1408 			if(i != tagmap->end()) {
1409 				FITAG *old_tag = (*i).second;
1410 				FreeImage_DeleteTag(old_tag);
1411 				tagmap->erase(key);
1412 			}
1413 		}
1414 	}
1415 	else {
1416 		// destroy the metadata model
1417 		if(tagmap) {
1418 			for(TAGMAP::iterator i = tagmap->begin(); i != tagmap->end(); i++) {
1419 				FITAG *tag = (*i).second;
1420 				FreeImage_DeleteTag(tag);
1421 			}
1422 
1423 			delete tagmap;
1424 			metadata->erase(model_iterator);
1425 		}
1426 	}
1427 
1428 	return TRUE;
1429 }
1430 
1431 BOOL DLL_CALLCONV
FreeImage_GetMetadata(FREE_IMAGE_MDMODEL model,FIBITMAP * dib,const char * key,FITAG ** tag)1432 FreeImage_GetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, FITAG **tag) {
1433 	if(!dib || !key || !tag) {
1434 		return FALSE;
1435 	}
1436 
1437 	TAGMAP *tagmap = NULL;
1438 	*tag = NULL;
1439 
1440 	// get the metadata model
1441 	METADATAMAP *metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
1442 	if(!(*metadata).empty()) {
1443 		METADATAMAP::iterator model_iterator = metadata->find(model);
1444 		if (model_iterator != metadata->end() ) {
1445 			// this model exists : try to get the requested tag
1446 			tagmap = model_iterator->second;
1447 			TAGMAP::iterator tag_iterator = tagmap->find(key);
1448 			if (tag_iterator != tagmap->end() ) {
1449 				// get the requested tag
1450 				*tag = tag_iterator->second;
1451 			}
1452 		}
1453 	}
1454 
1455 	return (*tag != NULL) ? TRUE : FALSE;
1456 }
1457 
1458 /**
1459 Build and set a FITAG whose type is FIDT_ASCII.
1460 @param model Metadata model to be filled
1461 @param dib Image to be filled
1462 @param key Tag key
1463 @param value Tag value as a ASCII string
1464 @return Returns TRUE if successful, returns FALSE otherwise
1465 */
1466 BOOL DLL_CALLCONV
FreeImage_SetMetadataKeyValue(FREE_IMAGE_MDMODEL model,FIBITMAP * dib,const char * key,const char * value)1467 FreeImage_SetMetadataKeyValue(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, const char *value) {
1468 	if(!dib || !key || !value) {
1469 		return FALSE;
1470 	}
1471 	// create a tag
1472 	FITAG *tag = FreeImage_CreateTag();
1473 	if(tag) {
1474 		BOOL bSuccess = TRUE;
1475 		// fill the tag
1476 		DWORD tag_length = (DWORD)(strlen(value) + 1);
1477 		bSuccess &= FreeImage_SetTagKey(tag, key);
1478 		bSuccess &= FreeImage_SetTagLength(tag, tag_length);
1479 		bSuccess &= FreeImage_SetTagCount(tag, tag_length);
1480 		bSuccess &= FreeImage_SetTagType(tag, FIDT_ASCII);
1481 		bSuccess &= FreeImage_SetTagValue(tag, value);
1482 		if(bSuccess) {
1483 			// set the tag
1484 			bSuccess &= FreeImage_SetMetadata(model, dib, FreeImage_GetTagKey(tag), tag);
1485 		}
1486 		// delete the tag
1487 		FreeImage_DeleteTag(tag);
1488 
1489 		return bSuccess;
1490 	}
1491 
1492 	return FALSE;
1493 }
1494 
1495 // ----------------------------------------------------------
1496 
1497 unsigned DLL_CALLCONV
FreeImage_GetMetadataCount(FREE_IMAGE_MDMODEL model,FIBITMAP * dib)1498 FreeImage_GetMetadataCount(FREE_IMAGE_MDMODEL model, FIBITMAP *dib) {
1499 	if(!dib) {
1500 		return FALSE;
1501 	}
1502 
1503 	TAGMAP *tagmap = NULL;
1504 
1505 	// get the metadata model
1506 	METADATAMAP *metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
1507 	if( (*metadata).find(model) != (*metadata).end() ) {
1508 		tagmap = (*metadata)[model];
1509 	}
1510 	if(!tagmap) {
1511 		// this model, doesn't exist: return
1512 		return 0;
1513 	}
1514 
1515 	// get the tag count
1516 	return (unsigned)tagmap->size();
1517 }
1518 
1519 // ----------------------------------------------------------
1520 
1521 unsigned DLL_CALLCONV
FreeImage_GetMemorySize(FIBITMAP * dib)1522 FreeImage_GetMemorySize(FIBITMAP *dib) {
1523 	if (!dib) {
1524 		return 0;
1525 	}
1526 	FREEIMAGEHEADER *header = (FREEIMAGEHEADER *)dib->data;
1527 	BITMAPINFOHEADER *bih = FreeImage_GetInfoHeader(dib);
1528 
1529 	BOOL header_only = !header->has_pixels || header->external_bits != NULL;
1530 	BOOL need_masks = bih->biCompression == BI_BITFIELDS;
1531 	unsigned width = bih->biWidth;
1532 	unsigned height = bih->biHeight;
1533 	unsigned bpp = bih->biBitCount;
1534 
1535 	// start off with the size of the FIBITMAP structure
1536 	size_t size = sizeof(FIBITMAP);
1537 
1538 	// add sizes of FREEIMAGEHEADER, BITMAPINFOHEADER, palette and DIB data
1539 	size += FreeImage_GetInternalImageSize(header_only, width, height, bpp, need_masks);
1540 
1541 	// add ICC profile size
1542 	size += header->iccProfile.size;
1543 
1544 	// add thumbnail image size
1545 	if (header->thumbnail) {
1546 		// we assume a thumbnail not having a thumbnail as well,
1547 		// so this recursive call should not create an infinite loop
1548 		size += FreeImage_GetMemorySize(header->thumbnail);
1549 	}
1550 
1551 	// add metadata size
1552 	METADATAMAP *md = header->metadata;
1553 	if (!md) {
1554 		return (unsigned)size;
1555 	}
1556 
1557 	// add size of METADATAMAP
1558 	size += sizeof(METADATAMAP);
1559 
1560 	const size_t models = md->size();
1561 	if (models == 0) {
1562 		return (unsigned)size;
1563 	}
1564 
1565 	unsigned tags = 0;
1566 
1567 	for (METADATAMAP::iterator i = md->begin(); i != md->end(); i++) {
1568 		TAGMAP *tm = i->second;
1569 		if (tm) {
1570 			for (TAGMAP::iterator j = tm->begin(); j != tm->end(); j++) {
1571 				++tags;
1572 				const std::string & key = j->first;
1573 				size += key.capacity();
1574 				size += FreeImage_GetTagMemorySize(j->second);
1575 			}
1576 		}
1577 	}
1578 
1579 	// add size of all TAGMAP instances
1580 	size += models * sizeof(TAGMAP);
1581 	// add size of tree nodes in METADATAMAP
1582 	size += MapIntrospector<METADATAMAP>::GetNodesMemorySize(models);
1583 	// add size of tree nodes in TAGMAP
1584 	size += MapIntrospector<TAGMAP>::GetNodesMemorySize(tags);
1585 
1586 	return (unsigned)size;
1587 }
1588 
1589