Coverage Report

Created: 2025-06-24 07:02

/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