diff options
author | Kirill Volinsky <mataes2007@gmail.com> | 2015-05-18 07:31:16 +0000 |
---|---|---|
committer | Kirill Volinsky <mataes2007@gmail.com> | 2015-05-18 07:31:16 +0000 |
commit | 76b86227951fdb5096572c36a256f07aee76def3 (patch) | |
tree | 713dcf30179d88b685605bdc8a03a5068832e4ff /plugins/AdvaImg/src/FreeImage/BitmapAccess.cpp | |
parent | 4b289716d4cdd6b3ea29aec8d50e0b69afdc8384 (diff) |
git-svn-id: http://svn.miranda-ng.org/main/trunk@13671 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/AdvaImg/src/FreeImage/BitmapAccess.cpp')
-rw-r--r-- | plugins/AdvaImg/src/FreeImage/BitmapAccess.cpp | 427 |
1 files changed, 347 insertions, 80 deletions
diff --git a/plugins/AdvaImg/src/FreeImage/BitmapAccess.cpp b/plugins/AdvaImg/src/FreeImage/BitmapAccess.cpp index 2ba5539d4c..347ad1f3e5 100644 --- a/plugins/AdvaImg/src/FreeImage/BitmapAccess.cpp +++ b/plugins/AdvaImg/src/FreeImage/BitmapAccess.cpp @@ -36,10 +36,18 @@ #include "FreeImage.h" #include "FreeImageIO.h" #include "Utilities.h" +#include "MapIntrospector.h" #include "../Metadata/FreeImageTag.h" -/** Constants for the BITMAPINFOHEADER::biCompression field */ +/** +Constants for the BITMAPINFOHEADER::biCompression field +BI_RGB: +The bitmap is in uncompressed red green blue (RGB) format that is not compressed and does not use color masks. +BI_BITFIELDS: +The bitmap is not compressed and the color table consists of three DWORD color masks that specify the red, green, and blue components, +respectively, of each pixel. This is valid when used with 16 and 32-bits per pixel bitmaps. +*/ #ifndef _WINGDI_ #define BI_RGB 0L #define BI_BITFIELDS 3L @@ -49,38 +57,66 @@ // Metadata definitions // ---------------------------------------------------------- -// helper for map<key, value> where value is a pointer to a FreeImage tag +/** helper for map<key, value> where value is a pointer to a FreeImage tag */ typedef std::map<std::string, FITAG*> TAGMAP; -// helper for map<FREE_IMAGE_MDMODEL, TAGMAP*> +/** helper for map<FREE_IMAGE_MDMODEL, TAGMAP*> */ typedef std::map<int, TAGMAP*> METADATAMAP; -// helper for metadata iterator +/** helper for metadata iterator */ FI_STRUCT (METADATAHEADER) { - long pos; // current position when iterating the map - TAGMAP *tagmap; // pointer to the tag map + long pos; //! current position when iterating the map + TAGMAP *tagmap; //! pointer to the tag map }; // ---------------------------------------------------------- // FIBITMAP definition // ---------------------------------------------------------- +/** +FreeImage header structure +*/ FI_STRUCT (FREEIMAGEHEADER) { - FREE_IMAGE_TYPE type; // data type - bitmap, array of long, double, complex, etc + /** data type - bitmap, array of long, double, complex, etc */ + FREE_IMAGE_TYPE type; + + /** background color used for RGB transparency */ + RGBQUAD bkgnd_color; + + /**@name transparency management */ + //@{ + /** + why another table ? for easy transparency table retrieval ! + transparency could be stored in the palette, which is better + overall, but it requires quite some changes and it will render + FreeImage_GetTransparencyTable obsolete in its current form; + */ + BYTE transparent_table[256]; + /** number of transparent colors */ + int transparency_count; + /** TRUE if the image is transparent */ + BOOL transparent; + //@} - RGBQUAD bkgnd_color; // background color used for RGB transparency + /** space to hold ICC profile */ + FIICCPROFILE iccProfile; - BOOL transparent; // why another table? for easy transparency table retrieval! - int transparency_count; // transparency could be stored in the palette, which is better - BYTE transparent_table[256];// overall, but it requires quite some changes and it will render - // FreeImage_GetTransparencyTable obsolete in its current form; - FIICCPROFILE iccProfile; // space to hold ICC profile + /** contains a list of metadata models attached to the bitmap */ + METADATAMAP *metadata; - METADATAMAP *metadata; // contains a list of metadata models attached to the bitmap + /** FALSE if the FIBITMAP only contains the header and no pixel data */ + BOOL has_pixels; - BOOL has_pixels; // FALSE if the FIBITMAP only contains the header and no pixel data + /** optionally contains a thumbnail attached to the bitmap */ + FIBITMAP *thumbnail; - FIBITMAP *thumbnail; // optionally contains a thumbnail attached to the bitmap + /**@name external pixel buffer management */ + //@{ + /** pointer to user provided pixels, NULL otherwise */ + BYTE *external_bits; + /** user provided pitch, 0 otherwise */ + unsigned external_pitch; + //@} //BYTE filler[1]; // fill to 32-bit alignment }; @@ -89,10 +125,13 @@ FI_STRUCT (FREEIMAGEHEADER) { // FREEIMAGERGBMASKS definition // ---------------------------------------------------------- +/** +RGB mask structure - mainly used for 16-bit RGB555 / RGB 565 FIBITMAP +*/ FI_STRUCT (FREEIMAGERGBMASKS) { - unsigned red_mask; // bit layout of the red components - unsigned green_mask; // bit layout of the green components - unsigned blue_mask; // bit layout of the blue components + unsigned red_mask; //! bit layout of the red components + unsigned green_mask; //! bit layout of the green components + unsigned blue_mask; //! bit layout of the blue components }; // ---------------------------------------------------------- @@ -155,40 +194,50 @@ void FreeImage_Aligned_Free(void* mem) { #endif // _WIN32 || _WIN64 // ---------------------------------------------------------- -// DIB information functions +// FIBITMAP memory management // ---------------------------------------------------------- /** Calculate the size of a FreeImage image. Align the palette and the pixels on a FIBITMAP_ALIGNMENT bytes alignment boundary. +This function includes a protection against malicious images, based on a KISS integer overflow detection mechanism. @param header_only If TRUE, calculate a 'header only' FIBITMAP size, otherwise calculate a full FIBITMAP size -@param width -@param height -@param bpp -@param need_masks -@see FreeImage_AllocateHeaderT +@param width Image width +@param height Image height +@param bpp Number of bits-per-pixel +@param need_masks We only store the masks (and allocate memory for them) for 16-bit images of type FIT_BITMAP +@return Returns a size in BYTE units +@see FreeImage_AllocateBitmap */ static size_t -FreeImage_GetImageSizeHeader(BOOL header_only, unsigned width, unsigned height, unsigned bpp, BOOL need_masks) { - size_t dib_size = sizeof(FREEIMAGEHEADER); - dib_size += (dib_size % FIBITMAP_ALIGNMENT ? FIBITMAP_ALIGNMENT - dib_size % FIBITMAP_ALIGNMENT : 0); - dib_size += FIBITMAP_ALIGNMENT - sizeof(BITMAPINFOHEADER) % FIBITMAP_ALIGNMENT; - dib_size += sizeof(BITMAPINFOHEADER); +FreeImage_GetInternalImageSize(BOOL header_only, unsigned width, unsigned height, unsigned bpp, BOOL need_masks) { + size_t dib_size = sizeof(FREEIMAGEHEADER); + dib_size += (dib_size % FIBITMAP_ALIGNMENT ? FIBITMAP_ALIGNMENT - dib_size % FIBITMAP_ALIGNMENT : 0); + dib_size += FIBITMAP_ALIGNMENT - sizeof(BITMAPINFOHEADER) % FIBITMAP_ALIGNMENT; + dib_size += sizeof(BITMAPINFOHEADER); // palette is aligned on a 16 bytes boundary dib_size += sizeof(RGBQUAD) * CalculateUsedPaletteEntries(bpp); // we both add palette size and masks size if need_masks is true, since CalculateUsedPaletteEntries // always returns 0 if need_masks is true (which is only true for 16 bit images). dib_size += need_masks ? sizeof(DWORD) * 3 : 0; - dib_size += (dib_size % FIBITMAP_ALIGNMENT ? FIBITMAP_ALIGNMENT - dib_size % FIBITMAP_ALIGNMENT : 0); + dib_size += (dib_size % FIBITMAP_ALIGNMENT ? FIBITMAP_ALIGNMENT - dib_size % FIBITMAP_ALIGNMENT : 0); + if(!header_only) { const size_t header_size = dib_size; // pixels are aligned on a 16 bytes boundary - dib_size += (size_t)CalculatePitch(CalculateLine(width, bpp)) * (size_t)height; + dib_size += (size_t)CalculatePitch(CalculateLine(width, bpp)) * (size_t)height; // check for possible malloc overflow using a KISS integer overflow detection mechanism { + const double dPitch = floor( ((double)bpp * width + 31.0) / 32.0 ) * 4.0; + const double dImageSize = (double)header_size + dPitch * height; + if(dImageSize != (double)dib_size) { + // here, we are sure to encounter a malloc overflow: try to avoid it ... + return 0; + } + /* The following constant take into account the additionnal memory used by aligned malloc functions as well as debug malloc functions. @@ -196,12 +245,7 @@ FreeImage_GetImageSizeHeader(BOOL header_only, unsigned width, unsigned height, for the target compiler. */ const double FIBITMAP_MAX_MEMORY = (double)((size_t)-1) - 8 * FIBITMAP_ALIGNMENT; - const double dPitch = floor( ((double)bpp * width + 31.0) / 32.0 ) * 4.0; - const double dImageSize = (double)header_size + dPitch * height; - if(dImageSize != (double)dib_size) { - // here, we are sure to encounter a malloc overflow: try to avoid it ... - return 0; - } + if(dImageSize > FIBITMAP_MAX_MEMORY) { // avoid possible overflow inside C allocation functions return 0; @@ -224,8 +268,33 @@ FreeImage_GetRGBMasks(FIBITMAP *dib) { return FreeImage_HasRGBMasks(dib) ? (FREEIMAGERGBMASKS *)(((BYTE *)FreeImage_GetInfoHeader(dib)) + sizeof(BITMAPINFOHEADER)) : NULL; } -FIBITMAP * DLL_CALLCONV -FreeImage_AllocateHeaderT(BOOL header_only, FREE_IMAGE_TYPE type, int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) { +/** +Internal FIBITMAP allocation. + +This function accepts (ext_bits, ext_pitch) arguments. If these are provided the FIBITMAP +will be allocated as "header only", but bits and pitch will be stored within the FREEIMAGEHEADER +and the resulting FIBITMAP will have pixels, i.e. HasPixels() will return TRUE. +- GetBits() and GetPitch return the correct values - either offsets or the stored values (user-provided bits and pitch). +- Clone() creates a new FIBITMAP with copy of the user pixel data. +- Unload's implementation does not need to change - it just release a "header only" dib. +Note that when using external data, the data does not need to have the same alignment as the default 4-byte alignment. +This enables the possibility to access buffers with, for instance, stricter alignment, +like the ones used in low-level APIs like OpenCL or intrinsics. + +@param header_only If TRUE, allocate a 'header only' FIBITMAP, otherwise allocate a full FIBITMAP +@param ext_bits Pointer to external user's pixel buffer if using wrapped buffer, NULL otherwise +@param ext_pitch Pointer to external user's pixel buffer pitch if using wrapped buffer, 0 otherwise +@param type Image type +@param width Image width +@param height Image height +@param bpp Number of bits per pixel +@param red_mask Image red mask +@param green_mask Image green mask +@param blue_mask Image blue mask +@return Returns the allocated FIBITMAP if successful, returns NULL otherwise +*/ +static FIBITMAP * +FreeImage_AllocateBitmap(BOOL header_only, BYTE *ext_bits, unsigned ext_pitch, FREE_IMAGE_TYPE type, int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) { // check input variables width = abs(width); @@ -233,6 +302,12 @@ FreeImage_AllocateHeaderT(BOOL header_only, FREE_IMAGE_TYPE type, int width, int if(!((width > 0) && (height > 0))) { return NULL; } + if(ext_bits) { + if(ext_pitch == 0) { + return NULL; + } + assert(header_only == FALSE); + } // we only store the masks (and allocate memory for them) for 16-bit images of type FIT_BITMAP BOOL need_masks = FALSE; @@ -302,7 +377,9 @@ FreeImage_AllocateHeaderT(BOOL header_only, FREE_IMAGE_TYPE type, int width, int // palette is aligned on a 16 bytes boundary // pixels are aligned on a 16 bytes boundary - size_t dib_size = FreeImage_GetImageSizeHeader(header_only, width, height, bpp, need_masks); + // when using a user provided pixel buffer, force a 'header only' allocation + + size_t dib_size = FreeImage_GetInternalImageSize(header_only || ext_bits, width, height, bpp, need_masks); if(dib_size == 0) { // memory allocation will fail (probably a malloc overflow) @@ -317,12 +394,13 @@ FreeImage_AllocateHeaderT(BOOL header_only, FREE_IMAGE_TYPE type, int width, int // write out the FREEIMAGEHEADER - FREEIMAGEHEADER *fih = (FREEIMAGEHEADER *)bitmap->data; - fih->type = type; + FREEIMAGEHEADER *fih = (FREEIMAGEHEADER *)bitmap->data; + + fih->type = type; memset(&fih->bkgnd_color, 0, sizeof(RGBQUAD)); - fih->transparent = FALSE; + fih->transparent = FALSE; fih->transparency_count = 0; memset(fih->transparent_table, 0xff, 256); @@ -331,9 +409,9 @@ FreeImage_AllocateHeaderT(BOOL header_only, FREE_IMAGE_TYPE type, int width, int // initialize FIICCPROFILE link FIICCPROFILE *iccProfile = FreeImage_GetICCProfile(bitmap); - iccProfile->size = 0; - iccProfile->data = 0; - iccProfile->flags = 0; + iccProfile->size = 0; + iccProfile->data = 0; + iccProfile->flags = 0; // initialize metadata models list @@ -343,6 +421,11 @@ FreeImage_AllocateHeaderT(BOOL header_only, FREE_IMAGE_TYPE type, int width, int fih->thumbnail = NULL; + // store a pointer to user provided pixel buffer (if any) + + fih->external_bits = ext_bits; + fih->external_pitch = ext_pitch; + // write out the BITMAPINFOHEADER BITMAPINFOHEADER *bih = FreeImage_GetInfoHeader(bitmap); @@ -385,18 +468,28 @@ FreeImage_AllocateHeaderT(BOOL header_only, FREE_IMAGE_TYPE type, int width, int } FIBITMAP * DLL_CALLCONV +FreeImage_AllocateHeaderForBits(BYTE *ext_bits, unsigned ext_pitch, FREE_IMAGE_TYPE type, int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) { + return FreeImage_AllocateBitmap(FALSE, ext_bits, ext_pitch, type, width, height, bpp, red_mask, green_mask, blue_mask); +} + +FIBITMAP * DLL_CALLCONV +FreeImage_AllocateHeaderT(BOOL header_only, FREE_IMAGE_TYPE type, int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) { + return FreeImage_AllocateBitmap(header_only, NULL, 0, type, width, height, bpp, red_mask, green_mask, blue_mask); +} + +FIBITMAP * DLL_CALLCONV FreeImage_AllocateHeader(BOOL header_only, int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) { - return FreeImage_AllocateHeaderT(header_only, FIT_BITMAP, width, height, bpp, red_mask, green_mask, blue_mask); + return FreeImage_AllocateBitmap(header_only, NULL, 0, FIT_BITMAP, width, height, bpp, red_mask, green_mask, blue_mask); } FIBITMAP * DLL_CALLCONV FreeImage_Allocate(int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) { - return FreeImage_AllocateHeaderT(FALSE, FIT_BITMAP, width, height, bpp, red_mask, green_mask, blue_mask); + return FreeImage_AllocateBitmap(FALSE, NULL, 0, FIT_BITMAP, width, height, bpp, red_mask, green_mask, blue_mask); } FIBITMAP * DLL_CALLCONV FreeImage_AllocateT(FREE_IMAGE_TYPE type, int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) { - return FreeImage_AllocateHeaderT(FALSE, type, width, height, bpp, red_mask, green_mask, blue_mask); + return FreeImage_AllocateBitmap(FALSE, NULL, 0, type, width, height, bpp, red_mask, green_mask, blue_mask); } void DLL_CALLCONV @@ -404,8 +497,9 @@ FreeImage_Unload(FIBITMAP *dib) { if (NULL != dib) { if (NULL != dib->data) { // delete possible icc profile ... - if (FreeImage_GetICCProfile(dib)->data) + if (FreeImage_GetICCProfile(dib)->data) { free(FreeImage_GetICCProfile(dib)->data); + } // delete metadata models METADATAMAP *metadata = ((FREEIMAGEHEADER *)dib->data)->metadata; @@ -431,6 +525,7 @@ FreeImage_Unload(FIBITMAP *dib) { // delete bitmap ... FreeImage_Aligned_Free(dib->data); } + free(dib); // ... and the wrapper } } @@ -439,17 +534,22 @@ FreeImage_Unload(FIBITMAP *dib) { FIBITMAP * DLL_CALLCONV FreeImage_Clone(FIBITMAP *dib) { - if(!dib) return NULL; + if(!dib) { + return NULL; + } FREE_IMAGE_TYPE type = FreeImage_GetImageType(dib); - unsigned width = FreeImage_GetWidth(dib); - unsigned height = FreeImage_GetHeight(dib); - unsigned bpp = FreeImage_GetBPP(dib); + unsigned width = FreeImage_GetWidth(dib); + unsigned height = FreeImage_GetHeight(dib); + unsigned bpp = FreeImage_GetBPP(dib); + + const BYTE *ext_bits = ((FREEIMAGEHEADER *)dib->data)->external_bits; // check for pixel availability ... BOOL header_only = FreeImage_HasPixels(dib) ? FALSE : TRUE; + // check whether this image has masks defined ... - BOOL need_masks = (bpp == 16 && type == FIT_BITMAP) ? TRUE : FALSE; + BOOL need_masks = (bpp == 16 && type == FIT_BITMAP) ? TRUE : FALSE; // allocate a new dib FIBITMAP *new_dib = FreeImage_AllocateHeaderT(header_only, type, width, height, bpp, @@ -464,12 +564,14 @@ FreeImage_Clone(FIBITMAP *dib) { METADATAMAP *src_metadata = ((FREEIMAGEHEADER *)dib->data)->metadata; METADATAMAP *dst_metadata = ((FREEIMAGEHEADER *)new_dib->data)->metadata; - // calculate the size of a FreeImage image + // calculate the size of the src image // align the palette and the pixels on a FIBITMAP_ALIGNMENT bytes alignment boundary // palette is aligned on a 16 bytes boundary // pixels are aligned on a 16 bytes boundary + + // when using a user provided pixel buffer, force a 'header only' calculation - size_t dib_size = FreeImage_GetImageSizeHeader(header_only, width, height, bpp, need_masks); + size_t dib_size = FreeImage_GetInternalImageSize(header_only || ext_bits, width, height, bpp, need_masks); // copy the bitmap + internal pointers (remember to restore new_dib internal pointers later) memcpy(new_dib->data, dib->data, dib_size); @@ -515,6 +617,16 @@ FreeImage_Clone(FIBITMAP *dib) { // copy the thumbnail FreeImage_SetThumbnail(new_dib, FreeImage_GetThumbnail(dib)); + // copy user provided pixel buffer (if any) + if(ext_bits) { + const unsigned pitch = FreeImage_GetPitch(dib); + const unsigned linesize = FreeImage_GetLine(dib); + for(unsigned y = 0; y < height; y++) { + memcpy(FreeImage_GetScanLine(new_dib, y), ext_bits, linesize); + ext_bits += pitch; + } + } + return new_dib; } @@ -523,6 +635,28 @@ FreeImage_Clone(FIBITMAP *dib) { // ---------------------------------------------------------- +BYTE * DLL_CALLCONV +FreeImage_GetBits(FIBITMAP *dib) { + if(!FreeImage_HasPixels(dib)) { + return NULL; + } + + if(((FREEIMAGEHEADER *)dib->data)->external_bits) { + return ((FREEIMAGEHEADER *)dib->data)->external_bits; + } + + // returns the pixels aligned on a FIBITMAP_ALIGNMENT bytes alignment boundary + size_t lp = (size_t)FreeImage_GetInfoHeader(dib); + lp += sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * FreeImage_GetColorsUsed(dib); + lp += FreeImage_HasRGBMasks(dib) ? sizeof(DWORD) * 3 : 0; + lp += (lp % FIBITMAP_ALIGNMENT ? FIBITMAP_ALIGNMENT - lp % FIBITMAP_ALIGNMENT : 0); + return (BYTE *)lp; +} + +// ---------------------------------------------------------- +// DIB information functions +// ---------------------------------------------------------- + FIBITMAP* DLL_CALLCONV FreeImage_GetThumbnail(FIBITMAP *dib) { return (dib != NULL) ? ((FREEIMAGEHEADER *)dib->data)->thumbnail : NULL; @@ -589,15 +723,17 @@ FreeImage_GetColorType(FIBITMAP *dib) { if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0)) { rgb++; - if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255)) - return FIC_MINISBLACK; + if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255)) { + return FIC_MINISBLACK; + } } if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255)) { rgb++; - if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0)) - return FIC_MINISWHITE; + if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0)) { + return FIC_MINISWHITE; + } } return FIC_PALETTE; @@ -611,16 +747,18 @@ FreeImage_GetColorType(FIBITMAP *dib) { rgb = FreeImage_GetPalette(dib); for (int i = 0; i < ncolors; i++) { - if ((rgb->rgbRed != rgb->rgbGreen) || (rgb->rgbRed != rgb->rgbBlue)) + if ((rgb->rgbRed != rgb->rgbGreen) || (rgb->rgbRed != rgb->rgbBlue)) { return FIC_PALETTE; + } // The DIB has a color palette if the greyscale isn't a linear ramp // Take care of reversed grey images if (rgb->rgbRed != i) { - if ((ncolors-i-1) != rgb->rgbRed) + if ((ncolors-i-1) != rgb->rgbRed) { return FIC_PALETTE; - else + } else { minisblack = 0; + } } rgb++; @@ -635,17 +773,20 @@ FreeImage_GetColorType(FIBITMAP *dib) { case 32: { - if (FreeImage_GetICCProfile(dib)->flags & FIICC_COLOR_IS_CMYK) + if (FreeImage_GetICCProfile(dib)->flags & FIICC_COLOR_IS_CMYK) { return FIC_CMYK; + } if( FreeImage_HasPixels(dib) ) { // check for fully opaque alpha layer for (unsigned y = 0; y < FreeImage_GetHeight(dib); y++) { rgb = (RGBQUAD *)FreeImage_GetScanLine(dib, y); - for (unsigned x = 0; x < FreeImage_GetWidth(dib); x++) - if (rgb[x].rgbReserved != 0xFF) - return FIC_RGBALPHA; + for (unsigned x = 0; x < FreeImage_GetWidth(dib); x++) { + if (rgb[x].rgbReserved != 0xFF) { + return FIC_RGBALPHA; + } + } } return FIC_RGB; } @@ -687,7 +828,10 @@ FreeImage_GetRedMask(FIBITMAP *dib) { case FIT_BITMAP: // check for 16-bit RGB (565 or 555) masks = FreeImage_GetRGBMasks(dib); - return masks ? masks->red_mask : FI_RGBA_RED_MASK; + if (masks) { + return masks->red_mask; + } + return FreeImage_GetBPP(dib) >= 24 ? FI_RGBA_RED_MASK : 0; default: return 0; } @@ -701,7 +845,10 @@ FreeImage_GetGreenMask(FIBITMAP *dib) { case FIT_BITMAP: // check for 16-bit RGB (565 or 555) masks = FreeImage_GetRGBMasks(dib); - return masks ? masks->green_mask : FI_RGBA_GREEN_MASK; + if (masks) { + return masks->green_mask; + } + return FreeImage_GetBPP(dib) >= 24 ? FI_RGBA_GREEN_MASK : 0; default: return 0; } @@ -715,7 +862,10 @@ FreeImage_GetBlueMask(FIBITMAP *dib) { case FIT_BITMAP: // check for 16-bit RGB (565 or 555) masks = FreeImage_GetRGBMasks(dib); - return masks ? masks->blue_mask : FI_RGBA_BLUE_MASK; + if (masks) { + return masks->blue_mask; + } + return FreeImage_GetBPP(dib) >= 24 ? FI_RGBA_BLUE_MASK : 0; default: return 0; } @@ -967,7 +1117,11 @@ FreeImage_GetLine(FIBITMAP *dib) { unsigned DLL_CALLCONV FreeImage_GetPitch(FIBITMAP *dib) { - return dib ? FreeImage_GetLine(dib) + 3 & ~3 : 0; + if(dib) { + FREEIMAGEHEADER *fih = (FREEIMAGEHEADER *)dib->data; + return fih->external_bits ? fih->external_pitch : (FreeImage_GetLine(dib) + 3 & ~3); + } + return 0; } unsigned DLL_CALLCONV @@ -1011,7 +1165,9 @@ FreeImage_SetDotsPerMeterY(FIBITMAP *dib, unsigned res) { BITMAPINFOHEADER * DLL_CALLCONV FreeImage_GetInfoHeader(FIBITMAP *dib) { - if(!dib) return NULL; + if(!dib) { + return NULL; + } size_t lp = (size_t)dib->data + sizeof(FREEIMAGEHEADER); lp += (lp % FIBITMAP_ALIGNMENT ? FIBITMAP_ALIGNMENT - lp % FIBITMAP_ALIGNMENT : 0); lp += FIBITMAP_ALIGNMENT - sizeof(BITMAPINFOHEADER) % FIBITMAP_ALIGNMENT; @@ -1029,8 +1185,9 @@ FreeImage_GetInfo(FIBITMAP *dib) { FIMETADATA * DLL_CALLCONV FreeImage_FindFirstMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, FITAG **tag) { - if(!dib) + if(!dib) { return NULL; + } // get the metadata model METADATAMAP *metadata = ((FREEIMAGEHEADER *)dib->data)->metadata; @@ -1072,8 +1229,9 @@ FreeImage_FindFirstMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, FITAG **tag BOOL DLL_CALLCONV FreeImage_FindNextMetadata(FIMETADATA *mdhandle, FITAG **tag) { - if(!mdhandle) + if(!mdhandle) { return FALSE; + } METADATAHEADER *mdh = (METADATAHEADER *)mdhandle->data; TAGMAP *tagmap = mdh->tagmap; @@ -1115,7 +1273,9 @@ FreeImage_FindCloseMetadata(FIMETADATA *mdhandle) { BOOL DLL_CALLCONV FreeImage_CloneMetadata(FIBITMAP *dst, FIBITMAP *src) { - if(!src || !dst) return FALSE; + if(!src || !dst) { + return FALSE; + } // get metadata links METADATAMAP *src_metadata = ((FREEIMAGEHEADER *)src->data)->metadata; @@ -1165,8 +1325,9 @@ FreeImage_CloneMetadata(FIBITMAP *dst, FIBITMAP *src) { BOOL DLL_CALLCONV FreeImage_SetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, FITAG *tag) { - if(!dib) + if(!dib) { return FALSE; + } TAGMAP *tagmap = NULL; @@ -1254,8 +1415,9 @@ FreeImage_SetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, BOOL DLL_CALLCONV FreeImage_GetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, FITAG **tag) { - if(!dib || !key || !tag) + if(!dib || !key || !tag) { return FALSE; + } TAGMAP *tagmap = NULL; *tag = NULL; @@ -1278,12 +1440,50 @@ FreeImage_GetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, return (*tag != NULL) ? TRUE : FALSE; } +/** +Build and set a FITAG whose type is FIDT_ASCII. +@param model Metadata model to be filled +@param dib Image to be filled +@param key Tag key +@param value Tag value as a ASCII string +@return Returns TRUE if successful, returns FALSE otherwise +*/ +BOOL DLL_CALLCONV +FreeImage_SetMetadataKeyValue(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, const char *value) { + if(!dib || !key || !value) { + return FALSE; + } + // create a tag + FITAG *tag = FreeImage_CreateTag(); + if(tag) { + BOOL bSuccess = TRUE; + // fill the tag + DWORD tag_length = (DWORD)(strlen(value) + 1); + bSuccess &= FreeImage_SetTagKey(tag, key); + bSuccess &= FreeImage_SetTagLength(tag, tag_length); + bSuccess &= FreeImage_SetTagCount(tag, tag_length); + bSuccess &= FreeImage_SetTagType(tag, FIDT_ASCII); + bSuccess &= FreeImage_SetTagValue(tag, value); + if(bSuccess) { + // set the tag + bSuccess &= FreeImage_SetMetadata(model, dib, FreeImage_GetTagKey(tag), tag); + } + // delete the tag + FreeImage_DeleteTag(tag); + + return bSuccess; + } + + return FALSE; +} + // ---------------------------------------------------------- unsigned DLL_CALLCONV FreeImage_GetMetadataCount(FREE_IMAGE_MDMODEL model, FIBITMAP *dib) { - if(!dib) + if(!dib) { return FALSE; + } TAGMAP *tagmap = NULL; @@ -1303,4 +1503,71 @@ FreeImage_GetMetadataCount(FREE_IMAGE_MDMODEL model, FIBITMAP *dib) { // ---------------------------------------------------------- +unsigned DLL_CALLCONV +FreeImage_GetMemorySize(FIBITMAP *dib) { + if (!dib) { + return 0; + } + FREEIMAGEHEADER *header = (FREEIMAGEHEADER *)dib->data; + BITMAPINFOHEADER *bih = FreeImage_GetInfoHeader(dib); + + BOOL header_only = !header->has_pixels || header->external_bits != NULL; + BOOL need_masks = bih->biCompression == BI_BITFIELDS; + unsigned width = bih->biWidth; + unsigned height = bih->biHeight; + unsigned bpp = bih->biBitCount; + + // start off with the size of the FIBITMAP structure + size_t size = sizeof(FIBITMAP); + + // add sizes of FREEIMAGEHEADER, BITMAPINFOHEADER, palette and DIB data + size += FreeImage_GetInternalImageSize(header_only, width, height, bpp, need_masks); + + // add ICC profile size + size += header->iccProfile.size; + + // add thumbnail image size + if (header->thumbnail) { + // we assume a thumbnail not having a thumbnail as well, + // so this recursive call should not create an infinite loop + size += FreeImage_GetMemorySize(header->thumbnail); + } + + // add metadata size + METADATAMAP *md = header->metadata; + if (!md) { + return (unsigned)size; + } + + // add size of METADATAMAP + size += sizeof(METADATAMAP); + + const size_t models = md->size(); + if (models == 0) { + return (unsigned)size; + } + + unsigned tags = 0; + + for (METADATAMAP::iterator i = md->begin(); i != md->end(); i++) { + TAGMAP *tm = i->second; + if (tm) { + for (TAGMAP::iterator j = tm->begin(); j != tm->end(); j++) { + ++tags; + const std::string & key = j->first; + size += key.capacity(); + size += FreeImage_GetTagMemorySize(j->second); + } + } + } + + // add size of all TAGMAP instances + size += models * sizeof(TAGMAP); + // add size of tree nodes in METADATAMAP + size += MapIntrospector<METADATAMAP>::GetNodesMemorySize(models); + // add size of tree nodes in TAGMAP + size += MapIntrospector<TAGMAP>::GetNodesMemorySize(tags); + + return (unsigned)size; +} |