/src/freeimage-svn/FreeImage/trunk/Source/FreeImage/BitmapAccess.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 101 | #define BI_RGB 0L |
53 | 12.2k | #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 */ |
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 | | */ |
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 | | */ |
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 | | |
143 | | void* FreeImage_Aligned_Malloc(size_t amount, size_t alignment) { |
144 | | assert(alignment == FIBITMAP_ALIGNMENT); |
145 | | return _aligned_malloc(amount, alignment); |
146 | | } |
147 | | |
148 | | void FreeImage_Aligned_Free(void* mem) { |
149 | | _aligned_free(mem); |
150 | | } |
151 | | |
152 | | #elif defined (__MINGW32__) |
153 | | |
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 | | |
159 | | void FreeImage_Aligned_Free(void* mem) { |
160 | | __mingw_aligned_free (mem); |
161 | | } |
162 | | |
163 | | #else |
164 | | |
165 | 53 | void* FreeImage_Aligned_Malloc(size_t amount, size_t alignment) { |
166 | 53 | 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 | 53 | void* mem_real = malloc(amount + 2 * alignment); |
184 | 53 | if(!mem_real) return NULL; |
185 | 52 | char* mem_align = (char*)((unsigned long)(2 * alignment - (unsigned long)mem_real % (unsigned long)alignment) + (unsigned long)mem_real); |
186 | 52 | *((long*)mem_align - 1) = (long)mem_real; |
187 | 52 | return mem_align; |
188 | 53 | } |
189 | | |
190 | 52 | void FreeImage_Aligned_Free(void* mem) { |
191 | 52 | free((void*)*((long*)mem - 1)); |
192 | 52 | } |
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 |
214 | 53 | FreeImage_GetInternalImageSize(BOOL header_only, unsigned width, unsigned height, unsigned bpp, BOOL need_masks) { |
215 | 53 | size_t dib_size = sizeof(FREEIMAGEHEADER); |
216 | 53 | dib_size += (dib_size % FIBITMAP_ALIGNMENT ? FIBITMAP_ALIGNMENT - dib_size % FIBITMAP_ALIGNMENT : 0); |
217 | 53 | dib_size += FIBITMAP_ALIGNMENT - sizeof(BITMAPINFOHEADER) % FIBITMAP_ALIGNMENT; |
218 | 53 | dib_size += sizeof(BITMAPINFOHEADER); |
219 | | // palette is aligned on a 16 bytes boundary |
220 | 53 | 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 | 53 | dib_size += need_masks ? sizeof(DWORD) * 3 : 0; |
224 | 53 | dib_size += (dib_size % FIBITMAP_ALIGNMENT ? FIBITMAP_ALIGNMENT - dib_size % FIBITMAP_ALIGNMENT : 0); |
225 | | |
226 | 53 | if(!header_only) { |
227 | 53 | const size_t header_size = dib_size; |
228 | | |
229 | | // pixels are aligned on a 16 bytes boundary |
230 | 53 | 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 | 53 | { |
234 | 53 | const double dPitch = floor( ((double)bpp * width + 31.0) / 32.0 ) * 4.0; |
235 | 53 | const double dImageSize = (double)header_size + dPitch * height; |
236 | 53 | if(dImageSize != (double)dib_size) { |
237 | | // here, we are sure to encounter a malloc overflow: try to avoid it ... |
238 | 0 | return 0; |
239 | 0 | } |
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 | 53 | const double FIBITMAP_MAX_MEMORY = (double)((size_t)-1) - 8 * FIBITMAP_ALIGNMENT; |
248 | | |
249 | 53 | if(dImageSize > FIBITMAP_MAX_MEMORY) { |
250 | | // avoid possible overflow inside C allocation functions |
251 | 0 | return 0; |
252 | 0 | } |
253 | 53 | } |
254 | 53 | } |
255 | | |
256 | 53 | return dib_size; |
257 | 53 | } |
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 * |
267 | 3 | FreeImage_GetRGBMasks(FIBITMAP *dib) { |
268 | 3 | return FreeImage_HasRGBMasks(dib) ? (FREEIMAGERGBMASKS *)(((BYTE *)FreeImage_GetInfoHeader(dib)) + sizeof(BITMAPINFOHEADER)) : NULL; |
269 | 3 | } |
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 * |
297 | 53 | 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 | 53 | width = abs(width); |
301 | 53 | height = abs(height); |
302 | 53 | if(!((width > 0) && (height > 0))) { |
303 | 0 | return NULL; |
304 | 0 | } |
305 | 53 | if(ext_bits) { |
306 | 0 | if(ext_pitch == 0) { |
307 | 0 | return NULL; |
308 | 0 | } |
309 | 0 | assert(header_only == FALSE); |
310 | 0 | } |
311 | | |
312 | | // we only store the masks (and allocate memory for them) for 16-bit images of type FIT_BITMAP |
313 | 53 | BOOL need_masks = FALSE; |
314 | | |
315 | | // check pixel bit depth |
316 | 53 | switch(type) { |
317 | 53 | case FIT_BITMAP: |
318 | 53 | switch(bpp) { |
319 | 1 | case 1: |
320 | 20 | case 4: |
321 | 42 | case 8: |
322 | 42 | break; |
323 | 3 | case 16: |
324 | 3 | need_masks = TRUE; |
325 | 3 | break; |
326 | 2 | case 24: |
327 | 8 | case 32: |
328 | 8 | break; |
329 | 0 | default: |
330 | 0 | bpp = 8; |
331 | 0 | break; |
332 | 53 | } |
333 | 53 | break; |
334 | 53 | case FIT_UINT16: |
335 | 0 | bpp = 8 * sizeof(unsigned short); |
336 | 0 | break; |
337 | 0 | case FIT_INT16: |
338 | 0 | bpp = 8 * sizeof(short); |
339 | 0 | break; |
340 | 0 | case FIT_UINT32: |
341 | 0 | bpp = 8 * sizeof(DWORD); |
342 | 0 | break; |
343 | 0 | case FIT_INT32: |
344 | 0 | bpp = 8 * sizeof(LONG); |
345 | 0 | break; |
346 | 0 | case FIT_FLOAT: |
347 | 0 | bpp = 8 * sizeof(float); |
348 | 0 | break; |
349 | 0 | case FIT_DOUBLE: |
350 | 0 | bpp = 8 * sizeof(double); |
351 | 0 | break; |
352 | 0 | case FIT_COMPLEX: |
353 | 0 | bpp = 8 * sizeof(FICOMPLEX); |
354 | 0 | break; |
355 | 0 | case FIT_RGB16: |
356 | 0 | bpp = 8 * sizeof(FIRGB16); |
357 | 0 | break; |
358 | 0 | case FIT_RGBA16: |
359 | 0 | bpp = 8 * sizeof(FIRGBA16); |
360 | 0 | break; |
361 | 0 | case FIT_RGBF: |
362 | 0 | bpp = 8 * sizeof(FIRGBF); |
363 | 0 | break; |
364 | 0 | case FIT_RGBAF: |
365 | 0 | bpp = 8 * sizeof(FIRGBAF); |
366 | 0 | break; |
367 | 0 | default: |
368 | 0 | return NULL; |
369 | 53 | } |
370 | | |
371 | 53 | FIBITMAP *bitmap = (FIBITMAP *)malloc(sizeof(FIBITMAP)); |
372 | | |
373 | 53 | 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 | 53 | size_t dib_size = FreeImage_GetInternalImageSize(header_only || ext_bits, width, height, bpp, need_masks); |
383 | | |
384 | 53 | if(dib_size == 0) { |
385 | | // memory allocation will fail (probably a malloc overflow) |
386 | 0 | free(bitmap); |
387 | 0 | return NULL; |
388 | 0 | } |
389 | | |
390 | 53 | bitmap->data = (BYTE *)FreeImage_Aligned_Malloc(dib_size * sizeof(BYTE), FIBITMAP_ALIGNMENT); |
391 | | |
392 | 53 | if (bitmap->data != NULL) { |
393 | 52 | memset(bitmap->data, 0, dib_size); |
394 | | |
395 | | // write out the FREEIMAGEHEADER |
396 | | |
397 | 52 | FREEIMAGEHEADER *fih = (FREEIMAGEHEADER *)bitmap->data; |
398 | | |
399 | 52 | fih->type = type; |
400 | | |
401 | 52 | memset(&fih->bkgnd_color, 0, sizeof(RGBQUAD)); |
402 | | |
403 | 52 | fih->transparent = FALSE; |
404 | 52 | fih->transparency_count = 0; |
405 | 52 | memset(fih->transparent_table, 0xff, 256); |
406 | | |
407 | 52 | fih->has_pixels = header_only ? FALSE : TRUE; |
408 | | |
409 | | // initialize FIICCPROFILE link |
410 | | |
411 | 52 | FIICCPROFILE *iccProfile = FreeImage_GetICCProfile(bitmap); |
412 | 52 | iccProfile->size = 0; |
413 | 52 | iccProfile->data = 0; |
414 | 52 | iccProfile->flags = 0; |
415 | | |
416 | | // initialize metadata models list |
417 | | |
418 | 52 | fih->metadata = new(std::nothrow) METADATAMAP; |
419 | | |
420 | | // initialize attached thumbnail |
421 | | |
422 | 52 | fih->thumbnail = NULL; |
423 | | |
424 | | // store a pointer to user provided pixel buffer (if any) |
425 | | |
426 | 52 | fih->external_bits = ext_bits; |
427 | 52 | fih->external_pitch = ext_pitch; |
428 | | |
429 | | // write out the BITMAPINFOHEADER |
430 | | |
431 | 52 | BITMAPINFOHEADER *bih = FreeImage_GetInfoHeader(bitmap); |
432 | 52 | bih->biSize = sizeof(BITMAPINFOHEADER); |
433 | 52 | bih->biWidth = width; |
434 | 52 | bih->biHeight = height; |
435 | 52 | bih->biPlanes = 1; |
436 | 52 | bih->biCompression = need_masks ? BI_BITFIELDS : BI_RGB; |
437 | 52 | bih->biBitCount = (WORD)bpp; |
438 | 52 | bih->biClrUsed = CalculateUsedPaletteEntries(bpp); |
439 | 52 | bih->biClrImportant = bih->biClrUsed; |
440 | 52 | bih->biXPelsPerMeter = 2835; // 72 dpi |
441 | 52 | bih->biYPelsPerMeter = 2835; // 72 dpi |
442 | | |
443 | 52 | if(bpp == 8) { |
444 | | // build a default greyscale palette (very useful for image processing) |
445 | 22 | RGBQUAD *pal = FreeImage_GetPalette(bitmap); |
446 | 5.65k | for(int i = 0; i < 256; i++) { |
447 | 5.63k | pal[i].rgbRed = (BYTE)i; |
448 | 5.63k | pal[i].rgbGreen = (BYTE)i; |
449 | 5.63k | pal[i].rgbBlue = (BYTE)i; |
450 | 5.63k | } |
451 | 22 | } |
452 | | |
453 | | // just setting the masks (only if needed) just like the palette. |
454 | 52 | if (need_masks) { |
455 | 3 | FREEIMAGERGBMASKS *masks = FreeImage_GetRGBMasks(bitmap); |
456 | 3 | masks->red_mask = red_mask; |
457 | 3 | masks->green_mask = green_mask; |
458 | 3 | masks->blue_mask = blue_mask; |
459 | 3 | } |
460 | | |
461 | 52 | return bitmap; |
462 | 52 | } |
463 | | |
464 | 1 | free(bitmap); |
465 | 1 | } |
466 | | |
467 | 1 | return NULL; |
468 | 53 | } |
469 | | |
470 | | FIBITMAP * DLL_CALLCONV |
471 | 0 | 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 | 0 | return FreeImage_AllocateBitmap(FALSE, ext_bits, ext_pitch, type, width, height, bpp, red_mask, green_mask, blue_mask); |
473 | 0 | } |
474 | | |
475 | | FIBITMAP * DLL_CALLCONV |
476 | 0 | 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 | 0 | return FreeImage_AllocateBitmap(header_only, NULL, 0, type, width, height, bpp, red_mask, green_mask, blue_mask); |
478 | 0 | } |
479 | | |
480 | | FIBITMAP * DLL_CALLCONV |
481 | 53 | FreeImage_AllocateHeader(BOOL header_only, int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) { |
482 | 53 | return FreeImage_AllocateBitmap(header_only, NULL, 0, FIT_BITMAP, width, height, bpp, red_mask, green_mask, blue_mask); |
483 | 53 | } |
484 | | |
485 | | FIBITMAP * DLL_CALLCONV |
486 | 0 | FreeImage_Allocate(int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) { |
487 | 0 | return FreeImage_AllocateBitmap(FALSE, NULL, 0, FIT_BITMAP, width, height, bpp, red_mask, green_mask, blue_mask); |
488 | 0 | } |
489 | | |
490 | | FIBITMAP * DLL_CALLCONV |
491 | 0 | FreeImage_AllocateT(FREE_IMAGE_TYPE type, int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) { |
492 | 0 | return FreeImage_AllocateBitmap(FALSE, NULL, 0, type, width, height, bpp, red_mask, green_mask, blue_mask); |
493 | 0 | } |
494 | | |
495 | | void DLL_CALLCONV |
496 | 146 | FreeImage_Unload(FIBITMAP *dib) { |
497 | 146 | if (NULL != dib) { |
498 | 52 | if (NULL != dib->data) { |
499 | | // delete possible icc profile ... |
500 | 52 | if (FreeImage_GetICCProfile(dib)->data) { |
501 | 0 | free(FreeImage_GetICCProfile(dib)->data); |
502 | 0 | } |
503 | | |
504 | | // delete metadata models |
505 | 52 | METADATAMAP *metadata = ((FREEIMAGEHEADER *)dib->data)->metadata; |
506 | | |
507 | 52 | for(METADATAMAP::iterator i = (*metadata).begin(); i != (*metadata).end(); i++) { |
508 | 0 | TAGMAP *tagmap = (*i).second; |
509 | |
|
510 | 0 | if(tagmap) { |
511 | 0 | for(TAGMAP::iterator j = tagmap->begin(); j != tagmap->end(); j++) { |
512 | 0 | FITAG *tag = (*j).second; |
513 | 0 | FreeImage_DeleteTag(tag); |
514 | 0 | } |
515 | |
|
516 | 0 | delete tagmap; |
517 | 0 | } |
518 | 0 | } |
519 | | |
520 | 52 | delete metadata; |
521 | | |
522 | | // delete embedded thumbnail |
523 | 52 | FreeImage_Unload(FreeImage_GetThumbnail(dib)); |
524 | | |
525 | | // delete bitmap ... |
526 | 52 | FreeImage_Aligned_Free(dib->data); |
527 | 52 | } |
528 | | |
529 | 52 | free(dib); // ... and the wrapper |
530 | 52 | } |
531 | 146 | } |
532 | | |
533 | | // ---------------------------------------------------------- |
534 | | |
535 | | FIBITMAP * DLL_CALLCONV |
536 | 0 | FreeImage_Clone(FIBITMAP *dib) { |
537 | 0 | if(!dib) { |
538 | 0 | return NULL; |
539 | 0 | } |
540 | | |
541 | 0 | FREE_IMAGE_TYPE type = FreeImage_GetImageType(dib); |
542 | 0 | unsigned width = FreeImage_GetWidth(dib); |
543 | 0 | unsigned height = FreeImage_GetHeight(dib); |
544 | 0 | 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 | 0 | const BYTE *ext_bits = ((FREEIMAGEHEADER *)dib->data)->external_bits; |
548 | | |
549 | | // check for pixel availability ... |
550 | 0 | BOOL header_only = FreeImage_HasPixels(dib) ? FALSE : TRUE; |
551 | | |
552 | | // check whether this image has masks defined ... |
553 | 0 | BOOL need_masks = (bpp == 16 && type == FIT_BITMAP) ? TRUE : FALSE; |
554 | | |
555 | | // allocate a new dib |
556 | 0 | FIBITMAP *new_dib = FreeImage_AllocateHeaderT(header_only, type, width, height, bpp, |
557 | 0 | FreeImage_GetRedMask(dib), FreeImage_GetGreenMask(dib), FreeImage_GetBlueMask(dib)); |
558 | |
|
559 | 0 | if (new_dib) { |
560 | | // save ICC profile links |
561 | 0 | FIICCPROFILE *src_iccProfile = FreeImage_GetICCProfile(dib); |
562 | 0 | FIICCPROFILE *dst_iccProfile = FreeImage_GetICCProfile(new_dib); |
563 | | |
564 | | // save metadata links |
565 | 0 | METADATAMAP *src_metadata = ((FREEIMAGEHEADER *)dib->data)->metadata; |
566 | 0 | 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 | 0 | 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 | 0 | memcpy(new_dib->data, dib->data, dib_size); |
579 | | |
580 | | // reset ICC profile link for new_dib |
581 | 0 | memset(dst_iccProfile, 0, sizeof(FIICCPROFILE)); |
582 | | |
583 | | // restore metadata link for new_dib |
584 | 0 | ((FREEIMAGEHEADER *)new_dib->data)->metadata = dst_metadata; |
585 | | |
586 | | // reset thumbnail link for new_dib |
587 | 0 | ((FREEIMAGEHEADER *)new_dib->data)->thumbnail = NULL; |
588 | | |
589 | | // reset external wrapped buffer link for new_dib |
590 | 0 | ((FREEIMAGEHEADER *)new_dib->data)->external_bits = NULL; |
591 | 0 | ((FREEIMAGEHEADER *)new_dib->data)->external_pitch = 0; |
592 | | |
593 | | // copy possible ICC profile |
594 | 0 | FreeImage_CreateICCProfile(new_dib, src_iccProfile->data, src_iccProfile->size); |
595 | 0 | dst_iccProfile->flags = src_iccProfile->flags; |
596 | | |
597 | | // copy metadata models |
598 | 0 | for(METADATAMAP::iterator i = (*src_metadata).begin(); i != (*src_metadata).end(); i++) { |
599 | 0 | int model = (*i).first; |
600 | 0 | TAGMAP *src_tagmap = (*i).second; |
601 | |
|
602 | 0 | if(src_tagmap) { |
603 | | // create a metadata model |
604 | 0 | TAGMAP *dst_tagmap = new(std::nothrow) TAGMAP(); |
605 | |
|
606 | 0 | if(dst_tagmap) { |
607 | | // fill the model |
608 | 0 | for(TAGMAP::iterator j = src_tagmap->begin(); j != src_tagmap->end(); j++) { |
609 | 0 | std::string dst_key = (*j).first; |
610 | 0 | FITAG *dst_tag = FreeImage_CloneTag( (*j).second ); |
611 | | |
612 | | // assign key and tag value |
613 | 0 | (*dst_tagmap)[dst_key] = dst_tag; |
614 | 0 | } |
615 | | |
616 | | // assign model and tagmap |
617 | 0 | (*dst_metadata)[model] = dst_tagmap; |
618 | 0 | } |
619 | 0 | } |
620 | 0 | } |
621 | | |
622 | | // copy the thumbnail |
623 | 0 | FreeImage_SetThumbnail(new_dib, FreeImage_GetThumbnail(dib)); |
624 | | |
625 | | // copy user provided pixel buffer (if any) |
626 | 0 | if(ext_bits) { |
627 | 0 | const unsigned pitch = FreeImage_GetPitch(dib); |
628 | 0 | const unsigned linesize = FreeImage_GetLine(dib); |
629 | 0 | for(unsigned y = 0; y < height; y++) { |
630 | 0 | memcpy(FreeImage_GetScanLine(new_dib, y), ext_bits, linesize); |
631 | 0 | ext_bits += pitch; |
632 | 0 | } |
633 | 0 | } |
634 | |
|
635 | 0 | return new_dib; |
636 | 0 | } |
637 | | |
638 | 0 | return NULL; |
639 | 0 | } |
640 | | |
641 | | // ---------------------------------------------------------- |
642 | | |
643 | | BYTE * DLL_CALLCONV |
644 | 6.10k | FreeImage_GetBits(FIBITMAP *dib) { |
645 | 6.10k | if(!FreeImage_HasPixels(dib)) { |
646 | 0 | return NULL; |
647 | 0 | } |
648 | | |
649 | 6.10k | if(((FREEIMAGEHEADER *)dib->data)->external_bits) { |
650 | 0 | return ((FREEIMAGEHEADER *)dib->data)->external_bits; |
651 | 0 | } |
652 | | |
653 | | // returns the pixels aligned on a FIBITMAP_ALIGNMENT bytes alignment boundary |
654 | 6.10k | size_t lp = (size_t)FreeImage_GetInfoHeader(dib); |
655 | 6.10k | lp += sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * FreeImage_GetColorsUsed(dib); |
656 | 6.10k | lp += FreeImage_HasRGBMasks(dib) ? sizeof(DWORD) * 3 : 0; |
657 | 6.10k | lp += (lp % FIBITMAP_ALIGNMENT ? FIBITMAP_ALIGNMENT - lp % FIBITMAP_ALIGNMENT : 0); |
658 | 6.10k | return (BYTE *)lp; |
659 | 6.10k | } |
660 | | |
661 | | // ---------------------------------------------------------- |
662 | | // DIB information functions |
663 | | // ---------------------------------------------------------- |
664 | | |
665 | | FIBITMAP* DLL_CALLCONV |
666 | 52 | FreeImage_GetThumbnail(FIBITMAP *dib) { |
667 | 52 | return (dib != NULL) ? ((FREEIMAGEHEADER *)dib->data)->thumbnail : NULL; |
668 | 52 | } |
669 | | |
670 | | BOOL DLL_CALLCONV |
671 | 0 | FreeImage_SetThumbnail(FIBITMAP *dib, FIBITMAP *thumbnail) { |
672 | 0 | if(dib == NULL) { |
673 | 0 | return FALSE; |
674 | 0 | } |
675 | 0 | FIBITMAP *currentThumbnail = ((FREEIMAGEHEADER *)dib->data)->thumbnail; |
676 | 0 | if(currentThumbnail == thumbnail) { |
677 | 0 | return TRUE; |
678 | 0 | } |
679 | 0 | FreeImage_Unload(currentThumbnail); |
680 | |
|
681 | 0 | ((FREEIMAGEHEADER *)dib->data)->thumbnail = FreeImage_HasPixels(thumbnail) ? FreeImage_Clone(thumbnail) : NULL; |
682 | |
|
683 | 0 | return TRUE; |
684 | 0 | } |
685 | | |
686 | | // ---------------------------------------------------------- |
687 | | |
688 | | FREE_IMAGE_COLOR_TYPE DLL_CALLCONV |
689 | 7 | FreeImage_GetColorType(FIBITMAP *dib) { |
690 | 7 | RGBQUAD *rgb; |
691 | | |
692 | 7 | const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); |
693 | | |
694 | | // special bitmap type |
695 | 7 | if(image_type != FIT_BITMAP) { |
696 | 0 | switch(image_type) { |
697 | 0 | case FIT_UINT16: |
698 | 0 | { |
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 | 0 | FITAG *photometricTag = NULL; |
702 | 0 | if(FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, "PhotometricInterpretation", &photometricTag)) { |
703 | 0 | const short *value = (short*)FreeImage_GetTagValue(photometricTag); |
704 | | // PHOTOMETRIC_MINISWHITE = 0 => min value is white |
705 | | // PHOTOMETRIC_MINISBLACK = 1 => min value is black |
706 | 0 | return (*value == 0) ? FIC_MINISWHITE : FIC_MINISBLACK; |
707 | 0 | } |
708 | 0 | return FIC_MINISBLACK; |
709 | 0 | } |
710 | 0 | break; |
711 | | |
712 | 0 | case FIT_RGB16: |
713 | 0 | case FIT_RGBF: |
714 | 0 | return FIC_RGB; |
715 | | |
716 | 0 | case FIT_RGBA16: |
717 | 0 | case FIT_RGBAF: |
718 | 0 | return (((FreeImage_GetICCProfile(dib)->flags) & FIICC_COLOR_IS_CMYK) == FIICC_COLOR_IS_CMYK) ? FIC_CMYK : FIC_RGBALPHA; |
719 | 0 | } |
720 | | |
721 | 0 | return FIC_MINISBLACK; |
722 | 0 | } |
723 | | |
724 | | // standard image type |
725 | 7 | switch (FreeImage_GetBPP(dib)) { |
726 | 0 | case 1: |
727 | 0 | { |
728 | 0 | rgb = FreeImage_GetPalette(dib); |
729 | |
|
730 | 0 | if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0)) { |
731 | 0 | rgb++; |
732 | |
|
733 | 0 | if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255)) { |
734 | 0 | return FIC_MINISBLACK; |
735 | 0 | } |
736 | 0 | } |
737 | | |
738 | 0 | if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255)) { |
739 | 0 | rgb++; |
740 | |
|
741 | 0 | if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0)) { |
742 | 0 | return FIC_MINISWHITE; |
743 | 0 | } |
744 | 0 | } |
745 | | |
746 | 0 | return FIC_PALETTE; |
747 | 0 | } |
748 | | |
749 | 0 | case 4: |
750 | 0 | case 8: // Check if the DIB has a color or a greyscale palette |
751 | 0 | { |
752 | 0 | int ncolors = FreeImage_GetColorsUsed(dib); |
753 | 0 | int minisblack = 1; |
754 | 0 | rgb = FreeImage_GetPalette(dib); |
755 | |
|
756 | 0 | for (int i = 0; i < ncolors; i++) { |
757 | 0 | if ((rgb->rgbRed != rgb->rgbGreen) || (rgb->rgbRed != rgb->rgbBlue)) { |
758 | 0 | return FIC_PALETTE; |
759 | 0 | } |
760 | | |
761 | | // The DIB has a color palette if the greyscale isn't a linear ramp |
762 | | // Take care of reversed grey images |
763 | 0 | if (rgb->rgbRed != i) { |
764 | 0 | if ((ncolors-i-1) != rgb->rgbRed) { |
765 | 0 | return FIC_PALETTE; |
766 | 0 | } else { |
767 | 0 | minisblack = 0; |
768 | 0 | } |
769 | 0 | } |
770 | | |
771 | 0 | rgb++; |
772 | 0 | } |
773 | | |
774 | 0 | return minisblack ? FIC_MINISBLACK : FIC_MINISWHITE; |
775 | 0 | } |
776 | | |
777 | 0 | case 16: |
778 | 2 | case 24: |
779 | 2 | return FIC_RGB; |
780 | | |
781 | 5 | case 32: |
782 | 5 | { |
783 | 5 | if (((FreeImage_GetICCProfile(dib)->flags) & FIICC_COLOR_IS_CMYK) == FIICC_COLOR_IS_CMYK) { |
784 | 0 | return FIC_CMYK; |
785 | 0 | } |
786 | | |
787 | 5 | if( FreeImage_HasPixels(dib) ) { |
788 | | // check for fully opaque alpha layer |
789 | 131 | for (unsigned y = 0; y < FreeImage_GetHeight(dib); y++) { |
790 | 131 | rgb = (RGBQUAD *)FreeImage_GetScanLine(dib, y); |
791 | | |
792 | 257 | for (unsigned x = 0; x < FreeImage_GetWidth(dib); x++) { |
793 | 131 | if (rgb[x].rgbReserved != 0xFF) { |
794 | 5 | return FIC_RGBALPHA; |
795 | 5 | } |
796 | 131 | } |
797 | 131 | } |
798 | 0 | return FIC_RGB; |
799 | 5 | } |
800 | | |
801 | 0 | return FIC_RGBALPHA; |
802 | 5 | } |
803 | | |
804 | 0 | default : |
805 | 0 | return FIC_MINISBLACK; |
806 | 7 | } |
807 | 7 | } |
808 | | |
809 | | // ---------------------------------------------------------- |
810 | | |
811 | | FREE_IMAGE_TYPE DLL_CALLCONV |
812 | 7 | FreeImage_GetImageType(FIBITMAP *dib) { |
813 | 7 | return (dib != NULL) ? ((FREEIMAGEHEADER *)dib->data)->type : FIT_UNKNOWN; |
814 | 7 | } |
815 | | |
816 | | // ---------------------------------------------------------- |
817 | | |
818 | | BOOL DLL_CALLCONV |
819 | 12.2k | FreeImage_HasPixels(FIBITMAP *dib) { |
820 | 12.2k | return (dib != NULL) ? ((FREEIMAGEHEADER *)dib->data)->has_pixels : FALSE; |
821 | 12.2k | } |
822 | | |
823 | | // ---------------------------------------------------------- |
824 | | |
825 | | BOOL DLL_CALLCONV |
826 | 6.10k | FreeImage_HasRGBMasks(FIBITMAP *dib) { |
827 | 6.10k | return dib && FreeImage_GetInfoHeader(dib)->biCompression == BI_BITFIELDS; |
828 | 6.10k | } |
829 | | |
830 | | unsigned DLL_CALLCONV |
831 | 0 | FreeImage_GetRedMask(FIBITMAP *dib) { |
832 | 0 | FREEIMAGERGBMASKS *masks = NULL; |
833 | 0 | FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); |
834 | 0 | switch(image_type) { |
835 | 0 | case FIT_BITMAP: |
836 | | // check for 16-bit RGB (565 or 555) |
837 | 0 | masks = FreeImage_GetRGBMasks(dib); |
838 | 0 | if (masks) { |
839 | 0 | return masks->red_mask; |
840 | 0 | } |
841 | 0 | return FreeImage_GetBPP(dib) >= 24 ? FI_RGBA_RED_MASK : 0; |
842 | 0 | default: |
843 | 0 | return 0; |
844 | 0 | } |
845 | 0 | } |
846 | | |
847 | | unsigned DLL_CALLCONV |
848 | 0 | FreeImage_GetGreenMask(FIBITMAP *dib) { |
849 | 0 | FREEIMAGERGBMASKS *masks = NULL; |
850 | 0 | FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); |
851 | 0 | switch(image_type) { |
852 | 0 | case FIT_BITMAP: |
853 | | // check for 16-bit RGB (565 or 555) |
854 | 0 | masks = FreeImage_GetRGBMasks(dib); |
855 | 0 | if (masks) { |
856 | 0 | return masks->green_mask; |
857 | 0 | } |
858 | 0 | return FreeImage_GetBPP(dib) >= 24 ? FI_RGBA_GREEN_MASK : 0; |
859 | 0 | default: |
860 | 0 | return 0; |
861 | 0 | } |
862 | 0 | } |
863 | | |
864 | | unsigned DLL_CALLCONV |
865 | 0 | FreeImage_GetBlueMask(FIBITMAP *dib) { |
866 | 0 | FREEIMAGERGBMASKS *masks = NULL; |
867 | 0 | FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); |
868 | 0 | switch(image_type) { |
869 | 0 | case FIT_BITMAP: |
870 | | // check for 16-bit RGB (565 or 555) |
871 | 0 | masks = FreeImage_GetRGBMasks(dib); |
872 | 0 | if (masks) { |
873 | 0 | return masks->blue_mask; |
874 | 0 | } |
875 | 0 | return FreeImage_GetBPP(dib) >= 24 ? FI_RGBA_BLUE_MASK : 0; |
876 | 0 | default: |
877 | 0 | return 0; |
878 | 0 | } |
879 | 0 | } |
880 | | |
881 | | // ---------------------------------------------------------- |
882 | | |
883 | | BOOL DLL_CALLCONV |
884 | 0 | FreeImage_HasBackgroundColor(FIBITMAP *dib) { |
885 | 0 | if(dib) { |
886 | 0 | RGBQUAD *bkgnd_color = &((FREEIMAGEHEADER *)dib->data)->bkgnd_color; |
887 | 0 | return (bkgnd_color->rgbReserved != 0) ? TRUE : FALSE; |
888 | 0 | } |
889 | 0 | return FALSE; |
890 | 0 | } |
891 | | |
892 | | BOOL DLL_CALLCONV |
893 | 0 | FreeImage_GetBackgroundColor(FIBITMAP *dib, RGBQUAD *bkcolor) { |
894 | 0 | if(dib && bkcolor) { |
895 | 0 | if(FreeImage_HasBackgroundColor(dib)) { |
896 | | // get the background color |
897 | 0 | RGBQUAD *bkgnd_color = &((FREEIMAGEHEADER *)dib->data)->bkgnd_color; |
898 | 0 | memcpy(bkcolor, bkgnd_color, sizeof(RGBQUAD)); |
899 | | // get the background index |
900 | 0 | if(FreeImage_GetBPP(dib) == 8) { |
901 | 0 | RGBQUAD *pal = FreeImage_GetPalette(dib); |
902 | 0 | for(unsigned i = 0; i < FreeImage_GetColorsUsed(dib); i++) { |
903 | 0 | if(bkgnd_color->rgbRed == pal[i].rgbRed) { |
904 | 0 | if(bkgnd_color->rgbGreen == pal[i].rgbGreen) { |
905 | 0 | if(bkgnd_color->rgbBlue == pal[i].rgbBlue) { |
906 | 0 | bkcolor->rgbReserved = (BYTE)i; |
907 | 0 | return TRUE; |
908 | 0 | } |
909 | 0 | } |
910 | 0 | } |
911 | 0 | } |
912 | 0 | } |
913 | | |
914 | 0 | bkcolor->rgbReserved = 0; |
915 | |
|
916 | 0 | return TRUE; |
917 | 0 | } |
918 | 0 | } |
919 | | |
920 | 0 | return FALSE; |
921 | 0 | } |
922 | | |
923 | | BOOL DLL_CALLCONV |
924 | 0 | FreeImage_SetBackgroundColor(FIBITMAP *dib, RGBQUAD *bkcolor) { |
925 | 0 | if(dib) { |
926 | 0 | RGBQUAD *bkgnd_color = &((FREEIMAGEHEADER *)dib->data)->bkgnd_color; |
927 | 0 | if(bkcolor) { |
928 | | // set the background color |
929 | 0 | memcpy(bkgnd_color, bkcolor, sizeof(RGBQUAD)); |
930 | | // enable the file background color |
931 | 0 | bkgnd_color->rgbReserved = 1; |
932 | 0 | } else { |
933 | | // clear and disable the file background color |
934 | 0 | memset(bkgnd_color, 0, sizeof(RGBQUAD)); |
935 | 0 | } |
936 | 0 | return TRUE; |
937 | 0 | } |
938 | | |
939 | 0 | return FALSE; |
940 | 0 | } |
941 | | |
942 | | // ---------------------------------------------------------- |
943 | | |
944 | | BOOL DLL_CALLCONV |
945 | 0 | FreeImage_IsTransparent(FIBITMAP *dib) { |
946 | 0 | if(dib) { |
947 | 0 | FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); |
948 | 0 | switch(image_type) { |
949 | 0 | case FIT_BITMAP: |
950 | 0 | if(FreeImage_GetBPP(dib) == 32) { |
951 | 0 | if(FreeImage_GetColorType(dib) == FIC_RGBALPHA) { |
952 | 0 | return TRUE; |
953 | 0 | } |
954 | 0 | } else { |
955 | 0 | return ((FREEIMAGEHEADER *)dib->data)->transparent ? TRUE : FALSE; |
956 | 0 | } |
957 | 0 | break; |
958 | 0 | case FIT_RGBA16: |
959 | 0 | case FIT_RGBAF: |
960 | 0 | return (((FreeImage_GetICCProfile(dib)->flags) & FIICC_COLOR_IS_CMYK) == FIICC_COLOR_IS_CMYK) ? FALSE : TRUE; |
961 | 0 | default: |
962 | 0 | break; |
963 | 0 | } |
964 | 0 | } |
965 | 0 | return FALSE; |
966 | 0 | } |
967 | | |
968 | | BYTE * DLL_CALLCONV |
969 | 0 | FreeImage_GetTransparencyTable(FIBITMAP *dib) { |
970 | 0 | return dib ? ((FREEIMAGEHEADER *)dib->data)->transparent_table : NULL; |
971 | 0 | } |
972 | | |
973 | | void DLL_CALLCONV |
974 | 7 | FreeImage_SetTransparent(FIBITMAP *dib, BOOL enabled) { |
975 | 7 | if (dib) { |
976 | 7 | if ((FreeImage_GetBPP(dib) <= 8) || (FreeImage_GetBPP(dib) == 32)) { |
977 | 5 | ((FREEIMAGEHEADER *)dib->data)->transparent = enabled; |
978 | 5 | } else { |
979 | 2 | ((FREEIMAGEHEADER *)dib->data)->transparent = FALSE; |
980 | 2 | } |
981 | 7 | } |
982 | 7 | } |
983 | | |
984 | | unsigned DLL_CALLCONV |
985 | 0 | FreeImage_GetTransparencyCount(FIBITMAP *dib) { |
986 | 0 | return dib ? ((FREEIMAGEHEADER *)dib->data)->transparency_count : 0; |
987 | 0 | } |
988 | | |
989 | | void DLL_CALLCONV |
990 | 0 | FreeImage_SetTransparencyTable(FIBITMAP *dib, BYTE *table, int count) { |
991 | 0 | if (dib) { |
992 | 0 | count = MAX(0, MIN(count, 256)); |
993 | 0 | if (FreeImage_GetBPP(dib) <= 8) { |
994 | 0 | ((FREEIMAGEHEADER *)dib->data)->transparent = (count > 0) ? TRUE : FALSE; |
995 | 0 | ((FREEIMAGEHEADER *)dib->data)->transparency_count = count; |
996 | |
|
997 | 0 | if (table) { |
998 | 0 | memcpy(((FREEIMAGEHEADER *)dib->data)->transparent_table, table, count); |
999 | 0 | } else { |
1000 | 0 | memset(((FREEIMAGEHEADER *)dib->data)->transparent_table, 0xff, count); |
1001 | 0 | } |
1002 | 0 | } |
1003 | 0 | } |
1004 | 0 | } |
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 |
1027 | 0 | FreeImage_SetTransparentIndex(FIBITMAP *dib, int index) { |
1028 | 0 | if (dib) { |
1029 | 0 | int count = FreeImage_GetColorsUsed(dib); |
1030 | 0 | if (count) { |
1031 | 0 | BYTE *new_tt = (BYTE *)malloc(count * sizeof(BYTE)); |
1032 | 0 | memset(new_tt, 0xFF, count); |
1033 | 0 | if ((index >= 0) && (index < count)) { |
1034 | 0 | new_tt[index] = 0x00; |
1035 | 0 | } |
1036 | 0 | FreeImage_SetTransparencyTable(dib, new_tt, count); |
1037 | 0 | free(new_tt); |
1038 | 0 | } |
1039 | 0 | } |
1040 | 0 | } |
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 |
1056 | 0 | FreeImage_GetTransparentIndex(FIBITMAP *dib) { |
1057 | 0 | int count = FreeImage_GetTransparencyCount(dib); |
1058 | 0 | BYTE *tt = FreeImage_GetTransparencyTable(dib); |
1059 | 0 | for (int i = 0; i < count; i++) { |
1060 | 0 | if (tt[i] == 0) { |
1061 | 0 | return i; |
1062 | 0 | } |
1063 | 0 | } |
1064 | 0 | return -1; |
1065 | 0 | } |
1066 | | |
1067 | | // ---------------------------------------------------------- |
1068 | | |
1069 | | FIICCPROFILE * DLL_CALLCONV |
1070 | 109 | FreeImage_GetICCProfile(FIBITMAP *dib) { |
1071 | 109 | FIICCPROFILE *profile = (dib) ? (FIICCPROFILE *)&((FREEIMAGEHEADER *)dib->data)->iccProfile : NULL; |
1072 | 109 | return profile; |
1073 | 109 | } |
1074 | | |
1075 | | FIICCPROFILE * DLL_CALLCONV |
1076 | 0 | FreeImage_CreateICCProfile(FIBITMAP *dib, void *data, long size) { |
1077 | | // clear the profile but preserve profile->flags |
1078 | 0 | FreeImage_DestroyICCProfile(dib); |
1079 | | // create the new profile |
1080 | 0 | FIICCPROFILE *profile = FreeImage_GetICCProfile(dib); |
1081 | 0 | if(size && profile) { |
1082 | 0 | profile->data = malloc(size); |
1083 | 0 | if(profile->data) { |
1084 | 0 | memcpy(profile->data, data, profile->size = size); |
1085 | 0 | } |
1086 | 0 | } |
1087 | 0 | return profile; |
1088 | 0 | } |
1089 | | |
1090 | | void DLL_CALLCONV |
1091 | 0 | FreeImage_DestroyICCProfile(FIBITMAP *dib) { |
1092 | 0 | FIICCPROFILE *profile = FreeImage_GetICCProfile(dib); |
1093 | 0 | if(profile) { |
1094 | 0 | if (profile->data) { |
1095 | 0 | free (profile->data); |
1096 | 0 | } |
1097 | | // clear the profile but preserve profile->flags |
1098 | 0 | profile->data = NULL; |
1099 | 0 | profile->size = 0; |
1100 | 0 | } |
1101 | | |
1102 | | // destroy also Exif-Main ICC profile |
1103 | 0 | FreeImage_SetMetadata(FIMD_EXIF_MAIN, dib, "InterColorProfile", NULL); |
1104 | 0 | } |
1105 | | |
1106 | | // ---------------------------------------------------------- |
1107 | | |
1108 | | unsigned DLL_CALLCONV |
1109 | 6.35k | FreeImage_GetWidth(FIBITMAP *dib) { |
1110 | 6.35k | return dib ? FreeImage_GetInfoHeader(dib)->biWidth : 0; |
1111 | 6.35k | } |
1112 | | |
1113 | | unsigned DLL_CALLCONV |
1114 | 131 | FreeImage_GetHeight(FIBITMAP *dib) { |
1115 | 131 | return (dib) ? FreeImage_GetInfoHeader(dib)->biHeight : 0; |
1116 | 131 | } |
1117 | | |
1118 | | unsigned DLL_CALLCONV |
1119 | 6.18k | FreeImage_GetBPP(FIBITMAP *dib) { |
1120 | 6.18k | return dib ? FreeImage_GetInfoHeader(dib)->biBitCount : 0; |
1121 | 6.18k | } |
1122 | | |
1123 | | unsigned DLL_CALLCONV |
1124 | 6.09k | FreeImage_GetLine(FIBITMAP *dib) { |
1125 | 6.09k | return dib ? ((FreeImage_GetWidth(dib) * FreeImage_GetBPP(dib)) + 7) / 8 : 0; |
1126 | 6.09k | } |
1127 | | |
1128 | | unsigned DLL_CALLCONV |
1129 | 6.09k | FreeImage_GetPitch(FIBITMAP *dib) { |
1130 | 6.09k | if(dib) { |
1131 | 6.09k | FREEIMAGEHEADER *fih = (FREEIMAGEHEADER *)dib->data; |
1132 | 6.09k | return fih->external_bits ? fih->external_pitch : (FreeImage_GetLine(dib) + 3 & ~3); |
1133 | 6.09k | } |
1134 | 0 | return 0; |
1135 | 6.09k | } |
1136 | | |
1137 | | unsigned DLL_CALLCONV |
1138 | 6.10k | FreeImage_GetColorsUsed(FIBITMAP *dib) { |
1139 | 6.10k | return dib ? FreeImage_GetInfoHeader(dib)->biClrUsed : 0; |
1140 | 6.10k | } |
1141 | | |
1142 | | unsigned DLL_CALLCONV |
1143 | 0 | FreeImage_GetDIBSize(FIBITMAP *dib) { |
1144 | 0 | return (dib) ? sizeof(BITMAPINFOHEADER) + (FreeImage_GetColorsUsed(dib) * sizeof(RGBQUAD)) + (FreeImage_GetPitch(dib) * FreeImage_GetHeight(dib)) : 0; |
1145 | 0 | } |
1146 | | |
1147 | | RGBQUAD * DLL_CALLCONV |
1148 | 64 | FreeImage_GetPalette(FIBITMAP *dib) { |
1149 | 64 | return (dib && FreeImage_GetBPP(dib) < 16) ? (RGBQUAD *)(((BYTE *)FreeImage_GetInfoHeader(dib)) + sizeof(BITMAPINFOHEADER)) : NULL; |
1150 | 64 | } |
1151 | | |
1152 | | unsigned DLL_CALLCONV |
1153 | 0 | FreeImage_GetDotsPerMeterX(FIBITMAP *dib) { |
1154 | 0 | return (dib) ? FreeImage_GetInfoHeader(dib)->biXPelsPerMeter : 0; |
1155 | 0 | } |
1156 | | |
1157 | | unsigned DLL_CALLCONV |
1158 | 0 | FreeImage_GetDotsPerMeterY(FIBITMAP *dib) { |
1159 | 0 | return (dib) ? FreeImage_GetInfoHeader(dib)->biYPelsPerMeter : 0; |
1160 | 0 | } |
1161 | | |
1162 | | void DLL_CALLCONV |
1163 | 52 | FreeImage_SetDotsPerMeterX(FIBITMAP *dib, unsigned res) { |
1164 | 52 | if(dib) { |
1165 | 52 | FreeImage_GetInfoHeader(dib)->biXPelsPerMeter = res; |
1166 | 52 | } |
1167 | 52 | } |
1168 | | |
1169 | | void DLL_CALLCONV |
1170 | 52 | FreeImage_SetDotsPerMeterY(FIBITMAP *dib, unsigned res) { |
1171 | 52 | if(dib) { |
1172 | 52 | FreeImage_GetInfoHeader(dib)->biYPelsPerMeter = res; |
1173 | 52 | } |
1174 | 52 | } |
1175 | | |
1176 | | BITMAPINFOHEADER * DLL_CALLCONV |
1177 | 31.1k | FreeImage_GetInfoHeader(FIBITMAP *dib) { |
1178 | 31.1k | if(!dib) { |
1179 | 0 | return NULL; |
1180 | 0 | } |
1181 | 31.1k | size_t lp = (size_t)dib->data + sizeof(FREEIMAGEHEADER); |
1182 | 31.1k | lp += (lp % FIBITMAP_ALIGNMENT ? FIBITMAP_ALIGNMENT - lp % FIBITMAP_ALIGNMENT : 0); |
1183 | 31.1k | lp += FIBITMAP_ALIGNMENT - sizeof(BITMAPINFOHEADER) % FIBITMAP_ALIGNMENT; |
1184 | 31.1k | return (BITMAPINFOHEADER *)lp; |
1185 | 31.1k | } |
1186 | | |
1187 | | BITMAPINFO * DLL_CALLCONV |
1188 | 0 | FreeImage_GetInfo(FIBITMAP *dib) { |
1189 | 0 | return (BITMAPINFO *)FreeImage_GetInfoHeader(dib); |
1190 | 0 | } |
1191 | | |
1192 | | // ---------------------------------------------------------- |
1193 | | // Metadata routines |
1194 | | // ---------------------------------------------------------- |
1195 | | |
1196 | | FIMETADATA * DLL_CALLCONV |
1197 | 0 | FreeImage_FindFirstMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, FITAG **tag) { |
1198 | 0 | if(!dib) { |
1199 | 0 | return NULL; |
1200 | 0 | } |
1201 | | |
1202 | | // get the metadata model |
1203 | 0 | METADATAMAP *metadata = ((FREEIMAGEHEADER *)dib->data)->metadata; |
1204 | 0 | TAGMAP *tagmap = NULL; |
1205 | 0 | if( (*metadata).find(model) != (*metadata).end() ) { |
1206 | 0 | tagmap = (*metadata)[model]; |
1207 | 0 | } |
1208 | 0 | if(tagmap) { |
1209 | | // allocate a handle |
1210 | 0 | FIMETADATA *handle = (FIMETADATA *)malloc(sizeof(FIMETADATA)); |
1211 | 0 | if(handle) { |
1212 | | // calculate the size of a METADATAHEADER |
1213 | 0 | const size_t header_size = sizeof(METADATAHEADER); |
1214 | |
|
1215 | 0 | handle->data = (BYTE *)malloc(header_size); |
1216 | | |
1217 | 0 | if(handle->data) { |
1218 | 0 | memset(handle->data, 0, header_size); |
1219 | | |
1220 | | // write out the METADATAHEADER |
1221 | 0 | METADATAHEADER *mdh = (METADATAHEADER *)handle->data; |
1222 | |
|
1223 | 0 | mdh->pos = 1; |
1224 | 0 | mdh->tagmap = tagmap; |
1225 | | |
1226 | | // get the first element |
1227 | 0 | TAGMAP::iterator i = tagmap->begin(); |
1228 | 0 | *tag = (*i).second; |
1229 | |
|
1230 | 0 | return handle; |
1231 | 0 | } |
1232 | | |
1233 | 0 | free(handle); |
1234 | 0 | } |
1235 | 0 | } |
1236 | | |
1237 | 0 | return NULL; |
1238 | 0 | } |
1239 | | |
1240 | | BOOL DLL_CALLCONV |
1241 | 0 | FreeImage_FindNextMetadata(FIMETADATA *mdhandle, FITAG **tag) { |
1242 | 0 | if(!mdhandle) { |
1243 | 0 | return FALSE; |
1244 | 0 | } |
1245 | | |
1246 | 0 | METADATAHEADER *mdh = (METADATAHEADER *)mdhandle->data; |
1247 | 0 | TAGMAP *tagmap = mdh->tagmap; |
1248 | |
|
1249 | 0 | int current_pos = mdh->pos; |
1250 | 0 | int mapsize = (int)tagmap->size(); |
1251 | |
|
1252 | 0 | if(current_pos < mapsize) { |
1253 | | // get the tag element at position pos |
1254 | 0 | int count = 0; |
1255 | |
|
1256 | 0 | for(TAGMAP::iterator i = tagmap->begin(); i != tagmap->end(); i++) { |
1257 | 0 | if(count == current_pos) { |
1258 | 0 | *tag = (*i).second; |
1259 | 0 | mdh->pos++; |
1260 | 0 | break; |
1261 | 0 | } |
1262 | 0 | count++; |
1263 | 0 | } |
1264 | | |
1265 | 0 | return TRUE; |
1266 | 0 | } |
1267 | | |
1268 | 0 | return FALSE; |
1269 | 0 | } |
1270 | | |
1271 | | void DLL_CALLCONV |
1272 | 0 | FreeImage_FindCloseMetadata(FIMETADATA *mdhandle) { |
1273 | 0 | if (NULL != mdhandle) { // delete the handle |
1274 | 0 | if (NULL != mdhandle->data) { |
1275 | 0 | free(mdhandle->data); |
1276 | 0 | } |
1277 | 0 | free(mdhandle); // ... and the wrapper |
1278 | 0 | } |
1279 | 0 | } |
1280 | | |
1281 | | |
1282 | | // ---------------------------------------------------------- |
1283 | | |
1284 | | BOOL DLL_CALLCONV |
1285 | 0 | FreeImage_CloneMetadata(FIBITMAP *dst, FIBITMAP *src) { |
1286 | 0 | if(!src || !dst) { |
1287 | 0 | return FALSE; |
1288 | 0 | } |
1289 | | |
1290 | | // get metadata links |
1291 | 0 | METADATAMAP *src_metadata = ((FREEIMAGEHEADER *)src->data)->metadata; |
1292 | 0 | METADATAMAP *dst_metadata = ((FREEIMAGEHEADER *)dst->data)->metadata; |
1293 | | |
1294 | | // copy metadata models, *except* the FIMD_ANIMATION model |
1295 | 0 | for(METADATAMAP::iterator i = (*src_metadata).begin(); i != (*src_metadata).end(); i++) { |
1296 | 0 | int model = (*i).first; |
1297 | 0 | if(model == (int)FIMD_ANIMATION) { |
1298 | 0 | continue; |
1299 | 0 | } |
1300 | 0 | TAGMAP *src_tagmap = (*i).second; |
1301 | |
|
1302 | 0 | if(src_tagmap) { |
1303 | 0 | if( dst_metadata->find(model) != dst_metadata->end() ) { |
1304 | | // destroy dst model |
1305 | 0 | FreeImage_SetMetadata((FREE_IMAGE_MDMODEL)model, dst, NULL, NULL); |
1306 | 0 | } |
1307 | | |
1308 | | // create a metadata model |
1309 | 0 | TAGMAP *dst_tagmap = new(std::nothrow) TAGMAP(); |
1310 | |
|
1311 | 0 | if(dst_tagmap) { |
1312 | | // fill the model |
1313 | 0 | for(TAGMAP::iterator j = src_tagmap->begin(); j != src_tagmap->end(); j++) { |
1314 | 0 | std::string dst_key = (*j).first; |
1315 | 0 | FITAG *dst_tag = FreeImage_CloneTag( (*j).second ); |
1316 | | |
1317 | | // assign key and tag value |
1318 | 0 | (*dst_tagmap)[dst_key] = dst_tag; |
1319 | 0 | } |
1320 | | |
1321 | | // assign model and tagmap |
1322 | 0 | (*dst_metadata)[model] = dst_tagmap; |
1323 | 0 | } |
1324 | 0 | } |
1325 | 0 | } |
1326 | | |
1327 | | // clone resolution |
1328 | 0 | FreeImage_SetDotsPerMeterX(dst, FreeImage_GetDotsPerMeterX(src)); |
1329 | 0 | FreeImage_SetDotsPerMeterY(dst, FreeImage_GetDotsPerMeterY(src)); |
1330 | |
|
1331 | 0 | return TRUE; |
1332 | 0 | } |
1333 | | |
1334 | | // ---------------------------------------------------------- |
1335 | | |
1336 | | BOOL DLL_CALLCONV |
1337 | 0 | FreeImage_SetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, FITAG *tag) { |
1338 | 0 | if(!dib) { |
1339 | 0 | return FALSE; |
1340 | 0 | } |
1341 | | |
1342 | 0 | TAGMAP *tagmap = NULL; |
1343 | | |
1344 | | // get the metadata model |
1345 | 0 | METADATAMAP *metadata = ((FREEIMAGEHEADER *)dib->data)->metadata; |
1346 | 0 | METADATAMAP::iterator model_iterator = metadata->find(model); |
1347 | 0 | if (model_iterator != metadata->end()) { |
1348 | 0 | tagmap = model_iterator->second; |
1349 | 0 | } |
1350 | |
|
1351 | 0 | if(key != NULL) { |
1352 | |
|
1353 | 0 | if ((tag == NULL) && !tagmap) { |
1354 | | // remove a tag from an unknown tagmap, nothing to do |
1355 | 0 | return TRUE; |
1356 | 0 | } |
1357 | | |
1358 | 0 | if(!tagmap) { |
1359 | | // this model, doesn't exist: create it |
1360 | 0 | tagmap = new(std::nothrow) TAGMAP(); |
1361 | 0 | (*metadata)[model] = tagmap; |
1362 | 0 | } |
1363 | | |
1364 | 0 | if(tag) { |
1365 | | // first check the tag |
1366 | 0 | if(FreeImage_GetTagKey(tag) == NULL) { |
1367 | 0 | FreeImage_SetTagKey(tag, key); |
1368 | 0 | } else if(strcmp(key, FreeImage_GetTagKey(tag)) != 0) { |
1369 | | // set the tag key |
1370 | 0 | FreeImage_SetTagKey(tag, key); |
1371 | 0 | } |
1372 | 0 | if(FreeImage_GetTagCount(tag) * FreeImage_TagDataWidth(FreeImage_GetTagType(tag)) != FreeImage_GetTagLength(tag)) { |
1373 | 0 | FreeImage_OutputMessageProc(FIF_UNKNOWN, "Invalid data count for tag '%s'", key); |
1374 | 0 | return FALSE; |
1375 | 0 | } |
1376 | | |
1377 | | // fill the tag ID if possible and if it's needed |
1378 | 0 | TagLib& tag_lib = TagLib::instance(); |
1379 | 0 | switch(model) { |
1380 | 0 | case FIMD_IPTC: |
1381 | 0 | { |
1382 | 0 | 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 | 0 | FreeImage_SetTagID(tag, (WORD)id); |
1389 | 0 | } |
1390 | 0 | break; |
1391 | | |
1392 | 0 | default: |
1393 | 0 | break; |
1394 | 0 | } |
1395 | | |
1396 | | // delete existing tag |
1397 | 0 | FITAG *old_tag = (*tagmap)[key]; |
1398 | 0 | if(old_tag) { |
1399 | 0 | FreeImage_DeleteTag(old_tag); |
1400 | 0 | } |
1401 | | |
1402 | | // create a new tag |
1403 | 0 | (*tagmap)[key] = FreeImage_CloneTag(tag); |
1404 | 0 | } |
1405 | 0 | else { |
1406 | | // delete existing tag |
1407 | 0 | TAGMAP::iterator i = tagmap->find(key); |
1408 | 0 | if(i != tagmap->end()) { |
1409 | 0 | FITAG *old_tag = (*i).second; |
1410 | 0 | FreeImage_DeleteTag(old_tag); |
1411 | 0 | tagmap->erase(key); |
1412 | 0 | } |
1413 | 0 | } |
1414 | 0 | } |
1415 | 0 | else { |
1416 | | // destroy the metadata model |
1417 | 0 | if(tagmap) { |
1418 | 0 | for(TAGMAP::iterator i = tagmap->begin(); i != tagmap->end(); i++) { |
1419 | 0 | FITAG *tag = (*i).second; |
1420 | 0 | FreeImage_DeleteTag(tag); |
1421 | 0 | } |
1422 | |
|
1423 | 0 | delete tagmap; |
1424 | 0 | metadata->erase(model_iterator); |
1425 | 0 | } |
1426 | 0 | } |
1427 | | |
1428 | 0 | return TRUE; |
1429 | 0 | } |
1430 | | |
1431 | | BOOL DLL_CALLCONV |
1432 | 0 | FreeImage_GetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, FITAG **tag) { |
1433 | 0 | if(!dib || !key || !tag) { |
1434 | 0 | return FALSE; |
1435 | 0 | } |
1436 | | |
1437 | 0 | TAGMAP *tagmap = NULL; |
1438 | 0 | *tag = NULL; |
1439 | | |
1440 | | // get the metadata model |
1441 | 0 | METADATAMAP *metadata = ((FREEIMAGEHEADER *)dib->data)->metadata; |
1442 | 0 | if(!(*metadata).empty()) { |
1443 | 0 | METADATAMAP::iterator model_iterator = metadata->find(model); |
1444 | 0 | if (model_iterator != metadata->end() ) { |
1445 | | // this model exists : try to get the requested tag |
1446 | 0 | tagmap = model_iterator->second; |
1447 | 0 | TAGMAP::iterator tag_iterator = tagmap->find(key); |
1448 | 0 | if (tag_iterator != tagmap->end() ) { |
1449 | | // get the requested tag |
1450 | 0 | *tag = tag_iterator->second; |
1451 | 0 | } |
1452 | 0 | } |
1453 | 0 | } |
1454 | |
|
1455 | 0 | return (*tag != NULL) ? TRUE : FALSE; |
1456 | 0 | } |
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 |
1467 | 0 | FreeImage_SetMetadataKeyValue(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, const char *value) { |
1468 | 0 | if(!dib || !key || !value) { |
1469 | 0 | return FALSE; |
1470 | 0 | } |
1471 | | // create a tag |
1472 | 0 | FITAG *tag = FreeImage_CreateTag(); |
1473 | 0 | if(tag) { |
1474 | 0 | BOOL bSuccess = TRUE; |
1475 | | // fill the tag |
1476 | 0 | DWORD tag_length = (DWORD)(strlen(value) + 1); |
1477 | 0 | bSuccess &= FreeImage_SetTagKey(tag, key); |
1478 | 0 | bSuccess &= FreeImage_SetTagLength(tag, tag_length); |
1479 | 0 | bSuccess &= FreeImage_SetTagCount(tag, tag_length); |
1480 | 0 | bSuccess &= FreeImage_SetTagType(tag, FIDT_ASCII); |
1481 | 0 | bSuccess &= FreeImage_SetTagValue(tag, value); |
1482 | 0 | if(bSuccess) { |
1483 | | // set the tag |
1484 | 0 | bSuccess &= FreeImage_SetMetadata(model, dib, FreeImage_GetTagKey(tag), tag); |
1485 | 0 | } |
1486 | | // delete the tag |
1487 | 0 | FreeImage_DeleteTag(tag); |
1488 | |
|
1489 | 0 | return bSuccess; |
1490 | 0 | } |
1491 | | |
1492 | 0 | return FALSE; |
1493 | 0 | } |
1494 | | |
1495 | | // ---------------------------------------------------------- |
1496 | | |
1497 | | unsigned DLL_CALLCONV |
1498 | 0 | FreeImage_GetMetadataCount(FREE_IMAGE_MDMODEL model, FIBITMAP *dib) { |
1499 | 0 | if(!dib) { |
1500 | 0 | return FALSE; |
1501 | 0 | } |
1502 | | |
1503 | 0 | TAGMAP *tagmap = NULL; |
1504 | | |
1505 | | // get the metadata model |
1506 | 0 | METADATAMAP *metadata = ((FREEIMAGEHEADER *)dib->data)->metadata; |
1507 | 0 | if( (*metadata).find(model) != (*metadata).end() ) { |
1508 | 0 | tagmap = (*metadata)[model]; |
1509 | 0 | } |
1510 | 0 | if(!tagmap) { |
1511 | | // this model, doesn't exist: return |
1512 | 0 | return 0; |
1513 | 0 | } |
1514 | | |
1515 | | // get the tag count |
1516 | 0 | return (unsigned)tagmap->size(); |
1517 | 0 | } |
1518 | | |
1519 | | // ---------------------------------------------------------- |
1520 | | |
1521 | | unsigned DLL_CALLCONV |
1522 | 0 | FreeImage_GetMemorySize(FIBITMAP *dib) { |
1523 | 0 | if (!dib) { |
1524 | 0 | return 0; |
1525 | 0 | } |
1526 | 0 | FREEIMAGEHEADER *header = (FREEIMAGEHEADER *)dib->data; |
1527 | 0 | BITMAPINFOHEADER *bih = FreeImage_GetInfoHeader(dib); |
1528 | |
|
1529 | 0 | BOOL header_only = !header->has_pixels || header->external_bits != NULL; |
1530 | 0 | BOOL need_masks = bih->biCompression == BI_BITFIELDS; |
1531 | 0 | unsigned width = bih->biWidth; |
1532 | 0 | unsigned height = bih->biHeight; |
1533 | 0 | unsigned bpp = bih->biBitCount; |
1534 | | |
1535 | | // start off with the size of the FIBITMAP structure |
1536 | 0 | size_t size = sizeof(FIBITMAP); |
1537 | | |
1538 | | // add sizes of FREEIMAGEHEADER, BITMAPINFOHEADER, palette and DIB data |
1539 | 0 | size += FreeImage_GetInternalImageSize(header_only, width, height, bpp, need_masks); |
1540 | | |
1541 | | // add ICC profile size |
1542 | 0 | size += header->iccProfile.size; |
1543 | | |
1544 | | // add thumbnail image size |
1545 | 0 | 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 | 0 | size += FreeImage_GetMemorySize(header->thumbnail); |
1549 | 0 | } |
1550 | | |
1551 | | // add metadata size |
1552 | 0 | METADATAMAP *md = header->metadata; |
1553 | 0 | if (!md) { |
1554 | 0 | return (unsigned)size; |
1555 | 0 | } |
1556 | | |
1557 | | // add size of METADATAMAP |
1558 | 0 | size += sizeof(METADATAMAP); |
1559 | |
|
1560 | 0 | const size_t models = md->size(); |
1561 | 0 | if (models == 0) { |
1562 | 0 | return (unsigned)size; |
1563 | 0 | } |
1564 | | |
1565 | 0 | unsigned tags = 0; |
1566 | |
|
1567 | 0 | for (METADATAMAP::iterator i = md->begin(); i != md->end(); i++) { |
1568 | 0 | TAGMAP *tm = i->second; |
1569 | 0 | if (tm) { |
1570 | 0 | for (TAGMAP::iterator j = tm->begin(); j != tm->end(); j++) { |
1571 | 0 | ++tags; |
1572 | 0 | const std::string & key = j->first; |
1573 | 0 | size += key.capacity(); |
1574 | 0 | size += FreeImage_GetTagMemorySize(j->second); |
1575 | 0 | } |
1576 | 0 | } |
1577 | 0 | } |
1578 | | |
1579 | | // add size of all TAGMAP instances |
1580 | 0 | size += models * sizeof(TAGMAP); |
1581 | | // add size of tree nodes in METADATAMAP |
1582 | 0 | size += MapIntrospector<METADATAMAP>::GetNodesMemorySize(models); |
1583 | | // add size of tree nodes in TAGMAP |
1584 | 0 | size += MapIntrospector<TAGMAP>::GetNodesMemorySize(tags); |
1585 | |
|
1586 | 0 | return (unsigned)size; |
1587 | 0 | } |
1588 | | |