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