diff options
Diffstat (limited to 'plugins/AdvaImg/src/FreeImage')
28 files changed, 1801 insertions, 738 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; +} diff --git a/plugins/AdvaImg/src/FreeImage/ColorLookup.cpp b/plugins/AdvaImg/src/FreeImage/ColorLookup.cpp index 5f677eee5c..0f4435a725 100644 --- a/plugins/AdvaImg/src/FreeImage/ColorLookup.cpp +++ b/plugins/AdvaImg/src/FreeImage/ColorLookup.cpp @@ -26,10 +26,10 @@ // RGB color names --------------------------------------------------------- typedef struct tagNamedColor { - const char *name; // color name - BYTE r; // red value - BYTE g; // green value - BYTE b; // blue value + const char *name; //! color name + BYTE r; //! red value + BYTE g; //! green value + BYTE b; //! blue value } NamedColor; // -------------------------------------------------------------------------- @@ -43,20 +43,21 @@ Helper function : perform a binary search on a color array */ static int binsearch(const char *name, const NamedColor *color_array, int n) { - int cond, low, mid, high; + int cond, low, mid, high; low = 0; high = n - 1; while (low <= high) { - mid = (low + high) / 2; - if ((cond = strcmp(name, color_array[mid].name)) < 0) - high = mid - 1; - else if (cond > 0) - low = mid + 1; - else - return mid; - } - return -1; + mid = (low + high) / 2; + if ((cond = strcmp(name, color_array[mid].name)) < 0) { + high = mid - 1; + } else if (cond > 0) { + low = mid + 1; + } else { + return mid; + } + } + return -1; } /** @@ -68,22 +69,24 @@ Perform a binary search on a color array */ static int FreeImage_LookupNamedColor(const char *szColor, const NamedColor *color_array, int ncolors) { - int i; + int i; char color[64]; // make lower case name, squezze white space for (i = 0; szColor[i] && i < sizeof(color) - 1; i++) { - if (isspace(szColor[i])) + if (isspace(szColor[i])) { continue; - if (isupper(szColor[i])) - color[i] = (char)tolower(szColor[i]); - else + } + if (isupper(szColor[i])) { + color[i] = (char)tolower(szColor[i]); + } else { color[i] = szColor[i]; + } } color[i] = 0; - return (binsearch(color, color_array, ncolors)); + return binsearch(color, color_array, ncolors); } // ========================================================== @@ -595,153 +598,153 @@ FreeImage_LookupX11Color(const char *szColor, BYTE *nRed, BYTE *nGreen, BYTE *nB the final recommendation for changes) */ static NamedColor SVGColorMap[] = { - { "aliceblue", 240, 248, 255 }, - { "antiquewhite", 250, 235, 215 }, - { "aqua", 0, 255, 255 }, - { "aquamarine", 127, 255, 212 }, - { "azure", 240, 255, 255 }, - { "beige", 245, 245, 220 }, - { "bisque", 255, 228, 196 }, - { "black", 0, 0, 0 }, - { "blanchedalmond", 255, 235, 205 }, - { "blue", 0, 0, 255 }, - { "blueviolet", 138, 43, 226 }, - { "brown", 165, 42, 42 }, - { "burlywood", 222, 184, 135 }, - { "cadetblue", 95, 158, 160 }, - { "chartreuse", 127, 255, 0 }, - { "chocolate", 210, 105, 30 }, - { "coral", 255, 127, 80 }, - { "cornflowerblue", 100, 149, 237 }, - { "cornsilk", 255, 248, 220 }, - { "crimson", 220, 20, 60 }, - { "cyan", 0, 255, 255 }, - { "darkblue", 0, 0, 139 }, - { "darkcyan", 0, 139, 139 }, - { "darkgoldenrod", 184, 134, 11 }, - { "darkgray", 169, 169, 169 }, - { "darkgreen", 0, 100, 0 }, - { "darkgrey", 169, 169, 169 }, - { "darkkhaki", 189, 183, 107 }, - { "darkmagenta", 139, 0, 139 }, - { "darkolivegreen", 85, 107, 47 }, - { "darkorange", 255, 140, 0 }, - { "darkorchid", 153, 50, 204 }, - { "darkred", 139, 0, 0 }, - { "darksalmon", 233, 150, 122 }, - { "darkseagreen", 143, 188, 143 }, - { "darkslateblue", 72, 61, 139 }, - { "darkslategray", 47, 79, 79 }, - { "darkslategrey", 47, 79, 79 }, - { "darkturquoise", 0, 206, 209 }, - { "darkviolet", 148, 0, 211 }, - { "deeppink", 255, 20, 147 }, - { "deepskyblue", 0, 191, 255 }, - { "dimgray", 105, 105, 105 }, - { "dimgrey", 105, 105, 105 }, - { "dodgerblue", 30, 144, 255 }, - { "firebrick", 178, 34, 34 }, - { "floralwhite", 255, 250, 240 }, - { "forestgreen", 34, 139, 34 }, - { "fuchsia", 255, 0, 255 }, - { "gainsboro", 220, 220, 220 }, - { "ghostwhite", 248, 248, 255 }, - { "gold", 255, 215, 0 }, - { "goldenrod", 218, 165, 32 }, - { "gray", 128, 128, 128 }, - { "grey", 128, 128, 128 }, - { "green", 0, 128, 0 }, - { "greenyellow", 173, 255, 47 }, - { "honeydew", 240, 255, 240 }, - { "hotpink", 255, 105, 180 }, - { "indianred", 205, 92, 92 }, - { "indigo", 75, 0, 130 }, - { "ivory", 255, 255, 240 }, - { "khaki", 240, 230, 140 }, - { "lavender", 230, 230, 250 }, - { "lavenderblush", 255, 240, 245 }, - { "lawngreen", 124, 252, 0 }, - { "lemonchiffon", 255, 250, 205 }, - { "lightblue", 173, 216, 230 }, - { "lightcoral", 240, 128, 128 }, - { "lightcyan", 224, 255, 255 }, - { "lightgoldenrodyellow", 250, 250, 210 }, - { "lightgray", 211, 211, 211 }, - { "lightgreen", 144, 238, 144 }, - { "lightgrey", 211, 211, 211 }, - { "lightpink", 255, 182, 193 }, - { "lightsalmon", 255, 160, 122 }, - { "lightseagreen", 32, 178, 170 }, - { "lightskyblue", 135, 206, 250 }, - { "lightslategray", 119, 136, 153 }, - { "lightslategrey", 119, 136, 153 }, - { "lightsteelblue", 176, 196, 222 }, - { "lightyellow", 255, 255, 224 }, - { "lime", 0, 255, 0 }, - { "limegreen", 50, 205, 50 }, - { "linen", 250, 240, 230 }, - { "magenta", 255, 0, 255 }, - { "maroon", 128, 0, 0 }, - { "mediumaquamarine", 102, 205, 170 }, - { "mediumblue", 0, 0, 205 }, - { "mediumorchid", 186, 85, 211 }, - { "mediumpurple", 147, 112, 219 }, - { "mediumseagreen", 60, 179, 113 }, - { "mediumslateblue", 123, 104, 238 }, - { "mediumspringgreen", 0, 250, 154 }, - { "mediumturquoise", 72, 209, 204 }, - { "mediumvioletred", 199, 21, 133 }, - { "midnightblue", 25, 25, 112 }, - { "mintcream", 245, 255, 250 }, - { "mistyrose", 255, 228, 225 }, - { "moccasin", 255, 228, 181 }, - { "navajowhite", 255, 222, 173 }, - { "navy", 0, 0, 128 }, - { "oldlace", 253, 245, 230 }, - { "olive", 128, 128, 0 }, - { "olivedrab", 107, 142, 35 }, - { "orange", 255, 165, 0 }, - { "orangered", 255, 69, 0 }, - { "orchid", 218, 112, 214 }, - { "palegoldenrod", 238, 232, 170 }, - { "palegreen", 152, 251, 152 }, - { "paleturquoise", 175, 238, 238 }, - { "palevioletred", 219, 112, 147 }, - { "papayawhip", 255, 239, 213 }, - { "peachpuff", 255, 218, 185 }, - { "peru", 205, 133, 63 }, - { "pink", 255, 192, 203 }, - { "plum", 221, 160, 221 }, - { "powderblue", 176, 224, 230 }, - { "purple", 128, 0, 128 }, - { "red", 255, 0, 0 }, - { "rosybrown", 188, 143, 143 }, - { "royalblue", 65, 105, 225 }, - { "saddlebrown", 139, 69, 19 }, - { "salmon", 250, 128, 114 }, - { "sandybrown", 244, 164, 96 }, - { "seagreen", 46, 139, 87 }, - { "seashell", 255, 245, 238 }, - { "sienna", 160, 82, 45 }, - { "silver", 192, 192, 192 }, - { "skyblue", 135, 206, 235 }, - { "slateblue", 106, 90, 205 }, - { "slategray", 112, 128, 144 }, - { "slategrey", 112, 128, 144 }, - { "snow", 255, 250, 250 }, - { "springgreen", 0, 255, 127 }, - { "steelblue", 70, 130, 180 }, - { "tan", 210, 180, 140 }, - { "teal", 0, 128, 128 }, - { "thistle", 216, 191, 216 }, - { "tomato", 255, 99, 71 }, - { "turquoise", 64, 224, 208 }, - { "violet", 238, 130, 238 }, - { "wheat", 245, 222, 179 }, - { "white", 255, 255, 255 }, - { "whitesmoke", 245, 245, 245 }, - { "yellow", 255, 255, 0 }, - { "yellowgreen", 154, 205, 50 } + { "aliceblue", 240, 248, 255 }, + { "antiquewhite", 250, 235, 215 }, + { "aqua", 0, 255, 255 }, + { "aquamarine", 127, 255, 212 }, + { "azure", 240, 255, 255 }, + { "beige", 245, 245, 220 }, + { "bisque", 255, 228, 196 }, + { "black", 0, 0, 0 }, + { "blanchedalmond", 255, 235, 205 }, + { "blue", 0, 0, 255 }, + { "blueviolet", 138, 43, 226 }, + { "brown", 165, 42, 42 }, + { "burlywood", 222, 184, 135 }, + { "cadetblue", 95, 158, 160 }, + { "chartreuse", 127, 255, 0 }, + { "chocolate", 210, 105, 30 }, + { "coral", 255, 127, 80 }, + { "cornflowerblue", 100, 149, 237 }, + { "cornsilk", 255, 248, 220 }, + { "crimson", 220, 20, 60 }, + { "cyan", 0, 255, 255 }, + { "darkblue", 0, 0, 139 }, + { "darkcyan", 0, 139, 139 }, + { "darkgoldenrod", 184, 134, 11 }, + { "darkgray", 169, 169, 169 }, + { "darkgreen", 0, 100, 0 }, + { "darkgrey", 169, 169, 169 }, + { "darkkhaki", 189, 183, 107 }, + { "darkmagenta", 139, 0, 139 }, + { "darkolivegreen", 85, 107, 47 }, + { "darkorange", 255, 140, 0 }, + { "darkorchid", 153, 50, 204 }, + { "darkred", 139, 0, 0 }, + { "darksalmon", 233, 150, 122 }, + { "darkseagreen", 143, 188, 143 }, + { "darkslateblue", 72, 61, 139 }, + { "darkslategray", 47, 79, 79 }, + { "darkslategrey", 47, 79, 79 }, + { "darkturquoise", 0, 206, 209 }, + { "darkviolet", 148, 0, 211 }, + { "deeppink", 255, 20, 147 }, + { "deepskyblue", 0, 191, 255 }, + { "dimgray", 105, 105, 105 }, + { "dimgrey", 105, 105, 105 }, + { "dodgerblue", 30, 144, 255 }, + { "firebrick", 178, 34, 34 }, + { "floralwhite", 255, 250, 240 }, + { "forestgreen", 34, 139, 34 }, + { "fuchsia", 255, 0, 255 }, + { "gainsboro", 220, 220, 220 }, + { "ghostwhite", 248, 248, 255 }, + { "gold", 255, 215, 0 }, + { "goldenrod", 218, 165, 32 }, + { "gray", 128, 128, 128 }, + { "green", 0, 128, 0 }, + { "greenyellow", 173, 255, 47 }, + { "grey", 128, 128, 128 }, + { "honeydew", 240, 255, 240 }, + { "hotpink", 255, 105, 180 }, + { "indianred", 205, 92, 92 }, + { "indigo", 75, 0, 130 }, + { "ivory", 255, 255, 240 }, + { "khaki", 240, 230, 140 }, + { "lavender", 230, 230, 250 }, + { "lavenderblush", 255, 240, 245 }, + { "lawngreen", 124, 252, 0 }, + { "lemonchiffon", 255, 250, 205 }, + { "lightblue", 173, 216, 230 }, + { "lightcoral", 240, 128, 128 }, + { "lightcyan", 224, 255, 255 }, + { "lightgoldenrodyellow", 250, 250, 210 }, + { "lightgray", 211, 211, 211 }, + { "lightgreen", 144, 238, 144 }, + { "lightgrey", 211, 211, 211 }, + { "lightpink", 255, 182, 193 }, + { "lightsalmon", 255, 160, 122 }, + { "lightseagreen", 32, 178, 170 }, + { "lightskyblue", 135, 206, 250 }, + { "lightslategray", 119, 136, 153 }, + { "lightslategrey", 119, 136, 153 }, + { "lightsteelblue", 176, 196, 222 }, + { "lightyellow", 255, 255, 224 }, + { "lime", 0, 255, 0 }, + { "limegreen", 50, 205, 50 }, + { "linen", 250, 240, 230 }, + { "magenta", 255, 0, 255 }, + { "maroon", 128, 0, 0 }, + { "mediumaquamarine", 102, 205, 170 }, + { "mediumblue", 0, 0, 205 }, + { "mediumorchid", 186, 85, 211 }, + { "mediumpurple", 147, 112, 219 }, + { "mediumseagreen", 60, 179, 113 }, + { "mediumslateblue", 123, 104, 238 }, + { "mediumspringgreen", 0, 250, 154 }, + { "mediumturquoise", 72, 209, 204 }, + { "mediumvioletred", 199, 21, 133 }, + { "midnightblue", 25, 25, 112 }, + { "mintcream", 245, 255, 250 }, + { "mistyrose", 255, 228, 225 }, + { "moccasin", 255, 228, 181 }, + { "navajowhite", 255, 222, 173 }, + { "navy", 0, 0, 128 }, + { "oldlace", 253, 245, 230 }, + { "olive", 128, 128, 0 }, + { "olivedrab", 107, 142, 35 }, + { "orange", 255, 165, 0 }, + { "orangered", 255, 69, 0 }, + { "orchid", 218, 112, 214 }, + { "palegoldenrod", 238, 232, 170 }, + { "palegreen", 152, 251, 152 }, + { "paleturquoise", 175, 238, 238 }, + { "palevioletred", 219, 112, 147 }, + { "papayawhip", 255, 239, 213 }, + { "peachpuff", 255, 218, 185 }, + { "peru", 205, 133, 63 }, + { "pink", 255, 192, 203 }, + { "plum", 221, 160, 221 }, + { "powderblue", 176, 224, 230 }, + { "purple", 128, 0, 128 }, + { "red", 255, 0, 0 }, + { "rosybrown", 188, 143, 143 }, + { "royalblue", 65, 105, 225 }, + { "saddlebrown", 139, 69, 19 }, + { "salmon", 250, 128, 114 }, + { "sandybrown", 244, 164, 96 }, + { "seagreen", 46, 139, 87 }, + { "seashell", 255, 245, 238 }, + { "sienna", 160, 82, 45 }, + { "silver", 192, 192, 192 }, + { "skyblue", 135, 206, 235 }, + { "slateblue", 106, 90, 205 }, + { "slategray", 112, 128, 144 }, + { "slategrey", 112, 128, 144 }, + { "snow", 255, 250, 250 }, + { "springgreen", 0, 255, 127 }, + { "steelblue", 70, 130, 180 }, + { "tan", 210, 180, 140 }, + { "teal", 0, 128, 128 }, + { "thistle", 216, 191, 216 }, + { "tomato", 255, 99, 71 }, + { "turquoise", 64, 224, 208 }, + { "violet", 238, 130, 238 }, + { "wheat", 245, 222, 179 }, + { "white", 255, 255, 255 }, + { "whitesmoke", 245, 245, 245 }, + { "yellow", 255, 255, 0 }, + { "yellowgreen", 154, 205, 50 } }; diff --git a/plugins/AdvaImg/src/FreeImage/Conversion.cpp b/plugins/AdvaImg/src/FreeImage/Conversion.cpp index 04cec65ab5..815057ad08 100644 --- a/plugins/AdvaImg/src/FreeImage/Conversion.cpp +++ b/plugins/AdvaImg/src/FreeImage/Conversion.cpp @@ -6,6 +6,7 @@ // - Hervé Drolon (drolon@infonie.fr) // - Jani Kajala (janik@remedy.fi) // - Mihail Naydenov (mnaydenov@users.sourceforge.net) +// - Carsten Klein (cklein05@users.sourceforge.net) // // This file is part of FreeImage 3 // @@ -372,7 +373,8 @@ FreeImage_ColorQuantizeEx(FIBITMAP *dib, FREE_IMAGE_QUANTIZE quantize, int Palet if( ReserveSize < 0 ) ReserveSize = 0; if( ReserveSize > PaletteSize ) ReserveSize = PaletteSize; if (FreeImage_HasPixels(dib)) { - if (FreeImage_GetBPP(dib) == 24) { + const unsigned bpp = FreeImage_GetBPP(dib); + if((FreeImage_GetImageType(dib) == FIT_BITMAP) && (bpp == 24 || bpp == 32)) { switch(quantize) { case FIQ_WUQUANT : { @@ -387,9 +389,14 @@ FreeImage_ColorQuantizeEx(FIBITMAP *dib, FREE_IMAGE_QUANTIZE quantize, int Palet } catch (const char *) { return NULL; } + break; } case FIQ_NNQUANT : { + if (bpp == 32) { + // 32-bit images not supported by NNQUANT + return NULL; + } // sampling factor in range 1..30. // 1 => slower (but better), 30 => faster. Default value is 1 const int sampling = 1; @@ -402,6 +409,16 @@ FreeImage_ColorQuantizeEx(FIBITMAP *dib, FREE_IMAGE_QUANTIZE quantize, int Palet } return dst; } + case FIQ_LFPQUANT : + { + LFPQuantizer Q(PaletteSize); + FIBITMAP *dst = Q.Quantize(dib, ReserveSize, ReservePalette); + if(dst) { + // copy metadata from src to dst + FreeImage_CloneMetadata(dst, dib); + } + return dst; + } } } } @@ -412,26 +429,47 @@ FreeImage_ColorQuantizeEx(FIBITMAP *dib, FREE_IMAGE_QUANTIZE quantize, int Palet // ========================================================== FIBITMAP * DLL_CALLCONV -FreeImage_ConvertFromRawBits(BYTE *bits, int width, int height, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown) { - FIBITMAP *dib = FreeImage_Allocate(width, height, bpp, red_mask, green_mask, blue_mask); +FreeImage_ConvertFromRawBitsEx(BOOL copySource, BYTE *bits, FREE_IMAGE_TYPE type, int width, int height, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown) { + FIBITMAP *dib = NULL; - if (dib != NULL) { - if (topdown) { - for (int i = height - 1; i >= 0; --i) { - memcpy(FreeImage_GetScanLine(dib, i), bits, FreeImage_GetLine(dib)); - bits += pitch; - } - } else { - for (int i = 0; i < height; ++i) { - memcpy(FreeImage_GetScanLine(dib, i), bits, FreeImage_GetLine(dib)); - bits += pitch; - } + if(copySource) { + // allocate a FIBITMAP with internally managed pixel buffer + dib = FreeImage_AllocateT(type, width, height, bpp, red_mask, green_mask, blue_mask); + if(!dib) { + return NULL; + } + // copy user provided pixel buffer into the dib + const unsigned linesize = FreeImage_GetLine(dib); + for(int y = 0; y < height; y++) { + memcpy(FreeImage_GetScanLine(dib, y), bits, linesize); + // next line in user's buffer + bits += pitch; + } + // flip pixels vertically if needed + if(topdown) { + FreeImage_FlipVertical(dib); + } + } + else { + // allocate a FIBITMAP using a wrapper to user provided pixel buffer + dib = FreeImage_AllocateHeaderForBits(bits, pitch, type, width, height, bpp, red_mask, green_mask, blue_mask); + if(!dib) { + return NULL; + } + // flip pixels vertically if needed + if(topdown) { + FreeImage_FlipVertical(dib); } } return dib; } +FIBITMAP * DLL_CALLCONV +FreeImage_ConvertFromRawBits(BYTE *bits, int width, int height, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown) { + return FreeImage_ConvertFromRawBitsEx(TRUE /* copySource */, bits, FIT_BITMAP, width, height, pitch, bpp, red_mask, green_mask, blue_mask, topdown); +} + void DLL_CALLCONV FreeImage_ConvertToRawBits(BYTE *bits, FIBITMAP *dib, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown) { if (FreeImage_HasPixels(dib) && (bits != NULL)) { diff --git a/plugins/AdvaImg/src/FreeImage/ConversionType.cpp b/plugins/AdvaImg/src/FreeImage/ConversionType.cpp index b537f72814..a2ca90ff9d 100644 --- a/plugins/AdvaImg/src/FreeImage/ConversionType.cpp +++ b/plugins/AdvaImg/src/FreeImage/ConversionType.cpp @@ -3,6 +3,7 @@ // // Design and implementation by // - Hervé Drolon (drolon@infonie.fr) +// - Tanner Helland (tannerhelland@users.sf.net) // // This file is part of FreeImage 3 // @@ -346,11 +347,13 @@ FreeImage_ConvertToType(FIBITMAP *src, FREE_IMAGE_TYPE dst_type, BOOL scale_line dst = FreeImage_ConvertToRGB16(src); break; case FIT_RGBA16: + dst = FreeImage_ConvertToRGBA16(src); break; case FIT_RGBF: dst = FreeImage_ConvertToRGBF(src); break; case FIT_RGBAF: + dst = FreeImage_ConvertToRGBAF(src); break; } break; @@ -378,11 +381,13 @@ FreeImage_ConvertToType(FIBITMAP *src, FREE_IMAGE_TYPE dst_type, BOOL scale_line dst = FreeImage_ConvertToRGB16(src); break; case FIT_RGBA16: + dst = FreeImage_ConvertToRGBA16(src); break; case FIT_RGBF: dst = FreeImage_ConvertToRGBF(src); break; case FIT_RGBAF: + dst = FreeImage_ConvertToRGBAF(src); break; } break; @@ -503,6 +508,7 @@ FreeImage_ConvertToType(FIBITMAP *src, FREE_IMAGE_TYPE dst_type, BOOL scale_line dst = FreeImage_ConvertToRGBF(src); break; case FIT_RGBAF: + dst = FreeImage_ConvertToRGBAF(src); break; } break; @@ -582,11 +588,13 @@ FreeImage_ConvertToType(FIBITMAP *src, FREE_IMAGE_TYPE dst_type, BOOL scale_line case FIT_COMPLEX: break; case FIT_RGBA16: + dst = FreeImage_ConvertToRGBA16(src); break; case FIT_RGBF: dst = FreeImage_ConvertToRGBF(src); break; case FIT_RGBAF: + dst = FreeImage_ConvertToRGBAF(src); break; } break; @@ -618,6 +626,7 @@ FreeImage_ConvertToType(FIBITMAP *src, FREE_IMAGE_TYPE dst_type, BOOL scale_line dst = FreeImage_ConvertToRGBF(src); break; case FIT_RGBAF: + dst = FreeImage_ConvertToRGBAF(src); break; } break; @@ -645,6 +654,7 @@ FreeImage_ConvertToType(FIBITMAP *src, FREE_IMAGE_TYPE dst_type, BOOL scale_line case FIT_RGBA16: break; case FIT_RGBAF: + dst = FreeImage_ConvertToRGBAF(src); break; } break; diff --git a/plugins/AdvaImg/src/FreeImage/FreeImageIO.cpp b/plugins/AdvaImg/src/FreeImage/FreeImageIO.cpp index f8cf7604eb..83394f049c 100644 --- a/plugins/AdvaImg/src/FreeImage/FreeImageIO.cpp +++ b/plugins/AdvaImg/src/FreeImage/FreeImageIO.cpp @@ -68,14 +68,18 @@ _MemoryReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle) { FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(((FIMEMORY*)handle)->data); for(x = 0; x < count; x++) { - //if there isnt size bytes left to read, set pos to eof and return a short count - if( (mem_header->filelen - mem_header->curpos) < (long)size ) { - mem_header->curpos = mem_header->filelen; + long remaining_bytes = mem_header->file_length - mem_header->current_position; + //if there isn't size bytes left to read, set pos to eof and return a short count + if( remaining_bytes < (long)size ) { + if(remaining_bytes > 0) { + memcpy( buffer, (char *)mem_header->data + mem_header->current_position, remaining_bytes ); + } + mem_header->current_position = mem_header->file_length; break; } //copy size bytes count times - memcpy( buffer, (char *)mem_header->data + mem_header->curpos, size ); - mem_header->curpos += size; + memcpy( buffer, (char *)mem_header->data + mem_header->current_position, size ); + mem_header->current_position += size; buffer = (char *)buffer + size; } return x; @@ -89,32 +93,32 @@ _MemoryWriteProc(void *buffer, unsigned size, unsigned count, fi_handle handle) FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(((FIMEMORY*)handle)->data); //double the data block size if we need to - while( (mem_header->curpos + (long)(size*count)) >= mem_header->datalen ) { + while( (mem_header->current_position + (long)(size * count)) >= mem_header->data_length ) { //if we are at or above 1G, we cant double without going negative - if( mem_header->datalen & 0x40000000 ) { + if( mem_header->data_length & 0x40000000 ) { //max 2G - if( mem_header->datalen == 0x7FFFFFFF ) { + if( mem_header->data_length == 0x7FFFFFFF ) { return 0; } newdatalen = 0x7FFFFFFF; - } else if( mem_header->datalen == 0 ) { + } else if( mem_header->data_length == 0 ) { //default to 4K if nothing yet newdatalen = 4096; } else { //double size - newdatalen = mem_header->datalen << 1; + newdatalen = mem_header->data_length << 1; } newdata = realloc( mem_header->data, newdatalen ); if( !newdata ) { return 0; } mem_header->data = newdata; - mem_header->datalen = newdatalen; + mem_header->data_length = newdatalen; } - memcpy( (char *)mem_header->data + mem_header->curpos, buffer, size*count ); - mem_header->curpos += size*count; - if( mem_header->curpos > mem_header->filelen ) { - mem_header->filelen = mem_header->curpos; + memcpy( (char *)mem_header->data + mem_header->current_position, buffer, size * count ); + mem_header->current_position += size * count; + if( mem_header->current_position > mem_header->file_length ) { + mem_header->file_length = mem_header->current_position; } return count; } @@ -123,25 +127,28 @@ int DLL_CALLCONV _MemorySeekProc(fi_handle handle, long offset, int origin) { FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(((FIMEMORY*)handle)->data); + // you can use _MemorySeekProc to reposition the pointer anywhere in a file + // the pointer can also be positioned beyond the end of the file + switch(origin) { //0 to filelen-1 are 'inside' the file default: case SEEK_SET: //can fseek() to 0-7FFFFFFF always if( offset >= 0 ) { - mem_header->curpos = offset; + mem_header->current_position = offset; return 0; } break; case SEEK_CUR: - if( mem_header->curpos + offset >= 0 ) { - mem_header->curpos += offset; + if( mem_header->current_position + offset >= 0 ) { + mem_header->current_position += offset; return 0; } break; case SEEK_END: - if( mem_header->filelen + offset >= 0 ) { - mem_header->curpos = mem_header->filelen + offset; + if( mem_header->file_length + offset >= 0 ) { + mem_header->current_position = mem_header->file_length + offset; return 0; } break; @@ -154,7 +161,7 @@ long DLL_CALLCONV _MemoryTellProc(fi_handle handle) { FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(((FIMEMORY*)handle)->data); - return mem_header->curpos; + return mem_header->current_position; } // ---------------------------------------------------------- diff --git a/plugins/AdvaImg/src/FreeImage/LFPQuantizer.cpp b/plugins/AdvaImg/src/FreeImage/LFPQuantizer.cpp new file mode 100644 index 0000000000..8b592c30f1 --- /dev/null +++ b/plugins/AdvaImg/src/FreeImage/LFPQuantizer.cpp @@ -0,0 +1,208 @@ +// ========================================================== +// LFPQuantizer class implementation +// +// Design and implementation by +// - Carsten Klein (cklein05@users.sourceforge.net) +// +// This file is part of FreeImage 3 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include "Quantizers.h" +#include "FreeImage.h" +#include "Utilities.h" + +LFPQuantizer::LFPQuantizer(unsigned PaletteSize) : + m_size(0), m_limit(PaletteSize), m_index(0) { + m_map = new MapEntry[MAP_SIZE]; + memset(m_map, 0xFF, MAP_SIZE * sizeof(MapEntry)); +} + +LFPQuantizer::~LFPQuantizer() { + delete[] m_map; +} + +FIBITMAP* LFPQuantizer::Quantize(FIBITMAP *dib, int ReserveSize, RGBQUAD *ReservePalette) { + + if (ReserveSize > 0 && ReservePalette != NULL) { + AddReservePalette(ReservePalette, ReserveSize); + } + + const unsigned width = FreeImage_GetWidth(dib); + const unsigned height = FreeImage_GetHeight(dib); + + FIBITMAP *dib8 = FreeImage_Allocate(width, height, 8); + if (dib8 == NULL) { + return NULL; + } + + const unsigned src_pitch = FreeImage_GetPitch(dib); + const unsigned dst_pitch = FreeImage_GetPitch(dib8); + + const BYTE * const src_bits = FreeImage_GetBits(dib); + BYTE * const dst_bits = FreeImage_GetBits(dib8); + + unsigned last_color = -1; + int last_index = 0; + + if (FreeImage_GetBPP(dib) == 24) { + + // Getting the source pixel as an unsigned int is much faster than + // working with FI_RGBA_xxx and shifting. However, this may fail + // for the very last pixel, since its rgbReserved member (alpha) + // may actually point to an address beyond the bitmap's memory. So, + // we do not process the last scanline in the first loop. + + // Process all but the last scanline. + for (unsigned y = 0; y < height - 1; ++y) { + BYTE *dst_line = dst_bits + y * dst_pitch; + const BYTE *src_line = src_bits + y * src_pitch; + for (unsigned x = 0; x < width; ++x) { + const unsigned color = *((unsigned *) src_line) & 0x00FFFFFF; + if (color != last_color) { + last_color = color; + last_index = GetIndexForColor(color); + if (last_index == -1) { + FreeImage_Unload(dib8); + return NULL; + } + } + dst_line[x] = last_index; + src_line += 3; + } + } + + // Process all but the last pixel of the last scanline. + BYTE *dst_line = dst_bits + (height - 1) * dst_pitch; + const BYTE *src_line = src_bits + (height - 1) * src_pitch; + for (unsigned x = 0; x < width - 1; ++x) { + const unsigned color = *((unsigned *) src_line) & 0x00FFFFFF; + if (color != last_color) { + last_color = color; + last_index = GetIndexForColor(color); + if (last_index == -1) { + FreeImage_Unload(dib8); + return NULL; + } + } + dst_line[x] = last_index; + src_line += 3; + } + + // Process the last pixel (src_line should already point to it). + const unsigned color = 0 | src_line[FI_RGBA_BLUE] << FI_RGBA_BLUE_SHIFT + | src_line[FI_RGBA_GREEN] << FI_RGBA_GREEN_SHIFT + | src_line[FI_RGBA_RED] << FI_RGBA_RED_SHIFT; + if (color != last_color) { + last_color = color; + last_index = GetIndexForColor(color); + if (last_index == -1) { + FreeImage_Unload(dib8); + return NULL; + } + } + dst_line[width - 1] = last_index; + + } else { + for (unsigned y = 0; y < height; ++y) { + BYTE *dst_line = dst_bits + y * dst_pitch; + const BYTE *src_line = src_bits + y * src_pitch; + for (unsigned x = 0; x < width; ++x) { + const unsigned color = *((unsigned *) src_line) & 0x00FFFFFF; + if (color != last_color) { + last_color = color; + last_index = GetIndexForColor(color); + if (last_index == -1) { + FreeImage_Unload(dib8); + return NULL; + } + } + dst_line[x] = last_index; + src_line += 4; + } + } + } + + WritePalette(FreeImage_GetPalette(dib8)); + return dib8; +} + +/** + * Returns the palette index of the specified color. Tries to put the + * color into the map, if it's not already present in the map. In that + * case, a new index is used for the color. Returns -1, if adding the + * color would exceed the desired maximum number of colors in the + * palette. + * @param color the color to get the index from + * @return the palette index of the specified color or -1, if there + * is no space left in the palette + */ +inline int LFPQuantizer::GetIndexForColor(unsigned color) { + unsigned bucket = hash(color) & (MAP_SIZE - 1); + while (m_map[bucket].color != color) { + if (m_map[bucket].color == EMPTY_BUCKET) { + if (m_size == m_limit) { + return -1; + } + m_map[bucket].color = color; + m_map[bucket].index = m_index++; + ++m_size; + break; + } + bucket = (bucket + 1) % MAP_SIZE; + } + return m_map[bucket].index; +} + +/** + * Adds the specified number of entries of the specified reserve + * palette to the newly created palette. + * @param *palette a pointer to the reserve palette to copy from + * @param size the number of entries to copy + */ +void LFPQuantizer::AddReservePalette(const void *palette, unsigned size) { + if (size > MAX_SIZE) { + size = MAX_SIZE; + } + unsigned *ppal = (unsigned *) palette; + const unsigned offset = m_limit - size; + for (unsigned i = 0; i < size; ++i) { + const unsigned color = *ppal++; + const unsigned index = i + offset; + unsigned bucket = hash(color) & (MAP_SIZE - 1); + while((m_map[bucket].color != EMPTY_BUCKET) && (m_map[bucket].color != color)) { + bucket = (bucket + 1) % MAP_SIZE; + } + if(m_map[bucket].color != color) { + m_map[bucket].color = color; + m_map[bucket].index = index; + } + } + m_size += size; +} + +/** + * Copies the newly created palette into the specified destination + * palette. Although unused palette entries are not overwritten in + * the destination palette, it is assumed to have space for at + * least 256 entries. + * @param palette a pointer to the destination palette + */ +void LFPQuantizer::WritePalette(void *palette) { + for (unsigned i = 0; i < MAP_SIZE; ++i) { + if (m_map[i].color != EMPTY_BUCKET) { + ((unsigned *) palette)[m_map[i].index] = m_map[i].color; + } + } +} diff --git a/plugins/AdvaImg/src/FreeImage/MNGHelper.cpp b/plugins/AdvaImg/src/FreeImage/MNGHelper.cpp index a4c67a2abe..ed3664cf77 100644 --- a/plugins/AdvaImg/src/FreeImage/MNGHelper.cpp +++ b/plugins/AdvaImg/src/FreeImage/MNGHelper.cpp @@ -357,7 +357,6 @@ Retrieve the position of a chunk in a PNG stream */ static BOOL mng_FindChunk(FIMEMORY *hPngMemory, BYTE *chunk_name, long offset, DWORD *start_pos, DWORD *next_pos) { - BOOL mEnd = FALSE; DWORD mLength = 0; BYTE *data = NULL; @@ -513,10 +512,14 @@ mng_RemoveChunk(FIMEMORY *hPngMemory, BYTE *chunk_name) { DWORD next_pos = 0; bResult = mng_FindChunk(hPngMemory, chunk_name, 8, &start_pos, &next_pos); - if(!bResult) return FALSE; + if(!bResult) { + return FALSE; + } bResult = mng_CopyRemoveChunks(hPngMemory, start_pos, next_pos); - if(!bResult) return FALSE; + if(!bResult) { + return FALSE; + } return TRUE; } @@ -529,10 +532,14 @@ mng_InsertChunk(FIMEMORY *hPngMemory, BYTE *inNextChunkName, BYTE *inInsertChunk DWORD next_pos = 0; bResult = mng_FindChunk(hPngMemory, inNextChunkName, 8, &start_pos, &next_pos); - if(!bResult) return FALSE; + if(!bResult) { + return FALSE; + } bResult = mng_CopyInsertChunks(hPngMemory, inNextChunkName, inInsertChunk, chunk_length, start_pos, next_pos); - if(!bResult) return FALSE; + if(!bResult) { + return FALSE; + } return TRUE; } @@ -962,7 +969,7 @@ mng_ReadChunks(int format_id, FreeImageIO *io, fi_handle handle, long Offset, in jng_color_type = mChunk[8]; jng_image_sample_depth = mChunk[9]; jng_image_compression_method = mChunk[10]; - BYTE jng_image_interlace_method = mChunk[11]; + //BYTE jng_image_interlace_method = mChunk[11]; // for debug only jng_alpha_sample_depth = mChunk[12]; jng_alpha_compression_method = mChunk[13]; @@ -1000,7 +1007,9 @@ mng_ReadChunks(int format_id, FreeImageIO *io, fi_handle handle, long Offset, in break; } // load the JPEG - if(dib) FreeImage_Unload(dib); + if(dib) { + FreeImage_Unload(dib); + } dib = mng_LoadFromMemoryHandle(hJpegMemory, flags); // load the PNG alpha layer @@ -1017,7 +1026,9 @@ mng_ReadChunks(int format_id, FreeImageIO *io, fi_handle handle, long Offset, in } mng_WritePNGStream(jng_width, jng_height, jng_alpha_sample_depth, data, size_in_bytes, hPngMemory); // load the PNG - if(dib_alpha) FreeImage_Unload(dib_alpha); + if(dib_alpha) { + FreeImage_Unload(dib_alpha); + } dib_alpha = mng_LoadFromMemoryHandle(hPngMemory, flags); } } diff --git a/plugins/AdvaImg/src/FreeImage/MemoryIO.cpp b/plugins/AdvaImg/src/FreeImage/MemoryIO.cpp index 6ae3fb2e11..e0997856a9 100644 --- a/plugins/AdvaImg/src/FreeImage/MemoryIO.cpp +++ b/plugins/AdvaImg/src/FreeImage/MemoryIO.cpp @@ -48,7 +48,7 @@ FreeImage_OpenMemory(BYTE *data, DWORD size_in_bytes) { // wrap a user buffer mem_header->delete_me = FALSE; mem_header->data = (BYTE*)data; - mem_header->datalen = mem_header->filelen = size_in_bytes; + mem_header->data_length = mem_header->file_length = size_in_bytes; } else { mem_header->delete_me = TRUE; } @@ -120,7 +120,7 @@ FreeImage_AcquireMemory(FIMEMORY *stream, BYTE **data, DWORD *size_in_bytes) { FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(stream->data); *data = (BYTE*)mem_header->data; - *size_in_bytes = mem_header->filelen; + *size_in_bytes = mem_header->file_length; return TRUE; } diff --git a/plugins/AdvaImg/src/FreeImage/MultiPage.cpp b/plugins/AdvaImg/src/FreeImage/MultiPage.cpp index d48e11be94..4fe76adb16 100644 --- a/plugins/AdvaImg/src/FreeImage/MultiPage.cpp +++ b/plugins/AdvaImg/src/FreeImage/MultiPage.cpp @@ -269,8 +269,8 @@ FreeImage_OpenMultiBitmap(FREE_IMAGE_FORMAT fif, const char *filename, BOOL crea header->node = node; header->fif = fif; header->io = io.get (); - header->handle = handle; - header->changed = FALSE; + header->handle = handle; + header->changed = FALSE; header->read_only = read_only; header->m_cachefile = NULL; header->cache_fif = fif; @@ -344,13 +344,13 @@ FreeImage_OpenMultiBitmapFromHandle(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_h BOOL read_only = FALSE; // modifications (if any) will be stored into the memory cache if (io && handle) { - + // retrieve the plugin list to find the node belonging to this plugin PluginList *list = FreeImage_GetPluginList(); - + if (list) { PluginNode *node = list->FindNodeFromFIF(fif); - + if (node) { std::auto_ptr<FIMULTIBITMAP> bitmap (new FIMULTIBITMAP); std::auto_ptr<MULTIBITMAPHEADER> header (new MULTIBITMAPHEADER); @@ -359,13 +359,13 @@ FreeImage_OpenMultiBitmapFromHandle(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_h header->m_filename = NULL; header->node = node; header->fif = fif; - header->handle = handle; - header->changed = FALSE; - header->read_only = read_only; + header->handle = handle; + header->changed = FALSE; + header->read_only = read_only; header->m_cachefile = NULL; header->cache_fif = fif; header->load_flags = flags; - + // store the MULTIBITMAPHEADER in the surrounding FIMULTIBITMAP structure bitmap->data = header.get(); @@ -381,7 +381,7 @@ FreeImage_OpenMultiBitmapFromHandle(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_h if (!read_only) { // set up the cache std::auto_ptr<CacheFile> cache_file (new CacheFile("", TRUE)); - + if (cache_file->open()) { header->m_cachefile = cache_file.release(); } @@ -408,7 +408,7 @@ FreeImage_SaveMultiBitmapToHandle(FREE_IMAGE_FORMAT fif, FIMULTIBITMAP *bitmap, // retrieve the plugin list to find the node belonging to this plugin PluginList *list = FreeImage_GetPluginList(); - + if (list) { PluginNode *node = list->FindNodeFromFIF(fif); diff --git a/plugins/AdvaImg/src/FreeImage/PixelAccess.cpp b/plugins/AdvaImg/src/FreeImage/PixelAccess.cpp index c69463c316..b5714b2929 100644 --- a/plugins/AdvaImg/src/FreeImage/PixelAccess.cpp +++ b/plugins/AdvaImg/src/FreeImage/PixelAccess.cpp @@ -28,19 +28,6 @@ // ---------------------------------------------------------- BYTE * DLL_CALLCONV -FreeImage_GetBits(FIBITMAP *dib) { - if(!FreeImage_HasPixels(dib)) { - return NULL; - } - // 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; -} - -BYTE * DLL_CALLCONV FreeImage_GetScanLine(FIBITMAP *dib, int scanline) { if(!FreeImage_HasPixels(dib)) { return NULL; diff --git a/plugins/AdvaImg/src/FreeImage/Plugin.cpp b/plugins/AdvaImg/src/FreeImage/Plugin.cpp index 6f88e47e68..13da67434e 100644 --- a/plugins/AdvaImg/src/FreeImage/Plugin.cpp +++ b/plugins/AdvaImg/src/FreeImage/Plugin.cpp @@ -218,7 +218,7 @@ FreeImage_GetPluginList() { void DLL_CALLCONV FreeImage_Initialise(BOOL load_local_plugins_only) { if (s_plugin_reference_count++ == 0) { - + /* Note: initialize all singletons here in order to avoid race conditions with multi-threading @@ -261,8 +261,8 @@ FreeImage_Initialise(BOOL load_local_plugins_only) { //s_plugins->AddNode(InitXBM); //s_plugins->AddNode(InitXPM); //s_plugins->AddNode(InitDDS); - s_plugins->AddNode(InitGIF); - //s_plugins->AddNode(InitHDR); + s_plugins->AddNode(InitGIF); + //s_plugins->AddNode(InitHDR); //s_plugins->AddNode(InitG3); //s_plugins->AddNode(InitSGI); //s_plugins->AddNode(InitEXR); @@ -275,26 +275,26 @@ FreeImage_Initialise(BOOL load_local_plugins_only) { //#if !(defined(_MSC_VER) && (_MSC_VER <= 1310)) //s_plugins->AddNode(InitJXR); //#endif // unsupported by MS Visual Studio 2003 !!! - + // external plugin initialization #ifdef _WIN32 if (!load_local_plugins_only) { int count = 0; char buffer[MAX_PATH + 200]; - char current_dir[2 * _MAX_PATH], module[2 * _MAX_PATH]; + wchar_t current_dir[2 * _MAX_PATH], module[2 * _MAX_PATH]; BOOL bOk = FALSE; // store the current directory. then set the directory to the application location - if (GetCurrentDirectoryA(2 * _MAX_PATH, current_dir) != 0) { - if (GetModuleFileNameA(NULL, module, 2 * _MAX_PATH) != 0) { - char *last_point = strrchr(module, '\\'); + if (GetCurrentDirectoryW(2 * _MAX_PATH, current_dir) != 0) { + if (GetModuleFileNameW(NULL, module, 2 * _MAX_PATH) != 0) { + wchar_t *last_point = wcsrchr(module, L'\\'); if (last_point) { - *last_point = '\0'; + *last_point = L'\0'; - bOk = SetCurrentDirectoryA(module); + bOk = SetCurrentDirectoryW(module); } } } @@ -335,7 +335,7 @@ FreeImage_Initialise(BOOL load_local_plugins_only) { // restore the current directory if (bOk) { - SetCurrentDirectoryA(current_dir); + SetCurrentDirectoryW(current_dir); } } #endif // _WIN32 diff --git a/plugins/AdvaImg/src/FreeImage/PluginEXR.cpp b/plugins/AdvaImg/src/FreeImage/PluginEXR.cpp index 4a19b8b56f..b286430380 100644 --- a/plugins/AdvaImg/src/FreeImage/PluginEXR.cpp +++ b/plugins/AdvaImg/src/FreeImage/PluginEXR.cpp @@ -22,6 +22,12 @@ #include "FreeImage.h" #include "Utilities.h" + +#ifdef _MSC_VER +// OpenEXR has many problems with MSVC warnings (why not just correct them ?), just ignore one of them +#pragma warning (disable : 4800) // ImfVersion.h - 'const int' : forcing value to bool 'true' or 'false' (performance warning) +#endif + #include "../OpenEXR/IlmImf/ImfIO.h" #include "../OpenEXR/Iex/Iex.h" #include "../OpenEXR/IlmImf/ImfOutputFile.h" @@ -44,72 +50,64 @@ static int s_format_id; /** FreeImage input stream wrapper +@see Imf_2_2::IStream */ -class C_IStream: public Imf::IStream { -public: - C_IStream (FreeImageIO *io, fi_handle handle): - IStream(""), _io (io), _handle(handle) {} - - virtual bool read (char c[/*n*/], int n); - virtual Imf::Int64 tellg (); - virtual void seekg (Imf::Int64 pos); - virtual void clear () {}; - +class C_IStream : public Imf::IStream { private: FreeImageIO *_io; fi_handle _handle; + +public: + C_IStream (FreeImageIO *io, fi_handle handle) : + Imf::IStream(""), _io (io), _handle(handle) { + } + + virtual bool read (char c[/*n*/], int n) { + return ((unsigned)n != _io->read_proc(c, 1, n, _handle)); + } + + virtual Imath::Int64 tellg() { + return _io->tell_proc(_handle); + } + + virtual void seekg(Imath::Int64 pos) { + _io->seek_proc(_handle, (unsigned)pos, SEEK_SET); + } + + virtual void clear() { + } }; +// ---------------------------------------------------------- /** FreeImage output stream wrapper +@see Imf_2_2::OStream */ -class C_OStream: public Imf::OStream { -public: - C_OStream (FreeImageIO *io, fi_handle handle): - OStream(""), _io (io), _handle(handle) {} - - virtual void write (const char c[/*n*/], int n); - virtual Imf::Int64 tellp (); - virtual void seekp (Imf::Int64 pos); - +class C_OStream : public Imf::OStream { private: FreeImageIO *_io; fi_handle _handle; -}; - - -bool -C_IStream::read (char c[/*n*/], int n) { - return ((unsigned)n != _io->read_proc(c, 1, n, _handle)); -} - -Imf::Int64 -C_IStream::tellg () { - return _io->tell_proc(_handle); -} -void -C_IStream::seekg (Imf::Int64 pos) { - _io->seek_proc(_handle, (unsigned)pos, SEEK_SET); -} +public: + C_OStream (FreeImageIO *io, fi_handle handle) : + Imf::OStream(""), _io (io), _handle(handle) { + } -void -C_OStream::write (const char c[/*n*/], int n) { - if((unsigned)n != _io->write_proc((void*)&c[0], 1, n, _handle)) { - Iex::throwErrnoExc(); + virtual void write(const char c[/*n*/], int n) { + if((unsigned)n != _io->write_proc((void*)&c[0], 1, n, _handle)) { + Iex::throwErrnoExc(); + } } -} -Imf::Int64 -C_OStream::tellp () { - return _io->tell_proc(_handle); -} + virtual Imath::Int64 tellp() { + return _io->tell_proc(_handle); + } -void -C_OStream::seekp (Imf::Int64 pos) { - _io->seek_proc(_handle, (unsigned)pos, SEEK_SET); -} + virtual void seekp(Imath::Int64 pos) { + _io->seek_proc(_handle, (unsigned)pos, SEEK_SET); + } +}; // ---------------------------------------------------------- @@ -667,7 +665,9 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void if(pixelType == Imf::HALF) { // convert from float to half halfData = new(std::nothrow) half[width * height * components]; - if(!halfData) THROW (Iex::NullExc, FI_MSG_ERROR_MEMORY); + if(!halfData) { + THROW (Iex::NullExc, FI_MSG_ERROR_MEMORY); + } for(int y = 0; y < height; y++) { float *src_bits = (float*)FreeImage_GetScanLine(dib, height - 1 - y); @@ -716,7 +716,9 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void file.setFrameBuffer (frameBuffer); file.writePixels (height); - if(halfData != NULL) delete[] halfData; + if(halfData != NULL) { + delete[] halfData; + } if(bIsFlipped) { // invert dib scanlines FreeImage_FlipVertical(dib); @@ -725,7 +727,9 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void return TRUE; } catch(Iex::BaseExc & e) { - if(halfData != NULL) delete[] halfData; + if(halfData != NULL) { + delete[] halfData; + } if(bIsFlipped) { // invert dib scanlines FreeImage_FlipVertical(dib); @@ -745,6 +749,11 @@ void DLL_CALLCONV InitEXR(Plugin *plugin, int format_id) { s_format_id = format_id; + // initialize the OpenEXR library + // note that this OpenEXR function produce so called "false memory leaks" + // see http://lists.nongnu.org/archive/html/openexr-devel/2013-11/msg00000.html + Imf::staticInitialize(); + plugin->format_proc = Format; plugin->description_proc = Description; plugin->extension_proc = Extension; diff --git a/plugins/AdvaImg/src/FreeImage/PluginG3.cpp b/plugins/AdvaImg/src/FreeImage/PluginG3.cpp index d5c08b36e6..0a083b459b 100644 --- a/plugins/AdvaImg/src/FreeImage/PluginG3.cpp +++ b/plugins/AdvaImg/src/FreeImage/PluginG3.cpp @@ -92,7 +92,7 @@ G3GetFileSize(FreeImageIO *io, fi_handle handle) { static BOOL G3ReadFile(FreeImageIO *io, fi_handle handle, uint8 *tif_rawdata, tmsize_t tif_rawdatasize) { - return ((tmsize_t)(io->read_proc(tif_rawdata, tif_rawdatasize, 1, handle) * tif_rawdatasize) == tif_rawdatasize); + return ((tmsize_t)(io->read_proc(tif_rawdata, (unsigned)tif_rawdatasize, 1, handle) * tif_rawdatasize) == tif_rawdatasize); } // ========================================================== diff --git a/plugins/AdvaImg/src/FreeImage/PluginGIF.cpp b/plugins/AdvaImg/src/FreeImage/PluginGIF.cpp index 87c0185865..0153959ab8 100644 --- a/plugins/AdvaImg/src/FreeImage/PluginGIF.cpp +++ b/plugins/AdvaImg/src/FreeImage/PluginGIF.cpp @@ -4,6 +4,7 @@ // Design and implementation by // - Ryan Rubley <ryan@lostreality.org> // - Raphaël Gaquer <raphael.gaquer@alcer.com> +// - Aaron Shumate <aaron@shumate.us> // // This file is part of FreeImage 3 // @@ -773,7 +774,11 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { } if( info.disposal_method == GIF_DISPOSAL_BACKGROUND ) { for( y = 0; y < info.height; y++ ) { - scanline = (RGBQUAD *)FreeImage_GetScanLine(dib, logicalheight - (y + info.top) - 1) + info.left; + const int scanidx = logicalheight - (y + info.top) - 1; + if ( scanidx < 0 ) { + break; // If data is corrupt, don't calculate in invalid scanline + } + scanline = (RGBQUAD *)FreeImage_GetScanLine(dib, scanidx) + info.left; for( x = 0; x < info.width; x++ ) { *scanline++ = background; } @@ -800,7 +805,11 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { } //copy page data into logical buffer, with full alpha opaqueness for( y = 0; y < info.height; y++ ) { - scanline = (RGBQUAD *)FreeImage_GetScanLine(dib, logicalheight - (y + info.top) - 1) + info.left; + const int scanidx = logicalheight - (y + info.top) - 1; + if ( scanidx < 0 ) { + break; // If data is corrupt, don't calculate in invalid scanline + } + scanline = (RGBQUAD *)FreeImage_GetScanLine(dib, scanidx) + info.left; BYTE *pageline = FreeImage_GetScanLine(pagedib, info.height - y - 1); for( x = 0; x < info.width; x++ ) { if( !have_transparent || *pageline != transparent_color ) { diff --git a/plugins/AdvaImg/src/FreeImage/PluginHDR.cpp b/plugins/AdvaImg/src/FreeImage/PluginHDR.cpp index 0cde6139db..28ce1a5768 100644 --- a/plugins/AdvaImg/src/FreeImage/PluginHDR.cpp +++ b/plugins/AdvaImg/src/FreeImage/PluginHDR.cpp @@ -459,8 +459,9 @@ rgbe_WriteBytes_RLE(FreeImageIO *io, fi_handle handle, BYTE *data, int numbytes) beg_run += run_count; old_run_count = run_count; run_count = 1; - while((data[beg_run] == data[beg_run + run_count]) && (beg_run + run_count < numbytes) && (run_count < 127)) + while((beg_run + run_count < numbytes) && (run_count < 127) && (data[beg_run] == data[beg_run + run_count])) { run_count++; + } } // if data before next big run is a short run then write it as such if ((old_run_count > 1)&&(old_run_count == beg_run - cur)) { diff --git a/plugins/AdvaImg/src/FreeImage/PluginICO.cpp b/plugins/AdvaImg/src/FreeImage/PluginICO.cpp index df5ecee91d..c818379f78 100644 --- a/plugins/AdvaImg/src/FreeImage/PluginICO.cpp +++ b/plugins/AdvaImg/src/FreeImage/PluginICO.cpp @@ -110,6 +110,23 @@ CalculateImageOffset(std::vector<FIBITMAP*>& vPages, int nIndex ) { return dwSize; } +/** +Vista icon support +@return Returns TRUE if the bitmap data is stored in PNG format +*/ +static BOOL +IsPNG(FreeImageIO *io, fi_handle handle) { + BYTE png_signature[8] = { 137, 80, 78, 71, 13, 10, 26, 10 }; + BYTE signature[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + long tell = io->tell_proc(handle); + io->read_proc(&signature, 1, 8, handle); + BOOL bIsPNG = (memcmp(png_signature, signature, 8) == 0); + io->seek_proc(handle, tell, SEEK_SET); + + return bIsPNG; +} + #ifdef FREEIMAGE_BIGENDIAN static void SwapInfoHeader(BITMAPINFOHEADER *header) { @@ -407,16 +424,17 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { // load the requested icon if (page < icon_header->idCount) { // seek to the start of the bitmap data for the icon - io->seek_proc(handle, 0, SEEK_SET); - io->seek_proc(handle, icon_list[page].dwImageOffset, SEEK_CUR); + io->seek_proc(handle, icon_list[page].dwImageOffset, SEEK_SET); - if((icon_list[page].bWidth == 0) && (icon_list[page].bHeight == 0)) { + if( IsPNG(io, handle) ) { // Vista icon support + // see http://blogs.msdn.com/b/oldnewthing/archive/2010/10/22/10079192.aspx dib = FreeImage_LoadFromHandle(FIF_PNG, io, handle, header_only ? FIF_LOAD_NOPIXELS : PNG_DEFAULT); } else { // standard icon support // see http://msdn.microsoft.com/en-us/library/ms997538.aspx + // see http://blogs.msdn.com/b/oldnewthing/archive/2010/10/18/10077133.aspx dib = LoadStandardIcon(io, handle, flags, header_only); } diff --git a/plugins/AdvaImg/src/FreeImage/PluginJ2K.cpp b/plugins/AdvaImg/src/FreeImage/PluginJ2K.cpp index 5c23a7c6e1..b8bcfc8b58 100644 --- a/plugins/AdvaImg/src/FreeImage/PluginJ2K.cpp +++ b/plugins/AdvaImg/src/FreeImage/PluginJ2K.cpp @@ -175,7 +175,9 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { if (header_only) { // create output image dib = J2KImageToFIBITMAP(s_format_id, image, header_only); - if(!dib) throw "Failed to import JPEG2000 image"; + if(!dib) { + throw "Failed to import JPEG2000 image"; + } // clean-up and return header data opj_destroy_codec(d_codec); opj_image_destroy(image); @@ -193,7 +195,9 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { // create output image dib = J2KImageToFIBITMAP(s_format_id, image, header_only); - if(!dib) throw "Failed to import JPEG2000 image"; + if(!dib) { + throw "Failed to import JPEG2000 image"; + } // free image data structure opj_image_destroy(image); @@ -201,7 +205,9 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { return dib; } catch (const char *text) { - if(dib) FreeImage_Unload(dib); + if(dib) { + FreeImage_Unload(dib); + } // free remaining structures opj_destroy_codec(d_codec); opj_image_destroy(image); @@ -231,27 +237,22 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void opj_set_default_encoder_parameters(¶meters); try { - parameters.numresolution = 1; - // check the resolution (i.e. parameters.numresolution) - int min_size = MIN(FreeImage_GetWidth(dib), FreeImage_GetHeight(dib)); - if(min_size < (1 << parameters.numresolution)) { - throw "Invalid image size - image is too small"; - } - - parameters.tcp_numlayers = 0; + parameters.tcp_numlayers = 0; // if no rate entered, apply a 16:1 rate by default if(flags == J2K_DEFAULT) { parameters.tcp_rates[0] = (float)16; } else { // for now, the flags parameter is only used to specify the rate - parameters.tcp_rates[0] = (float)flags; + parameters.tcp_rates[0] = (float)(flags & 0x3FF); } parameters.tcp_numlayers++; parameters.cp_disto_alloc = 1; // convert the dib to a OpenJPEG image image = FIBITMAPToJ2KImage(s_format_id, dib, ¶meters); - if(!image) return FALSE; + if(!image) { + return FALSE; + } // decide if MCT should be used parameters.tcp_mct = (image->numcomps == 3) ? 1 : 0; diff --git a/plugins/AdvaImg/src/FreeImage/PluginJP2.cpp b/plugins/AdvaImg/src/FreeImage/PluginJP2.cpp index edf5b396c3..742fe2c038 100644 --- a/plugins/AdvaImg/src/FreeImage/PluginJP2.cpp +++ b/plugins/AdvaImg/src/FreeImage/PluginJP2.cpp @@ -175,7 +175,9 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { if (header_only) { // create output image dib = J2KImageToFIBITMAP(s_format_id, image, header_only); - if(!dib) throw "Failed to import JPEG2000 image"; + if(!dib) { + throw "Failed to import JPEG2000 image"; + } // clean-up and return header data opj_destroy_codec(d_codec); opj_image_destroy(image); @@ -193,7 +195,9 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { // create output image dib = J2KImageToFIBITMAP(s_format_id, image, header_only); - if(!dib) throw "Failed to import JPEG2000 image"; + if(!dib) { + throw "Failed to import JPEG2000 image"; + } // free image data structure opj_image_destroy(image); @@ -201,7 +205,9 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { return dib; } catch (const char *text) { - if(dib) FreeImage_Unload(dib); + if(dib) { + FreeImage_Unload(dib); + } // free remaining structures opj_destroy_codec(d_codec); opj_image_destroy(image); @@ -231,27 +237,22 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void opj_set_default_encoder_parameters(¶meters); try { - parameters.numresolution = 1; - // check the resolution (i.e. parameters.numresolution) - int min_size = MIN(FreeImage_GetWidth(dib), FreeImage_GetHeight(dib)); - if(min_size < (1 << parameters.numresolution)) { - throw "Invalid image size - image is too small"; - } - - parameters.tcp_numlayers = 0; + parameters.tcp_numlayers = 0; // if no rate entered, apply a 16:1 rate by default - if(flags == J2K_DEFAULT) { + if(flags == JP2_DEFAULT) { parameters.tcp_rates[0] = (float)16; } else { // for now, the flags parameter is only used to specify the rate - parameters.tcp_rates[0] = (float)flags; + parameters.tcp_rates[0] = (float)(flags & 0x3FF); } parameters.tcp_numlayers++; parameters.cp_disto_alloc = 1; // convert the dib to a OpenJPEG image image = FIBITMAPToJ2KImage(s_format_id, dib, ¶meters); - if(!image) return FALSE; + if(!image) { + return FALSE; + } // decide if MCT should be used parameters.tcp_mct = (image->numcomps == 3) ? 1 : 0; diff --git a/plugins/AdvaImg/src/FreeImage/PluginJPEG.cpp b/plugins/AdvaImg/src/FreeImage/PluginJPEG.cpp index c1b45e6347..573989c5df 100644 --- a/plugins/AdvaImg/src/FreeImage/PluginJPEG.cpp +++ b/plugins/AdvaImg/src/FreeImage/PluginJPEG.cpp @@ -919,9 +919,6 @@ jpeg_write_exif_profile_raw(j_compress_ptr cinfo, FIBITMAP *dib) { if(tag_exif) { const BYTE *tag_value = (BYTE*)FreeImage_GetTagValue(tag_exif); - - if (NULL == tag_value) - return FALSE; // verify the identifying string if(memcmp(exif_signature, tag_value, sizeof(exif_signature)) != 0) { @@ -929,21 +926,23 @@ jpeg_write_exif_profile_raw(j_compress_ptr cinfo, FIBITMAP *dib) { return FALSE; } - DWORD tag_length = FreeImage_GetTagLength(tag_exif); - - BYTE *profile = (BYTE*)malloc(tag_length * sizeof(BYTE)); - if(profile == NULL) return FALSE; + if(NULL != tag_value) { + DWORD tag_length = FreeImage_GetTagLength(tag_exif); - for(DWORD i = 0; i < tag_length; i += 65504L) { - unsigned length = MIN((long)(tag_length - i), 65504L); + BYTE *profile = (BYTE*)malloc(tag_length * sizeof(BYTE)); + if(profile == NULL) return FALSE; - memcpy(profile, tag_value + i, length); - jpeg_write_marker(cinfo, EXIF_MARKER, profile, length); - } + for(DWORD i = 0; i < tag_length; i += 65504L) { + unsigned length = MIN((long)(tag_length - i), 65504L); + + memcpy(profile, tag_value + i, length); + jpeg_write_marker(cinfo, EXIF_MARKER, profile, length); + } - free(profile); + free(profile); - return TRUE; + return TRUE; + } } return FALSE; diff --git a/plugins/AdvaImg/src/FreeImage/PluginJXR.cpp b/plugins/AdvaImg/src/FreeImage/PluginJXR.cpp index f5e4878c1d..0e14e09ac9 100644 --- a/plugins/AdvaImg/src/FreeImage/PluginJXR.cpp +++ b/plugins/AdvaImg/src/FreeImage/PluginJXR.cpp @@ -163,8 +163,6 @@ JXR_ErrorMessage(const int error) { default: return "Invalid instruction - please contact the FreeImage team"; } - - return NULL; } // ========================================================== @@ -410,11 +408,12 @@ GetOutputPixelFormat(FIBITMAP *dib, PKPixelFormatGUID *guid_format, BOOL *bHasAl } // ========================================================== -// Metadata loading & saving +// Metadata loading // ========================================================== /** Read a JPEG-XR IFD as a buffer +@see ReadMetadata */ static ERR ReadProfile(WMPStream* pStream, unsigned cbByteCount, unsigned uOffset, BYTE **ppbProfile) { @@ -436,6 +435,7 @@ ReadProfile(WMPStream* pStream, unsigned cbByteCount, unsigned uOffset, BYTE **p /** Convert a DPKPROPVARIANT to a FITAG, then store the tag as FIMD_EXIF_MAIN +@see ReadDescriptiveMetadata */ static BOOL ReadPropVariant(WORD tag_id, const DPKPROPVARIANT & varSrc, FIBITMAP *dib) { @@ -470,7 +470,7 @@ ReadPropVariant(WORD tag_id, const DPKPROPVARIANT & varSrc, FIBITMAP *dib) { case DPKVT_LPWSTR: FreeImage_SetTagType(tag, FIDT_UNDEFINED); dwSize = (DWORD)(sizeof(U16) * (wcslen((wchar_t *) varSrc.VT.pwszVal) + 1)); // +1 for NULL term - FreeImage_SetTagCount(tag, dwSize / 2); + FreeImage_SetTagCount(tag, dwSize); FreeImage_SetTagLength(tag, dwSize); FreeImage_SetTagValue(tag, varSrc.VT.pwszVal); break; @@ -533,6 +533,7 @@ ReadDescriptiveMetadata(PKImageDecode *pID, FIBITMAP *dib) { /** Read ICC, XMP, Exif, Exif-GPS, IPTC, descriptive (i.e. Exif-TIFF) metadata +@see ReadProfile, ReadDescriptiveMetadata */ static ERR ReadMetadata(PKImageDecode *pID, FIBITMAP *dib) { @@ -593,7 +594,7 @@ ReadMetadata(PKImageDecode *pID, FIBITMAP *dib) { error_code = ReadProfile(pStream, cbByteCount, uOffset, &pbProfile); JXR_CHECK(error_code); // decode the Exif profile - jpegxr_read_exif_profile(dib, pbProfile, cbByteCount); + jpegxr_read_exif_profile(dib, pbProfile, cbByteCount, uOffset); } // Exif-GPS metadata @@ -603,7 +604,7 @@ ReadMetadata(PKImageDecode *pID, FIBITMAP *dib) { error_code = ReadProfile(pStream, cbByteCount, uOffset, &pbProfile); JXR_CHECK(error_code); // decode the Exif-GPS profile - jpegxr_read_exif_gps_profile(dib, pbProfile, cbByteCount); + jpegxr_read_exif_gps_profile(dib, pbProfile, cbByteCount, uOffset); } // free profile buffer @@ -630,6 +631,168 @@ ReadMetadata(PKImageDecode *pID, FIBITMAP *dib) { } // ========================================================== +// Metadata saving +// ========================================================== + +/** +Convert a FITAG (coming from FIMD_EXIF_MAIN) to a DPKPROPVARIANT. +No allocation is needed here, the function just copy pointers when needed. +@see WriteDescriptiveMetadata +*/ +static BOOL +WritePropVariant(FIBITMAP *dib, WORD tag_id, DPKPROPVARIANT & varDst) { + FITAG *tag = NULL; + + TagLib& s = TagLib::instance(); + + // clear output DPKPROPVARIANT + varDst.vt = DPKVT_EMPTY; + + // given the tag id, get the tag key + const char *key = s.getTagFieldName(TagLib::EXIF_MAIN, tag_id, NULL); + // then, get the tag info + if(!FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, key, &tag)) { + return FALSE; + } + + // set the tag value + switch(FreeImage_GetTagType(tag)) { + case FIDT_ASCII: + varDst.vt = DPKVT_LPSTR; + varDst.VT.pszVal = (char*)FreeImage_GetTagValue(tag); + break; + case FIDT_BYTE: + case FIDT_UNDEFINED: + varDst.vt = DPKVT_LPWSTR; + varDst.VT.pwszVal = (U16*)FreeImage_GetTagValue(tag); + break; + case FIDT_SHORT: + varDst.vt = DPKVT_UI2; + varDst.VT.uiVal = *((U16*)FreeImage_GetTagValue(tag)); + break; + case FIDT_LONG: + varDst.vt = DPKVT_UI4; + varDst.VT.ulVal = *((U32*)FreeImage_GetTagValue(tag)); + break; + default: + break; + } + + return TRUE; +} + +/** +Write EXIF_MAIN metadata to JPEG-XR descriptive metadata +@see WritePropVariant +*/ +static ERR +WriteDescriptiveMetadata(PKImageEncode *pIE, FIBITMAP *dib) { + ERR error_code = 0; // error code as returned by the interface + DESCRIPTIVEMETADATA DescMetadata; + + // fill the DESCRIPTIVEMETADATA structure (use pointers to arrays when needed) + WritePropVariant(dib, WMP_tagImageDescription, DescMetadata.pvarImageDescription); + WritePropVariant(dib, WMP_tagCameraMake, DescMetadata.pvarCameraMake); + WritePropVariant(dib, WMP_tagCameraModel, DescMetadata.pvarCameraModel); + WritePropVariant(dib, WMP_tagSoftware, DescMetadata.pvarSoftware); + WritePropVariant(dib, WMP_tagDateTime, DescMetadata.pvarDateTime); + WritePropVariant(dib, WMP_tagArtist, DescMetadata.pvarArtist); + WritePropVariant(dib, WMP_tagCopyright, DescMetadata.pvarCopyright); + WritePropVariant(dib, WMP_tagRatingStars, DescMetadata.pvarRatingStars); + WritePropVariant(dib, WMP_tagRatingValue, DescMetadata.pvarRatingValue); + WritePropVariant(dib, WMP_tagCaption, DescMetadata.pvarCaption); + WritePropVariant(dib, WMP_tagDocumentName, DescMetadata.pvarDocumentName); + WritePropVariant(dib, WMP_tagPageName, DescMetadata.pvarPageName); + WritePropVariant(dib, WMP_tagPageNumber, DescMetadata.pvarPageNumber); + WritePropVariant(dib, WMP_tagHostComputer, DescMetadata.pvarHostComputer); + + // copy the structure to the encoder + error_code = pIE->SetDescriptiveMetadata(pIE, &DescMetadata); + + // no need to free anything here + return error_code; +} + +/** +Write ICC, XMP, Exif, Exif-GPS, IPTC, descriptive (i.e. Exif-TIFF) metadata +*/ +static ERR +WriteMetadata(PKImageEncode *pIE, FIBITMAP *dib) { + ERR error_code = 0; // error code as returned by the interface + BYTE *profile = NULL; + unsigned profile_size = 0; + + try { + // write ICC profile + { + FIICCPROFILE *iccProfile = FreeImage_GetICCProfile(dib); + if(iccProfile->data) { + error_code = pIE->SetColorContext(pIE, (U8*)iccProfile->data, iccProfile->size); + JXR_CHECK(error_code); + } + } + + // write descriptive metadata + if(FreeImage_GetMetadataCount(FIMD_EXIF_MAIN, dib)) { + error_code = WriteDescriptiveMetadata(pIE, dib); + JXR_CHECK(error_code); + } + + // write IPTC metadata + if(FreeImage_GetMetadataCount(FIMD_IPTC, dib)) { + // create a binary profile + if(write_iptc_profile(dib, &profile, &profile_size)) { + // write the profile + error_code = PKImageEncode_SetIPTCNAAMetadata_WMP(pIE, profile, profile_size); + JXR_CHECK(error_code); + // release profile + free(profile); + profile = NULL; + } + } + + // write XMP metadata + { + FITAG *tag_xmp = NULL; + if(FreeImage_GetMetadata(FIMD_XMP, dib, g_TagLib_XMPFieldName, &tag_xmp)) { + error_code = PKImageEncode_SetXMPMetadata_WMP(pIE, (BYTE*)FreeImage_GetTagValue(tag_xmp), FreeImage_GetTagLength(tag_xmp)); + JXR_CHECK(error_code); + } + } + + // write Exif metadata + { + if(tiff_get_ifd_profile(dib, FIMD_EXIF_EXIF, &profile, &profile_size)) { + error_code = PKImageEncode_SetEXIFMetadata_WMP(pIE, profile, profile_size); + JXR_CHECK(error_code); + // release profile + free(profile); + profile = NULL; + } + } + + // write Exif GPS metadata + { + if(tiff_get_ifd_profile(dib, FIMD_EXIF_GPS, &profile, &profile_size)) { + error_code = PKImageEncode_SetGPSInfoMetadata_WMP(pIE, profile, profile_size); + JXR_CHECK(error_code); + // release profile + free(profile); + profile = NULL; + } + } + + return WMP_errSuccess; + + } catch(...) { + free(profile); + return error_code; + } +} + + + +// ========================================================== // Quantization tables (Y, U, V, YHP, UHP, VHP), // optimized for PSNR // ========================================================== @@ -1238,8 +1401,11 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void float resY = (float)(unsigned)(0.5F + 0.0254F * FreeImage_GetDotsPerMeterY(dib)); pEncoder->SetResolution(pEncoder, resX, resY); - // write pixels - // -------------- + // set metadata + WriteMetadata(pEncoder, dib); + + // write metadata & pixels + // ----------------------- // dib coordinates are upside-down relative to usual conventions bIsFlipped = FreeImage_FlipVertical(dib); @@ -1250,7 +1416,7 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void // get dst pitch (count of BYTE for stride) const unsigned cbStride = FreeImage_GetPitch(dib); - // write pixels on output + // write metadata + pixels on output error_code = pEncoder->WritePixels(pEncoder, height, dib_bits, cbStride); JXR_CHECK(error_code); diff --git a/plugins/AdvaImg/src/FreeImage/PluginPFM.cpp b/plugins/AdvaImg/src/FreeImage/PluginPFM.cpp index 231e8baa22..ea3c46b14e 100644 --- a/plugins/AdvaImg/src/FreeImage/PluginPFM.cpp +++ b/plugins/AdvaImg/src/FreeImage/PluginPFM.cpp @@ -63,11 +63,13 @@ Get an integer value from the actual position pointed by handle static int pfm_get_int(FreeImageIO *io, fi_handle handle) { char c = 0; - BOOL firstchar; + BOOL bFirstChar; // skip forward to start of next number - if(!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING; + if(!io->read_proc(&c, 1, 1, handle)) { + throw FI_MSG_ERROR_PARSING; + } while (1) { // eat comments @@ -75,15 +77,16 @@ pfm_get_int(FreeImageIO *io, fi_handle handle) { if (c == '#') { // if we're at a comment, read to end of line - firstchar = TRUE; + bFirstChar = TRUE; while (1) { - if(!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING; + if(!io->read_proc(&c, 1, 1, handle)) { + throw FI_MSG_ERROR_PARSING; + } - if (firstchar && c == ' ') { + if (bFirstChar && c == ' ') { // loop off 1 sp after # - - firstchar = FALSE; + bFirstChar = FALSE; } else if (c == '\n') { break; } @@ -92,11 +95,12 @@ pfm_get_int(FreeImageIO *io, fi_handle handle) { if (c >= '0' && c <='9') { // we've found what we were looking for - break; } - if(!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING; + if(!io->read_proc(&c, 1, 1, handle)) { + throw FI_MSG_ERROR_PARSING; + } } // we're at the start of a number, continue until we hit a non-number @@ -106,10 +110,13 @@ pfm_get_int(FreeImageIO *io, fi_handle handle) { while (1) { i = (i * 10) + (c - '0'); - if(!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING; + if(!io->read_proc(&c, 1, 1, handle)) { + throw FI_MSG_ERROR_PARSING; + } - if (c < '0' || c > '9') - break; + if (c < '0' || c > '9') { + break; + } } return i; diff --git a/plugins/AdvaImg/src/FreeImage/PluginPICT.cpp b/plugins/AdvaImg/src/FreeImage/PluginPICT.cpp index 99958a489c..371056d20b 100644 --- a/plugins/AdvaImg/src/FreeImage/PluginPICT.cpp +++ b/plugins/AdvaImg/src/FreeImage/PluginPICT.cpp @@ -82,21 +82,21 @@ static const int outputMessageSize = 256; // Internal functions // ========================================================== -static unsigned +static BYTE Read8(FreeImageIO *io, fi_handle handle) { - unsigned char i = 0; + BYTE i = 0; io->read_proc(&i, 1, 1, handle); return i; } -static unsigned +static WORD Read16(FreeImageIO *io, fi_handle handle) { // reads a two-byte big-endian integer from the given file and returns its value. // assumes unsigned. unsigned hi = Read8(io, handle); unsigned lo = Read8(io, handle); - return lo + (hi << 8); + return (WORD)(lo + (hi << 8)); } static unsigned @@ -388,7 +388,7 @@ ReadColorTable( FreeImageIO *io, fi_handle handle, WORD* pNumColors, RGBQUAD* pP // The indicies in a device colour table are bogus and // usually == 0, so I assume we allocate up the list of // colours in order. - val = i; + val = (WORD)i; } if (val >= numColors) { throw "pixel value greater than color table size."; @@ -416,7 +416,7 @@ SkipBits( FreeImageIO *io, fi_handle handle, MacRect* bounds, WORD rowBytes, int if (pixelSize <= 8) { rowBytes &= 0x7fff; } - pixwidth = width; + pixwidth = (WORD)width; if (pixelSize == 16) { pixwidth *= 2; @@ -541,6 +541,7 @@ expandBuf8( FreeImageIO *io, fi_handle handle, int width, int bpp, BYTE* dst ) static BYTE* UnpackPictRow( FreeImageIO *io, fi_handle handle, BYTE* pLineBuf, int width, int rowBytes, int srcBytes ) { + if (rowBytes < 8) { // Ah-ha! The bits aren't actually packed. This will be easy. io->read_proc( pLineBuf, rowBytes, 1, handle ); } @@ -589,7 +590,7 @@ Unpack32Bits( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacRect* bounds, int width = bounds->right - bounds->left; if (rowBytes == 0) { - rowBytes = width*4; + rowBytes = (WORD)( width * 4 ); } BYTE* pLineBuf = (BYTE*)malloc( rowBytes ); // Let's allocate enough for 4 bit planes @@ -656,7 +657,7 @@ Unpack8Bits( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacRect* bounds, rowBytes &= 0x7fff; if (rowBytes == 0) { - rowBytes = width; + rowBytes = (WORD)width; } for ( int i = 0; i < height; i++ ) { @@ -694,7 +695,7 @@ UnpackBits( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacRect* bounds, W rowBytes &= 0x7fff; } - pixwidth = width; + pixwidth = (WORD)width; pkpixsize = 1; // RLE unit: one byte for everything... if (pixelSize == 16) { // ...except 16 bpp. pkpixsize = 2; diff --git a/plugins/AdvaImg/src/FreeImage/PluginPNG.cpp b/plugins/AdvaImg/src/FreeImage/PluginPNG.cpp index f6b59e299b..fe80a2b533 100644 --- a/plugins/AdvaImg/src/FreeImage/PluginPNG.cpp +++ b/plugins/AdvaImg/src/FreeImage/PluginPNG.cpp @@ -6,6 +6,7 @@ // - Herve Drolon (drolon@infonie.fr) // - Detlev Vendt (detlev.vendt@brillit.de) // - Aaron Shumate (trek@startreker.com) +// - Tanner Helland (tannerhelland@users.sf.net) // // This file is part of FreeImage 3 // @@ -49,9 +50,9 @@ typedef struct { fi_handle s_handle; } fi_ioStructure, *pfi_ioStructure; -///////////////////////////////////////////////////////////////////////////// -// libpng interface -// +// ========================================================== +// libpng interface +// ========================================================== static void _ReadProc(png_structp png_ptr, unsigned char *data, png_size_t size) { @@ -99,6 +100,7 @@ ReadMetadata(png_structp png_ptr, png_infop info_ptr, FIBITMAP *dib) { FITAG *tag = NULL; png_textp text_ptr = NULL; + png_timep mod_time = NULL; int num_text = 0; // iTXt/tEXt/zTXt chuncks @@ -130,6 +132,31 @@ ReadMetadata(png_structp png_ptr, png_infop info_ptr, FIBITMAP *dib) { } } + // timestamp chunk + if(png_get_tIME(png_ptr, info_ptr, &mod_time)) { + char timestamp[32]; + // create a tag + tag = FreeImage_CreateTag(); + if(!tag) return FALSE; + + // convert as 'yyyy:MM:dd hh:mm:ss' + sprintf(timestamp, "%4d:%02d:%02d %2d:%02d:%02d", mod_time->year, mod_time->month, mod_time->day, mod_time->hour, mod_time->minute, mod_time->second); + + DWORD tag_length = (DWORD)strlen(timestamp) + 1; + FreeImage_SetTagLength(tag, tag_length); + FreeImage_SetTagCount(tag, tag_length); + FreeImage_SetTagType(tag, FIDT_ASCII); + FreeImage_SetTagID(tag, TAG_DATETIME); + FreeImage_SetTagValue(tag, timestamp); + + // store the tag as Exif-TIFF + FreeImage_SetTagKey(tag, "DateTime"); + FreeImage_SetMetadata(FIMD_EXIF_MAIN, dib, FreeImage_GetTagKey(tag), tag); + + // destroy the tag + FreeImage_DeleteTag(tag); + } + return TRUE; } @@ -143,6 +170,7 @@ WriteMetadata(png_structp png_ptr, png_infop info_ptr, FIBITMAP *dib) { BOOL bResult = TRUE; png_text text_metadata; + png_time mod_time; // set the 'Comments' metadata as iTXt chuncks @@ -174,7 +202,7 @@ WriteMetadata(png_structp png_ptr, png_infop info_ptr, FIBITMAP *dib) { if(tag && FreeImage_GetTagLength(tag)) { memset(&text_metadata, 0, sizeof(png_text)); text_metadata.compression = 1; // iTXt, none - text_metadata.key = (char*)g_png_xmp_keyword; // keyword, 1-79 character description of "text" + text_metadata.key = (char*)g_png_xmp_keyword; // keyword, 1-79 character description of "text" text_metadata.text = (char*)FreeImage_GetTagValue(tag); // comment, may be an empty string (ie "") text_metadata.text_length = FreeImage_GetTagLength(tag);// length of the text string text_metadata.itxt_length = FreeImage_GetTagLength(tag);// length of the itxt string @@ -186,6 +214,23 @@ WriteMetadata(png_structp png_ptr, png_infop info_ptr, FIBITMAP *dib) { bResult &= TRUE; } + // set the Exif-TIFF 'DateTime' metadata as a tIME chunk + tag = NULL; + FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, "DateTime", &tag); + if(tag && FreeImage_GetTagLength(tag)) { + int year, month, day, hour, minute, second; + const char *value = (char*)FreeImage_GetTagValue(tag); + if(sscanf(value, "%4d:%02d:%02d %2d:%02d:%02d", &year, &month, &day, &hour, &minute, &second) == 6) { + mod_time.year = (png_uint_16)year; + mod_time.month = (png_byte)month; + mod_time.day = (png_byte)day; + mod_time.hour = (png_byte)hour; + mod_time.minute = (png_byte)minute; + mod_time.second = (png_byte)second; + png_set_tIME (png_ptr, info_ptr, &mod_time); + } + } + return bResult; } @@ -265,21 +310,207 @@ SupportsNoPixels() { return TRUE; } -// ---------------------------------------------------------- +// -------------------------------------------------------------------------- + +/** +Configure the decoder so that decoded pixels are compatible with a FREE_IMAGE_TYPE format. +Set conversion instructions as needed. +@param png_ptr PNG handle +@param info_ptr PNG info handle +@param flags Decoder flags +@param output_image_type Returned FreeImage converted image type +@return Returns TRUE if successful, returns FALSE otherwise +@see png_read_update_info +*/ +static BOOL +ConfigureDecoder(png_structp png_ptr, png_infop info_ptr, int flags, FREE_IMAGE_TYPE *output_image_type) { + // get original image info + const int color_type = png_get_color_type(png_ptr, info_ptr); + const int bit_depth = png_get_bit_depth(png_ptr, info_ptr); + const int pixel_depth = bit_depth * png_get_channels(png_ptr, info_ptr); + + FREE_IMAGE_TYPE image_type = FIT_BITMAP; // assume standard image type + + // check for transparency table or single transparent color + BOOL bIsTransparent = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) == PNG_INFO_tRNS ? TRUE : FALSE; + + // check allowed combinations of colour type and bit depth + // then get converted FreeImage type + + switch(color_type) { + case PNG_COLOR_TYPE_GRAY: // color type '0', bitdepth = 1, 2, 4, 8, 16 + switch(bit_depth) { + case 1: + case 2: + case 4: + case 8: + // expand grayscale images to the full 8-bit from 2-bit/pixel + if (pixel_depth == 2) { + png_set_expand_gray_1_2_4_to_8(png_ptr); + } + + // if a tRNS chunk is provided, we must also expand the grayscale data to 8-bits, + // this allows us to make use of the transparency table with existing FreeImage methods + if (bIsTransparent && (pixel_depth < 8)) { + png_set_expand_gray_1_2_4_to_8(png_ptr); + } + break; + + case 16: + image_type = (pixel_depth == 16) ? FIT_UINT16 : FIT_UNKNOWN; + + // 16-bit grayscale images can contain a transparent value (shade) + // if found, expand the transparent value to a full alpha channel + if (bIsTransparent && (image_type != FIT_UNKNOWN)) { + // expand tRNS to a full alpha channel + png_set_tRNS_to_alpha(png_ptr); + + // expand new 16-bit gray + 16-bit alpha to full 64-bit RGBA + png_set_gray_to_rgb(png_ptr); + + image_type = FIT_RGBA16; + } + break; + + default: + image_type = FIT_UNKNOWN; + break; + } + break; + + case PNG_COLOR_TYPE_RGB: // color type '2', bitdepth = 8, 16 + switch(bit_depth) { + case 8: + image_type = (pixel_depth == 24) ? FIT_BITMAP : FIT_UNKNOWN; + break; + case 16: + image_type = (pixel_depth == 48) ? FIT_RGB16 : FIT_UNKNOWN; + break; + default: + image_type = FIT_UNKNOWN; + break; + } + // sometimes, 24- or 48-bit images may contain transparency information + // check for this use case and convert to an alpha-compatible format + if (bIsTransparent && (image_type != FIT_UNKNOWN)) { + // if the image is 24-bit RGB, mark it as 32-bit; if it is 48-bit, mark it as 64-bit + image_type = (pixel_depth == 24) ? FIT_BITMAP : (pixel_depth == 48) ? FIT_RGBA16 : FIT_UNKNOWN; + // expand tRNS chunk to alpha channel + png_set_tRNS_to_alpha(png_ptr); + } + break; + + case PNG_COLOR_TYPE_PALETTE: // color type '3', bitdepth = 1, 2, 4, 8 + switch(bit_depth) { + case 1: + case 2: + case 4: + case 8: + // expand palette images to the full 8 bits from 2 bits/pixel + if (pixel_depth == 2) { + png_set_packing(png_ptr); + } + + // if a tRNS chunk is provided, we must also expand the palletized data to 8-bits, + // this allows us to make use of the transparency table with existing FreeImage methods + if (bIsTransparent && (pixel_depth < 8)) { + png_set_packing(png_ptr); + } + break; + + default: + image_type = FIT_UNKNOWN; + break; + } + break; + + case PNG_COLOR_TYPE_GRAY_ALPHA: // color type '4', bitdepth = 8, 16 + switch(bit_depth) { + case 8: + // 8-bit grayscale + 8-bit alpha => convert to 32-bit RGBA + image_type = (pixel_depth == 16) ? FIT_BITMAP : FIT_UNKNOWN; + break; + case 16: + // 16-bit grayscale + 16-bit alpha => convert to 64-bit RGBA + image_type = (pixel_depth == 32) ? FIT_RGBA16 : FIT_UNKNOWN; + break; + default: + image_type = FIT_UNKNOWN; + break; + } + // expand 8-bit greyscale + 8-bit alpha to 32-bit + // expand 16-bit greyscale + 16-bit alpha to 64-bit + png_set_gray_to_rgb(png_ptr); + break; + + case PNG_COLOR_TYPE_RGB_ALPHA: // color type '6', bitdepth = 8, 16 + switch(bit_depth) { + case 8: + break; + case 16: + image_type = (pixel_depth == 64) ? FIT_RGBA16 : FIT_UNKNOWN; + break; + default: + image_type = FIT_UNKNOWN; + break; + } + break; + } + + // check for unknown or invalid formats + if(image_type == FIT_UNKNOWN) { + *output_image_type = image_type; + return FALSE; + } + +#ifndef FREEIMAGE_BIGENDIAN + if((image_type == FIT_UINT16) || (image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) { + // turn on 16-bit byte swapping + png_set_swap(png_ptr); + } +#endif + +#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR + if((image_type == FIT_BITMAP) && ((color_type == PNG_COLOR_TYPE_RGB) || (color_type == PNG_COLOR_TYPE_RGB_ALPHA))) { + // flip the RGB pixels to BGR (or RGBA to BGRA) + png_set_bgr(png_ptr); + } +#endif + + // gamma correction + // unlike the example in the libpng documentation, we have *no* idea where + // this file may have come from--so if it doesn't have a file gamma, don't + // do any correction ("do no harm") + + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) { + double gamma = 0; + double screen_gamma = 2.2; + + if (png_get_gAMA(png_ptr, info_ptr, &gamma) && ( flags & PNG_IGNOREGAMMA ) != PNG_IGNOREGAMMA) { + png_set_gamma(png_ptr, screen_gamma, gamma); + } + } + + // all transformations have been registered; now update info_ptr data + png_read_update_info(png_ptr, info_ptr); + + // return the output image type + *output_image_type = image_type; + + return TRUE; +} static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { png_structp png_ptr = NULL; - png_infop info_ptr; + png_infop info_ptr = NULL; png_uint_32 width, height; - png_colorp png_palette = NULL; - int color_type, palette_entries = 0; - int bit_depth, pixel_depth; // pixel_depth = bit_depth * channels + int color_type; + int bit_depth; + int pixel_depth = 0; // pixel_depth = bit_depth * channels FIBITMAP *dib = NULL; - RGBQUAD *palette = NULL; // pointer to dib palette - png_bytepp row_pointers = NULL; - int i; + png_bytepp row_pointers = NULL; fi_ioStructure fio; fio.s_handle = handle; @@ -334,154 +565,58 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); - pixel_depth = png_get_bit_depth(png_ptr, info_ptr) * png_get_channels(png_ptr, info_ptr); - - // get image data type (assume standard image type) + // configure the decoder FREE_IMAGE_TYPE image_type = FIT_BITMAP; - if (bit_depth == 16) { - if ((pixel_depth == 16) && (color_type == PNG_COLOR_TYPE_GRAY)) { - image_type = FIT_UINT16; - } - else if ((pixel_depth == 48) && (color_type == PNG_COLOR_TYPE_RGB)) { - image_type = FIT_RGB16; - } - else if ((pixel_depth == 64) && (color_type == PNG_COLOR_TYPE_RGB_ALPHA)) { - image_type = FIT_RGBA16; - } else { - // tell libpng to strip 16 bit/color files down to 8 bits/color - png_set_strip_16(png_ptr); - bit_depth = 8; - } - } - -#ifndef FREEIMAGE_BIGENDIAN - if((image_type == FIT_UINT16) || (image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) { - // turn on 16 bit byte swapping - png_set_swap(png_ptr); - } -#endif - - // set some additional flags - - switch(color_type) { - case PNG_COLOR_TYPE_RGB: - case PNG_COLOR_TYPE_RGB_ALPHA: -#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR - // flip the RGB pixels to BGR (or RGBA to BGRA) - - if(image_type == FIT_BITMAP) { - png_set_bgr(png_ptr); - } -#endif - break; - - case PNG_COLOR_TYPE_PALETTE: - // expand palette images to the full 8 bits from 2 bits/pixel - - if (pixel_depth == 2) { - png_set_packing(png_ptr); - pixel_depth = 8; - } - - break; - - case PNG_COLOR_TYPE_GRAY: - // expand grayscale images to the full 8 bits from 2 bits/pixel - // but *do not* expand fully transparent palette entries to a full alpha channel - - if (pixel_depth == 2) { - png_set_expand_gray_1_2_4_to_8(png_ptr); - pixel_depth = 8; - } - - break; - - case PNG_COLOR_TYPE_GRAY_ALPHA: - // expand 8-bit greyscale + 8-bit alpha to 32-bit - png_set_gray_to_rgb(png_ptr); -#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR - // flip the RGBA pixels to BGRA - - png_set_bgr(png_ptr); -#endif - pixel_depth = 32; - - break; - - default: - throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; + if(!ConfigureDecoder(png_ptr, info_ptr, flags, &image_type)) { + throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; } - // unlike the example in the libpng documentation, we have *no* idea where - // this file may have come from--so if it doesn't have a file gamma, don't - // do any correction ("do no harm") - - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) { - double gamma = 0; - double screen_gamma = 2.2; - - if (png_get_gAMA(png_ptr, info_ptr, &gamma) && ( flags & PNG_IGNOREGAMMA ) != PNG_IGNOREGAMMA) { - png_set_gamma(png_ptr, screen_gamma, gamma); - } - } - - // all transformations have been registered; now update info_ptr data - - png_read_update_info(png_ptr, info_ptr); + // update image info - // color type may have changed, due to our transformations + color_type = png_get_color_type(png_ptr, info_ptr); + bit_depth = png_get_bit_depth(png_ptr, info_ptr); + pixel_depth = bit_depth * png_get_channels(png_ptr, info_ptr); - color_type = png_get_color_type(png_ptr,info_ptr); - - // create a DIB and write the bitmap header - // set up the DIB palette, if needed + // create a dib and write the bitmap header + // set up the dib palette, if needed switch (color_type) { case PNG_COLOR_TYPE_RGB: - png_set_invert_alpha(png_ptr); - - if(image_type == FIT_BITMAP) { - dib = FreeImage_AllocateHeader(header_only, width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); - } else { - dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth); - } - break; - case PNG_COLOR_TYPE_RGB_ALPHA: - if(image_type == FIT_BITMAP) { - dib = FreeImage_AllocateHeader(header_only, width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); - } else { - dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth); - } + dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); break; case PNG_COLOR_TYPE_PALETTE: - dib = FreeImage_AllocateHeader(header_only, width, height, pixel_depth); + dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); + if(dib) { + png_colorp png_palette = NULL; + int palette_entries = 0; - png_get_PLTE(png_ptr,info_ptr, &png_palette, &palette_entries); + png_get_PLTE(png_ptr,info_ptr, &png_palette, &palette_entries); - palette_entries = MIN((unsigned)palette_entries, FreeImage_GetColorsUsed(dib)); - palette = FreeImage_GetPalette(dib); + palette_entries = MIN((unsigned)palette_entries, FreeImage_GetColorsUsed(dib)); - // store the palette + // store the palette - for (i = 0; i < palette_entries; i++) { - palette[i].rgbRed = png_palette[i].red; - palette[i].rgbGreen = png_palette[i].green; - palette[i].rgbBlue = png_palette[i].blue; + RGBQUAD *palette = FreeImage_GetPalette(dib); + for(int i = 0; i < palette_entries; i++) { + palette[i].rgbRed = png_palette[i].red; + palette[i].rgbGreen = png_palette[i].green; + palette[i].rgbBlue = png_palette[i].blue; + } } break; case PNG_COLOR_TYPE_GRAY: - dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth); + dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); - if(pixel_depth <= 8) { - palette = FreeImage_GetPalette(dib); - palette_entries = 1 << pixel_depth; + if(dib && (pixel_depth <= 8)) { + RGBQUAD *palette = FreeImage_GetPalette(dib); + const int palette_entries = 1 << pixel_depth; - for (i = 0; i < palette_entries; i++) { + for(int i = 0; i < palette_entries; i++) { palette[i].rgbRed = palette[i].rgbGreen = palette[i].rgbBlue = (BYTE)((i * 255) / (palette_entries - 1)); @@ -493,6 +628,10 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; } + if(!dib) { + throw FI_MSG_ERROR_DIB_MEMORY; + } + // store the transparency table if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { @@ -507,21 +646,26 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { if((color_type == PNG_COLOR_TYPE_GRAY) && trans_color) { // single transparent color - if (trans_color->gray < palette_entries) { + if (trans_color->gray < 256) { BYTE table[256]; - memset(table, 0xFF, palette_entries); + memset(table, 0xFF, 256); table[trans_color->gray] = 0; - FreeImage_SetTransparencyTable(dib, table, palette_entries); + FreeImage_SetTransparencyTable(dib, table, 256); + } + // check for a full transparency table, too + else if ((trans_alpha) && (pixel_depth <= 8)) { + FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans); } + } else if((color_type == PNG_COLOR_TYPE_PALETTE) && trans_alpha) { // transparency table FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans); } } - // store the background color + // store the background color (only supported for FIT_BITMAP types) - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) { + if ((image_type == FIT_BITMAP) && png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) { // Get the background color to draw transparent and alpha images over. // Note that even if the PNG file supplies a background, you are not required to // use it - you should use the (solid) application background if it has one. @@ -598,7 +742,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { // allow loading of PNG with minor errors (such as images with several IDAT chunks) for (png_uint_32 k = 0; k < height; k++) { - row_pointers[height - 1 - k] = FreeImage_GetScanLine(dib, k); + row_pointers[height - 1 - k] = FreeImage_GetScanLine(dib, k); } png_set_benign_errors(png_ptr, 1); @@ -644,7 +788,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { free(row_pointers); } if (dib) { - FreeImage_Unload(dib); + FreeImage_Unload(dib); } FreeImage_OutputMessageProc(s_format_id, text); @@ -655,6 +799,8 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { return NULL; } +// -------------------------------------------------------------------------- + static BOOL DLL_CALLCONV Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) { png_structp png_ptr; @@ -903,7 +1049,7 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void // the number of passes is either 1 for non-interlaced images, or 7 for interlaced images for (int pass = 0; pass < number_passes; pass++) { for (png_uint_32 k = 0; k < height; k++) { - FreeImage_ConvertLine32To24(buffer, FreeImage_GetScanLine(dib, height - k - 1), width); + FreeImage_ConvertLine32To24(buffer, FreeImage_GetScanLine(dib, height - k - 1), width); png_write_row(png_ptr, buffer); } } @@ -911,8 +1057,8 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void } else { // the number of passes is either 1 for non-interlaced images, or 7 for interlaced images for (int pass = 0; pass < number_passes; pass++) { - for (png_uint_32 k = 0; k < height; k++) { - png_write_row(png_ptr, FreeImage_GetScanLine(dib, height - k - 1)); + for (png_uint_32 k = 0; k < height; k++) { + png_write_row(png_ptr, FreeImage_GetScanLine(dib, height - k - 1)); } } } @@ -930,7 +1076,11 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void png_destroy_write_struct(&png_ptr, &info_ptr); return TRUE; + } catch (const char *text) { + if(png_ptr) { + png_destroy_write_struct(&png_ptr, &info_ptr); + } FreeImage_OutputMessageProc(s_format_id, text); } } diff --git a/plugins/AdvaImg/src/FreeImage/PluginPNM.cpp b/plugins/AdvaImg/src/FreeImage/PluginPNM.cpp index 3155315559..3b4d0de554 100644 --- a/plugins/AdvaImg/src/FreeImage/PluginPNM.cpp +++ b/plugins/AdvaImg/src/FreeImage/PluginPNM.cpp @@ -33,11 +33,13 @@ Get an integer value from the actual position pointed by handle static int GetInt(FreeImageIO *io, fi_handle handle) { char c = 0; - BOOL firstchar; + BOOL bFirstChar; // skip forward to start of next number - if(!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING; + if(!io->read_proc(&c, 1, 1, handle)) { + throw FI_MSG_ERROR_PARSING; + } while (1) { // eat comments @@ -45,15 +47,16 @@ GetInt(FreeImageIO *io, fi_handle handle) { if (c == '#') { // if we're at a comment, read to end of line - firstchar = TRUE; + bFirstChar = TRUE; while (1) { - if(!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING; + if(!io->read_proc(&c, 1, 1, handle)) { + throw FI_MSG_ERROR_PARSING; + } - if (firstchar && c == ' ') { + if (bFirstChar && c == ' ') { // loop off 1 sp after # - - firstchar = FALSE; + bFirstChar = FALSE; } else if (c == '\n') { break; } @@ -62,11 +65,12 @@ GetInt(FreeImageIO *io, fi_handle handle) { if (c >= '0' && c <='9') { // we've found what we were looking for - break; } - if(!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING; + if(!io->read_proc(&c, 1, 1, handle)) { + throw FI_MSG_ERROR_PARSING; + } } // we're at the start of a number, continue until we hit a non-number @@ -76,10 +80,13 @@ GetInt(FreeImageIO *io, fi_handle handle) { while (1) { i = (i * 10) + (c - '0'); - if(!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING; + if(!io->read_proc(&c, 1, 1, handle)) { + throw FI_MSG_ERROR_PARSING; + } - if (c < '0' || c > '9') - break; + if (c < '0' || c > '9') { + break; + } } return i; diff --git a/plugins/AdvaImg/src/FreeImage/PluginRAW.cpp b/plugins/AdvaImg/src/FreeImage/PluginRAW.cpp index bf5d82169c..e9bd5bfa77 100644 --- a/plugins/AdvaImg/src/FreeImage/PluginRAW.cpp +++ b/plugins/AdvaImg/src/FreeImage/PluginRAW.cpp @@ -140,12 +140,72 @@ public: /** Convert a processed raw data array to a FIBITMAP +@param RawProcessor LibRaw handle containing the processed raw image +@return Returns the converted dib if successfull, returns NULL otherwise +*/ +static FIBITMAP * +libraw_ConvertProcessedRawToDib(LibRaw *RawProcessor) { + FIBITMAP *dib = NULL; + int width, height, colors, bpp; + + try { + int bgr = 0; // pixel copy order: RGB if (bgr == 0) and BGR otherwise + + // get image info + RawProcessor->get_mem_image_format(&width, &height, &colors, &bpp); + + // only 3-color images supported... + if(colors != 3) { + throw "LibRaw : only 3-color images supported"; + } + + if(bpp == 16) { + // allocate output dib + dib = FreeImage_AllocateT(FIT_RGB16, width, height); + if(!dib) { + throw FI_MSG_ERROR_DIB_MEMORY; + } + + } else if(bpp == 8) { +#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR + bgr = 1; // only useful for FIT_BITMAP types +#endif + + // allocate output dib + dib = FreeImage_AllocateT(FIT_BITMAP, width, height, 24); + if(!dib) { + throw FI_MSG_ERROR_DIB_MEMORY; + } + } + + // copy post-processed bitmap data into FIBITMAP buffer + if(RawProcessor->copy_mem_image(FreeImage_GetBits(dib), FreeImage_GetPitch(dib), bgr) != LIBRAW_SUCCESS) { + throw "LibRaw : failed to copy data into dib"; + } + + // flip vertically + FreeImage_FlipVertical(dib); + + return dib; + + } catch(const char *text) { + FreeImage_Unload(dib); + FreeImage_OutputMessageProc(s_format_id, text); + return NULL; + } +} + + +/** +Convert a processed raw image to a FIBITMAP @param image Processed raw image @return Returns the converted dib if successfull, returns NULL otherwise +@see libraw_LoadEmbeddedPreview */ static FIBITMAP * -libraw_ConvertToDib(libraw_processed_image_t *image) { +libraw_ConvertProcessedImageToDib(libraw_processed_image_t *image) { FIBITMAP *dib = NULL; + try { unsigned width = image->width; unsigned height = image->height; @@ -185,12 +245,14 @@ libraw_ConvertToDib(libraw_processed_image_t *image) { } } } + + return dib; } catch(const char *text) { + FreeImage_Unload(dib); FreeImage_OutputMessageProc(s_format_id, text); + return NULL; } - - return dib; } /** @@ -228,9 +290,9 @@ libraw_LoadEmbeddedPreview(LibRaw *RawProcessor, int flags) { dib = FreeImage_LoadFromMemory(fif, hmem, flags); // close the stream FreeImage_CloseMemory(hmem); - } else { + } else if((flags & FIF_LOAD_NOPIXELS) != FIF_LOAD_NOPIXELS) { // convert processed data to output dib - dib = libraw_ConvertToDib(thumb_image); + dib = libraw_ConvertProcessedImageToDib(thumb_image); } } else { throw "LibRaw : failed to run dcraw_make_mem_thumb"; @@ -262,7 +324,6 @@ Load raw data and convert to FIBITMAP static FIBITMAP * libraw_LoadRawData(LibRaw *RawProcessor, int bitspersample) { FIBITMAP *dib = NULL; - libraw_processed_image_t *processed_image = NULL; try { // set decoding parameters @@ -300,38 +361,119 @@ libraw_LoadRawData(LibRaw *RawProcessor, int bitspersample) { } // retrieve processed image - int error_code = 0; - processed_image = RawProcessor->dcraw_make_mem_image(&error_code); - if(processed_image) { - // type SHOULD be LIBRAW_IMAGE_BITMAP, but we'll check - if(processed_image->type != LIBRAW_IMAGE_BITMAP) { - throw "invalid image type"; + dib = libraw_ConvertProcessedRawToDib(RawProcessor); + + return dib; + + } catch(const char *text) { + FreeImage_OutputMessageProc(s_format_id, text); + return NULL; + } +} + +/** +Load the Bayer matrix (unprocessed raw data) as a FIT_UINT16 image. +Note that some formats don't have a Bayer matrix (e.g. Foveon, Canon sRAW, demosaiced DNG files). +@param RawProcessor Libraw handle +@return Returns the loaded dib if successfull, returns NULL otherwise +*/ +static FIBITMAP * +libraw_LoadUnprocessedData(LibRaw *RawProcessor) { + FIBITMAP *dib = NULL; + + try { + // unpack data + if(RawProcessor->unpack() != LIBRAW_SUCCESS) { + throw "LibRaw : failed to unpack data"; + } + + // check for a supported Bayer format + if(!(RawProcessor->imgdata.idata.filters || RawProcessor->imgdata.idata.colors == 1)) { + throw "LibRaw : only Bayer-pattern RAW files are supported"; + } + + // allocate output dib + const unsigned width = RawProcessor->imgdata.sizes.raw_width; + const unsigned height = RawProcessor->imgdata.sizes.raw_height; + const size_t line_size = width * sizeof(WORD); + const WORD *src_bits = (WORD*)RawProcessor->imgdata.rawdata.raw_image; + + if(src_bits) { + dib = FreeImage_AllocateT(FIT_UINT16, width, height); + } + if(!dib) { + throw FI_MSG_ERROR_DIB_MEMORY; + } + + // retrieve the raw image + for(unsigned y = 0; y < height; y++) { + WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dib, height - 1 - y); + memcpy(dst_bits, src_bits, line_size); + src_bits += width; + } + + // store metadata needed for post-processing + { + char value[512]; + + const libraw_image_sizes_t *sizes = &RawProcessor->imgdata.sizes; + + // image output width & height + { + sprintf(value, "%d", sizes->iwidth); + FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.Output.Width", value); + + sprintf(value, "%d", sizes->iheight); + FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.Output.Height", value); } - // only 3-color images supported... - if(processed_image->colors != 3) { - throw "only 3-color images supported"; + + // image output frame + { + const unsigned f_left = sizes->left_margin; + const unsigned f_top = sizes->top_margin; + const unsigned f_width = sizes->width; + const unsigned f_height = sizes->height; + + sprintf(value, "%d", f_left); + FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.Frame.Left", value); + + sprintf(value, "%d", f_top); + FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.Frame.Top", value); + + sprintf(value, "%d", f_width); + FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.Frame.Width", value); + + sprintf(value, "%d", f_height); + FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.Frame.Height", value); } - } else { - throw "LibRaw : failed to run dcraw_make_mem_image"; - } - // convert processed data to output dib - dib = libraw_ConvertToDib(processed_image); - - // clean-up and return - RawProcessor->dcraw_clear_mem(processed_image); + // Bayer pattern + // Mask describing the order of color pixels in the matrix. + // This field describe 16 pixels (8 rows with two pixels in each, from left to right and from top to bottom). + + if(RawProcessor->imgdata.idata.filters) { + // description of colors numbered from 0 to 3 (RGBG,RGBE,GMCY, or GBTG) + char *cdesc = RawProcessor->imgdata.idata.cdesc; + if(!cdesc[3]) { + cdesc[3] = 'G'; + } + char *pattern = &value[0]; + for(int i = 0; i < 16; i++) { + pattern[i] = cdesc[ RawProcessor->fcol(i >> 1, i & 1) ]; + } + pattern[16] = 0; + FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.BayerPattern", value); + } + } + return dib; } catch(const char *text) { - // clean-up and return - if(processed_image) { - RawProcessor->dcraw_clear_mem(processed_image); - } + FreeImage_Unload(dib); FreeImage_OutputMessageProc(s_format_id, text); + return NULL; } - - return NULL; } // ========================================================== @@ -397,8 +539,8 @@ Extension() { "sr2," // Sony Digital Camera Raw Image Format. "srf," // Sony Digital Camera Raw Image Format for DSC-F828 8 megapixel digital camera or Sony DSC-R1. "srw," // Samsung Raw Image Format. - "sti"; // Sinar Capture Shop Raw Image File. -// "x3f" // Sigma Digital Camera Raw Image Format for devices based on Foveon X3 direct image sensor. + "sti," // Sinar Capture Shop Raw Image File. + "x3f"; // Sigma Digital Camera Raw Image Format for devices based on Foveon X3 direct image sensor. return raw_extensions; } @@ -416,33 +558,37 @@ static BOOL HasMagicHeader(FreeImageIO *io, fi_handle handle) { const unsigned signature_size = 32; BYTE signature[signature_size] = { 0 }; - - // Canon (CR2), Intel byte order + /* + note: classic TIFF signature is + { 0x49, 0x49, 0x2A, 0x00 } Classic TIFF, little-endian + { 0x4D, 0x4D, 0x00, 0x2A } Classic TIFF, big-endian + */ + // Canon (CR2), little-endian byte order const BYTE CR2_II[] = { 0x49, 0x49, 0x2A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x43, 0x52, 0x02, 0x00 }; - // Canon (CR2), Motorola byte order - const BYTE CR2_MM[] = { 0x4D, 0x4D, 0x2A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x43, 0x52, 0x02, 0x00 }; - // Canon (CRW), Intel byte order - const BYTE CRW_II[] = { 0x49, 0x49, 0x1A, 0x00, 0x00, 0x00, 0x48, 0x45, 0x41, 0x50, 0x43, 0x43, 0x44, 0x52, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // Canon (CRW), little-endian byte order + const BYTE CRW_II[] = { 0x49, 0x49, 0x1A, 0x00, 0x00, 0x00, 0x48, 0x45, 0x41, 0x50, 0x43, 0x43, 0x44, 0x52, 0x02, 0x00 }; // Minolta (MRW) const BYTE MRW[] = { 0x00, 0x4D, 0x52, 0x4D, 0x00 }; - // Olympus (ORF), Intel byte order + // Olympus (ORF), little-endian byte order const BYTE ORF_IIRS[] = { 0x49, 0x49, 0x52, 0x53, 0x08, 0x00, 0x00, 0x00 }; const BYTE ORF_IIRO[] = { 0x49, 0x49, 0x52, 0x4F, 0x08, 0x00, 0x00, 0x00 }; - // Olympus (ORF), Motorola byte order + // Olympus (ORF), big-endian byte order const BYTE ORF_MMOR[] = { 0x4D, 0x4D, 0x4F, 0x52, 0x00, 0x00, 0x00, 0x08 }; // Fujifilm (RAF) - const BYTE RAF[] = { 0x46, 0x55, 0x4A, 0x49, 0x46, 0x49, 0x4C, 0x4D, 0x43, 0x43, 0x44, 0x2D, 0x52, 0x41, 0x57, 0x20, 0x30, 0x32, 0x30, 0x31 }; - // Panasonic (RW2) or Leica (RWL) - const BYTE RW2_II[] = { 0x49, 0x49, 0x55, 0x00, 0x18, 0x00, 0x00, 0x00, 0x88, 0xE7, 0x74, 0xD8, 0xF8, 0x25, 0x1D, 0x4D, 0x94, 0x7A, 0x6E, 0x77, 0x82, 0x2B, 0x5D, 0x6A }; + const BYTE RAF[] = { 0x46, 0x55, 0x4A, 0x49, 0x46, 0x49, 0x4C, 0x4D, 0x43, 0x43, 0x44, 0x2D, 0x52, 0x41, 0x57, 0x20 }; + // Panasonic (RW2) or Leica (RWL), little-endian byte order + const BYTE RWx_II[] = { 0x49, 0x49, 0x55, 0x00, 0x18, 0x00, 0x00, 0x00, 0x88, 0xE7, 0x74, 0xD8, 0xF8, 0x25, 0x1D, 0x4D, 0x94, 0x7A, 0x6E, 0x77, 0x82, 0x2B, 0x5D, 0x6A }; + // Panasonic (RAW) or Leica (RAW), little-endian byte order + const BYTE RAW_II[] = { 0x49, 0x49, 0x55, 0x00, 0x08, 0x00, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00 }; + // Foveon (X3F) + const BYTE X3F[] = { 0x46, 0x4F, 0x56, 0x62 }; if(io->read_proc(signature, 1, signature_size, handle) != signature_size) { return FALSE; } if(memcmp(CR2_II, signature, 12) == 0) return TRUE; - if(memcmp(CR2_MM, signature, 12) == 0) - return TRUE; - if(memcmp(CRW_II, signature, 26) == 0) + if(memcmp(CRW_II, signature, 16) == 0) return TRUE; if(memcmp(MRW, signature, 5) == 0) return TRUE; @@ -452,9 +598,13 @@ HasMagicHeader(FreeImageIO *io, fi_handle handle) { return TRUE; if(memcmp(ORF_MMOR, signature, 8) == 0) return TRUE; - if(memcmp(RAF, signature, 20) == 0) + if(memcmp(RAF, signature, 16) == 0) return TRUE; - if(memcmp(RW2_II, signature, 24) == 0) + if(memcmp(RWx_II, signature, 24) == 0) + return TRUE; + if(memcmp(RAW_II, signature, 18) == 0) + return TRUE; + if(memcmp(X3F, signature, 4) == 0) return TRUE; return FALSE; @@ -547,6 +697,8 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { RawProcessor->imgdata.params.shot_select = 0; // (-w) Use camera white balance, if possible (otherwise, fallback to auto_wb) RawProcessor->imgdata.params.use_camera_wb = 1; + // (-M) Use any color matrix from the camera metadata. This option only affects Olympus, Leaf, and Phase One cameras. + RawProcessor->imgdata.params.use_camera_matrix = 1; // (-h) outputs the image in 50% size RawProcessor->imgdata.params.half_size = ((flags & RAW_HALFSIZE) == RAW_HALFSIZE) ? 1 : 0; @@ -559,6 +711,10 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { // header only mode dib = FreeImage_AllocateHeaderT(header_only, FIT_RGB16, RawProcessor->imgdata.sizes.width, RawProcessor->imgdata.sizes.height); } + else if((flags & RAW_UNPROCESSED) == RAW_UNPROCESSED) { + // load raw data without post-processing (i.e. as a Bayer matrix) + dib = libraw_LoadUnprocessedData(RawProcessor); + } else if((flags & RAW_PREVIEW) == RAW_PREVIEW) { // try to get the embedded JPEG dib = libraw_LoadEmbeddedPreview(RawProcessor, 0); diff --git a/plugins/AdvaImg/src/FreeImage/PluginTARGA.cpp b/plugins/AdvaImg/src/FreeImage/PluginTARGA.cpp index f12d7286ce..84864308e0 100644 --- a/plugins/AdvaImg/src/FreeImage/PluginTARGA.cpp +++ b/plugins/AdvaImg/src/FreeImage/PluginTARGA.cpp @@ -39,20 +39,20 @@ #endif typedef struct tagTGAHEADER { - BYTE id_length; // ID length - BYTE color_map_type; // color map type - BYTE image_type; // image type - - WORD cm_first_entry; // first entry index - WORD cm_length; // color map length - BYTE cm_size; // color map entry size, in bits - - WORD is_xorigin; // X-origin of image - WORD is_yorigin; // Y-origin of image - WORD is_width; // image width - WORD is_height; // image height - BYTE is_pixel_depth; // pixel depth - BYTE is_image_descriptor; // image descriptor + BYTE id_length; //! length of the image ID field + BYTE color_map_type; //! whether a color map is included + BYTE image_type; //! compression and color types + + WORD cm_first_entry; //! first entry index (offset into the color map table) + WORD cm_length; //! color map length (number of entries) + BYTE cm_size; //! color map entry size, in bits (number of bits per pixel) + + WORD is_xorigin; //! X-origin of image (absolute coordinate of lower-left corner for displays where origin is at the lower left) + WORD is_yorigin; //! Y-origin of image (as for X-origin) + WORD is_width; //! image width + WORD is_height; //! image height + BYTE is_pixel_depth; //! bits per pixel + BYTE is_image_descriptor; //! image descriptor, bits 3-0 give the alpha channel depth, bits 5-4 give direction } TGAHEADER; typedef struct tagTGAEXTENSIONAREA { @@ -400,14 +400,14 @@ Validate(FreeImageIO *io, fi_handle handle) { } // if the color map type is 1 then we validate the map entry information... if(header.color_map_type > 0) { - // It doesn't make any sense if the first entry is larger than the color map table + // it doesn't make any sense if the first entry is larger than the color map table if(header.cm_first_entry >= header.cm_length) { return FALSE; } - } - // check header.cm_size, don't allow 0 or anything bigger than 32 - if(header.cm_size == 0 || header.cm_size > 32) { - return FALSE; + // check header.cm_size, don't allow 0 or anything bigger than 32 + if(header.cm_size == 0 || header.cm_size > 32) { + return FALSE; + } } // the width/height shouldn't be 0, right ? if(header.is_width == 0 || header.is_height == 0) { @@ -415,9 +415,9 @@ Validate(FreeImageIO *io, fi_handle handle) { } // let's now verify all the types that are supported by FreeImage (this is our final verification) switch(header.image_type) { - case TGA_CMAP : + case TGA_CMAP: case TGA_RGB: - case TGA_MONO : + case TGA_MONO: case TGA_RLECMAP: case TGA_RLERGB: case TGA_RLEMONO: @@ -435,8 +435,6 @@ Validate(FreeImageIO *io, fi_handle handle) { return FALSE; } } - - return FALSE; } static BOOL DLL_CALLCONV @@ -1339,7 +1337,7 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void header.is_width = (WORD)FreeImage_GetWidth(dib); header.is_height = (WORD)FreeImage_GetHeight(dib); header.is_pixel_depth = (BYTE)bpp; - header.is_image_descriptor = 0; + header.is_image_descriptor = (bpp == 32 ? 8 : 0); if (palette) { header.color_map_type = 1; diff --git a/plugins/AdvaImg/src/FreeImage/PluginTIFF.cpp b/plugins/AdvaImg/src/FreeImage/PluginTIFF.cpp index 4e502c56e8..1b454531c1 100644 --- a/plugins/AdvaImg/src/FreeImage/PluginTIFF.cpp +++ b/plugins/AdvaImg/src/FreeImage/PluginTIFF.cpp @@ -44,29 +44,22 @@ #include "FreeImageIO.h" #include "PSDParser.h" -// ---------------------------------------------------------- -// geotiff interface (see XTIFF.cpp) -// ---------------------------------------------------------- - -// Extended TIFF Directory GEO Tag Support +// -------------------------------------------------------------------------- +// GeoTIFF profile (see XTIFF.cpp) +// -------------------------------------------------------------------------- void XTIFFInitialize(); +BOOL tiff_read_geotiff_profile(TIFF *tif, FIBITMAP *dib); +BOOL tiff_write_geotiff_profile(TIFF *tif, FIBITMAP *dib); -// GeoTIFF profile -void tiff_read_geotiff_profile(TIFF *tif, FIBITMAP *dib); -void tiff_write_geotiff_profile(TIFF *tif, FIBITMAP *dib); - -// ---------------------------------------------------------- -// exif interface (see XTIFF.cpp) +// -------------------------------------------------------------------------- +// TIFF Exif profile (see XTIFF.cpp) // ---------------------------------------------------------- - -// TIFF Exif profile BOOL tiff_read_exif_tags(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib); BOOL tiff_write_exif_tags(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib); -// ---------------------------------------------------------- +// -------------------------------------------------------------------------- // LogLuv conversion functions interface (see TIFFLogLuv.cpp) -// ---------------------------------------------------------- - +// -------------------------------------------------------------------------- void tiff_ConvertLineXYZToRGB(BYTE *target, BYTE *source, double stonits, int width_in_pixels); void tiff_ConvertLineRGBToXYZ(BYTE *target, BYTE *source, int width_in_pixels); @@ -141,13 +134,13 @@ typedef struct { static tmsize_t _tiffReadProc(thandle_t handle, void *buf, tmsize_t size) { fi_TIFFIO *fio = (fi_TIFFIO*)handle; - return fio->io->read_proc(buf, size, 1, fio->handle) * size; + return fio->io->read_proc(buf, (unsigned)size, 1, fio->handle) * size; } static tmsize_t _tiffWriteProc(thandle_t handle, void *buf, tmsize_t size) { fi_TIFFIO *fio = (fi_TIFFIO*)handle; - return fio->io->write_proc(buf, size, 1, fio->handle) * size; + return fio->io->write_proc(buf, (unsigned)size, 1, fio->handle) * size; } static toff_t @@ -192,21 +185,12 @@ Open a TIFF file descriptor for reading or writing TIFF * TIFFFdOpen(thandle_t handle, const char *name, const char *mode) { TIFF *tif; - // Open the file; the callback will set everything up tif = TIFFClientOpen(name, mode, handle, _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc, _tiffSizeProc, _tiffMapProc, _tiffUnmapProc); - // Warning: tif_fd is declared as 'int' currently (see libTIFF), - // may result in incorrect file pointers inside libTIFF on - // 64bit machines (sizeof(int) != sizeof(long)). - // Needs to be fixed within libTIFF. - if (tif) { - tif->tif_fd = (long)handle; - } - return tif; } @@ -933,7 +917,6 @@ tiff_write_xmp_profile(TIFF *tiff, FIBITMAP *dib) { static BOOL tiff_write_exif_profile(TIFF *tiff, FIBITMAP *dib) { BOOL bResult = FALSE; - uint32 exif_offset = 0; // write EXIF_MAIN tags, EXIF_EXIF not supported yet bResult = tiff_write_exif_tags(tiff, TagLib::EXIF_MAIN, dib); @@ -1062,6 +1045,8 @@ Open(FreeImageIO *io, fi_handle handle, BOOL read) { if (read) { fio->tif = TIFFFdOpen((thandle_t)fio, "", "r"); } else { + // mode = "w" : write Classic TIFF + // mode = "w8" : write Big TIFF fio->tif = TIFFFdOpen((thandle_t)fio, "", "w"); } if(fio->tif == NULL) { @@ -1106,11 +1091,10 @@ PageCount(FreeImageIO *io, fi_handle handle, void *data) { check for uncommon bitspersample values (e.g. 10, 12, ...) @param photometric TIFFTAG_PHOTOMETRIC tiff tag @param bitspersample TIFFTAG_BITSPERSAMPLE tiff tag -@param samplesperpixel TIFFTAG_SAMPLESPERPIXEL tiff tag @return Returns FALSE if a uncommon bit-depth is encountered, returns TRUE otherwise */ static BOOL -IsValidBitsPerSample(uint16 photometric, uint16 bitspersample, uint16 samplesperpixel) { +IsValidBitsPerSample(uint16 photometric, uint16 bitspersample) { switch(bitspersample) { case 1: @@ -1131,7 +1115,12 @@ IsValidBitsPerSample(uint16 photometric, uint16 bitspersample, uint16 samplesper } break; case 32: - return TRUE; + if((photometric == PHOTOMETRIC_MINISWHITE) || (photometric == PHOTOMETRIC_MINISBLACK) || (photometric == PHOTOMETRIC_LOGLUV)) { + return TRUE; + } else { + return FALSE; + } + break; case 64: case 128: if(photometric == PHOTOMETRIC_MINISBLACK) { @@ -1376,7 +1365,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { // check for unsupported formats // --------------------------------------------------------------------------------- - if(IsValidBitsPerSample(photometric, bitspersample, samplesperpixel) == FALSE) { + if(IsValidBitsPerSample(photometric, bitspersample) == FALSE) { FreeImage_OutputMessageProc(s_format_id, "Unable to handle this format: bitspersample = %d, samplesperpixel = %d, photometric = %d", (int)bitspersample, (int)samplesperpixel, (int)photometric); @@ -2029,8 +2018,8 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { // calculate src line and dst pitch int dst_pitch = FreeImage_GetPitch(dib); - int tileRowSize = TIFFTileRowSize(tif); - int imageRowSize = TIFFScanlineSize(tif); + uint32 tileRowSize = (uint32)TIFFTileRowSize(tif); + uint32 imageRowSize = (uint32)TIFFScanlineSize(tif); // In the tiff file the lines are saved from up to down @@ -2038,11 +2027,10 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { BYTE *bits = FreeImage_GetScanLine(dib, height - 1); - uint32 x, y, rowSize; - for (y = 0; y < height; y += tileHeight) { + for (uint32 y = 0; y < height; y += tileHeight) { int32 nrows = (y + tileHeight > height ? height - y : tileHeight); - for (x = 0, rowSize = 0; x < width; x += tileWidth, rowSize += tileRowSize) { + for (uint32 x = 0, rowSize = 0; x < width; x += tileWidth, rowSize += tileRowSize) { memset(tileBuffer, 0, tileSize); // read one tile diff --git a/plugins/AdvaImg/src/FreeImage/WuQuantizer.cpp b/plugins/AdvaImg/src/FreeImage/WuQuantizer.cpp index 041eae368b..66d37066bf 100644 --- a/plugins/AdvaImg/src/FreeImage/WuQuantizer.cpp +++ b/plugins/AdvaImg/src/FreeImage/WuQuantizer.cpp @@ -108,22 +108,43 @@ WuQuantizer::Hist3D(LONG *vwt, LONG *vmr, LONG *vmg, LONG *vmb, float *m2, int R for(i = 0; i < 256; i++) table[i] = i * i; - for(y = 0; y < height; y++) { - BYTE *bits = FreeImage_GetScanLine(m_dib, y); - - for(x = 0; x < width; x++) { - inr = (bits[FI_RGBA_RED] >> 3) + 1; - ing = (bits[FI_RGBA_GREEN] >> 3) + 1; - inb = (bits[FI_RGBA_BLUE] >> 3) + 1; - ind = INDEX(inr, ing, inb); - Qadd[y*width + x] = (WORD)ind; - // [inr][ing][inb] - vwt[ind]++; - vmr[ind] += bits[FI_RGBA_RED]; - vmg[ind] += bits[FI_RGBA_GREEN]; - vmb[ind] += bits[FI_RGBA_BLUE]; - m2[ind] += (float)(table[bits[FI_RGBA_RED]] + table[bits[FI_RGBA_GREEN]] + table[bits[FI_RGBA_BLUE]]); - bits += 3; + if (FreeImage_GetBPP(m_dib) == 24) { + for(y = 0; y < height; y++) { + BYTE *bits = FreeImage_GetScanLine(m_dib, y); + + for(x = 0; x < width; x++) { + inr = (bits[FI_RGBA_RED] >> 3) + 1; + ing = (bits[FI_RGBA_GREEN] >> 3) + 1; + inb = (bits[FI_RGBA_BLUE] >> 3) + 1; + ind = INDEX(inr, ing, inb); + Qadd[y*width + x] = (WORD)ind; + // [inr][ing][inb] + vwt[ind]++; + vmr[ind] += bits[FI_RGBA_RED]; + vmg[ind] += bits[FI_RGBA_GREEN]; + vmb[ind] += bits[FI_RGBA_BLUE]; + m2[ind] += (float)(table[bits[FI_RGBA_RED]] + table[bits[FI_RGBA_GREEN]] + table[bits[FI_RGBA_BLUE]]); + bits += 3; + } + } + } else { + for(y = 0; y < height; y++) { + BYTE *bits = FreeImage_GetScanLine(m_dib, y); + + for(x = 0; x < width; x++) { + inr = (bits[FI_RGBA_RED] >> 3) + 1; + ing = (bits[FI_RGBA_GREEN] >> 3) + 1; + inb = (bits[FI_RGBA_BLUE] >> 3) + 1; + ind = INDEX(inr, ing, inb); + Qadd[y*width + x] = (WORD)ind; + // [inr][ing][inb] + vwt[ind]++; + vmr[ind] += bits[FI_RGBA_RED]; + vmg[ind] += bits[FI_RGBA_GREEN]; + vmb[ind] += bits[FI_RGBA_BLUE]; + m2[ind] += (float)(table[bits[FI_RGBA_RED]] + table[bits[FI_RGBA_GREEN]] + table[bits[FI_RGBA_BLUE]]); + bits += 4; + } } } |