summaryrefslogtreecommitdiff
path: root/plugins/AdvaImg/src/FreeImage
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/AdvaImg/src/FreeImage')
-rw-r--r--plugins/AdvaImg/src/FreeImage/BitmapAccess.cpp2573
-rw-r--r--plugins/AdvaImg/src/FreeImage/CacheFile.h92
-rw-r--r--plugins/AdvaImg/src/FreeImage/Conversion24.cpp504
-rw-r--r--plugins/AdvaImg/src/FreeImage/Conversion32.cpp690
-rw-r--r--plugins/AdvaImg/src/FreeImage/Conversion8.cpp610
-rw-r--r--plugins/AdvaImg/src/FreeImage/ConversionFloat.cpp386
-rw-r--r--plugins/AdvaImg/src/FreeImage/ConversionRGB16.cpp288
-rw-r--r--plugins/AdvaImg/src/FreeImage/ConversionRGBF.cpp484
-rw-r--r--plugins/AdvaImg/src/FreeImage/ConversionUINT16.cpp268
-rw-r--r--plugins/AdvaImg/src/FreeImage/J2KHelper.cpp1091
-rw-r--r--plugins/AdvaImg/src/FreeImage/J2KHelper.h36
-rw-r--r--plugins/AdvaImg/src/FreeImage/MultiPage.cpp1980
-rw-r--r--plugins/AdvaImg/src/FreeImage/PSDParser.cpp4
-rw-r--r--plugins/AdvaImg/src/FreeImage/PixelAccess.cpp420
-rw-r--r--plugins/AdvaImg/src/FreeImage/Plugin.cpp77
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginBMP.cpp118
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginGIF.cpp4
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginHDR.cpp2
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginICO.cpp3
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginJ2K.cpp666
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginJP2.cpp666
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginJPEG.cpp106
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginJXR.cpp1309
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginPNG.cpp2
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginSGI.cpp2
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginTARGA.cpp112
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginTIFF.cpp8
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginWebP.cpp698
-rw-r--r--plugins/AdvaImg/src/FreeImage/tmoColorConvert.cpp958
-rw-r--r--plugins/AdvaImg/src/FreeImage/tmoDrago03.cpp590
-rw-r--r--plugins/AdvaImg/src/FreeImage/tmoFattal02.cpp1378
31 files changed, 9104 insertions, 7021 deletions
diff --git a/plugins/AdvaImg/src/FreeImage/BitmapAccess.cpp b/plugins/AdvaImg/src/FreeImage/BitmapAccess.cpp
index 5b90ed8607..2ba5539d4c 100644
--- a/plugins/AdvaImg/src/FreeImage/BitmapAccess.cpp
+++ b/plugins/AdvaImg/src/FreeImage/BitmapAccess.cpp
@@ -1,1269 +1,1306 @@
-// ==========================================================
-// FreeImage implementation
-//
-// Design and implementation by
-// - Floris van den Berg (flvdberg@wxs.nl)
-// - Hervé Drolon (drolon@infonie.fr)
-// - Detlev Vendt (detlev.vendt@brillit.de)
-// - Petr Supina (psup@centrum.cz)
-// - Carsten Klein (c.klein@datagis.com)
-// - Mihail Naydenov (mnaydenov@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!
-// ==========================================================
-
-#ifdef _MSC_VER
-#pragma warning (disable : 4786) // identifier was truncated to 'number' characters
-#endif
-
-#include <stdlib.h>
-#if defined(_WIN32) || defined(_WIN64) || defined(__MINGW32__)
-#include <malloc.h>
-#endif // _WIN32 || _WIN64 || __MINGW32__
-
-#include "FreeImage.h"
-#include "FreeImageIO.h"
-#include "Utilities.h"
-
-#include "../Metadata/FreeImageTag.h"
-
-/** Constants for the BITMAPINFOHEADER::biCompression field */
-#ifndef _WINGDI_
-#define BI_RGB 0L
-#define BI_BITFIELDS 3L
-#endif // _WINGDI_
-
-// ----------------------------------------------------------
-// Metadata definitions
-// ----------------------------------------------------------
-
-// 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*>
-typedef std::map<int, TAGMAP*> METADATAMAP;
-
-// helper for metadata iterator
-FI_STRUCT (METADATAHEADER) {
- long pos; // current position when iterating the map
- TAGMAP *tagmap; // pointer to the tag map
-};
-
-// ----------------------------------------------------------
-// FIBITMAP definition
-// ----------------------------------------------------------
-
-FI_STRUCT (FREEIMAGEHEADER) {
- FREE_IMAGE_TYPE type; // data type - bitmap, array of long, double, complex, etc
-
- RGBQUAD bkgnd_color; // background color used for RGB transparency
-
- 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
-
- METADATAMAP *metadata; // contains a list of metadata models attached to the bitmap
-
- BOOL has_pixels; // FALSE if the FIBITMAP only contains the header and no pixel data
-
- FIBITMAP *thumbnail; // optionally contains a thumbnail attached to the bitmap
-
- //BYTE filler[1]; // fill to 32-bit alignment
-};
-
-// ----------------------------------------------------------
-// FREEIMAGERGBMASKS definition
-// ----------------------------------------------------------
-
-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
-};
-
-// ----------------------------------------------------------
-// Memory allocation on a specified alignment boundary
-// ----------------------------------------------------------
-
-#if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__)
-
-void* FreeImage_Aligned_Malloc(size_t amount, size_t alignment) {
- assert(alignment == FIBITMAP_ALIGNMENT);
- return _aligned_malloc(amount, alignment);
-}
-
-void FreeImage_Aligned_Free(void* mem) {
- _aligned_free(mem);
-}
-
-#elif defined (__MINGW32__)
-
-void* FreeImage_Aligned_Malloc(size_t amount, size_t alignment) {
- assert(alignment == FIBITMAP_ALIGNMENT);
- return __mingw_aligned_malloc (amount, alignment);
-}
-
-void FreeImage_Aligned_Free(void* mem) {
- __mingw_aligned_free (mem);
-}
-
-#else
-
-void* FreeImage_Aligned_Malloc(size_t amount, size_t alignment) {
- assert(alignment == FIBITMAP_ALIGNMENT);
- /*
- In some rare situations, the malloc routines can return misaligned memory.
- The routine FreeImage_Aligned_Malloc allocates a bit more memory to do
- aligned writes. Normally, it *should* allocate "alignment" extra memory and then writes
- one dword back the true pointer. But if the memory manager returns a
- misaligned block that is less than a dword from the next alignment,
- then the writing back one dword will corrupt memory.
-
- For example, suppose that alignment is 16 and malloc returns the address 0xFFFF.
-
- 16 - 0xFFFF % 16 + 0xFFFF = 16 - 15 + 0xFFFF = 0x10000.
-
- Now, you subtract one dword from that and write and that will corrupt memory.
-
- That's why the code below allocates *two* alignments instead of one.
- */
- void* mem_real = malloc(amount + 2 * alignment);
- if(!mem_real) return NULL;
- char* mem_align = (char*)((unsigned long)(2 * alignment - (unsigned long)mem_real % (unsigned long)alignment) + (unsigned long)mem_real);
- *((long*)mem_align - 1) = (long)mem_real;
- return mem_align;
-}
-
-void FreeImage_Aligned_Free(void* mem) {
- free((void*)*((long*)mem - 1));
-}
-
-#endif // _WIN32 || _WIN64
-
-// ----------------------------------------------------------
-// DIB information functions
-// ----------------------------------------------------------
-
-/**
-Calculate the size of a FreeImage image.
-Align the palette and the pixels on a FIBITMAP_ALIGNMENT bytes alignment boundary.
-
-@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
-*/
-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);
- // 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);
- 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;
-
- // check for possible malloc overflow using a KISS integer overflow detection mechanism
- {
- /*
- The following constant take into account the additionnal memory used by
- aligned malloc functions as well as debug malloc functions.
- It is supposed here that using a (8 * FIBITMAP_ALIGNMENT) risk margin will be enough
- 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;
- }
- }
- }
-
- return dib_size;
-}
-
-/**
+// ==========================================================
+// FreeImage implementation
+//
+// Design and implementation by
+// - Floris van den Berg (flvdberg@wxs.nl)
+// - Hervé Drolon (drolon@infonie.fr)
+// - Detlev Vendt (detlev.vendt@brillit.de)
+// - Petr Supina (psup@centrum.cz)
+// - Carsten Klein (c.klein@datagis.com)
+// - Mihail Naydenov (mnaydenov@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!
+// ==========================================================
+
+#ifdef _MSC_VER
+#pragma warning (disable : 4786) // identifier was truncated to 'number' characters
+#endif
+
+#include <stdlib.h>
+#if defined(_WIN32) || defined(_WIN64) || defined(__MINGW32__)
+#include <malloc.h>
+#endif // _WIN32 || _WIN64 || __MINGW32__
+
+#include "FreeImage.h"
+#include "FreeImageIO.h"
+#include "Utilities.h"
+
+#include "../Metadata/FreeImageTag.h"
+
+/** Constants for the BITMAPINFOHEADER::biCompression field */
+#ifndef _WINGDI_
+#define BI_RGB 0L
+#define BI_BITFIELDS 3L
+#endif // _WINGDI_
+
+// ----------------------------------------------------------
+// Metadata definitions
+// ----------------------------------------------------------
+
+// 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*>
+typedef std::map<int, TAGMAP*> METADATAMAP;
+
+// helper for metadata iterator
+FI_STRUCT (METADATAHEADER) {
+ long pos; // current position when iterating the map
+ TAGMAP *tagmap; // pointer to the tag map
+};
+
+// ----------------------------------------------------------
+// FIBITMAP definition
+// ----------------------------------------------------------
+
+FI_STRUCT (FREEIMAGEHEADER) {
+ FREE_IMAGE_TYPE type; // data type - bitmap, array of long, double, complex, etc
+
+ RGBQUAD bkgnd_color; // background color used for RGB transparency
+
+ 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
+
+ METADATAMAP *metadata; // contains a list of metadata models attached to the bitmap
+
+ BOOL has_pixels; // FALSE if the FIBITMAP only contains the header and no pixel data
+
+ FIBITMAP *thumbnail; // optionally contains a thumbnail attached to the bitmap
+
+ //BYTE filler[1]; // fill to 32-bit alignment
+};
+
+// ----------------------------------------------------------
+// FREEIMAGERGBMASKS definition
+// ----------------------------------------------------------
+
+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
+};
+
+// ----------------------------------------------------------
+// Memory allocation on a specified alignment boundary
+// ----------------------------------------------------------
+
+#if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__)
+
+void* FreeImage_Aligned_Malloc(size_t amount, size_t alignment) {
+ assert(alignment == FIBITMAP_ALIGNMENT);
+ return _aligned_malloc(amount, alignment);
+}
+
+void FreeImage_Aligned_Free(void* mem) {
+ _aligned_free(mem);
+}
+
+#elif defined (__MINGW32__)
+
+void* FreeImage_Aligned_Malloc(size_t amount, size_t alignment) {
+ assert(alignment == FIBITMAP_ALIGNMENT);
+ return __mingw_aligned_malloc (amount, alignment);
+}
+
+void FreeImage_Aligned_Free(void* mem) {
+ __mingw_aligned_free (mem);
+}
+
+#else
+
+void* FreeImage_Aligned_Malloc(size_t amount, size_t alignment) {
+ assert(alignment == FIBITMAP_ALIGNMENT);
+ /*
+ In some rare situations, the malloc routines can return misaligned memory.
+ The routine FreeImage_Aligned_Malloc allocates a bit more memory to do
+ aligned writes. Normally, it *should* allocate "alignment" extra memory and then writes
+ one dword back the true pointer. But if the memory manager returns a
+ misaligned block that is less than a dword from the next alignment,
+ then the writing back one dword will corrupt memory.
+
+ For example, suppose that alignment is 16 and malloc returns the address 0xFFFF.
+
+ 16 - 0xFFFF % 16 + 0xFFFF = 16 - 15 + 0xFFFF = 0x10000.
+
+ Now, you subtract one dword from that and write and that will corrupt memory.
+
+ That's why the code below allocates *two* alignments instead of one.
+ */
+ void* mem_real = malloc(amount + 2 * alignment);
+ if(!mem_real) return NULL;
+ char* mem_align = (char*)((unsigned long)(2 * alignment - (unsigned long)mem_real % (unsigned long)alignment) + (unsigned long)mem_real);
+ *((long*)mem_align - 1) = (long)mem_real;
+ return mem_align;
+}
+
+void FreeImage_Aligned_Free(void* mem) {
+ free((void*)*((long*)mem - 1));
+}
+
+#endif // _WIN32 || _WIN64
+
+// ----------------------------------------------------------
+// DIB information functions
+// ----------------------------------------------------------
+
+/**
+Calculate the size of a FreeImage image.
+Align the palette and the pixels on a FIBITMAP_ALIGNMENT bytes alignment boundary.
+
+@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
+*/
+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);
+ // 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);
+ 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;
+
+ // check for possible malloc overflow using a KISS integer overflow detection mechanism
+ {
+ /*
+ The following constant take into account the additionnal memory used by
+ aligned malloc functions as well as debug malloc functions.
+ It is supposed here that using a (8 * FIBITMAP_ALIGNMENT) risk margin will be enough
+ 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;
+ }
+ }
+ }
+
+ return dib_size;
+}
+
+/**
Helper for 16-bit FIT_BITMAP
-Returns a pointer to the bitmap's red-, green- and blue masks.
-@param dib The bitmap to obtain masks from.
-@return Returns a pointer to the bitmap's red-, green- and blue masks
-or NULL, if no masks are present (e.g. for 24 bit images).
-*/
-static FREEIMAGERGBMASKS *
-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) {
-
- // check input variables
- width = abs(width);
- height = abs(height);
- if(!((width > 0) && (height > 0))) {
- return NULL;
- }
-
- // we only store the masks (and allocate memory for
- // them) for 16 images of type FIT_BITMAP
- BOOL need_masks = FALSE;
-
- // check pixel bit depth
- switch(type) {
- case FIT_BITMAP:
- switch(bpp) {
- case 1:
- case 4:
- case 8:
- break;
- case 16:
- need_masks = TRUE;
- break;
- case 24:
- case 32:
- break;
- default:
- bpp = 8;
- break;
- }
- break;
- case FIT_UINT16:
- bpp = 8 * sizeof(unsigned short);
- break;
- case FIT_INT16:
- bpp = 8 * sizeof(short);
- break;
- case FIT_UINT32:
- bpp = 8 * sizeof(DWORD);
- break;
- case FIT_INT32:
- bpp = 8 * sizeof(LONG);
- break;
- case FIT_FLOAT:
- bpp = 8 * sizeof(float);
- break;
- case FIT_DOUBLE:
- bpp = 8 * sizeof(double);
- break;
- case FIT_COMPLEX:
- bpp = 8 * sizeof(FICOMPLEX);
- break;
- case FIT_RGB16:
- bpp = 8 * sizeof(FIRGB16);
- break;
- case FIT_RGBA16:
- bpp = 8 * sizeof(FIRGBA16);
- break;
- case FIT_RGBF:
- bpp = 8 * sizeof(FIRGBF);
- break;
- case FIT_RGBAF:
- bpp = 8 * sizeof(FIRGBAF);
- break;
- default:
- return NULL;
- }
-
- FIBITMAP *bitmap = (FIBITMAP *)malloc(sizeof(FIBITMAP));
-
- if (bitmap != NULL) {
-
- // calculate the size of a FreeImage 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
-
- size_t dib_size = FreeImage_GetImageSizeHeader(header_only, width, height, bpp, need_masks);
-
- if(dib_size == 0) {
- // memory allocation will fail (probably a malloc overflow)
- free(bitmap);
- return NULL;
- }
-
- bitmap->data = (BYTE *)FreeImage_Aligned_Malloc(dib_size * sizeof(BYTE), FIBITMAP_ALIGNMENT);
-
- if (bitmap->data != NULL) {
- memset(bitmap->data, 0, dib_size);
-
- // write out the FREEIMAGEHEADER
-
- FREEIMAGEHEADER *fih = (FREEIMAGEHEADER *)bitmap->data;
- fih->type = type;
-
- memset(&fih->bkgnd_color, 0, sizeof(RGBQUAD));
-
- fih->transparent = FALSE;
- fih->transparency_count = 0;
- memset(fih->transparent_table, 0xff, 256);
-
- fih->has_pixels = header_only ? FALSE : TRUE;
-
- // initialize FIICCPROFILE link
-
- FIICCPROFILE *iccProfile = FreeImage_GetICCProfile(bitmap);
- iccProfile->size = 0;
- iccProfile->data = 0;
- iccProfile->flags = 0;
-
- // initialize metadata models list
-
- fih->metadata = new(std::nothrow) METADATAMAP;
-
- // initialize attached thumbnail
-
- fih->thumbnail = NULL;
-
- // write out the BITMAPINFOHEADER
-
- BITMAPINFOHEADER *bih = FreeImage_GetInfoHeader(bitmap);
- bih->biSize = sizeof(BITMAPINFOHEADER);
- bih->biWidth = width;
- bih->biHeight = height;
- bih->biPlanes = 1;
- bih->biCompression = need_masks ? BI_BITFIELDS : BI_RGB;
- bih->biBitCount = (WORD)bpp;
- bih->biClrUsed = CalculateUsedPaletteEntries(bpp);
- bih->biClrImportant = bih->biClrUsed;
- bih->biXPelsPerMeter = 2835; // 72 dpi
- bih->biYPelsPerMeter = 2835; // 72 dpi
-
- if(bpp == 8) {
- // build a default greyscale palette (very useful for image processing)
- RGBQUAD *pal = FreeImage_GetPalette(bitmap);
- for(int i = 0; i < 256; i++) {
- pal[i].rgbRed = (BYTE)i;
- pal[i].rgbGreen = (BYTE)i;
- pal[i].rgbBlue = (BYTE)i;
- }
- }
-
- // just setting the masks (only if needed) just like the palette.
- if (need_masks) {
- FREEIMAGERGBMASKS *masks = FreeImage_GetRGBMasks(bitmap);
- masks->red_mask = red_mask;
- masks->green_mask = green_mask;
- masks->blue_mask = blue_mask;
- }
-
- return bitmap;
- }
-
- free(bitmap);
- }
-
- return NULL;
-}
-
-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);
-}
-
-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);
-}
-
-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);
-}
-
-void DLL_CALLCONV
-FreeImage_Unload(FIBITMAP *dib) {
- if (NULL != dib) {
- if (NULL != dib->data) {
- // delete possible icc profile ...
- if (FreeImage_GetICCProfile(dib)->data)
- free(FreeImage_GetICCProfile(dib)->data);
-
- // delete metadata models
- METADATAMAP *metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
-
- for(METADATAMAP::iterator i = (*metadata).begin(); i != (*metadata).end(); i++) {
- TAGMAP *tagmap = (*i).second;
-
- if(tagmap) {
- for(TAGMAP::iterator j = tagmap->begin(); j != tagmap->end(); j++) {
- FITAG *tag = (*j).second;
- FreeImage_DeleteTag(tag);
- }
-
- delete tagmap;
- }
- }
-
- delete metadata;
-
- // delete embedded thumbnail
- FreeImage_Unload(FreeImage_GetThumbnail(dib));
-
- // delete bitmap ...
- FreeImage_Aligned_Free(dib->data);
- }
- free(dib); // ... and the wrapper
- }
-}
-
-// ----------------------------------------------------------
-
-FIBITMAP * DLL_CALLCONV
-FreeImage_Clone(FIBITMAP *dib) {
- 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);
-
- // 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;
-
- // allocate a new dib
- FIBITMAP *new_dib = FreeImage_AllocateHeaderT(header_only, type, width, height, bpp,
- FreeImage_GetRedMask(dib), FreeImage_GetGreenMask(dib), FreeImage_GetBlueMask(dib));
-
- if (new_dib) {
- // save ICC profile links
- FIICCPROFILE *src_iccProfile = FreeImage_GetICCProfile(dib);
- FIICCPROFILE *dst_iccProfile = FreeImage_GetICCProfile(new_dib);
-
- // save metadata links
- METADATAMAP *src_metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
- METADATAMAP *dst_metadata = ((FREEIMAGEHEADER *)new_dib->data)->metadata;
-
- // calculate the size of a FreeImage 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
-
- size_t dib_size = FreeImage_GetImageSizeHeader(header_only, 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);
-
- // reset ICC profile link for new_dib
- memset(dst_iccProfile, 0, sizeof(FIICCPROFILE));
-
- // restore metadata link for new_dib
- ((FREEIMAGEHEADER *)new_dib->data)->metadata = dst_metadata;
-
- // reset thumbnail link for new_dib
- ((FREEIMAGEHEADER *)new_dib->data)->thumbnail = NULL;
-
- // copy possible ICC profile
- FreeImage_CreateICCProfile(new_dib, src_iccProfile->data, src_iccProfile->size);
- dst_iccProfile->flags = src_iccProfile->flags;
-
- // copy metadata models
- for(METADATAMAP::iterator i = (*src_metadata).begin(); i != (*src_metadata).end(); i++) {
- int model = (*i).first;
- TAGMAP *src_tagmap = (*i).second;
-
- if(src_tagmap) {
- // create a metadata model
- TAGMAP *dst_tagmap = new(std::nothrow) TAGMAP();
-
- if(dst_tagmap) {
- // fill the model
- for(TAGMAP::iterator j = src_tagmap->begin(); j != src_tagmap->end(); j++) {
- std::string dst_key = (*j).first;
- FITAG *dst_tag = FreeImage_CloneTag( (*j).second );
-
- // assign key and tag value
- (*dst_tagmap)[dst_key] = dst_tag;
- }
-
- // assign model and tagmap
- (*dst_metadata)[model] = dst_tagmap;
- }
- }
- }
-
- // copy the thumbnail
- FreeImage_SetThumbnail(new_dib, FreeImage_GetThumbnail(dib));
-
- return new_dib;
- }
-
- return NULL;
-}
-
-// ----------------------------------------------------------
-
-FIBITMAP* DLL_CALLCONV
-FreeImage_GetThumbnail(FIBITMAP *dib) {
- return (dib != NULL) ? ((FREEIMAGEHEADER *)dib->data)->thumbnail : NULL;
-}
-
-BOOL DLL_CALLCONV
-FreeImage_SetThumbnail(FIBITMAP *dib, FIBITMAP *thumbnail) {
- if(dib == NULL) {
- return FALSE;
- }
- FIBITMAP *currentThumbnail = ((FREEIMAGEHEADER *)dib->data)->thumbnail;
- if(currentThumbnail == thumbnail) {
- return TRUE;
- }
- FreeImage_Unload(currentThumbnail);
-
- ((FREEIMAGEHEADER *)dib->data)->thumbnail = FreeImage_HasPixels(thumbnail) ? FreeImage_Clone(thumbnail) : NULL;
-
- return TRUE;
-}
-
-// ----------------------------------------------------------
-
-FREE_IMAGE_COLOR_TYPE DLL_CALLCONV
-FreeImage_GetColorType(FIBITMAP *dib) {
- RGBQUAD *rgb;
-
- const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
-
- // special bitmap type
- if(image_type != FIT_BITMAP) {
- switch(image_type) {
- case FIT_RGB16:
- case FIT_RGBF:
- return FIC_RGB;
- case FIT_RGBA16:
- case FIT_RGBAF:
- return FIC_RGBALPHA;
- }
-
- return FIC_MINISBLACK;
- }
-
- // standard image type
- switch (FreeImage_GetBPP(dib)) {
- case 1:
- {
- rgb = FreeImage_GetPalette(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)) {
- rgb++;
-
- if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0))
- return FIC_MINISWHITE;
- }
-
- return FIC_PALETTE;
- }
-
- case 4:
- case 8: // Check if the DIB has a color or a greyscale palette
- {
- int ncolors = FreeImage_GetColorsUsed(dib);
- int minisblack = 1;
- rgb = FreeImage_GetPalette(dib);
-
- for (int i = 0; i < ncolors; i++) {
- 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)
- return FIC_PALETTE;
- else
- minisblack = 0;
- }
-
- rgb++;
- }
-
- return minisblack ? FIC_MINISBLACK : FIC_MINISWHITE;
- }
-
- case 16:
- case 24:
- return FIC_RGB;
-
- case 32:
- {
- 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;
- }
- return FIC_RGB;
- }
-
- return FIC_RGBALPHA;
- }
-
- default :
- return FIC_MINISBLACK;
- }
-}
-
-// ----------------------------------------------------------
-
-FREE_IMAGE_TYPE DLL_CALLCONV
-FreeImage_GetImageType(FIBITMAP *dib) {
- return (dib != NULL) ? ((FREEIMAGEHEADER *)dib->data)->type : FIT_UNKNOWN;
-}
-
-// ----------------------------------------------------------
-
-BOOL DLL_CALLCONV
-FreeImage_HasPixels(FIBITMAP *dib) {
- return (dib != NULL) ? ((FREEIMAGEHEADER *)dib->data)->has_pixels : FALSE;
-}
-
-// ----------------------------------------------------------
-
-BOOL DLL_CALLCONV
-FreeImage_HasRGBMasks(FIBITMAP *dib) {
- return dib && FreeImage_GetInfoHeader(dib)->biCompression == BI_BITFIELDS;
-}
-
-unsigned DLL_CALLCONV
-FreeImage_GetRedMask(FIBITMAP *dib) {
- FREEIMAGERGBMASKS *masks = FreeImage_GetRGBMasks(dib);
- return masks ? masks->red_mask : 0;
-}
-
-unsigned DLL_CALLCONV
-FreeImage_GetGreenMask(FIBITMAP *dib) {
- FREEIMAGERGBMASKS *masks = FreeImage_GetRGBMasks(dib);
- return masks ? masks->green_mask : 0;
-}
-
-unsigned DLL_CALLCONV
-FreeImage_GetBlueMask(FIBITMAP *dib) {
- FREEIMAGERGBMASKS *masks = FreeImage_GetRGBMasks(dib);
- return masks ? masks->blue_mask : 0;
-}
-
-// ----------------------------------------------------------
-
-BOOL DLL_CALLCONV
-FreeImage_HasBackgroundColor(FIBITMAP *dib) {
- if(dib) {
- RGBQUAD *bkgnd_color = &((FREEIMAGEHEADER *)dib->data)->bkgnd_color;
- return (bkgnd_color->rgbReserved != 0) ? TRUE : FALSE;
- }
- return FALSE;
-}
-
-BOOL DLL_CALLCONV
-FreeImage_GetBackgroundColor(FIBITMAP *dib, RGBQUAD *bkcolor) {
- if(dib && bkcolor) {
- if(FreeImage_HasBackgroundColor(dib)) {
- // get the background color
- RGBQUAD *bkgnd_color = &((FREEIMAGEHEADER *)dib->data)->bkgnd_color;
- memcpy(bkcolor, bkgnd_color, sizeof(RGBQUAD));
- // get the background index
- if(FreeImage_GetBPP(dib) == 8) {
- RGBQUAD *pal = FreeImage_GetPalette(dib);
- for(unsigned i = 0; i < FreeImage_GetColorsUsed(dib); i++) {
- if(bkgnd_color->rgbRed == pal[i].rgbRed) {
- if(bkgnd_color->rgbGreen == pal[i].rgbGreen) {
- if(bkgnd_color->rgbBlue == pal[i].rgbBlue) {
- bkcolor->rgbReserved = (BYTE)i;
- return TRUE;
- }
- }
- }
- }
- }
-
- bkcolor->rgbReserved = 0;
-
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-BOOL DLL_CALLCONV
-FreeImage_SetBackgroundColor(FIBITMAP *dib, RGBQUAD *bkcolor) {
- if(dib) {
- RGBQUAD *bkgnd_color = &((FREEIMAGEHEADER *)dib->data)->bkgnd_color;
- if(bkcolor) {
- // set the background color
- memcpy(bkgnd_color, bkcolor, sizeof(RGBQUAD));
- // enable the file background color
- bkgnd_color->rgbReserved = 1;
- } else {
- // clear and disable the file background color
- memset(bkgnd_color, 0, sizeof(RGBQUAD));
- }
- return TRUE;
- }
-
- return FALSE;
-}
-
-// ----------------------------------------------------------
-
-BOOL DLL_CALLCONV
-FreeImage_IsTransparent(FIBITMAP *dib) {
- if(dib) {
- FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
- switch(image_type) {
- case FIT_BITMAP:
- if(FreeImage_GetBPP(dib) == 32) {
- if(FreeImage_GetColorType(dib) == FIC_RGBALPHA) {
- return TRUE;
- }
- } else {
- return ((FREEIMAGEHEADER *)dib->data)->transparent ? TRUE : FALSE;
- }
- break;
- case FIT_RGBA16:
- case FIT_RGBAF:
- return TRUE;
- default:
- break;
- }
- }
- return FALSE;
-}
-
-BYTE * DLL_CALLCONV
-FreeImage_GetTransparencyTable(FIBITMAP *dib) {
- return dib ? ((FREEIMAGEHEADER *)dib->data)->transparent_table : NULL;
-}
-
-void DLL_CALLCONV
-FreeImage_SetTransparent(FIBITMAP *dib, BOOL enabled) {
- if (dib) {
- if ((FreeImage_GetBPP(dib) <= 8) || (FreeImage_GetBPP(dib) == 32)) {
- ((FREEIMAGEHEADER *)dib->data)->transparent = enabled;
- } else {
- ((FREEIMAGEHEADER *)dib->data)->transparent = FALSE;
- }
- }
-}
-
-unsigned DLL_CALLCONV
-FreeImage_GetTransparencyCount(FIBITMAP *dib) {
- return dib ? ((FREEIMAGEHEADER *)dib->data)->transparency_count : 0;
-}
-
-void DLL_CALLCONV
-FreeImage_SetTransparencyTable(FIBITMAP *dib, BYTE *table, int count) {
- if (dib) {
- count = MAX(0, MIN(count, 256));
- if (FreeImage_GetBPP(dib) <= 8) {
- ((FREEIMAGEHEADER *)dib->data)->transparent = (count > 0) ? TRUE : FALSE;
- ((FREEIMAGEHEADER *)dib->data)->transparency_count = count;
-
- if (table) {
- memcpy(((FREEIMAGEHEADER *)dib->data)->transparent_table, table, count);
- } else {
- memset(((FREEIMAGEHEADER *)dib->data)->transparent_table, 0xff, count);
- }
- }
- }
-}
-
-/** @brief Sets the index of the palette entry to be used as transparent color
- for the image specified. Does nothing on high color images.
-
- This method sets the index of the palette entry to be used as single transparent
- color for the image specified. This works on palletised images only and does
- nothing for high color images.
-
- Although it is possible for palletised images to have more than one transparent
- color, this method sets the palette entry specified as the single transparent
- color for the image. All other colors will be set to be non-transparent by this
- method.
-
- As with FreeImage_SetTransparencyTable(), this method also sets the image's
- transparency property to TRUE (as it is set and obtained by
- FreeImage_SetTransparent() and FreeImage_IsTransparent() respectively) for
- palletised images.
-
- @param dib Input image, whose transparent color is to be set.
- @param index The index of the palette entry to be set as transparent color.
- */
-void DLL_CALLCONV
-FreeImage_SetTransparentIndex(FIBITMAP *dib, int index) {
- if (dib) {
- int count = FreeImage_GetColorsUsed(dib);
- if (count) {
- BYTE *new_tt = (BYTE *)malloc(count * sizeof(BYTE));
- memset(new_tt, 0xFF, count);
- if ((index >= 0) && (index < count)) {
- new_tt[index] = 0x00;
- }
- FreeImage_SetTransparencyTable(dib, new_tt, count);
- free(new_tt);
- }
- }
-}
-
-/** @brief Returns the palette entry used as transparent color for the image
- specified. Works for palletised images only and returns -1 for high color
- images or if the image has no color set to be transparent.
-
- Although it is possible for palletised images to have more than one transparent
- color, this function always returns the index of the first palette entry, set
- to be transparent.
-
- @param dib Input image, whose transparent color is to be returned.
- @return Returns the index of the palette entry used as transparent color for
- the image specified or -1 if there is no transparent color found (e.g. the image
- is a high color image).
- */
-int DLL_CALLCONV
-FreeImage_GetTransparentIndex(FIBITMAP *dib) {
- int count = FreeImage_GetTransparencyCount(dib);
- BYTE *tt = FreeImage_GetTransparencyTable(dib);
- for (int i = 0; i < count; i++) {
- if (tt[i] == 0) {
- return i;
- }
- }
- return -1;
-}
-
-// ----------------------------------------------------------
-
-FIICCPROFILE * DLL_CALLCONV
-FreeImage_GetICCProfile(FIBITMAP *dib) {
- FIICCPROFILE *profile = (dib) ? (FIICCPROFILE *)&((FREEIMAGEHEADER *)dib->data)->iccProfile : NULL;
- return profile;
-}
-
-FIICCPROFILE * DLL_CALLCONV
-FreeImage_CreateICCProfile(FIBITMAP *dib, void *data, long size) {
- // clear the profile but preserve profile->flags
- FreeImage_DestroyICCProfile(dib);
- // create the new profile
- FIICCPROFILE *profile = FreeImage_GetICCProfile(dib);
- if(size && profile) {
- profile->data = malloc(size);
- if(profile->data) {
- memcpy(profile->data, data, profile->size = size);
- }
- }
- return profile;
-}
-
-void DLL_CALLCONV
-FreeImage_DestroyICCProfile(FIBITMAP *dib) {
- FIICCPROFILE *profile = FreeImage_GetICCProfile(dib);
- if(profile) {
- if (profile->data) {
- free (profile->data);
- }
- // clear the profile but preserve profile->flags
- profile->data = NULL;
- profile->size = 0;
- }
-}
-
-// ----------------------------------------------------------
-
-unsigned DLL_CALLCONV
-FreeImage_GetWidth(FIBITMAP *dib) {
- return dib ? FreeImage_GetInfoHeader(dib)->biWidth : 0;
-}
-
-unsigned DLL_CALLCONV
-FreeImage_GetHeight(FIBITMAP *dib) {
- return (dib) ? FreeImage_GetInfoHeader(dib)->biHeight : 0;
-}
-
-unsigned DLL_CALLCONV
-FreeImage_GetBPP(FIBITMAP *dib) {
- return dib ? FreeImage_GetInfoHeader(dib)->biBitCount : 0;
-}
-
-unsigned DLL_CALLCONV
-FreeImage_GetLine(FIBITMAP *dib) {
- return dib ? ((FreeImage_GetWidth(dib) * FreeImage_GetBPP(dib)) + 7) / 8 : 0;
-}
-
-unsigned DLL_CALLCONV
-FreeImage_GetPitch(FIBITMAP *dib) {
- return dib ? FreeImage_GetLine(dib) + 3 & ~3 : 0;
-}
-
-unsigned DLL_CALLCONV
-FreeImage_GetColorsUsed(FIBITMAP *dib) {
- return dib ? FreeImage_GetInfoHeader(dib)->biClrUsed : 0;
-}
-
-unsigned DLL_CALLCONV
-FreeImage_GetDIBSize(FIBITMAP *dib) {
- return (dib) ? sizeof(BITMAPINFOHEADER) + (FreeImage_GetColorsUsed(dib) * sizeof(RGBQUAD)) + (FreeImage_GetPitch(dib) * FreeImage_GetHeight(dib)) : 0;
-}
-
-RGBQUAD * DLL_CALLCONV
-FreeImage_GetPalette(FIBITMAP *dib) {
- return (dib && FreeImage_GetBPP(dib) < 16) ? (RGBQUAD *)(((BYTE *)FreeImage_GetInfoHeader(dib)) + sizeof(BITMAPINFOHEADER)) : NULL;
-}
-
-unsigned DLL_CALLCONV
-FreeImage_GetDotsPerMeterX(FIBITMAP *dib) {
- return (dib) ? FreeImage_GetInfoHeader(dib)->biXPelsPerMeter : 0;
-}
-
-unsigned DLL_CALLCONV
-FreeImage_GetDotsPerMeterY(FIBITMAP *dib) {
- return (dib) ? FreeImage_GetInfoHeader(dib)->biYPelsPerMeter : 0;
-}
-
-void DLL_CALLCONV
-FreeImage_SetDotsPerMeterX(FIBITMAP *dib, unsigned res) {
- if(dib) {
- FreeImage_GetInfoHeader(dib)->biXPelsPerMeter = res;
- }
-}
-
-void DLL_CALLCONV
-FreeImage_SetDotsPerMeterY(FIBITMAP *dib, unsigned res) {
- if(dib) {
- FreeImage_GetInfoHeader(dib)->biYPelsPerMeter = res;
- }
-}
-
-BITMAPINFOHEADER * DLL_CALLCONV
-FreeImage_GetInfoHeader(FIBITMAP *dib) {
- 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;
- return (BITMAPINFOHEADER *)lp;
-}
-
-BITMAPINFO * DLL_CALLCONV
-FreeImage_GetInfo(FIBITMAP *dib) {
- return (BITMAPINFO *)FreeImage_GetInfoHeader(dib);
-}
-
-// ----------------------------------------------------------
-// Metadata routines
-// ----------------------------------------------------------
-
-FIMETADATA * DLL_CALLCONV
-FreeImage_FindFirstMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, FITAG **tag) {
- if(!dib)
- return NULL;
-
- // get the metadata model
- METADATAMAP *metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
- TAGMAP *tagmap = NULL;
- if( (*metadata).find(model) != (*metadata).end() ) {
- tagmap = (*metadata)[model];
- }
- if(tagmap) {
- // allocate a handle
- FIMETADATA *handle = (FIMETADATA *)malloc(sizeof(FIMETADATA));
- if(handle) {
- // calculate the size of a METADATAHEADER
- int header_size = sizeof(METADATAHEADER);
-
- handle->data = (BYTE *)malloc(header_size * sizeof(BYTE));
-
- if(handle->data) {
- memset(handle->data, 0, header_size * sizeof(BYTE));
-
- // write out the METADATAHEADER
- METADATAHEADER *mdh = (METADATAHEADER *)handle->data;
-
- mdh->pos = 1;
- mdh->tagmap = tagmap;
-
- // get the first element
- TAGMAP::iterator i = tagmap->begin();
- *tag = (*i).second;
-
- return handle;
- }
-
- free(handle);
- }
- }
-
- return NULL;
-}
-
-BOOL DLL_CALLCONV
-FreeImage_FindNextMetadata(FIMETADATA *mdhandle, FITAG **tag) {
- if(!mdhandle)
- return FALSE;
-
- METADATAHEADER *mdh = (METADATAHEADER *)mdhandle->data;
- TAGMAP *tagmap = mdh->tagmap;
-
- int current_pos = mdh->pos;
- int mapsize = (int)tagmap->size();
-
- if(current_pos < mapsize) {
- // get the tag element at position pos
- int count = 0;
-
- for(TAGMAP::iterator i = tagmap->begin(); i != tagmap->end(); i++) {
- if(count == current_pos) {
- *tag = (*i).second;
- mdh->pos++;
- break;
- }
- count++;
- }
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-void DLL_CALLCONV
-FreeImage_FindCloseMetadata(FIMETADATA *mdhandle) {
- if (NULL != mdhandle) { // delete the handle
- if (NULL != mdhandle->data) {
- free(mdhandle->data);
- }
- free(mdhandle); // ... and the wrapper
- }
-}
-
-
-// ----------------------------------------------------------
-
-BOOL DLL_CALLCONV
-FreeImage_CloneMetadata(FIBITMAP *dst, FIBITMAP *src) {
- if(!src || !dst) return FALSE;
-
- // get metadata links
- METADATAMAP *src_metadata = ((FREEIMAGEHEADER *)src->data)->metadata;
- METADATAMAP *dst_metadata = ((FREEIMAGEHEADER *)dst->data)->metadata;
-
- // copy metadata models, *except* the FIMD_ANIMATION model
- for(METADATAMAP::iterator i = (*src_metadata).begin(); i != (*src_metadata).end(); i++) {
- int model = (*i).first;
- if(model == (int)FIMD_ANIMATION) {
- continue;
- }
- TAGMAP *src_tagmap = (*i).second;
-
- if(src_tagmap) {
- if( dst_metadata->find(model) != dst_metadata->end() ) {
- // destroy dst model
- FreeImage_SetMetadata((FREE_IMAGE_MDMODEL)model, dst, NULL, NULL);
- }
-
- // create a metadata model
- TAGMAP *dst_tagmap = new(std::nothrow) TAGMAP();
-
- if(dst_tagmap) {
- // fill the model
- for(TAGMAP::iterator j = src_tagmap->begin(); j != src_tagmap->end(); j++) {
- std::string dst_key = (*j).first;
- FITAG *dst_tag = FreeImage_CloneTag( (*j).second );
-
- // assign key and tag value
- (*dst_tagmap)[dst_key] = dst_tag;
- }
-
- // assign model and tagmap
- (*dst_metadata)[model] = dst_tagmap;
- }
- }
- }
-
- // clone resolution
- FreeImage_SetDotsPerMeterX(dst, FreeImage_GetDotsPerMeterX(src));
- FreeImage_SetDotsPerMeterY(dst, FreeImage_GetDotsPerMeterY(src));
-
- return TRUE;
-}
-
-// ----------------------------------------------------------
-
-BOOL DLL_CALLCONV
-FreeImage_SetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, FITAG *tag) {
- if(!dib)
- return FALSE;
-
- TAGMAP *tagmap = NULL;
-
- // get the metadata model
- METADATAMAP *metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
- METADATAMAP::iterator model_iterator = metadata->find(model);
- if (model_iterator != metadata->end()) {
- tagmap = model_iterator->second;
- }
-
- if(key != NULL) {
-
- if(!tagmap) {
- // this model, doesn't exist: create it
- tagmap = new(std::nothrow) TAGMAP();
- (*metadata)[model] = tagmap;
- }
-
- if(tag) {
- // first check the tag
- if(FreeImage_GetTagKey(tag) == NULL) {
- FreeImage_SetTagKey(tag, key);
- } else if(strcmp(key, FreeImage_GetTagKey(tag)) != 0) {
- // set the tag key
- FreeImage_SetTagKey(tag, key);
- }
- if(FreeImage_GetTagCount(tag) * FreeImage_TagDataWidth(FreeImage_GetTagType(tag)) != FreeImage_GetTagLength(tag)) {
- FreeImage_OutputMessageProc(FIF_UNKNOWN, "Invalid data count for tag '%s'", key);
- return FALSE;
- }
-
- // fill the tag ID if possible and if it's needed
- TagLib& tag_lib = TagLib::instance();
- switch(model) {
- case FIMD_IPTC:
- {
- int id = tag_lib.getTagID(TagLib::IPTC, key);
- /*
- if(id == -1) {
- FreeImage_OutputMessageProc(FIF_UNKNOWN, "IPTC: Invalid key '%s'", key);
- }
- */
- FreeImage_SetTagID(tag, (WORD)id);
- }
- break;
-
- default:
- break;
- }
-
- // delete existing tag
- FITAG *old_tag = (*tagmap)[key];
- if(old_tag) {
- FreeImage_DeleteTag(old_tag);
- }
-
- // create a new tag
- (*tagmap)[key] = FreeImage_CloneTag(tag);
- }
- else {
- // delete existing tag
- TAGMAP::iterator i = tagmap->find(key);
- if(i != tagmap->end()) {
- FITAG *old_tag = (*i).second;
- FreeImage_DeleteTag(old_tag);
- tagmap->erase(key);
- }
- }
- }
- else {
- // destroy the metadata model
- if(tagmap) {
- for(TAGMAP::iterator i = tagmap->begin(); i != tagmap->end(); i++) {
- FITAG *tag = (*i).second;
- FreeImage_DeleteTag(tag);
- }
-
- delete tagmap;
- metadata->erase(model_iterator);
- }
- }
-
- return TRUE;
-}
-
-BOOL DLL_CALLCONV
-FreeImage_GetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, FITAG **tag) {
- if(!dib || !key || !tag)
- return FALSE;
-
- TAGMAP *tagmap = NULL;
- *tag = NULL;
-
- // get the metadata model
- METADATAMAP *metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
- if(!(*metadata).empty()) {
- METADATAMAP::iterator model_iterator = metadata->find(model);
- if (model_iterator != metadata->end() ) {
- // this model exists : try to get the requested tag
- tagmap = model_iterator->second;
- TAGMAP::iterator tag_iterator = tagmap->find(key);
- if (tag_iterator != tagmap->end() ) {
- // get the requested tag
- *tag = tag_iterator->second;
- }
- }
- }
-
- return (*tag != NULL) ? TRUE : FALSE;
-}
-
-// ----------------------------------------------------------
-
-unsigned DLL_CALLCONV
-FreeImage_GetMetadataCount(FREE_IMAGE_MDMODEL model, FIBITMAP *dib) {
- if(!dib)
- return FALSE;
-
- TAGMAP *tagmap = NULL;
-
- // get the metadata model
- METADATAMAP *metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
- if( (*metadata).find(model) != (*metadata).end() ) {
- tagmap = (*metadata)[model];
- }
- if(!tagmap) {
- // this model, doesn't exist: return
- return 0;
- }
-
- // get the tag count
- return (unsigned)tagmap->size();
-}
-
-// ----------------------------------------------------------
-
-
+Returns a pointer to the bitmap's red-, green- and blue masks.
+@param dib The bitmap to obtain masks from.
+@return Returns a pointer to the bitmap's red-, green- and blue masks
+or NULL, if no masks are present (e.g. for 24 bit images).
+*/
+static FREEIMAGERGBMASKS *
+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) {
+
+ // check input variables
+ width = abs(width);
+ height = abs(height);
+ if(!((width > 0) && (height > 0))) {
+ return NULL;
+ }
+
+ // we only store the masks (and allocate memory for them) for 16-bit images of type FIT_BITMAP
+ BOOL need_masks = FALSE;
+
+ // check pixel bit depth
+ switch(type) {
+ case FIT_BITMAP:
+ switch(bpp) {
+ case 1:
+ case 4:
+ case 8:
+ break;
+ case 16:
+ need_masks = TRUE;
+ break;
+ case 24:
+ case 32:
+ break;
+ default:
+ bpp = 8;
+ break;
+ }
+ break;
+ case FIT_UINT16:
+ bpp = 8 * sizeof(unsigned short);
+ break;
+ case FIT_INT16:
+ bpp = 8 * sizeof(short);
+ break;
+ case FIT_UINT32:
+ bpp = 8 * sizeof(DWORD);
+ break;
+ case FIT_INT32:
+ bpp = 8 * sizeof(LONG);
+ break;
+ case FIT_FLOAT:
+ bpp = 8 * sizeof(float);
+ break;
+ case FIT_DOUBLE:
+ bpp = 8 * sizeof(double);
+ break;
+ case FIT_COMPLEX:
+ bpp = 8 * sizeof(FICOMPLEX);
+ break;
+ case FIT_RGB16:
+ bpp = 8 * sizeof(FIRGB16);
+ break;
+ case FIT_RGBA16:
+ bpp = 8 * sizeof(FIRGBA16);
+ break;
+ case FIT_RGBF:
+ bpp = 8 * sizeof(FIRGBF);
+ break;
+ case FIT_RGBAF:
+ bpp = 8 * sizeof(FIRGBAF);
+ break;
+ default:
+ return NULL;
+ }
+
+ FIBITMAP *bitmap = (FIBITMAP *)malloc(sizeof(FIBITMAP));
+
+ if (bitmap != NULL) {
+
+ // calculate the size of a FreeImage 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
+
+ size_t dib_size = FreeImage_GetImageSizeHeader(header_only, width, height, bpp, need_masks);
+
+ if(dib_size == 0) {
+ // memory allocation will fail (probably a malloc overflow)
+ free(bitmap);
+ return NULL;
+ }
+
+ bitmap->data = (BYTE *)FreeImage_Aligned_Malloc(dib_size * sizeof(BYTE), FIBITMAP_ALIGNMENT);
+
+ if (bitmap->data != NULL) {
+ memset(bitmap->data, 0, dib_size);
+
+ // write out the FREEIMAGEHEADER
+
+ FREEIMAGEHEADER *fih = (FREEIMAGEHEADER *)bitmap->data;
+ fih->type = type;
+
+ memset(&fih->bkgnd_color, 0, sizeof(RGBQUAD));
+
+ fih->transparent = FALSE;
+ fih->transparency_count = 0;
+ memset(fih->transparent_table, 0xff, 256);
+
+ fih->has_pixels = header_only ? FALSE : TRUE;
+
+ // initialize FIICCPROFILE link
+
+ FIICCPROFILE *iccProfile = FreeImage_GetICCProfile(bitmap);
+ iccProfile->size = 0;
+ iccProfile->data = 0;
+ iccProfile->flags = 0;
+
+ // initialize metadata models list
+
+ fih->metadata = new(std::nothrow) METADATAMAP;
+
+ // initialize attached thumbnail
+
+ fih->thumbnail = NULL;
+
+ // write out the BITMAPINFOHEADER
+
+ BITMAPINFOHEADER *bih = FreeImage_GetInfoHeader(bitmap);
+ bih->biSize = sizeof(BITMAPINFOHEADER);
+ bih->biWidth = width;
+ bih->biHeight = height;
+ bih->biPlanes = 1;
+ bih->biCompression = need_masks ? BI_BITFIELDS : BI_RGB;
+ bih->biBitCount = (WORD)bpp;
+ bih->biClrUsed = CalculateUsedPaletteEntries(bpp);
+ bih->biClrImportant = bih->biClrUsed;
+ bih->biXPelsPerMeter = 2835; // 72 dpi
+ bih->biYPelsPerMeter = 2835; // 72 dpi
+
+ if(bpp == 8) {
+ // build a default greyscale palette (very useful for image processing)
+ RGBQUAD *pal = FreeImage_GetPalette(bitmap);
+ for(int i = 0; i < 256; i++) {
+ pal[i].rgbRed = (BYTE)i;
+ pal[i].rgbGreen = (BYTE)i;
+ pal[i].rgbBlue = (BYTE)i;
+ }
+ }
+
+ // just setting the masks (only if needed) just like the palette.
+ if (need_masks) {
+ FREEIMAGERGBMASKS *masks = FreeImage_GetRGBMasks(bitmap);
+ masks->red_mask = red_mask;
+ masks->green_mask = green_mask;
+ masks->blue_mask = blue_mask;
+ }
+
+ return bitmap;
+ }
+
+ free(bitmap);
+ }
+
+ return NULL;
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+void DLL_CALLCONV
+FreeImage_Unload(FIBITMAP *dib) {
+ if (NULL != dib) {
+ if (NULL != dib->data) {
+ // delete possible icc profile ...
+ if (FreeImage_GetICCProfile(dib)->data)
+ free(FreeImage_GetICCProfile(dib)->data);
+
+ // delete metadata models
+ METADATAMAP *metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
+
+ for(METADATAMAP::iterator i = (*metadata).begin(); i != (*metadata).end(); i++) {
+ TAGMAP *tagmap = (*i).second;
+
+ if(tagmap) {
+ for(TAGMAP::iterator j = tagmap->begin(); j != tagmap->end(); j++) {
+ FITAG *tag = (*j).second;
+ FreeImage_DeleteTag(tag);
+ }
+
+ delete tagmap;
+ }
+ }
+
+ delete metadata;
+
+ // delete embedded thumbnail
+ FreeImage_Unload(FreeImage_GetThumbnail(dib));
+
+ // delete bitmap ...
+ FreeImage_Aligned_Free(dib->data);
+ }
+ free(dib); // ... and the wrapper
+ }
+}
+
+// ----------------------------------------------------------
+
+FIBITMAP * DLL_CALLCONV
+FreeImage_Clone(FIBITMAP *dib) {
+ 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);
+
+ // 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;
+
+ // allocate a new dib
+ FIBITMAP *new_dib = FreeImage_AllocateHeaderT(header_only, type, width, height, bpp,
+ FreeImage_GetRedMask(dib), FreeImage_GetGreenMask(dib), FreeImage_GetBlueMask(dib));
+
+ if (new_dib) {
+ // save ICC profile links
+ FIICCPROFILE *src_iccProfile = FreeImage_GetICCProfile(dib);
+ FIICCPROFILE *dst_iccProfile = FreeImage_GetICCProfile(new_dib);
+
+ // save metadata links
+ METADATAMAP *src_metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
+ METADATAMAP *dst_metadata = ((FREEIMAGEHEADER *)new_dib->data)->metadata;
+
+ // calculate the size of a FreeImage 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
+
+ size_t dib_size = FreeImage_GetImageSizeHeader(header_only, 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);
+
+ // reset ICC profile link for new_dib
+ memset(dst_iccProfile, 0, sizeof(FIICCPROFILE));
+
+ // restore metadata link for new_dib
+ ((FREEIMAGEHEADER *)new_dib->data)->metadata = dst_metadata;
+
+ // reset thumbnail link for new_dib
+ ((FREEIMAGEHEADER *)new_dib->data)->thumbnail = NULL;
+
+ // copy possible ICC profile
+ FreeImage_CreateICCProfile(new_dib, src_iccProfile->data, src_iccProfile->size);
+ dst_iccProfile->flags = src_iccProfile->flags;
+
+ // copy metadata models
+ for(METADATAMAP::iterator i = (*src_metadata).begin(); i != (*src_metadata).end(); i++) {
+ int model = (*i).first;
+ TAGMAP *src_tagmap = (*i).second;
+
+ if(src_tagmap) {
+ // create a metadata model
+ TAGMAP *dst_tagmap = new(std::nothrow) TAGMAP();
+
+ if(dst_tagmap) {
+ // fill the model
+ for(TAGMAP::iterator j = src_tagmap->begin(); j != src_tagmap->end(); j++) {
+ std::string dst_key = (*j).first;
+ FITAG *dst_tag = FreeImage_CloneTag( (*j).second );
+
+ // assign key and tag value
+ (*dst_tagmap)[dst_key] = dst_tag;
+ }
+
+ // assign model and tagmap
+ (*dst_metadata)[model] = dst_tagmap;
+ }
+ }
+ }
+
+ // copy the thumbnail
+ FreeImage_SetThumbnail(new_dib, FreeImage_GetThumbnail(dib));
+
+ return new_dib;
+ }
+
+ return NULL;
+}
+
+// ----------------------------------------------------------
+
+FIBITMAP* DLL_CALLCONV
+FreeImage_GetThumbnail(FIBITMAP *dib) {
+ return (dib != NULL) ? ((FREEIMAGEHEADER *)dib->data)->thumbnail : NULL;
+}
+
+BOOL DLL_CALLCONV
+FreeImage_SetThumbnail(FIBITMAP *dib, FIBITMAP *thumbnail) {
+ if(dib == NULL) {
+ return FALSE;
+ }
+ FIBITMAP *currentThumbnail = ((FREEIMAGEHEADER *)dib->data)->thumbnail;
+ if(currentThumbnail == thumbnail) {
+ return TRUE;
+ }
+ FreeImage_Unload(currentThumbnail);
+
+ ((FREEIMAGEHEADER *)dib->data)->thumbnail = FreeImage_HasPixels(thumbnail) ? FreeImage_Clone(thumbnail) : NULL;
+
+ return TRUE;
+}
+
+// ----------------------------------------------------------
+
+FREE_IMAGE_COLOR_TYPE DLL_CALLCONV
+FreeImage_GetColorType(FIBITMAP *dib) {
+ RGBQUAD *rgb;
+
+ const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
+
+ // special bitmap type
+ if(image_type != FIT_BITMAP) {
+ switch(image_type) {
+ case FIT_UINT16:
+ {
+ // 16-bit greyscale TIF can be either FIC_MINISBLACK (the most common case) or FIC_MINISWHITE
+ // you can check this using EXIF_MAIN metadata
+ FITAG *photometricTag = NULL;
+ if(FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, "PhotometricInterpretation", &photometricTag)) {
+ const short *value = (short*)FreeImage_GetTagValue(photometricTag);
+ // PHOTOMETRIC_MINISWHITE = 0 => min value is white
+ // PHOTOMETRIC_MINISBLACK = 1 => min value is black
+ return (*value == 0) ? FIC_MINISWHITE : FIC_MINISBLACK;
+ }
+ return FIC_MINISBLACK;
+ }
+ break;
+ case FIT_RGB16:
+ case FIT_RGBF:
+ return FIC_RGB;
+ case FIT_RGBA16:
+ case FIT_RGBAF:
+ return FIC_RGBALPHA;
+ }
+
+ return FIC_MINISBLACK;
+ }
+
+ // standard image type
+ switch (FreeImage_GetBPP(dib)) {
+ case 1:
+ {
+ rgb = FreeImage_GetPalette(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)) {
+ rgb++;
+
+ if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0))
+ return FIC_MINISWHITE;
+ }
+
+ return FIC_PALETTE;
+ }
+
+ case 4:
+ case 8: // Check if the DIB has a color or a greyscale palette
+ {
+ int ncolors = FreeImage_GetColorsUsed(dib);
+ int minisblack = 1;
+ rgb = FreeImage_GetPalette(dib);
+
+ for (int i = 0; i < ncolors; i++) {
+ 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)
+ return FIC_PALETTE;
+ else
+ minisblack = 0;
+ }
+
+ rgb++;
+ }
+
+ return minisblack ? FIC_MINISBLACK : FIC_MINISWHITE;
+ }
+
+ case 16:
+ case 24:
+ return FIC_RGB;
+
+ case 32:
+ {
+ 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;
+ }
+ return FIC_RGB;
+ }
+
+ return FIC_RGBALPHA;
+ }
+
+ default :
+ return FIC_MINISBLACK;
+ }
+}
+
+// ----------------------------------------------------------
+
+FREE_IMAGE_TYPE DLL_CALLCONV
+FreeImage_GetImageType(FIBITMAP *dib) {
+ return (dib != NULL) ? ((FREEIMAGEHEADER *)dib->data)->type : FIT_UNKNOWN;
+}
+
+// ----------------------------------------------------------
+
+BOOL DLL_CALLCONV
+FreeImage_HasPixels(FIBITMAP *dib) {
+ return (dib != NULL) ? ((FREEIMAGEHEADER *)dib->data)->has_pixels : FALSE;
+}
+
+// ----------------------------------------------------------
+
+BOOL DLL_CALLCONV
+FreeImage_HasRGBMasks(FIBITMAP *dib) {
+ return dib && FreeImage_GetInfoHeader(dib)->biCompression == BI_BITFIELDS;
+}
+
+unsigned DLL_CALLCONV
+FreeImage_GetRedMask(FIBITMAP *dib) {
+ FREEIMAGERGBMASKS *masks = NULL;
+ FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
+ switch(image_type) {
+ case FIT_BITMAP:
+ // check for 16-bit RGB (565 or 555)
+ masks = FreeImage_GetRGBMasks(dib);
+ return masks ? masks->red_mask : FI_RGBA_RED_MASK;
+ default:
+ return 0;
+ }
+}
+
+unsigned DLL_CALLCONV
+FreeImage_GetGreenMask(FIBITMAP *dib) {
+ FREEIMAGERGBMASKS *masks = NULL;
+ FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
+ switch(image_type) {
+ case FIT_BITMAP:
+ // check for 16-bit RGB (565 or 555)
+ masks = FreeImage_GetRGBMasks(dib);
+ return masks ? masks->green_mask : FI_RGBA_GREEN_MASK;
+ default:
+ return 0;
+ }
+}
+
+unsigned DLL_CALLCONV
+FreeImage_GetBlueMask(FIBITMAP *dib) {
+ FREEIMAGERGBMASKS *masks = NULL;
+ FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
+ switch(image_type) {
+ case FIT_BITMAP:
+ // check for 16-bit RGB (565 or 555)
+ masks = FreeImage_GetRGBMasks(dib);
+ return masks ? masks->blue_mask : FI_RGBA_BLUE_MASK;
+ default:
+ return 0;
+ }
+}
+
+// ----------------------------------------------------------
+
+BOOL DLL_CALLCONV
+FreeImage_HasBackgroundColor(FIBITMAP *dib) {
+ if(dib) {
+ RGBQUAD *bkgnd_color = &((FREEIMAGEHEADER *)dib->data)->bkgnd_color;
+ return (bkgnd_color->rgbReserved != 0) ? TRUE : FALSE;
+ }
+ return FALSE;
+}
+
+BOOL DLL_CALLCONV
+FreeImage_GetBackgroundColor(FIBITMAP *dib, RGBQUAD *bkcolor) {
+ if(dib && bkcolor) {
+ if(FreeImage_HasBackgroundColor(dib)) {
+ // get the background color
+ RGBQUAD *bkgnd_color = &((FREEIMAGEHEADER *)dib->data)->bkgnd_color;
+ memcpy(bkcolor, bkgnd_color, sizeof(RGBQUAD));
+ // get the background index
+ if(FreeImage_GetBPP(dib) == 8) {
+ RGBQUAD *pal = FreeImage_GetPalette(dib);
+ for(unsigned i = 0; i < FreeImage_GetColorsUsed(dib); i++) {
+ if(bkgnd_color->rgbRed == pal[i].rgbRed) {
+ if(bkgnd_color->rgbGreen == pal[i].rgbGreen) {
+ if(bkgnd_color->rgbBlue == pal[i].rgbBlue) {
+ bkcolor->rgbReserved = (BYTE)i;
+ return TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ bkcolor->rgbReserved = 0;
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+BOOL DLL_CALLCONV
+FreeImage_SetBackgroundColor(FIBITMAP *dib, RGBQUAD *bkcolor) {
+ if(dib) {
+ RGBQUAD *bkgnd_color = &((FREEIMAGEHEADER *)dib->data)->bkgnd_color;
+ if(bkcolor) {
+ // set the background color
+ memcpy(bkgnd_color, bkcolor, sizeof(RGBQUAD));
+ // enable the file background color
+ bkgnd_color->rgbReserved = 1;
+ } else {
+ // clear and disable the file background color
+ memset(bkgnd_color, 0, sizeof(RGBQUAD));
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// ----------------------------------------------------------
+
+BOOL DLL_CALLCONV
+FreeImage_IsTransparent(FIBITMAP *dib) {
+ if(dib) {
+ FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
+ switch(image_type) {
+ case FIT_BITMAP:
+ if(FreeImage_GetBPP(dib) == 32) {
+ if(FreeImage_GetColorType(dib) == FIC_RGBALPHA) {
+ return TRUE;
+ }
+ } else {
+ return ((FREEIMAGEHEADER *)dib->data)->transparent ? TRUE : FALSE;
+ }
+ break;
+ case FIT_RGBA16:
+ case FIT_RGBAF:
+ return TRUE;
+ default:
+ break;
+ }
+ }
+ return FALSE;
+}
+
+BYTE * DLL_CALLCONV
+FreeImage_GetTransparencyTable(FIBITMAP *dib) {
+ return dib ? ((FREEIMAGEHEADER *)dib->data)->transparent_table : NULL;
+}
+
+void DLL_CALLCONV
+FreeImage_SetTransparent(FIBITMAP *dib, BOOL enabled) {
+ if (dib) {
+ if ((FreeImage_GetBPP(dib) <= 8) || (FreeImage_GetBPP(dib) == 32)) {
+ ((FREEIMAGEHEADER *)dib->data)->transparent = enabled;
+ } else {
+ ((FREEIMAGEHEADER *)dib->data)->transparent = FALSE;
+ }
+ }
+}
+
+unsigned DLL_CALLCONV
+FreeImage_GetTransparencyCount(FIBITMAP *dib) {
+ return dib ? ((FREEIMAGEHEADER *)dib->data)->transparency_count : 0;
+}
+
+void DLL_CALLCONV
+FreeImage_SetTransparencyTable(FIBITMAP *dib, BYTE *table, int count) {
+ if (dib) {
+ count = MAX(0, MIN(count, 256));
+ if (FreeImage_GetBPP(dib) <= 8) {
+ ((FREEIMAGEHEADER *)dib->data)->transparent = (count > 0) ? TRUE : FALSE;
+ ((FREEIMAGEHEADER *)dib->data)->transparency_count = count;
+
+ if (table) {
+ memcpy(((FREEIMAGEHEADER *)dib->data)->transparent_table, table, count);
+ } else {
+ memset(((FREEIMAGEHEADER *)dib->data)->transparent_table, 0xff, count);
+ }
+ }
+ }
+}
+
+/** @brief Sets the index of the palette entry to be used as transparent color
+ for the image specified. Does nothing on high color images.
+
+ This method sets the index of the palette entry to be used as single transparent
+ color for the image specified. This works on palletised images only and does
+ nothing for high color images.
+
+ Although it is possible for palletised images to have more than one transparent
+ color, this method sets the palette entry specified as the single transparent
+ color for the image. All other colors will be set to be non-transparent by this
+ method.
+
+ As with FreeImage_SetTransparencyTable(), this method also sets the image's
+ transparency property to TRUE (as it is set and obtained by
+ FreeImage_SetTransparent() and FreeImage_IsTransparent() respectively) for
+ palletised images.
+
+ @param dib Input image, whose transparent color is to be set.
+ @param index The index of the palette entry to be set as transparent color.
+ */
+void DLL_CALLCONV
+FreeImage_SetTransparentIndex(FIBITMAP *dib, int index) {
+ if (dib) {
+ int count = FreeImage_GetColorsUsed(dib);
+ if (count) {
+ BYTE *new_tt = (BYTE *)malloc(count * sizeof(BYTE));
+ memset(new_tt, 0xFF, count);
+ if ((index >= 0) && (index < count)) {
+ new_tt[index] = 0x00;
+ }
+ FreeImage_SetTransparencyTable(dib, new_tt, count);
+ free(new_tt);
+ }
+ }
+}
+
+/** @brief Returns the palette entry used as transparent color for the image
+ specified. Works for palletised images only and returns -1 for high color
+ images or if the image has no color set to be transparent.
+
+ Although it is possible for palletised images to have more than one transparent
+ color, this function always returns the index of the first palette entry, set
+ to be transparent.
+
+ @param dib Input image, whose transparent color is to be returned.
+ @return Returns the index of the palette entry used as transparent color for
+ the image specified or -1 if there is no transparent color found (e.g. the image
+ is a high color image).
+ */
+int DLL_CALLCONV
+FreeImage_GetTransparentIndex(FIBITMAP *dib) {
+ int count = FreeImage_GetTransparencyCount(dib);
+ BYTE *tt = FreeImage_GetTransparencyTable(dib);
+ for (int i = 0; i < count; i++) {
+ if (tt[i] == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+// ----------------------------------------------------------
+
+FIICCPROFILE * DLL_CALLCONV
+FreeImage_GetICCProfile(FIBITMAP *dib) {
+ FIICCPROFILE *profile = (dib) ? (FIICCPROFILE *)&((FREEIMAGEHEADER *)dib->data)->iccProfile : NULL;
+ return profile;
+}
+
+FIICCPROFILE * DLL_CALLCONV
+FreeImage_CreateICCProfile(FIBITMAP *dib, void *data, long size) {
+ // clear the profile but preserve profile->flags
+ FreeImage_DestroyICCProfile(dib);
+ // create the new profile
+ FIICCPROFILE *profile = FreeImage_GetICCProfile(dib);
+ if(size && profile) {
+ profile->data = malloc(size);
+ if(profile->data) {
+ memcpy(profile->data, data, profile->size = size);
+ }
+ }
+ return profile;
+}
+
+void DLL_CALLCONV
+FreeImage_DestroyICCProfile(FIBITMAP *dib) {
+ FIICCPROFILE *profile = FreeImage_GetICCProfile(dib);
+ if(profile) {
+ if (profile->data) {
+ free (profile->data);
+ }
+ // clear the profile but preserve profile->flags
+ profile->data = NULL;
+ profile->size = 0;
+ }
+}
+
+// ----------------------------------------------------------
+
+unsigned DLL_CALLCONV
+FreeImage_GetWidth(FIBITMAP *dib) {
+ return dib ? FreeImage_GetInfoHeader(dib)->biWidth : 0;
+}
+
+unsigned DLL_CALLCONV
+FreeImage_GetHeight(FIBITMAP *dib) {
+ return (dib) ? FreeImage_GetInfoHeader(dib)->biHeight : 0;
+}
+
+unsigned DLL_CALLCONV
+FreeImage_GetBPP(FIBITMAP *dib) {
+ return dib ? FreeImage_GetInfoHeader(dib)->biBitCount : 0;
+}
+
+unsigned DLL_CALLCONV
+FreeImage_GetLine(FIBITMAP *dib) {
+ return dib ? ((FreeImage_GetWidth(dib) * FreeImage_GetBPP(dib)) + 7) / 8 : 0;
+}
+
+unsigned DLL_CALLCONV
+FreeImage_GetPitch(FIBITMAP *dib) {
+ return dib ? FreeImage_GetLine(dib) + 3 & ~3 : 0;
+}
+
+unsigned DLL_CALLCONV
+FreeImage_GetColorsUsed(FIBITMAP *dib) {
+ return dib ? FreeImage_GetInfoHeader(dib)->biClrUsed : 0;
+}
+
+unsigned DLL_CALLCONV
+FreeImage_GetDIBSize(FIBITMAP *dib) {
+ return (dib) ? sizeof(BITMAPINFOHEADER) + (FreeImage_GetColorsUsed(dib) * sizeof(RGBQUAD)) + (FreeImage_GetPitch(dib) * FreeImage_GetHeight(dib)) : 0;
+}
+
+RGBQUAD * DLL_CALLCONV
+FreeImage_GetPalette(FIBITMAP *dib) {
+ return (dib && FreeImage_GetBPP(dib) < 16) ? (RGBQUAD *)(((BYTE *)FreeImage_GetInfoHeader(dib)) + sizeof(BITMAPINFOHEADER)) : NULL;
+}
+
+unsigned DLL_CALLCONV
+FreeImage_GetDotsPerMeterX(FIBITMAP *dib) {
+ return (dib) ? FreeImage_GetInfoHeader(dib)->biXPelsPerMeter : 0;
+}
+
+unsigned DLL_CALLCONV
+FreeImage_GetDotsPerMeterY(FIBITMAP *dib) {
+ return (dib) ? FreeImage_GetInfoHeader(dib)->biYPelsPerMeter : 0;
+}
+
+void DLL_CALLCONV
+FreeImage_SetDotsPerMeterX(FIBITMAP *dib, unsigned res) {
+ if(dib) {
+ FreeImage_GetInfoHeader(dib)->biXPelsPerMeter = res;
+ }
+}
+
+void DLL_CALLCONV
+FreeImage_SetDotsPerMeterY(FIBITMAP *dib, unsigned res) {
+ if(dib) {
+ FreeImage_GetInfoHeader(dib)->biYPelsPerMeter = res;
+ }
+}
+
+BITMAPINFOHEADER * DLL_CALLCONV
+FreeImage_GetInfoHeader(FIBITMAP *dib) {
+ 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;
+ return (BITMAPINFOHEADER *)lp;
+}
+
+BITMAPINFO * DLL_CALLCONV
+FreeImage_GetInfo(FIBITMAP *dib) {
+ return (BITMAPINFO *)FreeImage_GetInfoHeader(dib);
+}
+
+// ----------------------------------------------------------
+// Metadata routines
+// ----------------------------------------------------------
+
+FIMETADATA * DLL_CALLCONV
+FreeImage_FindFirstMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, FITAG **tag) {
+ if(!dib)
+ return NULL;
+
+ // get the metadata model
+ METADATAMAP *metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
+ TAGMAP *tagmap = NULL;
+ if( (*metadata).find(model) != (*metadata).end() ) {
+ tagmap = (*metadata)[model];
+ }
+ if(tagmap) {
+ // allocate a handle
+ FIMETADATA *handle = (FIMETADATA *)malloc(sizeof(FIMETADATA));
+ if(handle) {
+ // calculate the size of a METADATAHEADER
+ int header_size = sizeof(METADATAHEADER);
+
+ handle->data = (BYTE *)malloc(header_size * sizeof(BYTE));
+
+ if(handle->data) {
+ memset(handle->data, 0, header_size * sizeof(BYTE));
+
+ // write out the METADATAHEADER
+ METADATAHEADER *mdh = (METADATAHEADER *)handle->data;
+
+ mdh->pos = 1;
+ mdh->tagmap = tagmap;
+
+ // get the first element
+ TAGMAP::iterator i = tagmap->begin();
+ *tag = (*i).second;
+
+ return handle;
+ }
+
+ free(handle);
+ }
+ }
+
+ return NULL;
+}
+
+BOOL DLL_CALLCONV
+FreeImage_FindNextMetadata(FIMETADATA *mdhandle, FITAG **tag) {
+ if(!mdhandle)
+ return FALSE;
+
+ METADATAHEADER *mdh = (METADATAHEADER *)mdhandle->data;
+ TAGMAP *tagmap = mdh->tagmap;
+
+ int current_pos = mdh->pos;
+ int mapsize = (int)tagmap->size();
+
+ if(current_pos < mapsize) {
+ // get the tag element at position pos
+ int count = 0;
+
+ for(TAGMAP::iterator i = tagmap->begin(); i != tagmap->end(); i++) {
+ if(count == current_pos) {
+ *tag = (*i).second;
+ mdh->pos++;
+ break;
+ }
+ count++;
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void DLL_CALLCONV
+FreeImage_FindCloseMetadata(FIMETADATA *mdhandle) {
+ if (NULL != mdhandle) { // delete the handle
+ if (NULL != mdhandle->data) {
+ free(mdhandle->data);
+ }
+ free(mdhandle); // ... and the wrapper
+ }
+}
+
+
+// ----------------------------------------------------------
+
+BOOL DLL_CALLCONV
+FreeImage_CloneMetadata(FIBITMAP *dst, FIBITMAP *src) {
+ if(!src || !dst) return FALSE;
+
+ // get metadata links
+ METADATAMAP *src_metadata = ((FREEIMAGEHEADER *)src->data)->metadata;
+ METADATAMAP *dst_metadata = ((FREEIMAGEHEADER *)dst->data)->metadata;
+
+ // copy metadata models, *except* the FIMD_ANIMATION model
+ for(METADATAMAP::iterator i = (*src_metadata).begin(); i != (*src_metadata).end(); i++) {
+ int model = (*i).first;
+ if(model == (int)FIMD_ANIMATION) {
+ continue;
+ }
+ TAGMAP *src_tagmap = (*i).second;
+
+ if(src_tagmap) {
+ if( dst_metadata->find(model) != dst_metadata->end() ) {
+ // destroy dst model
+ FreeImage_SetMetadata((FREE_IMAGE_MDMODEL)model, dst, NULL, NULL);
+ }
+
+ // create a metadata model
+ TAGMAP *dst_tagmap = new(std::nothrow) TAGMAP();
+
+ if(dst_tagmap) {
+ // fill the model
+ for(TAGMAP::iterator j = src_tagmap->begin(); j != src_tagmap->end(); j++) {
+ std::string dst_key = (*j).first;
+ FITAG *dst_tag = FreeImage_CloneTag( (*j).second );
+
+ // assign key and tag value
+ (*dst_tagmap)[dst_key] = dst_tag;
+ }
+
+ // assign model and tagmap
+ (*dst_metadata)[model] = dst_tagmap;
+ }
+ }
+ }
+
+ // clone resolution
+ FreeImage_SetDotsPerMeterX(dst, FreeImage_GetDotsPerMeterX(src));
+ FreeImage_SetDotsPerMeterY(dst, FreeImage_GetDotsPerMeterY(src));
+
+ return TRUE;
+}
+
+// ----------------------------------------------------------
+
+BOOL DLL_CALLCONV
+FreeImage_SetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, FITAG *tag) {
+ if(!dib)
+ return FALSE;
+
+ TAGMAP *tagmap = NULL;
+
+ // get the metadata model
+ METADATAMAP *metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
+ METADATAMAP::iterator model_iterator = metadata->find(model);
+ if (model_iterator != metadata->end()) {
+ tagmap = model_iterator->second;
+ }
+
+ if(key != NULL) {
+
+ if(!tagmap) {
+ // this model, doesn't exist: create it
+ tagmap = new(std::nothrow) TAGMAP();
+ (*metadata)[model] = tagmap;
+ }
+
+ if(tag) {
+ // first check the tag
+ if(FreeImage_GetTagKey(tag) == NULL) {
+ FreeImage_SetTagKey(tag, key);
+ } else if(strcmp(key, FreeImage_GetTagKey(tag)) != 0) {
+ // set the tag key
+ FreeImage_SetTagKey(tag, key);
+ }
+ if(FreeImage_GetTagCount(tag) * FreeImage_TagDataWidth(FreeImage_GetTagType(tag)) != FreeImage_GetTagLength(tag)) {
+ FreeImage_OutputMessageProc(FIF_UNKNOWN, "Invalid data count for tag '%s'", key);
+ return FALSE;
+ }
+
+ // fill the tag ID if possible and if it's needed
+ TagLib& tag_lib = TagLib::instance();
+ switch(model) {
+ case FIMD_IPTC:
+ {
+ int id = tag_lib.getTagID(TagLib::IPTC, key);
+ /*
+ if(id == -1) {
+ FreeImage_OutputMessageProc(FIF_UNKNOWN, "IPTC: Invalid key '%s'", key);
+ }
+ */
+ FreeImage_SetTagID(tag, (WORD)id);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // delete existing tag
+ FITAG *old_tag = (*tagmap)[key];
+ if(old_tag) {
+ FreeImage_DeleteTag(old_tag);
+ }
+
+ // create a new tag
+ (*tagmap)[key] = FreeImage_CloneTag(tag);
+ }
+ else {
+ // delete existing tag
+ TAGMAP::iterator i = tagmap->find(key);
+ if(i != tagmap->end()) {
+ FITAG *old_tag = (*i).second;
+ FreeImage_DeleteTag(old_tag);
+ tagmap->erase(key);
+ }
+ }
+ }
+ else {
+ // destroy the metadata model
+ if(tagmap) {
+ for(TAGMAP::iterator i = tagmap->begin(); i != tagmap->end(); i++) {
+ FITAG *tag = (*i).second;
+ FreeImage_DeleteTag(tag);
+ }
+
+ delete tagmap;
+ metadata->erase(model_iterator);
+ }
+ }
+
+ return TRUE;
+}
+
+BOOL DLL_CALLCONV
+FreeImage_GetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, FITAG **tag) {
+ if(!dib || !key || !tag)
+ return FALSE;
+
+ TAGMAP *tagmap = NULL;
+ *tag = NULL;
+
+ // get the metadata model
+ METADATAMAP *metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
+ if(!(*metadata).empty()) {
+ METADATAMAP::iterator model_iterator = metadata->find(model);
+ if (model_iterator != metadata->end() ) {
+ // this model exists : try to get the requested tag
+ tagmap = model_iterator->second;
+ TAGMAP::iterator tag_iterator = tagmap->find(key);
+ if (tag_iterator != tagmap->end() ) {
+ // get the requested tag
+ *tag = tag_iterator->second;
+ }
+ }
+ }
+
+ return (*tag != NULL) ? TRUE : FALSE;
+}
+
+// ----------------------------------------------------------
+
+unsigned DLL_CALLCONV
+FreeImage_GetMetadataCount(FREE_IMAGE_MDMODEL model, FIBITMAP *dib) {
+ if(!dib)
+ return FALSE;
+
+ TAGMAP *tagmap = NULL;
+
+ // get the metadata model
+ METADATAMAP *metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
+ if( (*metadata).find(model) != (*metadata).end() ) {
+ tagmap = (*metadata)[model];
+ }
+ if(!tagmap) {
+ // this model, doesn't exist: return
+ return 0;
+ }
+
+ // get the tag count
+ return (unsigned)tagmap->size();
+}
+
+// ----------------------------------------------------------
+
+
diff --git a/plugins/AdvaImg/src/FreeImage/CacheFile.h b/plugins/AdvaImg/src/FreeImage/CacheFile.h
deleted file mode 100644
index a1e5e782c9..0000000000
--- a/plugins/AdvaImg/src/FreeImage/CacheFile.h
+++ /dev/null
@@ -1,92 +0,0 @@
-// ==========================================================
-// Multi-Page functions
-//
-// Design and implementation by
-// - Floris van den Berg (flvdberg@wxs.nl)
-//
-// 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!
-// ==========================================================
-
-#ifndef CACHEFILE_H
-#define CACHEFILE_H
-
-// ----------------------------------------------------------
-
-#include "FreeImage.h"
-#include "Utilities.h"
-
-// ----------------------------------------------------------
-
-static const int CACHE_SIZE = 32;
-static const int BLOCK_SIZE = (64 * 1024) - 8;
-
-// ----------------------------------------------------------
-
-#ifdef _WIN32
-#pragma pack(push, 1)
-#else
-#pragma pack(1)
-#endif // _WIN32
-
-struct Block {
- unsigned nr;
- unsigned next;
- BYTE *data;
-};
-
-#ifdef _WIN32
-#pragma pack(pop)
-#else
-#pragma pack()
-#endif // _WIN32
-
-// ----------------------------------------------------------
-
-class CacheFile {
- typedef std::list<Block *> PageCache;
- typedef std::list<Block *>::iterator PageCacheIt;
- typedef std::map<int, PageCacheIt> PageMap;
- typedef std::map<int, PageCacheIt>::iterator PageMapIt;
-
-public :
- CacheFile(const std::string filename, BOOL keep_in_memory);
- ~CacheFile();
-
- BOOL open();
- void close();
- BOOL readFile(BYTE *data, int nr, int size);
- int writeFile(BYTE *data, int size);
- void deleteFile(int nr);
-
-private :
- void cleanupMemCache();
- int allocateBlock();
- Block *lockBlock(int nr);
- BOOL unlockBlock(int nr);
- BOOL deleteBlock(int nr);
-
-private :
- FILE *m_file;
- std::string m_filename;
- std::list<int> m_free_pages;
- PageCache m_page_cache_mem;
- PageCache m_page_cache_disk;
- PageMap m_page_map;
- int m_page_count;
- Block *m_current_block;
- BOOL m_keep_in_memory;
-};
-
-#endif // CACHEFILE_H
diff --git a/plugins/AdvaImg/src/FreeImage/Conversion24.cpp b/plugins/AdvaImg/src/FreeImage/Conversion24.cpp
index 1d5bba7f02..3b7a800696 100644
--- a/plugins/AdvaImg/src/FreeImage/Conversion24.cpp
+++ b/plugins/AdvaImg/src/FreeImage/Conversion24.cpp
@@ -1,252 +1,252 @@
-// ==========================================================
-// Bitmap conversion routines
-//
-// Design and implementation by
-// - Floris van den Berg (flvdberg@wxs.nl)
-// - Dale Larson (dlarson@norsesoft.com)
-// - Hervé Drolon (drolon@infonie.fr)
-// - Jani Kajala (janik@remedy.fi)
-//
-// 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 "FreeImage.h"
-#include "Utilities.h"
-
-// ----------------------------------------------------------
-// internal conversions X to 24 bits
-// ----------------------------------------------------------
-
-void DLL_CALLCONV
-FreeImage_ConvertLine1To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
- for (int cols = 0; cols < width_in_pixels; cols++) {
- BYTE index = (source[cols >> 3] & (0x80 >> (cols & 0x07))) != 0 ? 1 : 0;
-
- target[FI_RGBA_BLUE] = palette[index].rgbBlue;
- target[FI_RGBA_GREEN] = palette[index].rgbGreen;
- target[FI_RGBA_RED] = palette[index].rgbRed;
-
- target += 3;
- }
-}
-
-void DLL_CALLCONV
-FreeImage_ConvertLine4To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
- BOOL low_nibble = FALSE;
- int x = 0;
-
- for (int cols = 0; cols < width_in_pixels; ++cols ) {
- if (low_nibble) {
- target[FI_RGBA_BLUE] = palette[LOWNIBBLE(source[x])].rgbBlue;
- target[FI_RGBA_GREEN] = palette[LOWNIBBLE(source[x])].rgbGreen;
- target[FI_RGBA_RED] = palette[LOWNIBBLE(source[x])].rgbRed;
-
- x++;
- } else {
- target[FI_RGBA_BLUE] = palette[HINIBBLE(source[x]) >> 4].rgbBlue;
- target[FI_RGBA_GREEN] = palette[HINIBBLE(source[x]) >> 4].rgbGreen;
- target[FI_RGBA_RED] = palette[HINIBBLE(source[x]) >> 4].rgbRed;
- }
-
- low_nibble = !low_nibble;
-
- target += 3;
- }
-}
-
-void DLL_CALLCONV
-FreeImage_ConvertLine8To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
- for (int cols = 0; cols < width_in_pixels; cols++) {
- target[FI_RGBA_BLUE] = palette[source[cols]].rgbBlue;
- target[FI_RGBA_GREEN] = palette[source[cols]].rgbGreen;
- target[FI_RGBA_RED] = palette[source[cols]].rgbRed;
-
- target += 3;
- }
-}
-
-void DLL_CALLCONV
-FreeImage_ConvertLine16To24_555(BYTE *target, BYTE *source, int width_in_pixels) {
- WORD *bits = (WORD *)source;
-
- for (int cols = 0; cols < width_in_pixels; cols++) {
- target[FI_RGBA_RED] = (BYTE)((((bits[cols] & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) * 0xFF) / 0x1F);
- target[FI_RGBA_GREEN] = (BYTE)((((bits[cols] & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) * 0xFF) / 0x1F);
- target[FI_RGBA_BLUE] = (BYTE)((((bits[cols] & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) * 0xFF) / 0x1F);
-
- target += 3;
- }
-}
-
-void DLL_CALLCONV
-FreeImage_ConvertLine16To24_565(BYTE *target, BYTE *source, int width_in_pixels) {
- WORD *bits = (WORD *)source;
-
- for (int cols = 0; cols < width_in_pixels; cols++) {
- target[FI_RGBA_RED] = (BYTE)((((bits[cols] & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) * 0xFF) / 0x1F);
- target[FI_RGBA_GREEN] = (BYTE)((((bits[cols] & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) * 0xFF) / 0x3F);
- target[FI_RGBA_BLUE] = (BYTE)((((bits[cols] & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) * 0xFF) / 0x1F);
-
- target += 3;
- }
-}
-
-void DLL_CALLCONV
-FreeImage_ConvertLine32To24(BYTE *target, BYTE *source, int width_in_pixels) {
- for (int cols = 0; cols < width_in_pixels; cols++) {
- target[FI_RGBA_BLUE] = source[FI_RGBA_BLUE];
- target[FI_RGBA_GREEN] = source[FI_RGBA_GREEN];
- target[FI_RGBA_RED] = source[FI_RGBA_RED];
-
- target += 3;
- source += 4;
- }
-}
-
-// ----------------------------------------------------------
-// smart convert X to 24 bits
-// ----------------------------------------------------------
-
-FIBITMAP * DLL_CALLCONV
-FreeImage_ConvertTo24Bits(FIBITMAP *dib) {
- if(!FreeImage_HasPixels(dib)) return NULL;
-
- const unsigned bpp = FreeImage_GetBPP(dib);
- const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
-
- if((image_type != FIT_BITMAP) && (image_type != FIT_RGB16) && (image_type != FIT_RGBA16)) {
- return NULL;
- }
-
- const int width = FreeImage_GetWidth(dib);
- const int height = FreeImage_GetHeight(dib);
-
- if(image_type == FIT_BITMAP) {
- if(bpp == 24) {
- return FreeImage_Clone(dib);
- }
-
- FIBITMAP *new_dib = FreeImage_Allocate(width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
- if(new_dib == NULL) {
- return NULL;
- }
-
- // copy metadata from src to dst
- FreeImage_CloneMetadata(new_dib, dib);
-
- switch(bpp) {
- case 1 :
- {
- for (int rows = 0; rows < height; rows++) {
- FreeImage_ConvertLine1To24(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
- }
- return new_dib;
- }
-
- case 4 :
- {
- for (int rows = 0; rows < height; rows++) {
- FreeImage_ConvertLine4To24(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
- }
- return new_dib;
- }
-
- case 8 :
- {
- for (int rows = 0; rows < height; rows++) {
- FreeImage_ConvertLine8To24(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
- }
- return new_dib;
- }
-
- case 16 :
- {
- for (int rows = 0; rows < height; rows++) {
- if ((FreeImage_GetRedMask(dib) == FI16_565_RED_MASK) && (FreeImage_GetGreenMask(dib) == FI16_565_GREEN_MASK) && (FreeImage_GetBlueMask(dib) == FI16_565_BLUE_MASK)) {
- FreeImage_ConvertLine16To24_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
- } else {
- // includes case where all the masks are 0
- FreeImage_ConvertLine16To24_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
- }
- }
- return new_dib;
- }
-
- case 32 :
- {
- for (int rows = 0; rows < height; rows++) {
- FreeImage_ConvertLine32To24(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
- }
- return new_dib;
- }
- }
-
- } else if(image_type == FIT_RGB16) {
- FIBITMAP *new_dib = FreeImage_Allocate(width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
- if(new_dib == NULL) {
- return NULL;
- }
-
- // copy metadata from src to dst
- FreeImage_CloneMetadata(new_dib, dib);
-
- const unsigned src_pitch = FreeImage_GetPitch(dib);
- const unsigned dst_pitch = FreeImage_GetPitch(new_dib);
- const BYTE *src_bits = FreeImage_GetBits(dib);
- BYTE *dst_bits = FreeImage_GetBits(new_dib);
- for (int rows = 0; rows < height; rows++) {
- const FIRGB16 *src_pixel = (FIRGB16*)src_bits;
- RGBTRIPLE *dst_pixel = (RGBTRIPLE*)dst_bits;
- for(int cols = 0; cols < width; cols++) {
- dst_pixel[cols].rgbtRed = (BYTE)(src_pixel[cols].red >> 8);
- dst_pixel[cols].rgbtGreen = (BYTE)(src_pixel[cols].green >> 8);
- dst_pixel[cols].rgbtBlue = (BYTE)(src_pixel[cols].blue >> 8);
- }
- src_bits += src_pitch;
- dst_bits += dst_pitch;
- }
-
- return new_dib;
-
- } else if(image_type == FIT_RGBA16) {
- FIBITMAP *new_dib = FreeImage_Allocate(width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
- if(new_dib == NULL) {
- return NULL;
- }
-
- // copy metadata from src to dst
- FreeImage_CloneMetadata(new_dib, dib);
-
- const unsigned src_pitch = FreeImage_GetPitch(dib);
- const unsigned dst_pitch = FreeImage_GetPitch(new_dib);
- const BYTE *src_bits = FreeImage_GetBits(dib);
- BYTE *dst_bits = FreeImage_GetBits(new_dib);
- for (int rows = 0; rows < height; rows++) {
- const FIRGBA16 *src_pixel = (FIRGBA16*)src_bits;
- RGBTRIPLE *dst_pixel = (RGBTRIPLE*)dst_bits;
- for(int cols = 0; cols < width; cols++) {
- dst_pixel[cols].rgbtRed = (BYTE)(src_pixel[cols].red >> 8);
- dst_pixel[cols].rgbtGreen = (BYTE)(src_pixel[cols].green >> 8);
- dst_pixel[cols].rgbtBlue = (BYTE)(src_pixel[cols].blue >> 8);
- }
- src_bits += src_pitch;
- dst_bits += dst_pitch;
- }
-
- return new_dib;
- }
-
- return NULL;
-}
+// ==========================================================
+// Bitmap conversion routines
+//
+// Design and implementation by
+// - Floris van den Berg (flvdberg@wxs.nl)
+// - Dale Larson (dlarson@norsesoft.com)
+// - Hervé Drolon (drolon@infonie.fr)
+// - Jani Kajala (janik@remedy.fi)
+//
+// 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 "FreeImage.h"
+#include "Utilities.h"
+
+// ----------------------------------------------------------
+// internal conversions X to 24 bits
+// ----------------------------------------------------------
+
+void DLL_CALLCONV
+FreeImage_ConvertLine1To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
+ for (int cols = 0; cols < width_in_pixels; cols++) {
+ BYTE index = (source[cols >> 3] & (0x80 >> (cols & 0x07))) != 0 ? 1 : 0;
+
+ target[FI_RGBA_BLUE] = palette[index].rgbBlue;
+ target[FI_RGBA_GREEN] = palette[index].rgbGreen;
+ target[FI_RGBA_RED] = palette[index].rgbRed;
+
+ target += 3;
+ }
+}
+
+void DLL_CALLCONV
+FreeImage_ConvertLine4To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
+ BOOL low_nibble = FALSE;
+ int x = 0;
+
+ for (int cols = 0; cols < width_in_pixels; ++cols ) {
+ if (low_nibble) {
+ target[FI_RGBA_BLUE] = palette[LOWNIBBLE(source[x])].rgbBlue;
+ target[FI_RGBA_GREEN] = palette[LOWNIBBLE(source[x])].rgbGreen;
+ target[FI_RGBA_RED] = palette[LOWNIBBLE(source[x])].rgbRed;
+
+ x++;
+ } else {
+ target[FI_RGBA_BLUE] = palette[HINIBBLE(source[x]) >> 4].rgbBlue;
+ target[FI_RGBA_GREEN] = palette[HINIBBLE(source[x]) >> 4].rgbGreen;
+ target[FI_RGBA_RED] = palette[HINIBBLE(source[x]) >> 4].rgbRed;
+ }
+
+ low_nibble = !low_nibble;
+
+ target += 3;
+ }
+}
+
+void DLL_CALLCONV
+FreeImage_ConvertLine8To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
+ for (int cols = 0; cols < width_in_pixels; cols++) {
+ target[FI_RGBA_BLUE] = palette[source[cols]].rgbBlue;
+ target[FI_RGBA_GREEN] = palette[source[cols]].rgbGreen;
+ target[FI_RGBA_RED] = palette[source[cols]].rgbRed;
+
+ target += 3;
+ }
+}
+
+void DLL_CALLCONV
+FreeImage_ConvertLine16To24_555(BYTE *target, BYTE *source, int width_in_pixels) {
+ WORD *bits = (WORD *)source;
+
+ for (int cols = 0; cols < width_in_pixels; cols++) {
+ target[FI_RGBA_RED] = (BYTE)((((bits[cols] & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) * 0xFF) / 0x1F);
+ target[FI_RGBA_GREEN] = (BYTE)((((bits[cols] & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) * 0xFF) / 0x1F);
+ target[FI_RGBA_BLUE] = (BYTE)((((bits[cols] & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) * 0xFF) / 0x1F);
+
+ target += 3;
+ }
+}
+
+void DLL_CALLCONV
+FreeImage_ConvertLine16To24_565(BYTE *target, BYTE *source, int width_in_pixels) {
+ WORD *bits = (WORD *)source;
+
+ for (int cols = 0; cols < width_in_pixels; cols++) {
+ target[FI_RGBA_RED] = (BYTE)((((bits[cols] & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) * 0xFF) / 0x1F);
+ target[FI_RGBA_GREEN] = (BYTE)((((bits[cols] & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) * 0xFF) / 0x3F);
+ target[FI_RGBA_BLUE] = (BYTE)((((bits[cols] & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) * 0xFF) / 0x1F);
+
+ target += 3;
+ }
+}
+
+void DLL_CALLCONV
+FreeImage_ConvertLine32To24(BYTE *target, BYTE *source, int width_in_pixels) {
+ for (int cols = 0; cols < width_in_pixels; cols++) {
+ target[FI_RGBA_BLUE] = source[FI_RGBA_BLUE];
+ target[FI_RGBA_GREEN] = source[FI_RGBA_GREEN];
+ target[FI_RGBA_RED] = source[FI_RGBA_RED];
+
+ target += 3;
+ source += 4;
+ }
+}
+
+// ----------------------------------------------------------
+// smart convert X to 24 bits
+// ----------------------------------------------------------
+
+FIBITMAP * DLL_CALLCONV
+FreeImage_ConvertTo24Bits(FIBITMAP *dib) {
+ if(!FreeImage_HasPixels(dib)) return NULL;
+
+ const unsigned bpp = FreeImage_GetBPP(dib);
+ const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
+
+ if((image_type != FIT_BITMAP) && (image_type != FIT_RGB16) && (image_type != FIT_RGBA16)) {
+ return NULL;
+ }
+
+ const int width = FreeImage_GetWidth(dib);
+ const int height = FreeImage_GetHeight(dib);
+
+ if(image_type == FIT_BITMAP) {
+ if(bpp == 24) {
+ return FreeImage_Clone(dib);
+ }
+
+ FIBITMAP *new_dib = FreeImage_Allocate(width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
+ if(new_dib == NULL) {
+ return NULL;
+ }
+
+ // copy metadata from src to dst
+ FreeImage_CloneMetadata(new_dib, dib);
+
+ switch(bpp) {
+ case 1 :
+ {
+ for (int rows = 0; rows < height; rows++) {
+ FreeImage_ConvertLine1To24(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
+ }
+ return new_dib;
+ }
+
+ case 4 :
+ {
+ for (int rows = 0; rows < height; rows++) {
+ FreeImage_ConvertLine4To24(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
+ }
+ return new_dib;
+ }
+
+ case 8 :
+ {
+ for (int rows = 0; rows < height; rows++) {
+ FreeImage_ConvertLine8To24(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
+ }
+ return new_dib;
+ }
+
+ case 16 :
+ {
+ for (int rows = 0; rows < height; rows++) {
+ if ((FreeImage_GetRedMask(dib) == FI16_565_RED_MASK) && (FreeImage_GetGreenMask(dib) == FI16_565_GREEN_MASK) && (FreeImage_GetBlueMask(dib) == FI16_565_BLUE_MASK)) {
+ FreeImage_ConvertLine16To24_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
+ } else {
+ // includes case where all the masks are 0
+ FreeImage_ConvertLine16To24_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
+ }
+ }
+ return new_dib;
+ }
+
+ case 32 :
+ {
+ for (int rows = 0; rows < height; rows++) {
+ FreeImage_ConvertLine32To24(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
+ }
+ return new_dib;
+ }
+ }
+
+ } else if(image_type == FIT_RGB16) {
+ FIBITMAP *new_dib = FreeImage_Allocate(width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
+ if(new_dib == NULL) {
+ return NULL;
+ }
+
+ // copy metadata from src to dst
+ FreeImage_CloneMetadata(new_dib, dib);
+
+ const unsigned src_pitch = FreeImage_GetPitch(dib);
+ const unsigned dst_pitch = FreeImage_GetPitch(new_dib);
+ const BYTE *src_bits = FreeImage_GetBits(dib);
+ BYTE *dst_bits = FreeImage_GetBits(new_dib);
+ for (int rows = 0; rows < height; rows++) {
+ const FIRGB16 *src_pixel = (FIRGB16*)src_bits;
+ RGBTRIPLE *dst_pixel = (RGBTRIPLE*)dst_bits;
+ for(int cols = 0; cols < width; cols++) {
+ dst_pixel[cols].rgbtRed = (BYTE)(src_pixel[cols].red >> 8);
+ dst_pixel[cols].rgbtGreen = (BYTE)(src_pixel[cols].green >> 8);
+ dst_pixel[cols].rgbtBlue = (BYTE)(src_pixel[cols].blue >> 8);
+ }
+ src_bits += src_pitch;
+ dst_bits += dst_pitch;
+ }
+
+ return new_dib;
+
+ } else if(image_type == FIT_RGBA16) {
+ FIBITMAP *new_dib = FreeImage_Allocate(width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
+ if(new_dib == NULL) {
+ return NULL;
+ }
+
+ // copy metadata from src to dst
+ FreeImage_CloneMetadata(new_dib, dib);
+
+ const unsigned src_pitch = FreeImage_GetPitch(dib);
+ const unsigned dst_pitch = FreeImage_GetPitch(new_dib);
+ const BYTE *src_bits = FreeImage_GetBits(dib);
+ BYTE *dst_bits = FreeImage_GetBits(new_dib);
+ for (int rows = 0; rows < height; rows++) {
+ const FIRGBA16 *src_pixel = (FIRGBA16*)src_bits;
+ RGBTRIPLE *dst_pixel = (RGBTRIPLE*)dst_bits;
+ for(int cols = 0; cols < width; cols++) {
+ dst_pixel[cols].rgbtRed = (BYTE)(src_pixel[cols].red >> 8);
+ dst_pixel[cols].rgbtGreen = (BYTE)(src_pixel[cols].green >> 8);
+ dst_pixel[cols].rgbtBlue = (BYTE)(src_pixel[cols].blue >> 8);
+ }
+ src_bits += src_pitch;
+ dst_bits += dst_pitch;
+ }
+
+ return new_dib;
+ }
+
+ return NULL;
+}
diff --git a/plugins/AdvaImg/src/FreeImage/Conversion32.cpp b/plugins/AdvaImg/src/FreeImage/Conversion32.cpp
index b8bd518471..4874dcfaca 100644
--- a/plugins/AdvaImg/src/FreeImage/Conversion32.cpp
+++ b/plugins/AdvaImg/src/FreeImage/Conversion32.cpp
@@ -1,345 +1,345 @@
-// ==========================================================
-// Bitmap conversion routines
-//
-// Design and implementation by
-// - Floris van den Berg (flvdberg@wxs.nl)
-// - Hervé Drolon (drolon@infonie.fr)
-// - Jani Kajala (janik@remedy.fi)
-// - Detlev Vendt (detlev.vendt@brillit.de)
-//
-// 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 "FreeImage.h"
-#include "Utilities.h"
-
-// ----------------------------------------------------------
-// internal conversions X to 32 bits
-// ----------------------------------------------------------
-
-void DLL_CALLCONV
-FreeImage_ConvertLine1To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
- for (int cols = 0; cols < width_in_pixels; cols++) {
- int index = (source[cols>>3] & (0x80 >> (cols & 0x07))) != 0 ? 1 : 0;
-
- target[FI_RGBA_BLUE] = palette[index].rgbBlue;
- target[FI_RGBA_GREEN] = palette[index].rgbGreen;
- target[FI_RGBA_RED] = palette[index].rgbRed;
- target[FI_RGBA_ALPHA] = 0xFF;
- target += 4;
- }
-}
-
-void DLL_CALLCONV
-FreeImage_ConvertLine4To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
- BOOL low_nibble = FALSE;
- int x = 0;
-
- for (int cols = 0 ; cols < width_in_pixels ; ++cols) {
- if (low_nibble) {
- target[FI_RGBA_BLUE] = palette[LOWNIBBLE(source[x])].rgbBlue;
- target[FI_RGBA_GREEN] = palette[LOWNIBBLE(source[x])].rgbGreen;
- target[FI_RGBA_RED] = palette[LOWNIBBLE(source[x])].rgbRed;
-
- x++;
- } else {
- target[FI_RGBA_BLUE] = palette[HINIBBLE(source[x]) >> 4].rgbBlue;
- target[FI_RGBA_GREEN] = palette[HINIBBLE(source[x]) >> 4].rgbGreen;
- target[FI_RGBA_RED] = palette[HINIBBLE(source[x]) >> 4].rgbRed;
- }
-
- low_nibble = !low_nibble;
-
- target[FI_RGBA_ALPHA] = 0xFF;
- target += 4;
- }
-}
-
-void DLL_CALLCONV
-FreeImage_ConvertLine8To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
- for (int cols = 0; cols < width_in_pixels; cols++) {
- target[FI_RGBA_BLUE] = palette[source[cols]].rgbBlue;
- target[FI_RGBA_GREEN] = palette[source[cols]].rgbGreen;
- target[FI_RGBA_RED] = palette[source[cols]].rgbRed;
- target[FI_RGBA_ALPHA] = 0xFF;
- target += 4;
- }
-}
-
-void DLL_CALLCONV
-FreeImage_ConvertLine16To32_555(BYTE *target, BYTE *source, int width_in_pixels) {
- WORD *bits = (WORD *)source;
-
- for (int cols = 0; cols < width_in_pixels; cols++) {
- target[FI_RGBA_RED] = (BYTE)((((bits[cols] & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) * 0xFF) / 0x1F);
- target[FI_RGBA_GREEN] = (BYTE)((((bits[cols] & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) * 0xFF) / 0x1F);
- target[FI_RGBA_BLUE] = (BYTE)((((bits[cols] & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) * 0xFF) / 0x1F);
- target[FI_RGBA_ALPHA] = 0xFF;
- target += 4;
- }
-}
-
-void DLL_CALLCONV
-FreeImage_ConvertLine16To32_565(BYTE *target, BYTE *source, int width_in_pixels) {
- WORD *bits = (WORD *)source;
-
- for (int cols = 0; cols < width_in_pixels; cols++) {
- target[FI_RGBA_RED] = (BYTE)((((bits[cols] & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) * 0xFF) / 0x1F);
- target[FI_RGBA_GREEN] = (BYTE)((((bits[cols] & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) * 0xFF) / 0x3F);
- target[FI_RGBA_BLUE] = (BYTE)((((bits[cols] & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) * 0xFF) / 0x1F);
- target[FI_RGBA_ALPHA] = 0xFF;
- target += 4;
- }
-}
-/*
-void DLL_CALLCONV
-FreeImage_ConvertLine24To32(BYTE *target, BYTE *source, int width_in_pixels) {
- for (int cols = 0; cols < width_in_pixels; cols++) {
- *(DWORD *)target = (*(DWORD *) source & FI_RGBA_RGB_MASK) | FI_RGBA_ALPHA_MASK;
- target += 4;
- source += 3;
- }
-}
-*/
-/**
-This unoptimized version of the conversion function avoid an undetermined bug with VC++ SP6.
-The bug occurs in release mode only, when the image height is equal to 537
-(try e.g. a size of 432x537 to reproduce the bug with the optimized function).
-*/
-void DLL_CALLCONV
-FreeImage_ConvertLine24To32(BYTE *target, BYTE *source, int width_in_pixels) {
- for (int cols = 0; cols < width_in_pixels; cols++) {
- target[FI_RGBA_RED] = source[FI_RGBA_RED];
- target[FI_RGBA_GREEN] = source[FI_RGBA_GREEN];
- target[FI_RGBA_BLUE] = source[FI_RGBA_BLUE];
- target[FI_RGBA_ALPHA] = 0xFF;
- target += 4;
- source += 3;
- }
-}
-
-// ----------------------------------------------------------
-
-inline void
-FreeImage_ConvertLine1To32MapTransparency(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette, BYTE *table, int transparent_pixels) {
- for (int cols = 0; cols < width_in_pixels; cols++) {
- int index = (source[cols>>3] & (0x80 >> (cols & 0x07))) != 0 ? 1 : 0;
-
- target[FI_RGBA_BLUE] = palette[index].rgbBlue;
- target[FI_RGBA_GREEN] = palette[index].rgbGreen;
- target[FI_RGBA_RED] = palette[index].rgbRed;
- target[FI_RGBA_ALPHA] = (index < transparent_pixels) ? table[index] : 255;
- target += 4;
- }
-}
-
-inline void
-FreeImage_ConvertLine4To32MapTransparency(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette, BYTE *table, int transparent_pixels) {
- BOOL low_nibble = FALSE;
- int x = 0;
-
- for (int cols = 0 ; cols < width_in_pixels ; ++cols) {
- if (low_nibble) {
- target[FI_RGBA_BLUE] = palette[LOWNIBBLE(source[x])].rgbBlue;
- target[FI_RGBA_GREEN] = palette[LOWNIBBLE(source[x])].rgbGreen;
- target[FI_RGBA_RED] = palette[LOWNIBBLE(source[x])].rgbRed;
- target[FI_RGBA_ALPHA] = (LOWNIBBLE(source[x]) < transparent_pixels) ? table[LOWNIBBLE(source[x])] : 255;
-
- x++;
- } else {
- target[FI_RGBA_BLUE] = palette[HINIBBLE(source[x]) >> 4].rgbBlue;
- target[FI_RGBA_GREEN] = palette[HINIBBLE(source[x]) >> 4].rgbGreen;
- target[FI_RGBA_RED] = palette[HINIBBLE(source[x]) >> 4].rgbRed;
- target[FI_RGBA_ALPHA] = (HINIBBLE(source[x] >> 4) < transparent_pixels) ? table[HINIBBLE(source[x]) >> 4] : 255;
- }
-
- low_nibble = !low_nibble;
-
- target += 4;
- }
-}
-
-inline void
-FreeImage_ConvertLine8To32MapTransparency(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette, BYTE *table, int transparent_pixels) {
- for (int cols = 0; cols < width_in_pixels; cols++) {
- target[FI_RGBA_BLUE] = palette[source[cols]].rgbBlue;
- target[FI_RGBA_GREEN] = palette[source[cols]].rgbGreen;
- target[FI_RGBA_RED] = palette[source[cols]].rgbRed;
- target[FI_RGBA_ALPHA] = (source[cols] < transparent_pixels) ? table[source[cols]] : 255;
- target += 4;
- }
-}
-
-// ----------------------------------------------------------
-
-FIBITMAP * DLL_CALLCONV
-FreeImage_ConvertTo32Bits(FIBITMAP *dib) {
- if(!FreeImage_HasPixels(dib)) return NULL;
-
- const int bpp = FreeImage_GetBPP(dib);
- const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
-
- if((image_type != FIT_BITMAP) && (image_type != FIT_RGB16) && (image_type != FIT_RGBA16)) {
- return NULL;
- }
-
- const int width = FreeImage_GetWidth(dib);
- const int height = FreeImage_GetHeight(dib);
-
- if(image_type == FIT_BITMAP) {
-
- if(bpp == 32) {
- return FreeImage_Clone(dib);
- }
-
- FIBITMAP *new_dib = FreeImage_Allocate(width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
- if(new_dib == NULL) {
- return NULL;
- }
-
- // copy metadata from src to dst
- FreeImage_CloneMetadata(new_dib, dib);
-
- BOOL bIsTransparent = FreeImage_IsTransparent(dib);
-
- switch(bpp) {
- case 1:
- {
- if(bIsTransparent) {
- for (int rows = 0; rows < height; rows++) {
- FreeImage_ConvertLine1To32MapTransparency(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib), FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib));
- }
- } else {
- for (int rows = 0; rows < height; rows++) {
- FreeImage_ConvertLine1To32(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
- }
- }
-
- return new_dib;
- }
-
- case 4:
- {
- if(bIsTransparent) {
- for (int rows = 0; rows < height; rows++) {
- FreeImage_ConvertLine4To32MapTransparency(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib), FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib));
- }
- } else {
- for (int rows = 0; rows < height; rows++) {
- FreeImage_ConvertLine4To32(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
- }
- }
-
- return new_dib;
- }
-
- case 8:
- {
- if(bIsTransparent) {
- for (int rows = 0; rows < height; rows++) {
- FreeImage_ConvertLine8To32MapTransparency(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib), FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib));
- }
- } else {
- for (int rows = 0; rows < height; rows++) {
- FreeImage_ConvertLine8To32(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
- }
- }
-
- return new_dib;
- }
-
- case 16:
- {
- for (int rows = 0; rows < height; rows++) {
- if ((FreeImage_GetRedMask(dib) == FI16_565_RED_MASK) && (FreeImage_GetGreenMask(dib) == FI16_565_GREEN_MASK) && (FreeImage_GetBlueMask(dib) == FI16_565_BLUE_MASK)) {
- FreeImage_ConvertLine16To32_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
- } else {
- // includes case where all the masks are 0
- FreeImage_ConvertLine16To32_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
- }
- }
-
- return new_dib;
- }
-
- case 24:
- {
- for (int rows = 0; rows < height; rows++) {
- FreeImage_ConvertLine24To32(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
- }
-
- return new_dib;
- }
- }
-
- } else if(image_type == FIT_RGB16) {
- FIBITMAP *new_dib = FreeImage_Allocate(width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
- if(new_dib == NULL) {
- return NULL;
- }
-
- // copy metadata from src to dst
- FreeImage_CloneMetadata(new_dib, dib);
-
- const unsigned src_pitch = FreeImage_GetPitch(dib);
- const unsigned dst_pitch = FreeImage_GetPitch(new_dib);
- const BYTE *src_bits = FreeImage_GetBits(dib);
- BYTE *dst_bits = FreeImage_GetBits(new_dib);
- for (int rows = 0; rows < height; rows++) {
- const FIRGB16 *src_pixel = (FIRGB16*)src_bits;
- RGBQUAD *dst_pixel = (RGBQUAD*)dst_bits;
- for(int cols = 0; cols < width; cols++) {
- dst_pixel[cols].rgbRed = (BYTE)(src_pixel[cols].red >> 8);
- dst_pixel[cols].rgbGreen = (BYTE)(src_pixel[cols].green >> 8);
- dst_pixel[cols].rgbBlue = (BYTE)(src_pixel[cols].blue >> 8);
- dst_pixel[cols].rgbReserved = (BYTE)0xFF;
- }
- src_bits += src_pitch;
- dst_bits += dst_pitch;
- }
-
- return new_dib;
-
- } else if(image_type == FIT_RGBA16) {
- FIBITMAP *new_dib = FreeImage_Allocate(width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
- if(new_dib == NULL) {
- return NULL;
- }
-
- // copy metadata from src to dst
- FreeImage_CloneMetadata(new_dib, dib);
-
- const unsigned src_pitch = FreeImage_GetPitch(dib);
- const unsigned dst_pitch = FreeImage_GetPitch(new_dib);
- const BYTE *src_bits = FreeImage_GetBits(dib);
- BYTE *dst_bits = FreeImage_GetBits(new_dib);
- for (int rows = 0; rows < height; rows++) {
- const FIRGBA16 *src_pixel = (FIRGBA16*)src_bits;
- RGBQUAD *dst_pixel = (RGBQUAD*)dst_bits;
- for(int cols = 0; cols < width; cols++) {
- dst_pixel[cols].rgbRed = (BYTE)(src_pixel[cols].red >> 8);
- dst_pixel[cols].rgbGreen = (BYTE)(src_pixel[cols].green >> 8);
- dst_pixel[cols].rgbBlue = (BYTE)(src_pixel[cols].blue >> 8);
- dst_pixel[cols].rgbReserved = (BYTE)(src_pixel[cols].alpha >> 8);
- }
- src_bits += src_pitch;
- dst_bits += dst_pitch;
- }
-
- return new_dib;
- }
-
- return NULL;
-}
+// ==========================================================
+// Bitmap conversion routines
+//
+// Design and implementation by
+// - Floris van den Berg (flvdberg@wxs.nl)
+// - Hervé Drolon (drolon@infonie.fr)
+// - Jani Kajala (janik@remedy.fi)
+// - Detlev Vendt (detlev.vendt@brillit.de)
+//
+// 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 "FreeImage.h"
+#include "Utilities.h"
+
+// ----------------------------------------------------------
+// internal conversions X to 32 bits
+// ----------------------------------------------------------
+
+void DLL_CALLCONV
+FreeImage_ConvertLine1To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
+ for (int cols = 0; cols < width_in_pixels; cols++) {
+ int index = (source[cols>>3] & (0x80 >> (cols & 0x07))) != 0 ? 1 : 0;
+
+ target[FI_RGBA_BLUE] = palette[index].rgbBlue;
+ target[FI_RGBA_GREEN] = palette[index].rgbGreen;
+ target[FI_RGBA_RED] = palette[index].rgbRed;
+ target[FI_RGBA_ALPHA] = 0xFF;
+ target += 4;
+ }
+}
+
+void DLL_CALLCONV
+FreeImage_ConvertLine4To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
+ BOOL low_nibble = FALSE;
+ int x = 0;
+
+ for (int cols = 0 ; cols < width_in_pixels ; ++cols) {
+ if (low_nibble) {
+ target[FI_RGBA_BLUE] = palette[LOWNIBBLE(source[x])].rgbBlue;
+ target[FI_RGBA_GREEN] = palette[LOWNIBBLE(source[x])].rgbGreen;
+ target[FI_RGBA_RED] = palette[LOWNIBBLE(source[x])].rgbRed;
+
+ x++;
+ } else {
+ target[FI_RGBA_BLUE] = palette[HINIBBLE(source[x]) >> 4].rgbBlue;
+ target[FI_RGBA_GREEN] = palette[HINIBBLE(source[x]) >> 4].rgbGreen;
+ target[FI_RGBA_RED] = palette[HINIBBLE(source[x]) >> 4].rgbRed;
+ }
+
+ low_nibble = !low_nibble;
+
+ target[FI_RGBA_ALPHA] = 0xFF;
+ target += 4;
+ }
+}
+
+void DLL_CALLCONV
+FreeImage_ConvertLine8To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
+ for (int cols = 0; cols < width_in_pixels; cols++) {
+ target[FI_RGBA_BLUE] = palette[source[cols]].rgbBlue;
+ target[FI_RGBA_GREEN] = palette[source[cols]].rgbGreen;
+ target[FI_RGBA_RED] = palette[source[cols]].rgbRed;
+ target[FI_RGBA_ALPHA] = 0xFF;
+ target += 4;
+ }
+}
+
+void DLL_CALLCONV
+FreeImage_ConvertLine16To32_555(BYTE *target, BYTE *source, int width_in_pixels) {
+ WORD *bits = (WORD *)source;
+
+ for (int cols = 0; cols < width_in_pixels; cols++) {
+ target[FI_RGBA_RED] = (BYTE)((((bits[cols] & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) * 0xFF) / 0x1F);
+ target[FI_RGBA_GREEN] = (BYTE)((((bits[cols] & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) * 0xFF) / 0x1F);
+ target[FI_RGBA_BLUE] = (BYTE)((((bits[cols] & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) * 0xFF) / 0x1F);
+ target[FI_RGBA_ALPHA] = 0xFF;
+ target += 4;
+ }
+}
+
+void DLL_CALLCONV
+FreeImage_ConvertLine16To32_565(BYTE *target, BYTE *source, int width_in_pixels) {
+ WORD *bits = (WORD *)source;
+
+ for (int cols = 0; cols < width_in_pixels; cols++) {
+ target[FI_RGBA_RED] = (BYTE)((((bits[cols] & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) * 0xFF) / 0x1F);
+ target[FI_RGBA_GREEN] = (BYTE)((((bits[cols] & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) * 0xFF) / 0x3F);
+ target[FI_RGBA_BLUE] = (BYTE)((((bits[cols] & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) * 0xFF) / 0x1F);
+ target[FI_RGBA_ALPHA] = 0xFF;
+ target += 4;
+ }
+}
+/*
+void DLL_CALLCONV
+FreeImage_ConvertLine24To32(BYTE *target, BYTE *source, int width_in_pixels) {
+ for (int cols = 0; cols < width_in_pixels; cols++) {
+ *(DWORD *)target = (*(DWORD *) source & FI_RGBA_RGB_MASK) | FI_RGBA_ALPHA_MASK;
+ target += 4;
+ source += 3;
+ }
+}
+*/
+/**
+This unoptimized version of the conversion function avoid an undetermined bug with VC++ SP6.
+The bug occurs in release mode only, when the image height is equal to 537
+(try e.g. a size of 432x537 to reproduce the bug with the optimized function).
+*/
+void DLL_CALLCONV
+FreeImage_ConvertLine24To32(BYTE *target, BYTE *source, int width_in_pixels) {
+ for (int cols = 0; cols < width_in_pixels; cols++) {
+ target[FI_RGBA_RED] = source[FI_RGBA_RED];
+ target[FI_RGBA_GREEN] = source[FI_RGBA_GREEN];
+ target[FI_RGBA_BLUE] = source[FI_RGBA_BLUE];
+ target[FI_RGBA_ALPHA] = 0xFF;
+ target += 4;
+ source += 3;
+ }
+}
+
+// ----------------------------------------------------------
+
+inline void
+FreeImage_ConvertLine1To32MapTransparency(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette, BYTE *table, int transparent_pixels) {
+ for (int cols = 0; cols < width_in_pixels; cols++) {
+ int index = (source[cols>>3] & (0x80 >> (cols & 0x07))) != 0 ? 1 : 0;
+
+ target[FI_RGBA_BLUE] = palette[index].rgbBlue;
+ target[FI_RGBA_GREEN] = palette[index].rgbGreen;
+ target[FI_RGBA_RED] = palette[index].rgbRed;
+ target[FI_RGBA_ALPHA] = (index < transparent_pixels) ? table[index] : 255;
+ target += 4;
+ }
+}
+
+inline void
+FreeImage_ConvertLine4To32MapTransparency(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette, BYTE *table, int transparent_pixels) {
+ BOOL low_nibble = FALSE;
+ int x = 0;
+
+ for (int cols = 0 ; cols < width_in_pixels ; ++cols) {
+ if (low_nibble) {
+ target[FI_RGBA_BLUE] = palette[LOWNIBBLE(source[x])].rgbBlue;
+ target[FI_RGBA_GREEN] = palette[LOWNIBBLE(source[x])].rgbGreen;
+ target[FI_RGBA_RED] = palette[LOWNIBBLE(source[x])].rgbRed;
+ target[FI_RGBA_ALPHA] = (LOWNIBBLE(source[x]) < transparent_pixels) ? table[LOWNIBBLE(source[x])] : 255;
+
+ x++;
+ } else {
+ target[FI_RGBA_BLUE] = palette[HINIBBLE(source[x]) >> 4].rgbBlue;
+ target[FI_RGBA_GREEN] = palette[HINIBBLE(source[x]) >> 4].rgbGreen;
+ target[FI_RGBA_RED] = palette[HINIBBLE(source[x]) >> 4].rgbRed;
+ target[FI_RGBA_ALPHA] = (HINIBBLE(source[x] >> 4) < transparent_pixels) ? table[HINIBBLE(source[x]) >> 4] : 255;
+ }
+
+ low_nibble = !low_nibble;
+
+ target += 4;
+ }
+}
+
+inline void
+FreeImage_ConvertLine8To32MapTransparency(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette, BYTE *table, int transparent_pixels) {
+ for (int cols = 0; cols < width_in_pixels; cols++) {
+ target[FI_RGBA_BLUE] = palette[source[cols]].rgbBlue;
+ target[FI_RGBA_GREEN] = palette[source[cols]].rgbGreen;
+ target[FI_RGBA_RED] = palette[source[cols]].rgbRed;
+ target[FI_RGBA_ALPHA] = (source[cols] < transparent_pixels) ? table[source[cols]] : 255;
+ target += 4;
+ }
+}
+
+// ----------------------------------------------------------
+
+FIBITMAP * DLL_CALLCONV
+FreeImage_ConvertTo32Bits(FIBITMAP *dib) {
+ if(!FreeImage_HasPixels(dib)) return NULL;
+
+ const int bpp = FreeImage_GetBPP(dib);
+ const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
+
+ if((image_type != FIT_BITMAP) && (image_type != FIT_RGB16) && (image_type != FIT_RGBA16)) {
+ return NULL;
+ }
+
+ const int width = FreeImage_GetWidth(dib);
+ const int height = FreeImage_GetHeight(dib);
+
+ if(image_type == FIT_BITMAP) {
+
+ if(bpp == 32) {
+ return FreeImage_Clone(dib);
+ }
+
+ FIBITMAP *new_dib = FreeImage_Allocate(width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
+ if(new_dib == NULL) {
+ return NULL;
+ }
+
+ // copy metadata from src to dst
+ FreeImage_CloneMetadata(new_dib, dib);
+
+ BOOL bIsTransparent = FreeImage_IsTransparent(dib);
+
+ switch(bpp) {
+ case 1:
+ {
+ if(bIsTransparent) {
+ for (int rows = 0; rows < height; rows++) {
+ FreeImage_ConvertLine1To32MapTransparency(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib), FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib));
+ }
+ } else {
+ for (int rows = 0; rows < height; rows++) {
+ FreeImage_ConvertLine1To32(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
+ }
+ }
+
+ return new_dib;
+ }
+
+ case 4:
+ {
+ if(bIsTransparent) {
+ for (int rows = 0; rows < height; rows++) {
+ FreeImage_ConvertLine4To32MapTransparency(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib), FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib));
+ }
+ } else {
+ for (int rows = 0; rows < height; rows++) {
+ FreeImage_ConvertLine4To32(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
+ }
+ }
+
+ return new_dib;
+ }
+
+ case 8:
+ {
+ if(bIsTransparent) {
+ for (int rows = 0; rows < height; rows++) {
+ FreeImage_ConvertLine8To32MapTransparency(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib), FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib));
+ }
+ } else {
+ for (int rows = 0; rows < height; rows++) {
+ FreeImage_ConvertLine8To32(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
+ }
+ }
+
+ return new_dib;
+ }
+
+ case 16:
+ {
+ for (int rows = 0; rows < height; rows++) {
+ if ((FreeImage_GetRedMask(dib) == FI16_565_RED_MASK) && (FreeImage_GetGreenMask(dib) == FI16_565_GREEN_MASK) && (FreeImage_GetBlueMask(dib) == FI16_565_BLUE_MASK)) {
+ FreeImage_ConvertLine16To32_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
+ } else {
+ // includes case where all the masks are 0
+ FreeImage_ConvertLine16To32_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
+ }
+ }
+
+ return new_dib;
+ }
+
+ case 24:
+ {
+ for (int rows = 0; rows < height; rows++) {
+ FreeImage_ConvertLine24To32(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
+ }
+
+ return new_dib;
+ }
+ }
+
+ } else if(image_type == FIT_RGB16) {
+ FIBITMAP *new_dib = FreeImage_Allocate(width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
+ if(new_dib == NULL) {
+ return NULL;
+ }
+
+ // copy metadata from src to dst
+ FreeImage_CloneMetadata(new_dib, dib);
+
+ const unsigned src_pitch = FreeImage_GetPitch(dib);
+ const unsigned dst_pitch = FreeImage_GetPitch(new_dib);
+ const BYTE *src_bits = FreeImage_GetBits(dib);
+ BYTE *dst_bits = FreeImage_GetBits(new_dib);
+ for (int rows = 0; rows < height; rows++) {
+ const FIRGB16 *src_pixel = (FIRGB16*)src_bits;
+ RGBQUAD *dst_pixel = (RGBQUAD*)dst_bits;
+ for(int cols = 0; cols < width; cols++) {
+ dst_pixel[cols].rgbRed = (BYTE)(src_pixel[cols].red >> 8);
+ dst_pixel[cols].rgbGreen = (BYTE)(src_pixel[cols].green >> 8);
+ dst_pixel[cols].rgbBlue = (BYTE)(src_pixel[cols].blue >> 8);
+ dst_pixel[cols].rgbReserved = (BYTE)0xFF;
+ }
+ src_bits += src_pitch;
+ dst_bits += dst_pitch;
+ }
+
+ return new_dib;
+
+ } else if(image_type == FIT_RGBA16) {
+ FIBITMAP *new_dib = FreeImage_Allocate(width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
+ if(new_dib == NULL) {
+ return NULL;
+ }
+
+ // copy metadata from src to dst
+ FreeImage_CloneMetadata(new_dib, dib);
+
+ const unsigned src_pitch = FreeImage_GetPitch(dib);
+ const unsigned dst_pitch = FreeImage_GetPitch(new_dib);
+ const BYTE *src_bits = FreeImage_GetBits(dib);
+ BYTE *dst_bits = FreeImage_GetBits(new_dib);
+ for (int rows = 0; rows < height; rows++) {
+ const FIRGBA16 *src_pixel = (FIRGBA16*)src_bits;
+ RGBQUAD *dst_pixel = (RGBQUAD*)dst_bits;
+ for(int cols = 0; cols < width; cols++) {
+ dst_pixel[cols].rgbRed = (BYTE)(src_pixel[cols].red >> 8);
+ dst_pixel[cols].rgbGreen = (BYTE)(src_pixel[cols].green >> 8);
+ dst_pixel[cols].rgbBlue = (BYTE)(src_pixel[cols].blue >> 8);
+ dst_pixel[cols].rgbReserved = (BYTE)(src_pixel[cols].alpha >> 8);
+ }
+ src_bits += src_pitch;
+ dst_bits += dst_pitch;
+ }
+
+ return new_dib;
+ }
+
+ return NULL;
+}
diff --git a/plugins/AdvaImg/src/FreeImage/Conversion8.cpp b/plugins/AdvaImg/src/FreeImage/Conversion8.cpp
index 1c331a6552..c4f9b22441 100644
--- a/plugins/AdvaImg/src/FreeImage/Conversion8.cpp
+++ b/plugins/AdvaImg/src/FreeImage/Conversion8.cpp
@@ -1,305 +1,305 @@
-// ==========================================================
-// Bitmap conversion routines
-//
-// Design and implementation by
-// - Floris van den Berg (flvdberg@wxs.nl)
-// - Hervé Drolon (drolon@infonie.fr)
-// - Jani Kajala (janik@remedy.fi)
-// - Karl-Heinz Bussian (khbussian@moss.de)
-// - 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 "FreeImage.h"
-#include "Utilities.h"
-
-// ----------------------------------------------------------
-// internal conversions X to 8 bits
-// ----------------------------------------------------------
-
-void DLL_CALLCONV
-FreeImage_ConvertLine1To8(BYTE *target, BYTE *source, int width_in_pixels) {
- for (unsigned cols = 0; cols < (unsigned)width_in_pixels; cols++)
- target[cols] = (source[cols >> 3] & (0x80 >> (cols & 0x07))) != 0 ? 255 : 0;
-}
-
-void DLL_CALLCONV
-FreeImage_ConvertLine4To8(BYTE *target, BYTE *source, int width_in_pixels) {
- unsigned count_new = 0;
- unsigned count_org = 0;
- BOOL hinibble = TRUE;
-
- while (count_new < (unsigned)width_in_pixels) {
- if (hinibble) {
- target[count_new] = (source[count_org] >> 4);
- } else {
- target[count_new] = (source[count_org] & 0x0F);
- count_org++;
- }
- hinibble = !hinibble;
- count_new++;
- }
-}
-
-void DLL_CALLCONV
-FreeImage_ConvertLine16To8_555(BYTE *target, BYTE *source, int width_in_pixels) {
- const WORD *const bits = (WORD *)source;
- for (unsigned cols = 0; cols < (unsigned)width_in_pixels; cols++) {
- target[cols] = GREY((((bits[cols] & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) * 0xFF) / 0x1F,
- (((bits[cols] & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) * 0xFF) / 0x1F,
- (((bits[cols] & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) * 0xFF) / 0x1F);
- }
-}
-
-void DLL_CALLCONV
-FreeImage_ConvertLine16To8_565(BYTE *target, BYTE *source, int width_in_pixels) {
- const WORD *const bits = (WORD *)source;
- for (unsigned cols = 0; cols < (unsigned)width_in_pixels; cols++) {
- target[cols] = GREY((((bits[cols] & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) * 0xFF) / 0x1F,
- (((bits[cols] & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) * 0xFF) / 0x3F,
- (((bits[cols] & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) * 0xFF) / 0x1F);
- }
-}
-
-void DLL_CALLCONV
-FreeImage_ConvertLine24To8(BYTE *target, BYTE *source, int width_in_pixels) {
- for (unsigned cols = 0; cols < (unsigned)width_in_pixels; cols++) {
- target[cols] = GREY(source[FI_RGBA_RED], source[FI_RGBA_GREEN], source[FI_RGBA_BLUE]);
- source += 3;
- }
-}
-
-void DLL_CALLCONV
-FreeImage_ConvertLine32To8(BYTE *target, BYTE *source, int width_in_pixels) {
- for (unsigned cols = 0; cols < (unsigned)width_in_pixels; cols++) {
- target[cols] = GREY(source[FI_RGBA_RED], source[FI_RGBA_GREEN], source[FI_RGBA_BLUE]);
- source += 4;
- }
-}
-
-// ----------------------------------------------------------
-// smart convert X to 8 bits
-// ----------------------------------------------------------
-
-FIBITMAP * DLL_CALLCONV
-FreeImage_ConvertTo8Bits(FIBITMAP *dib) {
- if (!FreeImage_HasPixels(dib)) {
- return NULL;
- }
-
- const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
- if (image_type != FIT_BITMAP && image_type != FIT_UINT16) {
- return NULL;
- }
-
- const unsigned bpp = FreeImage_GetBPP(dib);
-
- if (bpp != 8) {
-
- const unsigned width = FreeImage_GetWidth(dib);
- const unsigned height = FreeImage_GetHeight(dib);
-
- // Allocate a destination image
- FIBITMAP *new_dib = FreeImage_Allocate(width, height, 8);
- if (new_dib == NULL) {
- return NULL;
- }
-
- // Copy metadata from src to dst
- FreeImage_CloneMetadata(new_dib, dib);
-
- // Palette of destination image has already been initialized
- RGBQUAD *new_pal = FreeImage_GetPalette(new_dib);
-
- const FREE_IMAGE_COLOR_TYPE color_type = FreeImage_GetColorType(dib);
-
- if (image_type == FIT_BITMAP) {
-
- switch(bpp) {
- case 1:
- {
- if (color_type == FIC_PALETTE) {
- // Copy the palette
- RGBQUAD *old_pal = FreeImage_GetPalette(dib);
- new_pal[0] = old_pal[0];
- new_pal[255] = old_pal[1];
-
- } else if (color_type == FIC_MINISWHITE) {
- // Create a reverse grayscale palette
- CREATE_GREYSCALE_PALETTE_REVERSE(new_pal, 256);
- }
-
- // Expand and copy the bitmap data
- for (unsigned rows = 0; rows < height; rows++) {
- FreeImage_ConvertLine1To8(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
- }
- return new_dib;
- }
-
- case 4 :
- {
- if (color_type == FIC_PALETTE) {
- // Copy the palette
- memcpy(new_pal, FreeImage_GetPalette(dib), 16 * sizeof(RGBQUAD));
- }
-
- // Expand and copy the bitmap data
- for (unsigned rows = 0; rows < height; rows++) {
- FreeImage_ConvertLine4To8(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
- }
- return new_dib;
- }
-
- case 16 :
- {
- // Expand and copy the bitmap data
- if (IS_FORMAT_RGB565(dib)) {
- for (unsigned rows = 0; rows < height; rows++) {
- FreeImage_ConvertLine16To8_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
- }
- } else {
- for (unsigned rows = 0; rows < height; rows++) {
- FreeImage_ConvertLine16To8_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
- }
- }
- return new_dib;
- }
-
- case 24 :
- {
- // Expand and copy the bitmap data
- for (unsigned rows = 0; rows < height; rows++) {
- FreeImage_ConvertLine24To8(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
- }
- return new_dib;
- }
-
- case 32 :
- {
- // Expand and copy the bitmap data
- for (unsigned rows = 0; rows < height; rows++) {
- FreeImage_ConvertLine32To8(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
- }
- return new_dib;
- }
- }
-
- } else if (image_type == FIT_UINT16) {
-
- const unsigned src_pitch = FreeImage_GetPitch(dib);
- const unsigned dst_pitch = FreeImage_GetPitch(new_dib);
- const BYTE *src_bits = FreeImage_GetBits(dib);
- BYTE *dst_bits = FreeImage_GetBits(new_dib);
-
- for (unsigned rows = 0; rows < height; rows++) {
- const WORD *const src_pixel = (WORD*)src_bits;
- BYTE *dst_pixel = (BYTE*)dst_bits;
- for(unsigned cols = 0; cols < width; cols++) {
- dst_pixel[cols] = (BYTE)(src_pixel[cols] >> 8);
- }
- src_bits += src_pitch;
- dst_bits += dst_pitch;
- }
- return new_dib;
- }
-
- } // bpp != 8
-
- return FreeImage_Clone(dib);
-}
-
-FIBITMAP * DLL_CALLCONV
-FreeImage_ConvertToGreyscale(FIBITMAP *dib) {
- if (!FreeImage_HasPixels(dib)) {
- return NULL;
- }
-
- const FREE_IMAGE_COLOR_TYPE color_type = FreeImage_GetColorType(dib);
-
- if (color_type == FIC_PALETTE || color_type == FIC_MINISWHITE) {
-
- const unsigned bpp = FreeImage_GetBPP(dib);
- const unsigned width = FreeImage_GetWidth(dib);
- const unsigned height = FreeImage_GetHeight(dib);
-
- FIBITMAP *new_dib = FreeImage_Allocate(width, height, 8);
- if (new_dib == NULL) {
- return NULL;
- }
-
- // Copy metadata from src to dst
- FreeImage_CloneMetadata(new_dib, dib);
-
- // Create a greyscale palette
- BYTE grey_pal[256];
- const RGBQUAD *pal = FreeImage_GetPalette(dib);
- const unsigned size = CalculateUsedPaletteEntries(bpp);
- for (unsigned i = 0; i < size; i++) {
- grey_pal[i] = GREY(pal->rgbRed, pal->rgbGreen, pal->rgbBlue);
- pal++;
- }
-
- const BYTE *src_bits = FreeImage_GetBits(dib);
- BYTE *dst_bits = FreeImage_GetBits(new_dib);
-
- const unsigned src_pitch = FreeImage_GetPitch(dib);
- const unsigned dst_pitch = FreeImage_GetPitch(new_dib);
-
- switch(bpp) {
- case 1:
- {
- for (unsigned y = 0; y < height; y++) {
- for (unsigned x = 0; x < width; x++) {
- const unsigned pixel = (src_bits[x >> 3] & (0x80 >> (x & 0x07))) != 0;
- dst_bits[x] = grey_pal[pixel];
- }
- src_bits += src_pitch;
- dst_bits += dst_pitch;
- }
- }
- break;
-
- case 4:
- {
- for (unsigned y = 0; y < height; y++) {
- for (unsigned x = 0; x < width; x++) {
- const unsigned pixel = x & 0x01 ? src_bits[x >> 1] & 0x0F : src_bits[x >> 1] >> 4;
- dst_bits[x] = grey_pal[pixel];
- }
- src_bits += src_pitch;
- dst_bits += dst_pitch;
- }
- }
- break;
-
- case 8:
- {
- for (unsigned y = 0; y < height; y++) {
- for (unsigned x = 0; x < width; x++) {
- dst_bits[x] = grey_pal[src_bits[x]];
- }
- src_bits += src_pitch;
- dst_bits += dst_pitch;
- }
- }
- break;
- }
- return new_dib;
- }
-
- // Convert the bitmap to 8-bit greyscale
- return FreeImage_ConvertTo8Bits(dib);
-}
+// ==========================================================
+// Bitmap conversion routines
+//
+// Design and implementation by
+// - Floris van den Berg (flvdberg@wxs.nl)
+// - Hervé Drolon (drolon@infonie.fr)
+// - Jani Kajala (janik@remedy.fi)
+// - Karl-Heinz Bussian (khbussian@moss.de)
+// - 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 "FreeImage.h"
+#include "Utilities.h"
+
+// ----------------------------------------------------------
+// internal conversions X to 8 bits
+// ----------------------------------------------------------
+
+void DLL_CALLCONV
+FreeImage_ConvertLine1To8(BYTE *target, BYTE *source, int width_in_pixels) {
+ for (unsigned cols = 0; cols < (unsigned)width_in_pixels; cols++)
+ target[cols] = (source[cols >> 3] & (0x80 >> (cols & 0x07))) != 0 ? 255 : 0;
+}
+
+void DLL_CALLCONV
+FreeImage_ConvertLine4To8(BYTE *target, BYTE *source, int width_in_pixels) {
+ unsigned count_new = 0;
+ unsigned count_org = 0;
+ BOOL hinibble = TRUE;
+
+ while (count_new < (unsigned)width_in_pixels) {
+ if (hinibble) {
+ target[count_new] = (source[count_org] >> 4);
+ } else {
+ target[count_new] = (source[count_org] & 0x0F);
+ count_org++;
+ }
+ hinibble = !hinibble;
+ count_new++;
+ }
+}
+
+void DLL_CALLCONV
+FreeImage_ConvertLine16To8_555(BYTE *target, BYTE *source, int width_in_pixels) {
+ const WORD *const bits = (WORD *)source;
+ for (unsigned cols = 0; cols < (unsigned)width_in_pixels; cols++) {
+ target[cols] = GREY((((bits[cols] & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) * 0xFF) / 0x1F,
+ (((bits[cols] & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) * 0xFF) / 0x1F,
+ (((bits[cols] & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) * 0xFF) / 0x1F);
+ }
+}
+
+void DLL_CALLCONV
+FreeImage_ConvertLine16To8_565(BYTE *target, BYTE *source, int width_in_pixels) {
+ const WORD *const bits = (WORD *)source;
+ for (unsigned cols = 0; cols < (unsigned)width_in_pixels; cols++) {
+ target[cols] = GREY((((bits[cols] & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) * 0xFF) / 0x1F,
+ (((bits[cols] & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) * 0xFF) / 0x3F,
+ (((bits[cols] & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) * 0xFF) / 0x1F);
+ }
+}
+
+void DLL_CALLCONV
+FreeImage_ConvertLine24To8(BYTE *target, BYTE *source, int width_in_pixels) {
+ for (unsigned cols = 0; cols < (unsigned)width_in_pixels; cols++) {
+ target[cols] = GREY(source[FI_RGBA_RED], source[FI_RGBA_GREEN], source[FI_RGBA_BLUE]);
+ source += 3;
+ }
+}
+
+void DLL_CALLCONV
+FreeImage_ConvertLine32To8(BYTE *target, BYTE *source, int width_in_pixels) {
+ for (unsigned cols = 0; cols < (unsigned)width_in_pixels; cols++) {
+ target[cols] = GREY(source[FI_RGBA_RED], source[FI_RGBA_GREEN], source[FI_RGBA_BLUE]);
+ source += 4;
+ }
+}
+
+// ----------------------------------------------------------
+// smart convert X to 8 bits
+// ----------------------------------------------------------
+
+FIBITMAP * DLL_CALLCONV
+FreeImage_ConvertTo8Bits(FIBITMAP *dib) {
+ if (!FreeImage_HasPixels(dib)) {
+ return NULL;
+ }
+
+ const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
+ if (image_type != FIT_BITMAP && image_type != FIT_UINT16) {
+ return NULL;
+ }
+
+ const unsigned bpp = FreeImage_GetBPP(dib);
+
+ if (bpp != 8) {
+
+ const unsigned width = FreeImage_GetWidth(dib);
+ const unsigned height = FreeImage_GetHeight(dib);
+
+ // Allocate a destination image
+ FIBITMAP *new_dib = FreeImage_Allocate(width, height, 8);
+ if (new_dib == NULL) {
+ return NULL;
+ }
+
+ // Copy metadata from src to dst
+ FreeImage_CloneMetadata(new_dib, dib);
+
+ // Palette of destination image has already been initialized
+ RGBQUAD *new_pal = FreeImage_GetPalette(new_dib);
+
+ const FREE_IMAGE_COLOR_TYPE color_type = FreeImage_GetColorType(dib);
+
+ if (image_type == FIT_BITMAP) {
+
+ switch(bpp) {
+ case 1:
+ {
+ if (color_type == FIC_PALETTE) {
+ // Copy the palette
+ RGBQUAD *old_pal = FreeImage_GetPalette(dib);
+ new_pal[0] = old_pal[0];
+ new_pal[255] = old_pal[1];
+
+ } else if (color_type == FIC_MINISWHITE) {
+ // Create a reverse grayscale palette
+ CREATE_GREYSCALE_PALETTE_REVERSE(new_pal, 256);
+ }
+
+ // Expand and copy the bitmap data
+ for (unsigned rows = 0; rows < height; rows++) {
+ FreeImage_ConvertLine1To8(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
+ }
+ return new_dib;
+ }
+
+ case 4 :
+ {
+ if (color_type == FIC_PALETTE) {
+ // Copy the palette
+ memcpy(new_pal, FreeImage_GetPalette(dib), 16 * sizeof(RGBQUAD));
+ }
+
+ // Expand and copy the bitmap data
+ for (unsigned rows = 0; rows < height; rows++) {
+ FreeImage_ConvertLine4To8(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
+ }
+ return new_dib;
+ }
+
+ case 16 :
+ {
+ // Expand and copy the bitmap data
+ if (IS_FORMAT_RGB565(dib)) {
+ for (unsigned rows = 0; rows < height; rows++) {
+ FreeImage_ConvertLine16To8_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
+ }
+ } else {
+ for (unsigned rows = 0; rows < height; rows++) {
+ FreeImage_ConvertLine16To8_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
+ }
+ }
+ return new_dib;
+ }
+
+ case 24 :
+ {
+ // Expand and copy the bitmap data
+ for (unsigned rows = 0; rows < height; rows++) {
+ FreeImage_ConvertLine24To8(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
+ }
+ return new_dib;
+ }
+
+ case 32 :
+ {
+ // Expand and copy the bitmap data
+ for (unsigned rows = 0; rows < height; rows++) {
+ FreeImage_ConvertLine32To8(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
+ }
+ return new_dib;
+ }
+ }
+
+ } else if (image_type == FIT_UINT16) {
+
+ const unsigned src_pitch = FreeImage_GetPitch(dib);
+ const unsigned dst_pitch = FreeImage_GetPitch(new_dib);
+ const BYTE *src_bits = FreeImage_GetBits(dib);
+ BYTE *dst_bits = FreeImage_GetBits(new_dib);
+
+ for (unsigned rows = 0; rows < height; rows++) {
+ const WORD *const src_pixel = (WORD*)src_bits;
+ BYTE *dst_pixel = (BYTE*)dst_bits;
+ for(unsigned cols = 0; cols < width; cols++) {
+ dst_pixel[cols] = (BYTE)(src_pixel[cols] >> 8);
+ }
+ src_bits += src_pitch;
+ dst_bits += dst_pitch;
+ }
+ return new_dib;
+ }
+
+ } // bpp != 8
+
+ return FreeImage_Clone(dib);
+}
+
+FIBITMAP * DLL_CALLCONV
+FreeImage_ConvertToGreyscale(FIBITMAP *dib) {
+ if (!FreeImage_HasPixels(dib)) {
+ return NULL;
+ }
+
+ const FREE_IMAGE_COLOR_TYPE color_type = FreeImage_GetColorType(dib);
+
+ if (color_type == FIC_PALETTE || color_type == FIC_MINISWHITE) {
+
+ const unsigned bpp = FreeImage_GetBPP(dib);
+ const unsigned width = FreeImage_GetWidth(dib);
+ const unsigned height = FreeImage_GetHeight(dib);
+
+ FIBITMAP *new_dib = FreeImage_Allocate(width, height, 8);
+ if (new_dib == NULL) {
+ return NULL;
+ }
+
+ // Copy metadata from src to dst
+ FreeImage_CloneMetadata(new_dib, dib);
+
+ // Create a greyscale palette
+ BYTE grey_pal[256];
+ const RGBQUAD *pal = FreeImage_GetPalette(dib);
+ const unsigned size = CalculateUsedPaletteEntries(bpp);
+ for (unsigned i = 0; i < size; i++) {
+ grey_pal[i] = GREY(pal->rgbRed, pal->rgbGreen, pal->rgbBlue);
+ pal++;
+ }
+
+ const BYTE *src_bits = FreeImage_GetBits(dib);
+ BYTE *dst_bits = FreeImage_GetBits(new_dib);
+
+ const unsigned src_pitch = FreeImage_GetPitch(dib);
+ const unsigned dst_pitch = FreeImage_GetPitch(new_dib);
+
+ switch(bpp) {
+ case 1:
+ {
+ for (unsigned y = 0; y < height; y++) {
+ for (unsigned x = 0; x < width; x++) {
+ const unsigned pixel = (src_bits[x >> 3] & (0x80 >> (x & 0x07))) != 0;
+ dst_bits[x] = grey_pal[pixel];
+ }
+ src_bits += src_pitch;
+ dst_bits += dst_pitch;
+ }
+ }
+ break;
+
+ case 4:
+ {
+ for (unsigned y = 0; y < height; y++) {
+ for (unsigned x = 0; x < width; x++) {
+ const unsigned pixel = x & 0x01 ? src_bits[x >> 1] & 0x0F : src_bits[x >> 1] >> 4;
+ dst_bits[x] = grey_pal[pixel];
+ }
+ src_bits += src_pitch;
+ dst_bits += dst_pitch;
+ }
+ }
+ break;
+
+ case 8:
+ {
+ for (unsigned y = 0; y < height; y++) {
+ for (unsigned x = 0; x < width; x++) {
+ dst_bits[x] = grey_pal[src_bits[x]];
+ }
+ src_bits += src_pitch;
+ dst_bits += dst_pitch;
+ }
+ }
+ break;
+ }
+ return new_dib;
+ }
+
+ // Convert the bitmap to 8-bit greyscale
+ return FreeImage_ConvertTo8Bits(dib);
+}
diff --git a/plugins/AdvaImg/src/FreeImage/ConversionFloat.cpp b/plugins/AdvaImg/src/FreeImage/ConversionFloat.cpp
index e72d14cb83..a36a6d423f 100644
--- a/plugins/AdvaImg/src/FreeImage/ConversionFloat.cpp
+++ b/plugins/AdvaImg/src/FreeImage/ConversionFloat.cpp
@@ -1,192 +1,194 @@
-// ==========================================================
-// Bitmap conversion routines
-//
-// Design and implementation by
-// - Hervé Drolon (drolon@infonie.fr)
-//
-// 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 "FreeImage.h"
-#include "Utilities.h"
-
-// ----------------------------------------------------------
-// smart convert X to Float
-// ----------------------------------------------------------
-
-FIBITMAP * DLL_CALLCONV
-FreeImage_ConvertToFloat(FIBITMAP *dib) {
- FIBITMAP *src = NULL;
- FIBITMAP *dst = NULL;
-
- if(!FreeImage_HasPixels(dib)) return NULL;
-
- FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(dib);
-
- // check for allowed conversions
- switch(src_type) {
- case FIT_BITMAP:
- {
- // allow conversion from 8-bit
- if((FreeImage_GetBPP(dib) == 8) && (FreeImage_GetColorType(dib) == FIC_MINISBLACK)) {
- src = dib;
- } else {
- src = FreeImage_ConvertToGreyscale(dib);
- if(!src) return NULL;
- }
- break;
- }
- case FIT_UINT16:
- case FIT_RGB16:
- case FIT_RGBA16:
- case FIT_RGBF:
- case FIT_RGBAF:
- src = dib;
- break;
- case FIT_FLOAT:
- // float type : clone the src
- return FreeImage_Clone(dib);
- default:
- return NULL;
- }
-
- // allocate dst image
-
- const unsigned width = FreeImage_GetWidth(src);
- const unsigned height = FreeImage_GetHeight(src);
-
- dst = FreeImage_AllocateT(FIT_FLOAT, width, height);
- if(!dst) {
- if(src != dib) {
- FreeImage_Unload(src);
- }
- return NULL;
- }
-
- // copy metadata from src to dst
- FreeImage_CloneMetadata(dst, src);
-
- // convert from src type to float
-
- const unsigned src_pitch = FreeImage_GetPitch(src);
- const unsigned dst_pitch = FreeImage_GetPitch(dst);
-
- const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src);
- BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst);
-
- switch(src_type) {
- case FIT_BITMAP:
- {
- for(unsigned y = 0; y < height; y++) {
- const BYTE *src_pixel = (BYTE*)src_bits;
- float *dst_pixel = (float*)dst_bits;
- for(unsigned x = 0; x < width; x++) {
- // convert and scale to the range [0..1]
- dst_pixel[x] = (float)(src_pixel[x]) / 255;
- }
- src_bits += src_pitch;
- dst_bits += dst_pitch;
- }
- }
- break;
-
- case FIT_UINT16:
- {
- for(unsigned y = 0; y < height; y++) {
- const WORD *src_pixel = (WORD*)src_bits;
- float *dst_pixel = (float*)dst_bits;
-
- for(unsigned x = 0; x < width; x++) {
- // convert and scale to the range [0..1]
- dst_pixel[x] = (float)(src_pixel[x]) / 65535;
- }
- src_bits += src_pitch;
- dst_bits += dst_pitch;
- }
- }
- break;
-
- case FIT_RGB16:
- {
- for(unsigned y = 0; y < height; y++) {
- const FIRGB16 *src_pixel = (FIRGB16*)src_bits;
- float *dst_pixel = (float*)dst_bits;
-
- for(unsigned x = 0; x < width; x++) {
- // convert and scale to the range [0..1]
- dst_pixel[x] = LUMA_REC709(src_pixel[x].red, src_pixel[x].green, src_pixel[x].blue) / 65535.0F;
- }
- src_bits += src_pitch;
- dst_bits += dst_pitch;
- }
- }
- break;
-
- case FIT_RGBA16:
- {
- for(unsigned y = 0; y < height; y++) {
- const FIRGBA16 *src_pixel = (FIRGBA16*)src_bits;
- float *dst_pixel = (float*)dst_bits;
-
- for(unsigned x = 0; x < width; x++) {
- // convert and scale to the range [0..1]
- dst_pixel[x] = LUMA_REC709(src_pixel[x].red, src_pixel[x].green, src_pixel[x].blue) / 65535.0F;
- }
- src_bits += src_pitch;
- dst_bits += dst_pitch;
- }
- }
- break;
-
- case FIT_RGBF:
- {
- for(unsigned y = 0; y < height; y++) {
- const FIRGBF *src_pixel = (FIRGBF*)src_bits;
- float *dst_pixel = (float*)dst_bits;
-
- for(unsigned x = 0; x < width; x++) {
- // convert (assume pixel values are in the range [0..1])
- dst_pixel[x] = LUMA_REC709(src_pixel[x].red, src_pixel[x].green, src_pixel[x].blue);
- }
- src_bits += src_pitch;
- dst_bits += dst_pitch;
- }
- }
- break;
-
- case FIT_RGBAF:
- {
- for(unsigned y = 0; y < height; y++) {
- const FIRGBAF *src_pixel = (FIRGBAF*)src_bits;
- float *dst_pixel = (float*)dst_bits;
-
- for(unsigned x = 0; x < width; x++) {
- // convert (assume pixel values are in the range [0..1])
- dst_pixel[x] = LUMA_REC709(src_pixel[x].red, src_pixel[x].green, src_pixel[x].blue);
- }
- src_bits += src_pitch;
- dst_bits += dst_pitch;
- }
- }
- break;
- }
-
- if(src != dib) {
- FreeImage_Unload(src);
- }
-
- return dst;
-}
-
+// ==========================================================
+// Bitmap conversion routines
+//
+// Design and implementation by
+// - Hervé Drolon (drolon@infonie.fr)
+//
+// 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 "FreeImage.h"
+#include "Utilities.h"
+
+// ----------------------------------------------------------
+// smart convert X to Float
+// ----------------------------------------------------------
+
+FIBITMAP * DLL_CALLCONV
+FreeImage_ConvertToFloat(FIBITMAP *dib) {
+ FIBITMAP *src = NULL;
+ FIBITMAP *dst = NULL;
+
+ if(!FreeImage_HasPixels(dib)) return NULL;
+
+ FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(dib);
+
+ // check for allowed conversions
+ switch(src_type) {
+ case FIT_BITMAP:
+ {
+ // allow conversion from 8-bit
+ if((FreeImage_GetBPP(dib) == 8) && (FreeImage_GetColorType(dib) == FIC_MINISBLACK)) {
+ src = dib;
+ } else {
+ src = FreeImage_ConvertToGreyscale(dib);
+ if(!src) return NULL;
+ }
+ break;
+ }
+ case FIT_UINT16:
+ case FIT_RGB16:
+ case FIT_RGBA16:
+ case FIT_RGBF:
+ case FIT_RGBAF:
+ src = dib;
+ break;
+ case FIT_FLOAT:
+ // float type : clone the src
+ return FreeImage_Clone(dib);
+ default:
+ return NULL;
+ }
+
+ // allocate dst image
+
+ const unsigned width = FreeImage_GetWidth(src);
+ const unsigned height = FreeImage_GetHeight(src);
+
+ dst = FreeImage_AllocateT(FIT_FLOAT, width, height);
+ if(!dst) {
+ if(src != dib) {
+ FreeImage_Unload(src);
+ }
+ return NULL;
+ }
+
+ // copy metadata from src to dst
+ FreeImage_CloneMetadata(dst, src);
+
+ // convert from src type to float
+
+ const unsigned src_pitch = FreeImage_GetPitch(src);
+ const unsigned dst_pitch = FreeImage_GetPitch(dst);
+
+ const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src);
+ BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst);
+
+ switch(src_type) {
+ case FIT_BITMAP:
+ {
+ for(unsigned y = 0; y < height; y++) {
+ const BYTE *src_pixel = (BYTE*)src_bits;
+ float *dst_pixel = (float*)dst_bits;
+ for(unsigned x = 0; x < width; x++) {
+ // convert and scale to the range [0..1]
+ dst_pixel[x] = (float)(src_pixel[x]) / 255;
+ }
+ src_bits += src_pitch;
+ dst_bits += dst_pitch;
+ }
+ }
+ break;
+
+ case FIT_UINT16:
+ {
+ for(unsigned y = 0; y < height; y++) {
+ const WORD *src_pixel = (WORD*)src_bits;
+ float *dst_pixel = (float*)dst_bits;
+
+ for(unsigned x = 0; x < width; x++) {
+ // convert and scale to the range [0..1]
+ dst_pixel[x] = (float)(src_pixel[x]) / 65535;
+ }
+ src_bits += src_pitch;
+ dst_bits += dst_pitch;
+ }
+ }
+ break;
+
+ case FIT_RGB16:
+ {
+ for(unsigned y = 0; y < height; y++) {
+ const FIRGB16 *src_pixel = (FIRGB16*)src_bits;
+ float *dst_pixel = (float*)dst_bits;
+
+ for(unsigned x = 0; x < width; x++) {
+ // convert and scale to the range [0..1]
+ dst_pixel[x] = LUMA_REC709(src_pixel[x].red, src_pixel[x].green, src_pixel[x].blue) / 65535.0F;
+ }
+ src_bits += src_pitch;
+ dst_bits += dst_pitch;
+ }
+ }
+ break;
+
+ case FIT_RGBA16:
+ {
+ for(unsigned y = 0; y < height; y++) {
+ const FIRGBA16 *src_pixel = (FIRGBA16*)src_bits;
+ float *dst_pixel = (float*)dst_bits;
+
+ for(unsigned x = 0; x < width; x++) {
+ // convert and scale to the range [0..1]
+ dst_pixel[x] = LUMA_REC709(src_pixel[x].red, src_pixel[x].green, src_pixel[x].blue) / 65535.0F;
+ }
+ src_bits += src_pitch;
+ dst_bits += dst_pitch;
+ }
+ }
+ break;
+
+ case FIT_RGBF:
+ {
+ for(unsigned y = 0; y < height; y++) {
+ const FIRGBF *src_pixel = (FIRGBF*)src_bits;
+ float *dst_pixel = (float*)dst_bits;
+
+ for(unsigned x = 0; x < width; x++) {
+ // convert (assume pixel values are in the range [0..1])
+ dst_pixel[x] = LUMA_REC709(src_pixel[x].red, src_pixel[x].green, src_pixel[x].blue);
+ dst_pixel[x] = CLAMP(dst_pixel[x], 0.0F, 1.0F);
+ }
+ src_bits += src_pitch;
+ dst_bits += dst_pitch;
+ }
+ }
+ break;
+
+ case FIT_RGBAF:
+ {
+ for(unsigned y = 0; y < height; y++) {
+ const FIRGBAF *src_pixel = (FIRGBAF*)src_bits;
+ float *dst_pixel = (float*)dst_bits;
+
+ for(unsigned x = 0; x < width; x++) {
+ // convert (assume pixel values are in the range [0..1])
+ dst_pixel[x] = LUMA_REC709(src_pixel[x].red, src_pixel[x].green, src_pixel[x].blue);
+ dst_pixel[x] = CLAMP(dst_pixel[x], 0.0F, 1.0F);
+ }
+ src_bits += src_pitch;
+ dst_bits += dst_pitch;
+ }
+ }
+ break;
+ }
+
+ if(src != dib) {
+ FreeImage_Unload(src);
+ }
+
+ return dst;
+}
+
diff --git a/plugins/AdvaImg/src/FreeImage/ConversionRGB16.cpp b/plugins/AdvaImg/src/FreeImage/ConversionRGB16.cpp
index bd38504a1e..9e28205688 100644
--- a/plugins/AdvaImg/src/FreeImage/ConversionRGB16.cpp
+++ b/plugins/AdvaImg/src/FreeImage/ConversionRGB16.cpp
@@ -1,144 +1,144 @@
-// ==========================================================
-// Bitmap conversion routines
-//
-// Design and implementation by
-// - Hervé Drolon (drolon@infonie.fr)
-//
-// 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 "FreeImage.h"
-#include "Utilities.h"
-
-// ----------------------------------------------------------
-// smart convert X to RGB16
-// ----------------------------------------------------------
-
-FIBITMAP * DLL_CALLCONV
-FreeImage_ConvertToRGB16(FIBITMAP *dib) {
- FIBITMAP *src = NULL;
- FIBITMAP *dst = NULL;
-
- if(!FreeImage_HasPixels(dib)) return NULL;
-
- const FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(dib);
-
- // check for allowed conversions
- switch(src_type) {
- case FIT_BITMAP:
- {
- // convert to 24-bit if needed
- if((FreeImage_GetBPP(dib) == 24) || (FreeImage_GetBPP(dib) == 32)) {
- src = dib;
- } else {
- src = FreeImage_ConvertTo24Bits(dib);
- if(!src) return NULL;
- }
- break;
- }
- case FIT_UINT16:
- // allow conversion from unsigned 16-bit
- src = dib;
- break;
- case FIT_RGB16:
- // RGB16 type : clone the src
- return FreeImage_Clone(dib);
- break;
- case FIT_RGBA16:
- // allow conversion from 64-bit RGBA (ignore the alpha channel)
- src = dib;
- break;
- default:
- return NULL;
- }
-
- // allocate dst image
-
- const unsigned width = FreeImage_GetWidth(src);
- const unsigned height = FreeImage_GetHeight(src);
-
- dst = FreeImage_AllocateT(FIT_RGB16, width, height);
- if(!dst) {
- if(src != dib) {
- FreeImage_Unload(src);
- }
- return NULL;
- }
-
- // copy metadata from src to dst
- FreeImage_CloneMetadata(dst, src);
-
- // convert from src type to RGB16
-
- switch(src_type) {
- case FIT_BITMAP:
- {
- // Calculate the number of bytes per pixel (1 for 8-bit, 3 for 24-bit or 4 for 32-bit)
- const unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);
-
- for(unsigned y = 0; y < height; y++) {
- const BYTE *src_bits = (BYTE*)FreeImage_GetScanLine(src, y);
- FIRGB16 *dst_bits = (FIRGB16*)FreeImage_GetScanLine(dst, y);
- for(unsigned x = 0; x < width; x++) {
- dst_bits[x].red = src_bits[FI_RGBA_RED] << 8;
- dst_bits[x].green = src_bits[FI_RGBA_GREEN] << 8;
- dst_bits[x].blue = src_bits[FI_RGBA_BLUE] << 8;
- src_bits += bytespp;
- }
- }
- }
- break;
-
- case FIT_UINT16:
- {
- for(unsigned y = 0; y < height; y++) {
- const WORD *src_bits = (WORD*)FreeImage_GetScanLine(src, y);
- FIRGB16 *dst_bits = (FIRGB16*)FreeImage_GetScanLine(dst, y);
- for(unsigned x = 0; x < width; x++) {
- // convert by copying greyscale channel to each R, G, B channels
- dst_bits[x].red = src_bits[x];
- dst_bits[x].green = src_bits[x];
- dst_bits[x].blue = src_bits[x];
- }
- }
- }
- break;
-
- case FIT_RGBA16:
- {
- for(unsigned y = 0; y < height; y++) {
- const FIRGBA16 *src_bits = (FIRGBA16*)FreeImage_GetScanLine(src, y);
- FIRGB16 *dst_bits = (FIRGB16*)FreeImage_GetScanLine(dst, y);
- for(unsigned x = 0; x < width; x++) {
- // convert and skip alpha channel
- dst_bits[x].red = src_bits[x].red;
- dst_bits[x].green = src_bits[x].green;
- dst_bits[x].blue = src_bits[x].blue;
- }
- }
- }
- break;
-
- default:
- break;
- }
-
- if(src != dib) {
- FreeImage_Unload(src);
- }
-
- return dst;
-}
-
+// ==========================================================
+// Bitmap conversion routines
+//
+// Design and implementation by
+// - Hervé Drolon (drolon@infonie.fr)
+//
+// 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 "FreeImage.h"
+#include "Utilities.h"
+
+// ----------------------------------------------------------
+// smart convert X to RGB16
+// ----------------------------------------------------------
+
+FIBITMAP * DLL_CALLCONV
+FreeImage_ConvertToRGB16(FIBITMAP *dib) {
+ FIBITMAP *src = NULL;
+ FIBITMAP *dst = NULL;
+
+ if(!FreeImage_HasPixels(dib)) return NULL;
+
+ const FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(dib);
+
+ // check for allowed conversions
+ switch(src_type) {
+ case FIT_BITMAP:
+ {
+ // convert to 24-bit if needed
+ if((FreeImage_GetBPP(dib) == 24) || (FreeImage_GetBPP(dib) == 32)) {
+ src = dib;
+ } else {
+ src = FreeImage_ConvertTo24Bits(dib);
+ if(!src) return NULL;
+ }
+ break;
+ }
+ case FIT_UINT16:
+ // allow conversion from unsigned 16-bit
+ src = dib;
+ break;
+ case FIT_RGB16:
+ // RGB16 type : clone the src
+ return FreeImage_Clone(dib);
+ break;
+ case FIT_RGBA16:
+ // allow conversion from 64-bit RGBA (ignore the alpha channel)
+ src = dib;
+ break;
+ default:
+ return NULL;
+ }
+
+ // allocate dst image
+
+ const unsigned width = FreeImage_GetWidth(src);
+ const unsigned height = FreeImage_GetHeight(src);
+
+ dst = FreeImage_AllocateT(FIT_RGB16, width, height);
+ if(!dst) {
+ if(src != dib) {
+ FreeImage_Unload(src);
+ }
+ return NULL;
+ }
+
+ // copy metadata from src to dst
+ FreeImage_CloneMetadata(dst, src);
+
+ // convert from src type to RGB16
+
+ switch(src_type) {
+ case FIT_BITMAP:
+ {
+ // Calculate the number of bytes per pixel (1 for 8-bit, 3 for 24-bit or 4 for 32-bit)
+ const unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);
+
+ for(unsigned y = 0; y < height; y++) {
+ const BYTE *src_bits = (BYTE*)FreeImage_GetScanLine(src, y);
+ FIRGB16 *dst_bits = (FIRGB16*)FreeImage_GetScanLine(dst, y);
+ for(unsigned x = 0; x < width; x++) {
+ dst_bits[x].red = src_bits[FI_RGBA_RED] << 8;
+ dst_bits[x].green = src_bits[FI_RGBA_GREEN] << 8;
+ dst_bits[x].blue = src_bits[FI_RGBA_BLUE] << 8;
+ src_bits += bytespp;
+ }
+ }
+ }
+ break;
+
+ case FIT_UINT16:
+ {
+ for(unsigned y = 0; y < height; y++) {
+ const WORD *src_bits = (WORD*)FreeImage_GetScanLine(src, y);
+ FIRGB16 *dst_bits = (FIRGB16*)FreeImage_GetScanLine(dst, y);
+ for(unsigned x = 0; x < width; x++) {
+ // convert by copying greyscale channel to each R, G, B channels
+ dst_bits[x].red = src_bits[x];
+ dst_bits[x].green = src_bits[x];
+ dst_bits[x].blue = src_bits[x];
+ }
+ }
+ }
+ break;
+
+ case FIT_RGBA16:
+ {
+ for(unsigned y = 0; y < height; y++) {
+ const FIRGBA16 *src_bits = (FIRGBA16*)FreeImage_GetScanLine(src, y);
+ FIRGB16 *dst_bits = (FIRGB16*)FreeImage_GetScanLine(dst, y);
+ for(unsigned x = 0; x < width; x++) {
+ // convert and skip alpha channel
+ dst_bits[x].red = src_bits[x].red;
+ dst_bits[x].green = src_bits[x].green;
+ dst_bits[x].blue = src_bits[x].blue;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if(src != dib) {
+ FreeImage_Unload(src);
+ }
+
+ return dst;
+}
+
diff --git a/plugins/AdvaImg/src/FreeImage/ConversionRGBF.cpp b/plugins/AdvaImg/src/FreeImage/ConversionRGBF.cpp
index b5161d566d..230dd7b11b 100644
--- a/plugins/AdvaImg/src/FreeImage/ConversionRGBF.cpp
+++ b/plugins/AdvaImg/src/FreeImage/ConversionRGBF.cpp
@@ -1,241 +1,243 @@
-// ==========================================================
-// Bitmap conversion routines
-//
-// Design and implementation by
-// - Hervé Drolon (drolon@infonie.fr)
-//
-// 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 "FreeImage.h"
-#include "Utilities.h"
-
-// ----------------------------------------------------------
-// smart convert X to RGBF
-// ----------------------------------------------------------
-
-FIBITMAP * DLL_CALLCONV
-FreeImage_ConvertToRGBF(FIBITMAP *dib) {
- FIBITMAP *src = NULL;
- FIBITMAP *dst = NULL;
-
- if(!FreeImage_HasPixels(dib)) return NULL;
-
- const FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(dib);
-
- // check for allowed conversions
- switch(src_type) {
- case FIT_BITMAP:
- {
- // allow conversion from 24- and 32-bit
- const FREE_IMAGE_COLOR_TYPE color_type = FreeImage_GetColorType(dib);
- if((color_type != FIC_RGB) && (color_type != FIC_RGBALPHA)) {
- src = FreeImage_ConvertTo24Bits(dib);
- if(!src) return NULL;
- } else {
- src = dib;
- }
- break;
- }
- case FIT_UINT16:
- // allow conversion from 16-bit
- src = dib;
- break;
- case FIT_RGB16:
- // allow conversion from 48-bit RGB
- src = dib;
- break;
- case FIT_RGBA16:
- // allow conversion from 64-bit RGBA (ignore the alpha channel)
- src = dib;
- break;
- case FIT_FLOAT:
- // allow conversion from 32-bit float
- src = dib;
- break;
- case FIT_RGBAF:
- // allow conversion from 128-bit RGBAF
- src = dib;
- break;
- case FIT_RGBF:
- // RGBF type : clone the src
- return FreeImage_Clone(dib);
- break;
- default:
- return NULL;
- }
-
- // allocate dst image
-
- const unsigned width = FreeImage_GetWidth(src);
- const unsigned height = FreeImage_GetHeight(src);
-
- dst = FreeImage_AllocateT(FIT_RGBF, width, height);
- if(!dst) {
- if(src != dib) {
- FreeImage_Unload(src);
- }
- return NULL;
- }
-
- // copy metadata from src to dst
- FreeImage_CloneMetadata(dst, src);
-
- // convert from src type to RGBF
-
- const unsigned src_pitch = FreeImage_GetPitch(src);
- const unsigned dst_pitch = FreeImage_GetPitch(dst);
-
- switch(src_type) {
- case FIT_BITMAP:
- {
- // calculate the number of bytes per pixel (3 for 24-bit or 4 for 32-bit)
- const unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);
-
- const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src);
- BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst);
-
- for(unsigned y = 0; y < height; y++) {
- const BYTE *src_pixel = (BYTE*)src_bits;
- FIRGBF *dst_pixel = (FIRGBF*)dst_bits;
- for(unsigned x = 0; x < width; x++) {
- // convert and scale to the range [0..1]
- dst_pixel->red = (float)(src_pixel[FI_RGBA_RED]) / 255.0F;
- dst_pixel->green = (float)(src_pixel[FI_RGBA_GREEN]) / 255.0F;
- dst_pixel->blue = (float)(src_pixel[FI_RGBA_BLUE]) / 255.0F;
-
- src_pixel += bytespp;
- dst_pixel ++;
- }
- src_bits += src_pitch;
- dst_bits += dst_pitch;
- }
- }
- break;
-
- case FIT_UINT16:
- {
- const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src);
- BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst);
-
- for(unsigned y = 0; y < height; y++) {
- const WORD *src_pixel = (WORD*)src_bits;
- FIRGBF *dst_pixel = (FIRGBF*)dst_bits;
-
- for(unsigned x = 0; x < width; x++) {
- // convert and scale to the range [0..1]
- const float dst_value = (float)src_pixel[x] / 65535.0F;
- dst_pixel[x].red = dst_value;
- dst_pixel[x].green = dst_value;
- dst_pixel[x].blue = dst_value;
- }
- src_bits += src_pitch;
- dst_bits += dst_pitch;
- }
- }
- break;
-
- case FIT_RGB16:
- {
- const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src);
- BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst);
-
- for(unsigned y = 0; y < height; y++) {
- const FIRGB16 *src_pixel = (FIRGB16*) src_bits;
- FIRGBF *dst_pixel = (FIRGBF*) dst_bits;
-
- for(unsigned x = 0; x < width; x++) {
- // convert and scale to the range [0..1]
- dst_pixel[x].red = (float)(src_pixel[x].red) / 65535.0F;
- dst_pixel[x].green = (float)(src_pixel[x].green) / 65535.0F;
- dst_pixel[x].blue = (float)(src_pixel[x].blue) / 65535.0F;
- }
- src_bits += src_pitch;
- dst_bits += dst_pitch;
- }
- }
- break;
-
- case FIT_RGBA16:
- {
- const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src);
- BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst);
-
- for(unsigned y = 0; y < height; y++) {
- const FIRGBA16 *src_pixel = (FIRGBA16*) src_bits;
- FIRGBF *dst_pixel = (FIRGBF*) dst_bits;
-
- for(unsigned x = 0; x < width; x++) {
- // convert and scale to the range [0..1]
- dst_pixel[x].red = (float)(src_pixel[x].red) / 65535.0F;
- dst_pixel[x].green = (float)(src_pixel[x].green) / 65535.0F;
- dst_pixel[x].blue = (float)(src_pixel[x].blue) / 65535.0F;
- }
- src_bits += src_pitch;
- dst_bits += dst_pitch;
- }
- }
- break;
-
- case FIT_FLOAT:
- {
- const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src);
- BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst);
-
- for(unsigned y = 0; y < height; y++) {
- const float *src_pixel = (float*) src_bits;
- FIRGBF *dst_pixel = (FIRGBF*) dst_bits;
-
- for(unsigned x = 0; x < width; x++) {
- // convert by copying greyscale channel to each R, G, B channels
- dst_pixel[x].red = src_pixel[x];
- dst_pixel[x].green = src_pixel[x];
- dst_pixel[x].blue = src_pixel[x];
- }
- src_bits += src_pitch;
- dst_bits += dst_pitch;
- }
- }
- break;
-
- case FIT_RGBAF:
- {
- const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src);
- BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst);
-
- for(unsigned y = 0; y < height; y++) {
- const FIRGBAF *src_pixel = (FIRGBAF*) src_bits;
- FIRGBF *dst_pixel = (FIRGBF*) dst_bits;
-
- for(unsigned x = 0; x < width; x++) {
- // convert and skip alpha channel
- dst_pixel[x].red = src_pixel[x].red;
- dst_pixel[x].green = src_pixel[x].green;
- dst_pixel[x].blue = src_pixel[x].blue;
- }
- src_bits += src_pitch;
- dst_bits += dst_pitch;
- }
- }
- break;
- }
-
- if(src != dib) {
- FreeImage_Unload(src);
- }
-
- return dst;
-}
-
+// ==========================================================
+// Bitmap conversion routines
+//
+// Design and implementation by
+// - Hervé Drolon (drolon@infonie.fr)
+//
+// 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 "FreeImage.h"
+#include "Utilities.h"
+
+// ----------------------------------------------------------
+// smart convert X to RGBF
+// ----------------------------------------------------------
+
+FIBITMAP * DLL_CALLCONV
+FreeImage_ConvertToRGBF(FIBITMAP *dib) {
+ FIBITMAP *src = NULL;
+ FIBITMAP *dst = NULL;
+
+ if(!FreeImage_HasPixels(dib)) return NULL;
+
+ const FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(dib);
+
+ // check for allowed conversions
+ switch(src_type) {
+ case FIT_BITMAP:
+ {
+ // allow conversion from 24- and 32-bit
+ const FREE_IMAGE_COLOR_TYPE color_type = FreeImage_GetColorType(dib);
+ if((color_type != FIC_RGB) && (color_type != FIC_RGBALPHA)) {
+ src = FreeImage_ConvertTo24Bits(dib);
+ if(!src) return NULL;
+ } else {
+ src = dib;
+ }
+ break;
+ }
+ case FIT_UINT16:
+ // allow conversion from 16-bit
+ src = dib;
+ break;
+ case FIT_RGB16:
+ // allow conversion from 48-bit RGB
+ src = dib;
+ break;
+ case FIT_RGBA16:
+ // allow conversion from 64-bit RGBA (ignore the alpha channel)
+ src = dib;
+ break;
+ case FIT_FLOAT:
+ // allow conversion from 32-bit float
+ src = dib;
+ break;
+ case FIT_RGBAF:
+ // allow conversion from 128-bit RGBAF
+ src = dib;
+ break;
+ case FIT_RGBF:
+ // RGBF type : clone the src
+ return FreeImage_Clone(dib);
+ break;
+ default:
+ return NULL;
+ }
+
+ // allocate dst image
+
+ const unsigned width = FreeImage_GetWidth(src);
+ const unsigned height = FreeImage_GetHeight(src);
+
+ dst = FreeImage_AllocateT(FIT_RGBF, width, height);
+ if(!dst) {
+ if(src != dib) {
+ FreeImage_Unload(src);
+ }
+ return NULL;
+ }
+
+ // copy metadata from src to dst
+ FreeImage_CloneMetadata(dst, src);
+
+ // convert from src type to RGBF
+
+ const unsigned src_pitch = FreeImage_GetPitch(src);
+ const unsigned dst_pitch = FreeImage_GetPitch(dst);
+
+ switch(src_type) {
+ case FIT_BITMAP:
+ {
+ // calculate the number of bytes per pixel (3 for 24-bit or 4 for 32-bit)
+ const unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);
+
+ const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src);
+ BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst);
+
+ for(unsigned y = 0; y < height; y++) {
+ const BYTE *src_pixel = (BYTE*)src_bits;
+ FIRGBF *dst_pixel = (FIRGBF*)dst_bits;
+ for(unsigned x = 0; x < width; x++) {
+ // convert and scale to the range [0..1]
+ dst_pixel->red = (float)(src_pixel[FI_RGBA_RED]) / 255.0F;
+ dst_pixel->green = (float)(src_pixel[FI_RGBA_GREEN]) / 255.0F;
+ dst_pixel->blue = (float)(src_pixel[FI_RGBA_BLUE]) / 255.0F;
+
+ src_pixel += bytespp;
+ dst_pixel ++;
+ }
+ src_bits += src_pitch;
+ dst_bits += dst_pitch;
+ }
+ }
+ break;
+
+ case FIT_UINT16:
+ {
+ const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src);
+ BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst);
+
+ for(unsigned y = 0; y < height; y++) {
+ const WORD *src_pixel = (WORD*)src_bits;
+ FIRGBF *dst_pixel = (FIRGBF*)dst_bits;
+
+ for(unsigned x = 0; x < width; x++) {
+ // convert and scale to the range [0..1]
+ const float dst_value = (float)src_pixel[x] / 65535.0F;
+ dst_pixel[x].red = dst_value;
+ dst_pixel[x].green = dst_value;
+ dst_pixel[x].blue = dst_value;
+ }
+ src_bits += src_pitch;
+ dst_bits += dst_pitch;
+ }
+ }
+ break;
+
+ case FIT_RGB16:
+ {
+ const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src);
+ BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst);
+
+ for(unsigned y = 0; y < height; y++) {
+ const FIRGB16 *src_pixel = (FIRGB16*) src_bits;
+ FIRGBF *dst_pixel = (FIRGBF*) dst_bits;
+
+ for(unsigned x = 0; x < width; x++) {
+ // convert and scale to the range [0..1]
+ dst_pixel[x].red = (float)(src_pixel[x].red) / 65535.0F;
+ dst_pixel[x].green = (float)(src_pixel[x].green) / 65535.0F;
+ dst_pixel[x].blue = (float)(src_pixel[x].blue) / 65535.0F;
+ }
+ src_bits += src_pitch;
+ dst_bits += dst_pitch;
+ }
+ }
+ break;
+
+ case FIT_RGBA16:
+ {
+ const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src);
+ BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst);
+
+ for(unsigned y = 0; y < height; y++) {
+ const FIRGBA16 *src_pixel = (FIRGBA16*) src_bits;
+ FIRGBF *dst_pixel = (FIRGBF*) dst_bits;
+
+ for(unsigned x = 0; x < width; x++) {
+ // convert and scale to the range [0..1]
+ dst_pixel[x].red = (float)(src_pixel[x].red) / 65535.0F;
+ dst_pixel[x].green = (float)(src_pixel[x].green) / 65535.0F;
+ dst_pixel[x].blue = (float)(src_pixel[x].blue) / 65535.0F;
+ }
+ src_bits += src_pitch;
+ dst_bits += dst_pitch;
+ }
+ }
+ break;
+
+ case FIT_FLOAT:
+ {
+ const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src);
+ BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst);
+
+ for(unsigned y = 0; y < height; y++) {
+ const float *src_pixel = (float*) src_bits;
+ FIRGBF *dst_pixel = (FIRGBF*) dst_bits;
+
+ for(unsigned x = 0; x < width; x++) {
+ // convert by copying greyscale channel to each R, G, B channels
+ // assume float values are in [0..1]
+ const float value = CLAMP(src_pixel[x], 0.0F, 1.0F);
+ dst_pixel[x].red = value;
+ dst_pixel[x].green = value;
+ dst_pixel[x].blue = value;
+ }
+ src_bits += src_pitch;
+ dst_bits += dst_pitch;
+ }
+ }
+ break;
+
+ case FIT_RGBAF:
+ {
+ const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src);
+ BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst);
+
+ for(unsigned y = 0; y < height; y++) {
+ const FIRGBAF *src_pixel = (FIRGBAF*) src_bits;
+ FIRGBF *dst_pixel = (FIRGBF*) dst_bits;
+
+ for(unsigned x = 0; x < width; x++) {
+ // convert and skip alpha channel
+ dst_pixel[x].red = CLAMP(src_pixel[x].red, 0.0F, 1.0F);
+ dst_pixel[x].green = CLAMP(src_pixel[x].green, 0.0F, 1.0F);
+ dst_pixel[x].blue = CLAMP(src_pixel[x].blue, 0.0F, 1.0F);
+ }
+ src_bits += src_pitch;
+ dst_bits += dst_pitch;
+ }
+ }
+ break;
+ }
+
+ if(src != dib) {
+ FreeImage_Unload(src);
+ }
+
+ return dst;
+}
+
diff --git a/plugins/AdvaImg/src/FreeImage/ConversionUINT16.cpp b/plugins/AdvaImg/src/FreeImage/ConversionUINT16.cpp
index ed4691f3a2..e6492aacd2 100644
--- a/plugins/AdvaImg/src/FreeImage/ConversionUINT16.cpp
+++ b/plugins/AdvaImg/src/FreeImage/ConversionUINT16.cpp
@@ -1,134 +1,134 @@
-// ==========================================================
-// Bitmap conversion routines
-//
-// Design and implementation by
-// - Hervé Drolon (drolon@infonie.fr)
-//
-// 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 "FreeImage.h"
-#include "Utilities.h"
-
-// ----------------------------------------------------------
-// smart convert X to UINT16
-// ----------------------------------------------------------
-
-FIBITMAP * DLL_CALLCONV
-FreeImage_ConvertToUINT16(FIBITMAP *dib) {
- FIBITMAP *src = NULL;
- FIBITMAP *dst = NULL;
-
- if(!FreeImage_HasPixels(dib)) return NULL;
-
- const FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(dib);
-
- // check for allowed conversions
- switch(src_type) {
- case FIT_BITMAP:
- {
- // convert to greyscale if needed
- if((FreeImage_GetBPP(dib) == 8) && (FreeImage_GetColorType(dib) == FIC_MINISBLACK)) {
- src = dib;
- } else {
- src = FreeImage_ConvertToGreyscale(dib);
- if(!src) return NULL;
- }
- break;
- }
- case FIT_UINT16:
- // UINT16 type : clone the src
- return FreeImage_Clone(dib);
- break;
- case FIT_RGB16:
- // allow conversion from 48-bit RGB
- src = dib;
- break;
- case FIT_RGBA16:
- // allow conversion from 64-bit RGBA (ignore the alpha channel)
- src = dib;
- break;
- default:
- return NULL;
- }
-
- // allocate dst image
-
- const unsigned width = FreeImage_GetWidth(src);
- const unsigned height = FreeImage_GetHeight(src);
-
- dst = FreeImage_AllocateT(FIT_UINT16, width, height);
- if(!dst) {
- if(src != dib) {
- FreeImage_Unload(src);
- }
- return NULL;
- }
-
- // copy metadata from src to dst
- FreeImage_CloneMetadata(dst, src);
-
- // convert from src type to UINT16
-
- switch(src_type) {
- case FIT_BITMAP:
- {
- for(unsigned y = 0; y < height; y++) {
- const BYTE *src_bits = (BYTE*)FreeImage_GetScanLine(src, y);
- WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y);
- for(unsigned x = 0; x < width; x++) {
- dst_bits[x] = src_bits[x] << 8;
- }
- }
- }
- break;
-
- case FIT_RGB16:
- {
- for(unsigned y = 0; y < height; y++) {
- const FIRGB16 *src_bits = (FIRGB16*)FreeImage_GetScanLine(src, y);
- WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y);
- for(unsigned x = 0; x < width; x++) {
- // convert to grey
- dst_bits[x] = (WORD)LUMA_REC709(src_bits[x].red, src_bits[x].green, src_bits[x].blue);
- }
- }
- }
- break;
-
- case FIT_RGBA16:
- {
- for(unsigned y = 0; y < height; y++) {
- const FIRGBA16 *src_bits = (FIRGBA16*)FreeImage_GetScanLine(src, y);
- WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y);
- for(unsigned x = 0; x < width; x++) {
- // convert to grey
- dst_bits[x] = (WORD)LUMA_REC709(src_bits[x].red, src_bits[x].green, src_bits[x].blue);
- }
- }
- }
- break;
-
- default:
- break;
- }
-
- if(src != dib) {
- FreeImage_Unload(src);
- }
-
- return dst;
-}
-
+// ==========================================================
+// Bitmap conversion routines
+//
+// Design and implementation by
+// - Hervé Drolon (drolon@infonie.fr)
+//
+// 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 "FreeImage.h"
+#include "Utilities.h"
+
+// ----------------------------------------------------------
+// smart convert X to UINT16
+// ----------------------------------------------------------
+
+FIBITMAP * DLL_CALLCONV
+FreeImage_ConvertToUINT16(FIBITMAP *dib) {
+ FIBITMAP *src = NULL;
+ FIBITMAP *dst = NULL;
+
+ if(!FreeImage_HasPixels(dib)) return NULL;
+
+ const FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(dib);
+
+ // check for allowed conversions
+ switch(src_type) {
+ case FIT_BITMAP:
+ {
+ // convert to greyscale if needed
+ if((FreeImage_GetBPP(dib) == 8) && (FreeImage_GetColorType(dib) == FIC_MINISBLACK)) {
+ src = dib;
+ } else {
+ src = FreeImage_ConvertToGreyscale(dib);
+ if(!src) return NULL;
+ }
+ break;
+ }
+ case FIT_UINT16:
+ // UINT16 type : clone the src
+ return FreeImage_Clone(dib);
+ break;
+ case FIT_RGB16:
+ // allow conversion from 48-bit RGB
+ src = dib;
+ break;
+ case FIT_RGBA16:
+ // allow conversion from 64-bit RGBA (ignore the alpha channel)
+ src = dib;
+ break;
+ default:
+ return NULL;
+ }
+
+ // allocate dst image
+
+ const unsigned width = FreeImage_GetWidth(src);
+ const unsigned height = FreeImage_GetHeight(src);
+
+ dst = FreeImage_AllocateT(FIT_UINT16, width, height);
+ if(!dst) {
+ if(src != dib) {
+ FreeImage_Unload(src);
+ }
+ return NULL;
+ }
+
+ // copy metadata from src to dst
+ FreeImage_CloneMetadata(dst, src);
+
+ // convert from src type to UINT16
+
+ switch(src_type) {
+ case FIT_BITMAP:
+ {
+ for(unsigned y = 0; y < height; y++) {
+ const BYTE *src_bits = (BYTE*)FreeImage_GetScanLine(src, y);
+ WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y);
+ for(unsigned x = 0; x < width; x++) {
+ dst_bits[x] = src_bits[x] << 8;
+ }
+ }
+ }
+ break;
+
+ case FIT_RGB16:
+ {
+ for(unsigned y = 0; y < height; y++) {
+ const FIRGB16 *src_bits = (FIRGB16*)FreeImage_GetScanLine(src, y);
+ WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y);
+ for(unsigned x = 0; x < width; x++) {
+ // convert to grey
+ dst_bits[x] = (WORD)LUMA_REC709(src_bits[x].red, src_bits[x].green, src_bits[x].blue);
+ }
+ }
+ }
+ break;
+
+ case FIT_RGBA16:
+ {
+ for(unsigned y = 0; y < height; y++) {
+ const FIRGBA16 *src_bits = (FIRGBA16*)FreeImage_GetScanLine(src, y);
+ WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y);
+ for(unsigned x = 0; x < width; x++) {
+ // convert to grey
+ dst_bits[x] = (WORD)LUMA_REC709(src_bits[x].red, src_bits[x].green, src_bits[x].blue);
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if(src != dib) {
+ FreeImage_Unload(src);
+ }
+
+ return dst;
+}
+
diff --git a/plugins/AdvaImg/src/FreeImage/J2KHelper.cpp b/plugins/AdvaImg/src/FreeImage/J2KHelper.cpp
index c9f8fa57af..1776c3bfd2 100644
--- a/plugins/AdvaImg/src/FreeImage/J2KHelper.cpp
+++ b/plugins/AdvaImg/src/FreeImage/J2KHelper.cpp
@@ -1,500 +1,591 @@
-// ==========================================================
-// JPEG2000 helpers
-//
-// Design and implementation by
-// - Hervé Drolon (drolon@infonie.fr)
-//
-// 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 "FreeImage.h"
-#include "Utilities.h"
-#include "../LibOpenJPEG/openjpeg.h"
-
-/**
-Divide an integer by a power of 2 and round upwards
-@return Returns a divided by 2^b
-*/
-static int int_ceildivpow2(int a, int b) {
- return (a + (1 << b) - 1) >> b;
-}
-
-/**
-Convert a OpenJPEG image to a FIBITMAP
-@param format_id Plugin ID
-@param image OpenJPEG image
-@return Returns the converted image if successful, returns NULL otherwise
-*/
-FIBITMAP* J2KImageToFIBITMAP(int format_id, const opj_image_t *image) {
- FIBITMAP *dib = NULL;
-
- try {
- // compute image width and height
-
- //int w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx);
- int wr = image->comps[0].w;
- int wrr = int_ceildivpow2(image->comps[0].w, image->comps[0].factor);
-
- //int h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy);
- //int hr = image->comps[0].h;
- int hrr = int_ceildivpow2(image->comps[0].h, image->comps[0].factor);
-
- // check the number of components
-
- int numcomps = image->numcomps;
-
- BOOL bIsValid = TRUE;
- for(int c = 0; c < numcomps - 1; c++) {
- if( (image->comps[c].dx == image->comps[c+1].dx) &&
- (image->comps[c].dy == image->comps[c+1].dy) &&
- (image->comps[c].prec == image->comps[c+1].prec) ) {
- continue;
- } else {
- bIsValid = FALSE;
- break;
- }
- }
- bIsValid &= ((numcomps == 1) || (numcomps == 3) || (numcomps == 4));
- if(!bIsValid) {
- if(numcomps) {
- FreeImage_OutputMessageProc(format_id, "Warning: image contains %d greyscale components. Only the first will be loaded.\n", numcomps);
- numcomps = 1;
- } else {
- // unknown type
- throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
- }
- }
-
- // create a new DIB
-
- if(image->comps[0].prec <= 8) {
- switch(numcomps) {
- case 1:
- dib = FreeImage_Allocate(wrr, hrr, 8);
- break;
- case 3:
- dib = FreeImage_Allocate(wrr, hrr, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
- break;
- case 4:
- dib = FreeImage_Allocate(wrr, hrr, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
- break;
- }
- } else if(image->comps[0].prec <= 16) {
- switch(numcomps) {
- case 1:
- dib = FreeImage_AllocateT(FIT_UINT16, wrr, hrr);
- break;
- case 3:
- dib = FreeImage_AllocateT(FIT_RGB16, wrr, hrr);
- break;
- case 4:
- dib = FreeImage_AllocateT(FIT_RGBA16, wrr, hrr);
- break;
- }
- } else {
- throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
- }
- if(!dib) {
- throw FI_MSG_ERROR_DIB_MEMORY;
- }
-
- if(image->comps[0].prec <= 8) {
- if(numcomps == 1) {
- // 8-bit greyscale
- // ----------------------------------------------------------
-
- // build a greyscale palette
-
- RGBQUAD *pal = FreeImage_GetPalette(dib);
- for (int i = 0; i < 256; i++) {
- pal[i].rgbRed = (BYTE)i;
- pal[i].rgbGreen = (BYTE)i;
- pal[i].rgbBlue = (BYTE)i;
- }
-
- // load pixel data
-
- unsigned pixel_count = 0;
-
- for(int y = 0; y < hrr; y++) {
- BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y);
-
- for(int x = 0; x < wrr; x++) {
- const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;
-
- int index = image->comps[0].data[pixel_pos];
- index += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
-
- bits[x] = (BYTE)index;
-
- pixel_count++;
- }
- }
- }
- else if(numcomps == 3) {
-
- // 24-bit RGB
- // ----------------------------------------------------------
-
- // load pixel data
-
- unsigned pixel_count = 0;
-
- for(int y = 0; y < hrr; y++) {
- BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y);
-
- for(int x = 0; x < wrr; x++) {
- const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;
-
- int r = image->comps[0].data[pixel_pos];
- r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
-
- int g = image->comps[1].data[pixel_pos];
- g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
-
- int b = image->comps[2].data[pixel_pos];
- b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);
-
- bits[FI_RGBA_RED] = (BYTE)r;
- bits[FI_RGBA_GREEN] = (BYTE)g;
- bits[FI_RGBA_BLUE] = (BYTE)b;
- bits += 3;
-
- pixel_count++;
- }
- }
- }
- else if(numcomps == 4) {
-
- // 32-bit RGBA
- // ----------------------------------------------------------
-
- // load pixel data
-
- unsigned pixel_count = 0;
-
- for(int y = 0; y < hrr; y++) {
- BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y);
-
- for(int x = 0; x < wrr; x++) {
- const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;
-
- int r = image->comps[0].data[pixel_pos];
- r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
-
- int g = image->comps[1].data[pixel_pos];
- g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
-
- int b = image->comps[2].data[pixel_pos];
- b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);
-
- int a = image->comps[3].data[pixel_pos];
- a += (image->comps[3].sgnd ? 1 << (image->comps[3].prec - 1) : 0);
-
- bits[FI_RGBA_RED] = (BYTE)r;
- bits[FI_RGBA_GREEN] = (BYTE)g;
- bits[FI_RGBA_BLUE] = (BYTE)b;
- bits[FI_RGBA_ALPHA] = (BYTE)a;
- bits += 4;
-
- pixel_count++;
- }
- }
- }
- }
- else if(image->comps[0].prec <= 16) {
- if(numcomps == 1) {
- // 16-bit greyscale
- // ----------------------------------------------------------
-
- // load pixel data
-
- unsigned pixel_count = 0;
-
- for(int y = 0; y < hrr; y++) {
- unsigned short *bits = (unsigned short*)FreeImage_GetScanLine(dib, hrr - 1 - y);
-
- for(int x = 0; x < wrr; x++) {
- const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;
-
- int index = image->comps[0].data[pixel_pos];
- index += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
-
- bits[x] = (unsigned short)index;
-
- pixel_count++;
- }
- }
- }
- else if(numcomps == 3) {
-
- // 48-bit RGB
- // ----------------------------------------------------------
-
- // load pixel data
-
- unsigned pixel_count = 0;
-
- for(int y = 0; y < hrr; y++) {
- FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, hrr - 1 - y);
-
- for(int x = 0; x < wrr; x++) {
- const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;
-
- int r = image->comps[0].data[pixel_pos];
- r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
-
- int g = image->comps[1].data[pixel_pos];
- g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
-
- int b = image->comps[2].data[pixel_pos];
- b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);
-
- bits[x].red = (WORD)r;
- bits[x].green = (WORD)g;
- bits[x].blue = (WORD)b;
-
- pixel_count++;
- }
- }
- }
- else if(numcomps == 4) {
-
- // 64-bit RGBA
- // ----------------------------------------------------------
-
- // load pixel data
-
- unsigned pixel_count = 0;
-
- for(int y = 0; y < hrr; y++) {
- FIRGBA16 *bits = (FIRGBA16*)FreeImage_GetScanLine(dib, hrr - 1 - y);
-
- for(int x = 0; x < wrr; x++) {
- const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;
-
- int r = image->comps[0].data[pixel_pos];
- r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
-
- int g = image->comps[1].data[pixel_pos];
- g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
-
- int b = image->comps[2].data[pixel_pos];
- b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);
-
- int a = image->comps[3].data[pixel_pos];
- a += (image->comps[3].sgnd ? 1 << (image->comps[3].prec - 1) : 0);
-
- bits[x].red = (WORD)r;
- bits[x].green = (WORD)g;
- bits[x].blue = (WORD)b;
- bits[x].alpha = (WORD)a;
-
- pixel_count++;
- }
- }
- }
- }
-
- return dib;
-
- } catch(const char *text) {
- if(dib) FreeImage_Unload(dib);
- FreeImage_OutputMessageProc(format_id, text);
- return NULL;
- }
-
-}
-
-/**
-Convert a FIBITMAP to a OpenJPEG image
-@param format_id Plugin ID
-@param dib FreeImage image
-@param parameters Compression parameters
-@return Returns the converted image if successful, returns NULL otherwise
-*/
-opj_image_t* FIBITMAPToJ2KImage(int format_id, FIBITMAP *dib, const opj_cparameters_t *parameters) {
- int prec, numcomps, x, y, index;
- OPJ_COLOR_SPACE color_space;
- opj_image_cmptparm_t cmptparm[4]; // maximum of 4 components
- opj_image_t *image = NULL; // image to encode
-
- try {
- int w = FreeImage_GetWidth(dib);
- int h = FreeImage_GetHeight(dib);
-
- // get image characteristics
- FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
-
- if(image_type == FIT_BITMAP) {
- // standard image ...
- prec = 8;
- switch(FreeImage_GetColorType(dib)) {
- case FIC_MINISBLACK:
- numcomps = 1;
- color_space = CLRSPC_GRAY;
- break;
- case FIC_RGB:
- if(FreeImage_GetBPP(dib) == 32) {
- // 32-bit image with a fully opaque layer
- numcomps = 4;
- color_space = CLRSPC_SRGB;
- } else {
- // 24-bit image
- numcomps = 3;
- color_space = CLRSPC_SRGB;
- }
- break;
- case FIC_RGBALPHA:
- numcomps = 4;
- color_space = CLRSPC_SRGB;
- break;
- default:
- return NULL;
- }
- } else {
- // HDR image ...
- prec = 16;
- switch(image_type) {
- case FIT_UINT16:
- numcomps = 1;
- color_space = CLRSPC_GRAY;
- break;
- case FIT_RGB16:
- numcomps = 3;
- color_space = CLRSPC_SRGB;
- break;
- case FIT_RGBA16:
- numcomps = 4;
- color_space = CLRSPC_SRGB;
- break;
- default:
- return NULL;
- }
- }
-
- // initialize image components
- memset(&cmptparm[0], 0, 4 * sizeof(opj_image_cmptparm_t));
- for(int i = 0; i < numcomps; i++) {
- cmptparm[i].dx = parameters->subsampling_dx;
- cmptparm[i].dy = parameters->subsampling_dy;
- cmptparm[i].w = w;
- cmptparm[i].h = h;
- cmptparm[i].prec = prec;
- cmptparm[i].bpp = prec;
- cmptparm[i].sgnd = 0;
- }
- // create the image
- image = opj_image_create(numcomps, &cmptparm[0], color_space);
- if(!image) {
- throw FI_MSG_ERROR_DIB_MEMORY;
- }
-
- // set image offset and reference grid
- image->x0 = parameters->image_offset_x0;
- image->y0 = parameters->image_offset_y0;
- image->x1 = parameters->image_offset_x0 + (w - 1) * parameters->subsampling_dx + 1;
- image->y1 = parameters->image_offset_y0 + (h - 1) * parameters->subsampling_dy + 1;
-
- // set image data
- if(prec == 8) {
- switch(numcomps) {
- case 1:
- index = 0;
- for(y = 0; y < h; y++) {
- BYTE *bits = FreeImage_GetScanLine(dib, h - 1 - y);
- for(x = 0; x < w; x++) {
- image->comps[0].data[index] = bits[x];
- index++;
- }
- }
- break;
- case 3:
- index = 0;
- for(y = 0; y < h; y++) {
- BYTE *bits = FreeImage_GetScanLine(dib, h - 1 - y);
- for(x = 0; x < w; x++) {
- image->comps[0].data[index] = bits[FI_RGBA_RED];
- image->comps[1].data[index] = bits[FI_RGBA_GREEN];
- image->comps[2].data[index] = bits[FI_RGBA_BLUE];
- bits += 3;
- index++;
- }
- }
- break;
- case 4:
- index = 0;
- for(y = 0; y < h; y++) {
- BYTE *bits = FreeImage_GetScanLine(dib, h - 1 - y);
- for(x = 0; x < w; x++) {
- image->comps[0].data[index] = bits[FI_RGBA_RED];
- image->comps[1].data[index] = bits[FI_RGBA_GREEN];
- image->comps[2].data[index] = bits[FI_RGBA_BLUE];
- image->comps[3].data[index] = bits[FI_RGBA_ALPHA];
- bits += 4;
- index++;
- }
- }
- break;
- }
- }
- else if(prec == 16) {
- switch(numcomps) {
- case 1:
- index = 0;
- for(y = 0; y < h; y++) {
- WORD *bits = (WORD*)FreeImage_GetScanLine(dib, h - 1 - y);
- for(x = 0; x < w; x++) {
- image->comps[0].data[index] = bits[x];
- index++;
- }
- }
- break;
- case 3:
- index = 0;
- for(y = 0; y < h; y++) {
- FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, h - 1 - y);
- for(x = 0; x < w; x++) {
- image->comps[0].data[index] = bits[x].red;
- image->comps[1].data[index] = bits[x].green;
- image->comps[2].data[index] = bits[x].blue;
- index++;
- }
- }
- break;
- case 4:
- index = 0;
- for(y = 0; y < h; y++) {
- FIRGBA16 *bits = (FIRGBA16*)FreeImage_GetScanLine(dib, h - 1 - y);
- for(x = 0; x < w; x++) {
- image->comps[0].data[index] = bits[x].red;
- image->comps[1].data[index] = bits[x].green;
- image->comps[2].data[index] = bits[x].blue;
- image->comps[3].data[index] = bits[x].alpha;
- index++;
- }
- }
- break;
- }
- }
-
- return image;
-
- } catch (const char *text) {
- if(image) opj_image_destroy(image);
- FreeImage_OutputMessageProc(format_id, text);
- return NULL;
- }
-}
+// ==========================================================
+// JPEG2000 helpers
+//
+// Design and implementation by
+// - Hervé Drolon (drolon@infonie.fr)
+//
+// 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 "FreeImage.h"
+#include "Utilities.h"
+#include "../LibOpenJPEG/openjpeg.h"
+#include "J2KHelper.h"
+
+// --------------------------------------------------------------------------
+
+static OPJ_UINT64
+_LengthProc(J2KFIO_t *fio) {
+ long start_pos = fio->io->tell_proc(fio->handle);
+ fio->io->seek_proc(fio->handle, 0, SEEK_END);
+ unsigned file_length = fio->io->tell_proc(fio->handle) - start_pos;
+ fio->io->seek_proc(fio->handle, start_pos, SEEK_SET);
+ return (OPJ_UINT64)file_length;
+}
+
+static OPJ_SIZE_T
+_ReadProc(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data) {
+ J2KFIO_t *fio = (J2KFIO_t*)p_user_data;
+ OPJ_SIZE_T l_nb_read = fio->io->read_proc(p_buffer, 1, (unsigned)p_nb_bytes, fio->handle);
+ return l_nb_read ? l_nb_read : (OPJ_SIZE_T)-1;
+}
+
+static OPJ_SIZE_T
+_WriteProc(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data) {
+ J2KFIO_t *fio = (J2KFIO_t*)p_user_data;
+ return fio->io->write_proc(p_buffer, 1, (unsigned)p_nb_bytes, fio->handle);
+}
+
+static OPJ_OFF_T
+_SkipProc(OPJ_OFF_T p_nb_bytes, void *p_user_data) {
+ J2KFIO_t *fio = (J2KFIO_t*)p_user_data;
+ if( fio->io->seek_proc(fio->handle, (long)p_nb_bytes, SEEK_CUR) ) {
+ return -1;
+ }
+ return p_nb_bytes;
+}
+
+static OPJ_BOOL
+_SeekProc(OPJ_OFF_T p_nb_bytes, FILE * p_user_data) {
+ J2KFIO_t *fio = (J2KFIO_t*)p_user_data;
+ if( fio->io->seek_proc(fio->handle, (long)p_nb_bytes, SEEK_SET) ) {
+ return OPJ_FALSE;
+ }
+ return OPJ_TRUE;
+}
+
+// --------------------------------------------------------------------------
+
+J2KFIO_t*
+opj_freeimage_stream_create(FreeImageIO *io, fi_handle handle, BOOL bRead) {
+ if(!handle) {
+ return NULL;
+ }
+ J2KFIO_t *fio = (J2KFIO_t*)malloc(sizeof(J2KFIO_t));
+ if(fio) {
+ fio->io = io;
+ fio->handle = handle;
+
+ opj_stream_t *l_stream = opj_stream_create(OPJ_J2K_STREAM_CHUNK_SIZE, bRead ? OPJ_TRUE : OPJ_FALSE);
+ if (l_stream) {
+ opj_stream_set_user_data(l_stream, fio, NULL);
+ opj_stream_set_user_data_length(l_stream, _LengthProc(fio));
+ opj_stream_set_read_function(l_stream, (opj_stream_read_fn)_ReadProc);
+ opj_stream_set_write_function(l_stream, (opj_stream_write_fn)_WriteProc);
+ opj_stream_set_skip_function(l_stream, (opj_stream_skip_fn)_SkipProc);
+ opj_stream_set_seek_function(l_stream, (opj_stream_seek_fn)_SeekProc);
+ fio->stream = l_stream;
+ return fio;
+ } else {
+ free(fio);
+ }
+ }
+
+ return NULL;
+}
+
+void
+opj_freeimage_stream_destroy(J2KFIO_t* fio) {
+ if(fio) {
+ if(fio->stream) {
+ opj_stream_destroy(fio->stream);
+ }
+ free(fio);
+ }
+}
+
+// --------------------------------------------------------------------------
+
+/**
+Divide an integer by a power of 2 and round upwards
+@return Returns a divided by 2^b
+*/
+static int int_ceildivpow2(int a, int b) {
+ return (a + (1 << b) - 1) >> b;
+}
+
+/**
+Convert a OpenJPEG image to a FIBITMAP
+@param format_id Plugin ID
+@param image OpenJPEG image
+@param header_only If TRUE, allocate a 'header only' FIBITMAP, otherwise allocate a full FIBITMAP
+@return Returns the converted image if successful, returns NULL otherwise
+*/
+FIBITMAP* J2KImageToFIBITMAP(int format_id, const opj_image_t *image, BOOL header_only) {
+ FIBITMAP *dib = NULL;
+
+ try {
+ // compute image width and height
+
+ //int w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx);
+ int wr = image->comps[0].w;
+ int wrr = int_ceildivpow2(image->comps[0].w, image->comps[0].factor);
+
+ //int h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy);
+ //int hr = image->comps[0].h;
+ int hrr = int_ceildivpow2(image->comps[0].h, image->comps[0].factor);
+
+ // check the number of components
+
+ int numcomps = image->numcomps;
+
+ BOOL bIsValid = TRUE;
+ for(int c = 0; c < numcomps - 1; c++) {
+ if( (image->comps[c].dx == image->comps[c+1].dx) &&
+ (image->comps[c].dy == image->comps[c+1].dy) &&
+ (image->comps[c].prec == image->comps[c+1].prec) ) {
+ continue;
+ } else {
+ bIsValid = FALSE;
+ break;
+ }
+ }
+ bIsValid &= ((numcomps == 1) || (numcomps == 3) || (numcomps == 4));
+ if(!bIsValid) {
+ if(numcomps) {
+ FreeImage_OutputMessageProc(format_id, "Warning: image contains %d greyscale components. Only the first will be loaded.\n", numcomps);
+ numcomps = 1;
+ } else {
+ // unknown type
+ throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
+ }
+ }
+
+ // create a new DIB
+
+ if(image->comps[0].prec <= 8) {
+ switch(numcomps) {
+ case 1:
+ dib = FreeImage_AllocateHeader(header_only, wrr, hrr, 8);
+ break;
+ case 3:
+ dib = FreeImage_AllocateHeader(header_only, wrr, hrr, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
+ break;
+ case 4:
+ dib = FreeImage_AllocateHeader(header_only, wrr, hrr, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
+ break;
+ }
+ } else if(image->comps[0].prec <= 16) {
+ switch(numcomps) {
+ case 1:
+ dib = FreeImage_AllocateHeaderT(header_only, FIT_UINT16, wrr, hrr);
+ break;
+ case 3:
+ dib = FreeImage_AllocateHeaderT(header_only, FIT_RGB16, wrr, hrr);
+ break;
+ case 4:
+ dib = FreeImage_AllocateHeaderT(header_only, FIT_RGBA16, wrr, hrr);
+ break;
+ }
+ } else {
+ throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
+ }
+ if(!dib) {
+ throw FI_MSG_ERROR_DIB_MEMORY;
+ }
+
+ // "header only" FIBITMAP ?
+ if(header_only) {
+ return dib;
+ }
+
+ if(image->comps[0].prec <= 8) {
+ if(numcomps == 1) {
+ // 8-bit greyscale
+ // ----------------------------------------------------------
+
+ // build a greyscale palette
+
+ RGBQUAD *pal = FreeImage_GetPalette(dib);
+ for (int i = 0; i < 256; i++) {
+ pal[i].rgbRed = (BYTE)i;
+ pal[i].rgbGreen = (BYTE)i;
+ pal[i].rgbBlue = (BYTE)i;
+ }
+
+ // load pixel data
+
+ unsigned pixel_count = 0;
+
+ for(int y = 0; y < hrr; y++) {
+ BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y);
+
+ for(int x = 0; x < wrr; x++) {
+ const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;
+
+ int index = image->comps[0].data[pixel_pos];
+ index += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
+
+ bits[x] = (BYTE)index;
+
+ pixel_count++;
+ }
+ }
+ }
+ else if(numcomps == 3) {
+
+ // 24-bit RGB
+ // ----------------------------------------------------------
+
+ // load pixel data
+
+ unsigned pixel_count = 0;
+
+ for(int y = 0; y < hrr; y++) {
+ BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y);
+
+ for(int x = 0; x < wrr; x++) {
+ const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;
+
+ int r = image->comps[0].data[pixel_pos];
+ r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
+
+ int g = image->comps[1].data[pixel_pos];
+ g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
+
+ int b = image->comps[2].data[pixel_pos];
+ b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);
+
+ bits[FI_RGBA_RED] = (BYTE)r;
+ bits[FI_RGBA_GREEN] = (BYTE)g;
+ bits[FI_RGBA_BLUE] = (BYTE)b;
+ bits += 3;
+
+ pixel_count++;
+ }
+ }
+ }
+ else if(numcomps == 4) {
+
+ // 32-bit RGBA
+ // ----------------------------------------------------------
+
+ // load pixel data
+
+ unsigned pixel_count = 0;
+
+ for(int y = 0; y < hrr; y++) {
+ BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y);
+
+ for(int x = 0; x < wrr; x++) {
+ const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;
+
+ int r = image->comps[0].data[pixel_pos];
+ r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
+
+ int g = image->comps[1].data[pixel_pos];
+ g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
+
+ int b = image->comps[2].data[pixel_pos];
+ b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);
+
+ int a = image->comps[3].data[pixel_pos];
+ a += (image->comps[3].sgnd ? 1 << (image->comps[3].prec - 1) : 0);
+
+ bits[FI_RGBA_RED] = (BYTE)r;
+ bits[FI_RGBA_GREEN] = (BYTE)g;
+ bits[FI_RGBA_BLUE] = (BYTE)b;
+ bits[FI_RGBA_ALPHA] = (BYTE)a;
+ bits += 4;
+
+ pixel_count++;
+ }
+ }
+ }
+ }
+ else if(image->comps[0].prec <= 16) {
+ if(numcomps == 1) {
+ // 16-bit greyscale
+ // ----------------------------------------------------------
+
+ // load pixel data
+
+ unsigned pixel_count = 0;
+
+ for(int y = 0; y < hrr; y++) {
+ WORD *bits = (WORD*)FreeImage_GetScanLine(dib, hrr - 1 - y);
+
+ for(int x = 0; x < wrr; x++) {
+ const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;
+
+ int index = image->comps[0].data[pixel_pos];
+ index += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
+
+ bits[x] = (WORD)index;
+
+ pixel_count++;
+ }
+ }
+ }
+ else if(numcomps == 3) {
+
+ // 48-bit RGB
+ // ----------------------------------------------------------
+
+ // load pixel data
+
+ unsigned pixel_count = 0;
+
+ for(int y = 0; y < hrr; y++) {
+ FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, hrr - 1 - y);
+
+ for(int x = 0; x < wrr; x++) {
+ const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;
+
+ int r = image->comps[0].data[pixel_pos];
+ r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
+
+ int g = image->comps[1].data[pixel_pos];
+ g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
+
+ int b = image->comps[2].data[pixel_pos];
+ b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);
+
+ bits[x].red = (WORD)r;
+ bits[x].green = (WORD)g;
+ bits[x].blue = (WORD)b;
+
+ pixel_count++;
+ }
+ }
+ }
+ else if(numcomps == 4) {
+
+ // 64-bit RGBA
+ // ----------------------------------------------------------
+
+ // load pixel data
+
+ unsigned pixel_count = 0;
+
+ for(int y = 0; y < hrr; y++) {
+ FIRGBA16 *bits = (FIRGBA16*)FreeImage_GetScanLine(dib, hrr - 1 - y);
+
+ for(int x = 0; x < wrr; x++) {
+ const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;
+
+ int r = image->comps[0].data[pixel_pos];
+ r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
+
+ int g = image->comps[1].data[pixel_pos];
+ g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
+
+ int b = image->comps[2].data[pixel_pos];
+ b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);
+
+ int a = image->comps[3].data[pixel_pos];
+ a += (image->comps[3].sgnd ? 1 << (image->comps[3].prec - 1) : 0);
+
+ bits[x].red = (WORD)r;
+ bits[x].green = (WORD)g;
+ bits[x].blue = (WORD)b;
+ bits[x].alpha = (WORD)a;
+
+ pixel_count++;
+ }
+ }
+ }
+ }
+
+ return dib;
+
+ } catch(const char *text) {
+ if(dib) FreeImage_Unload(dib);
+ FreeImage_OutputMessageProc(format_id, text);
+ return NULL;
+ }
+
+}
+
+/**
+Convert a FIBITMAP to a OpenJPEG image
+@param format_id Plugin ID
+@param dib FreeImage image
+@param parameters Compression parameters
+@return Returns the converted image if successful, returns NULL otherwise
+*/
+opj_image_t* FIBITMAPToJ2KImage(int format_id, FIBITMAP *dib, const opj_cparameters_t *parameters) {
+ int prec, numcomps, x, y, index;
+ OPJ_COLOR_SPACE color_space;
+ opj_image_cmptparm_t cmptparm[4]; // maximum of 4 components
+ opj_image_t *image = NULL; // image to encode
+
+ try {
+ int w = FreeImage_GetWidth(dib);
+ int h = FreeImage_GetHeight(dib);
+
+ // get image characteristics
+ FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
+
+ if(image_type == FIT_BITMAP) {
+ // standard image ...
+ prec = 8;
+ switch(FreeImage_GetColorType(dib)) {
+ case FIC_MINISBLACK:
+ numcomps = 1;
+ color_space = OPJ_CLRSPC_GRAY;
+ break;
+ case FIC_RGB:
+ if(FreeImage_GetBPP(dib) == 32) {
+ // 32-bit image with a fully opaque layer
+ numcomps = 4;
+ color_space = OPJ_CLRSPC_SRGB;
+ } else {
+ // 24-bit image
+ numcomps = 3;
+ color_space = OPJ_CLRSPC_SRGB;
+ }
+ break;
+ case FIC_RGBALPHA:
+ numcomps = 4;
+ color_space = OPJ_CLRSPC_SRGB;
+ break;
+ default:
+ return NULL;
+ }
+ } else {
+ // HDR image ...
+ prec = 16;
+ switch(image_type) {
+ case FIT_UINT16:
+ numcomps = 1;
+ color_space = OPJ_CLRSPC_GRAY;
+ break;
+ case FIT_RGB16:
+ numcomps = 3;
+ color_space = OPJ_CLRSPC_SRGB;
+ break;
+ case FIT_RGBA16:
+ numcomps = 4;
+ color_space = OPJ_CLRSPC_SRGB;
+ break;
+ default:
+ return NULL;
+ }
+ }
+
+ // initialize image components
+ memset(&cmptparm[0], 0, 4 * sizeof(opj_image_cmptparm_t));
+ for(int i = 0; i < numcomps; i++) {
+ cmptparm[i].dx = parameters->subsampling_dx;
+ cmptparm[i].dy = parameters->subsampling_dy;
+ cmptparm[i].w = w;
+ cmptparm[i].h = h;
+ cmptparm[i].prec = prec;
+ cmptparm[i].bpp = prec;
+ cmptparm[i].sgnd = 0;
+ }
+ // create the image
+ image = opj_image_create(numcomps, &cmptparm[0], color_space);
+ if(!image) {
+ throw FI_MSG_ERROR_DIB_MEMORY;
+ }
+
+ // set image offset and reference grid
+ image->x0 = parameters->image_offset_x0;
+ image->y0 = parameters->image_offset_y0;
+ image->x1 = parameters->image_offset_x0 + (w - 1) * parameters->subsampling_dx + 1;
+ image->y1 = parameters->image_offset_y0 + (h - 1) * parameters->subsampling_dy + 1;
+
+ // set image data
+ if(prec == 8) {
+ switch(numcomps) {
+ case 1:
+ index = 0;
+ for(y = 0; y < h; y++) {
+ BYTE *bits = FreeImage_GetScanLine(dib, h - 1 - y);
+ for(x = 0; x < w; x++) {
+ image->comps[0].data[index] = bits[x];
+ index++;
+ }
+ }
+ break;
+ case 3:
+ index = 0;
+ for(y = 0; y < h; y++) {
+ BYTE *bits = FreeImage_GetScanLine(dib, h - 1 - y);
+ for(x = 0; x < w; x++) {
+ image->comps[0].data[index] = bits[FI_RGBA_RED];
+ image->comps[1].data[index] = bits[FI_RGBA_GREEN];
+ image->comps[2].data[index] = bits[FI_RGBA_BLUE];
+ bits += 3;
+ index++;
+ }
+ }
+ break;
+ case 4:
+ index = 0;
+ for(y = 0; y < h; y++) {
+ BYTE *bits = FreeImage_GetScanLine(dib, h - 1 - y);
+ for(x = 0; x < w; x++) {
+ image->comps[0].data[index] = bits[FI_RGBA_RED];
+ image->comps[1].data[index] = bits[FI_RGBA_GREEN];
+ image->comps[2].data[index] = bits[FI_RGBA_BLUE];
+ image->comps[3].data[index] = bits[FI_RGBA_ALPHA];
+ bits += 4;
+ index++;
+ }
+ }
+ break;
+ }
+ }
+ else if(prec == 16) {
+ switch(numcomps) {
+ case 1:
+ index = 0;
+ for(y = 0; y < h; y++) {
+ WORD *bits = (WORD*)FreeImage_GetScanLine(dib, h - 1 - y);
+ for(x = 0; x < w; x++) {
+ image->comps[0].data[index] = bits[x];
+ index++;
+ }
+ }
+ break;
+ case 3:
+ index = 0;
+ for(y = 0; y < h; y++) {
+ FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, h - 1 - y);
+ for(x = 0; x < w; x++) {
+ image->comps[0].data[index] = bits[x].red;
+ image->comps[1].data[index] = bits[x].green;
+ image->comps[2].data[index] = bits[x].blue;
+ index++;
+ }
+ }
+ break;
+ case 4:
+ index = 0;
+ for(y = 0; y < h; y++) {
+ FIRGBA16 *bits = (FIRGBA16*)FreeImage_GetScanLine(dib, h - 1 - y);
+ for(x = 0; x < w; x++) {
+ image->comps[0].data[index] = bits[x].red;
+ image->comps[1].data[index] = bits[x].green;
+ image->comps[2].data[index] = bits[x].blue;
+ image->comps[3].data[index] = bits[x].alpha;
+ index++;
+ }
+ }
+ break;
+ }
+ }
+
+ return image;
+
+ } catch (const char *text) {
+ if(image) opj_image_destroy(image);
+ FreeImage_OutputMessageProc(format_id, text);
+ return NULL;
+ }
+}
diff --git a/plugins/AdvaImg/src/FreeImage/J2KHelper.h b/plugins/AdvaImg/src/FreeImage/J2KHelper.h
new file mode 100644
index 0000000000..a8121f164e
--- /dev/null
+++ b/plugins/AdvaImg/src/FreeImage/J2KHelper.h
@@ -0,0 +1,36 @@
+#ifndef J2K_HELPER_H
+#define J2K_HELPER_H
+
+// ==========================================================
+// Helper functions (see J2KHelper.cpp)
+// ==========================================================
+
+/**
+FreeImageIO wrapper
+*/
+typedef struct tagJ2KFIO_t {
+ FreeImageIO *io; //! FreeImage IO
+ fi_handle handle; //! FreeImage handle
+ opj_stream_t *stream; //! OpenJPEG stream
+} J2KFIO_t;
+
+/**
+Stream constructor
+*/
+J2KFIO_t* opj_freeimage_stream_create(FreeImageIO *io, fi_handle handle, BOOL bRead);
+
+/**
+Stream destructor
+*/
+void opj_freeimage_stream_destroy(J2KFIO_t* fio);
+
+/**
+Conversion opj_image_t => FIBITMAP
+*/
+FIBITMAP* J2KImageToFIBITMAP(int format_id, const opj_image_t *image, BOOL header_only);
+/**
+Conversion FIBITMAP => opj_image_t
+*/
+opj_image_t* FIBITMAPToJ2KImage(int format_id, FIBITMAP *dib, const opj_cparameters_t *parameters);
+
+#endif // J2K_HELPER_H \ No newline at end of file
diff --git a/plugins/AdvaImg/src/FreeImage/MultiPage.cpp b/plugins/AdvaImg/src/FreeImage/MultiPage.cpp
index 60ce85eb10..d48e11be94 100644
--- a/plugins/AdvaImg/src/FreeImage/MultiPage.cpp
+++ b/plugins/AdvaImg/src/FreeImage/MultiPage.cpp
@@ -1,990 +1,990 @@
-// ==========================================================
-// Multi-Page functions
-//
-// Design and implementation by
-// - Floris van den Berg (flvdberg@wxs.nl)
-// - Laurent Rocher (rocherl@club-internet.fr)
-// - Steve Johnson (steve@parisgroup.net)
-// - Petr Pytelka (pyta@lightcomp.com)
-// - Hervé Drolon (drolon@infonie.fr)
-// - Vadim Alexandrov (vadimalexandrov@users.sourceforge.net
-// - Martin Dyring-Andersen (mda@spamfighter.com)
-// - Volodymyr Goncharov (volodymyr.goncharov@gmail.com)
-//
-// 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!
-// ==========================================================
-
-#ifdef _MSC_VER
-#pragma warning (disable : 4786) // identifier was truncated to 'number' characters
-#endif
-
-#include "CacheFile.h"
-#include "FreeImageIO.h"
-#include "Plugin.h"
-#include "Utilities.h"
-#include "FreeImage.h"
-
-// ----------------------------------------------------------
-
-enum BlockType { BLOCK_CONTINUEUS, BLOCK_REFERENCE };
-
-// ----------------------------------------------------------
-
-struct BlockTypeS {
- BlockType m_type;
-
- BlockTypeS(BlockType type) : m_type(type) {
- }
- virtual ~BlockTypeS() {}
-};
-
-struct BlockContinueus : public BlockTypeS {
- int m_start;
- int m_end;
-
- BlockContinueus(int s, int e) : BlockTypeS(BLOCK_CONTINUEUS),
- m_start(s),
- m_end(e) {
- }
-};
-
-struct BlockReference : public BlockTypeS {
- int m_reference;
- int m_size;
-
- BlockReference(int r, int size) : BlockTypeS(BLOCK_REFERENCE),
- m_reference(r),
- m_size(size) {
- }
-};
-
-// ----------------------------------------------------------
-
-typedef std::list<BlockTypeS *> BlockList;
-typedef std::list<BlockTypeS *>::iterator BlockListIterator;
-
-// ----------------------------------------------------------
-
-FI_STRUCT (MULTIBITMAPHEADER) {
- PluginNode *node;
- FREE_IMAGE_FORMAT fif;
- FreeImageIO *io;
- fi_handle handle;
- CacheFile *m_cachefile;
- std::map<FIBITMAP *, int> locked_pages;
- BOOL changed;
- int page_count;
- BlockList m_blocks;
- char *m_filename;
- BOOL read_only;
- FREE_IMAGE_FORMAT cache_fif;
- int load_flags;
-};
-
-// =====================================================================
-// Helper functions
-// =====================================================================
-
-inline void
-ReplaceExtension(std::string& dst_filename, const std::string& src_filename, const std::string& dst_extension) {
- size_t lastDot = src_filename.find_last_of('.');
- if (lastDot == std::string::npos) {
- dst_filename = src_filename;
- dst_filename += ".";
- dst_filename += dst_extension;
- }
- else {
- dst_filename = src_filename.substr(0, lastDot + 1);
- dst_filename += dst_extension;
- }
-}
-
-// =====================================================================
-// Internal Multipage functions
-// =====================================================================
-
-inline MULTIBITMAPHEADER *
-FreeImage_GetMultiBitmapHeader(FIMULTIBITMAP *bitmap) {
- return (MULTIBITMAPHEADER *)bitmap->data;
-}
-
-static BlockListIterator DLL_CALLCONV
-FreeImage_FindBlock(FIMULTIBITMAP *bitmap, int position) {
- assert(NULL != bitmap);
-
- MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);
-
- // step 1: find the block that matches the given position
-
- int prev_count = 0;
- int count = 0;
- BlockListIterator i;
- BlockTypeS *current_block = NULL;
-
- for (i = header->m_blocks.begin(); i != header->m_blocks.end(); ++i) {
- prev_count = count;
-
- switch((*i)->m_type) {
- case BLOCK_CONTINUEUS :
- count += ((BlockContinueus *)(*i))->m_end - ((BlockContinueus *)(*i))->m_start + 1;
- break;
-
- case BLOCK_REFERENCE :
- count++;
- break;
- }
-
- current_block = *i;
-
- if (count > position)
- break;
- }
-
- // step 2: make sure we found the node. from here it gets a little complicated:
- // * if the block is there, just return it
- // * if the block is a series of blocks, split it in max 3 new blocks
- // and return the splitted block
-
- if ((current_block) && (count > position)) {
- switch(current_block->m_type) {
- case BLOCK_REFERENCE :
- return i;
-
- case BLOCK_CONTINUEUS :
- {
- BlockContinueus *block = (BlockContinueus *)current_block;
-
- if (block->m_start != block->m_end) {
- int item = block->m_start + (position - prev_count);
-
- // left part
-
- if (item != block->m_start) {
- BlockContinueus *block_a = new BlockContinueus(block->m_start, item - 1);
- header->m_blocks.insert(i, (BlockTypeS *)block_a);
- }
-
- // middle part
-
- BlockContinueus *block_b = new BlockContinueus(item, item);
- BlockListIterator block_target = header->m_blocks.insert(i, (BlockTypeS *)block_b);
-
- // right part
-
- if (item != block->m_end) {
- BlockContinueus *block_c = new BlockContinueus(item + 1, block->m_end);
- header->m_blocks.insert(i, (BlockTypeS *)block_c);
- }
-
- // remove the old block that was just splitted
-
- header->m_blocks.remove((BlockTypeS *)block);
- delete block;
-
- // return the splitted block
-
- return block_target;
- }
-
- return i;
- }
- }
- }
- // we should never go here ...
- assert(false);
- return header->m_blocks.end();
-}
-
-int DLL_CALLCONV
-FreeImage_InternalGetPageCount(FIMULTIBITMAP *bitmap) {
- if (bitmap) {
- if (((MULTIBITMAPHEADER *)bitmap->data)->handle) {
- MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);
-
- header->io->seek_proc(header->handle, 0, SEEK_SET);
-
- void *data = FreeImage_Open(header->node, header->io, header->handle, TRUE);
-
- int page_count = (header->node->m_plugin->pagecount_proc != NULL) ? header->node->m_plugin->pagecount_proc(header->io, header->handle, data) : 1;
-
- FreeImage_Close(header->node, header->io, header->handle, data);
-
- return page_count;
- }
- }
-
- return 0;
-}
-
-// =====================================================================
-// Multipage functions
-// =====================================================================
-
-FIMULTIBITMAP * DLL_CALLCONV
-FreeImage_OpenMultiBitmap(FREE_IMAGE_FORMAT fif, const char *filename, BOOL create_new, BOOL read_only, BOOL keep_cache_in_memory, int flags) {
-
- FILE *handle = NULL;
- try {
- // sanity check on the parameters
-
- if (create_new) {
- read_only = FALSE;
- }
-
- // 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<FreeImageIO> io (new FreeImageIO);
-
- SetDefaultIO(io.get());
-
- if (!create_new) {
- handle = fopen(filename, "rb");
- if (handle == NULL) {
- return NULL;
- }
- }
-
- std::auto_ptr<FIMULTIBITMAP> bitmap (new FIMULTIBITMAP);
- std::auto_ptr<MULTIBITMAPHEADER> header (new MULTIBITMAPHEADER);
- header->m_filename = new char[strlen(filename) + 1];
- strcpy(header->m_filename, filename);
- header->node = node;
- header->fif = fif;
- header->io = io.get ();
- 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();
-
- // cache the page count
-
- header->page_count = FreeImage_InternalGetPageCount(bitmap.get());
-
- // allocate a continueus block to describe the bitmap
-
- if (!create_new) {
- header->m_blocks.push_back((BlockTypeS *)new BlockContinueus(0, header->page_count - 1));
- }
-
- // set up the cache
-
- if (!read_only) {
- std::string cache_name;
- ReplaceExtension(cache_name, filename, "ficache");
-
- std::auto_ptr<CacheFile> cache_file (new CacheFile(cache_name, keep_cache_in_memory));
-
- if (cache_file->open()) {
- // we can use release() as std::bad_alloc won't be thrown from here on
- header->m_cachefile = cache_file.release();
- } else {
- // an error occured ...
- fclose(handle);
- return NULL;
- }
- }
- // return the multibitmap
- // std::bad_alloc won't be thrown from here on
- header.release(); // now owned by bitmap
- io.release(); // now owned by bitmap
- return bitmap.release(); // now owned by caller
- }
- }
- } catch (std::bad_alloc &) {
- /** @todo report error */
- }
- if (handle)
- fclose(handle);
- return NULL;
-}
-
-FIMULTIBITMAP * DLL_CALLCONV
-FreeImage_OpenMultiBitmapU(FREE_IMAGE_FORMAT fif, const wchar_t *filename, BOOL create_new, BOOL read_only, BOOL keep_cache_in_memory, int flags) {
-
- // convert to single character - no national chars in extensions
- char *extension = (char *)malloc(wcslen(filename)+1);
- unsigned int i=0;
- for (; i < wcslen(filename); i++) // convert 16-bit to 8-bit
- extension[i] = (char)(filename[i] & 0x00FF);
- // set terminating 0
- extension[i]=0;
- FIMULTIBITMAP *fRet = FreeImage_OpenMultiBitmap(fif, extension, create_new, read_only, keep_cache_in_memory, flags);
- free(extension);
-
- return fRet;
-}
-
-FIMULTIBITMAP * DLL_CALLCONV
-FreeImage_OpenMultiBitmapFromHandle(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_handle handle, int flags) {
- try {
- 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);
- std::auto_ptr<FreeImageIO> tmp_io (new FreeImageIO (*io));
- header->io = tmp_io.get();
- header->m_filename = NULL;
- header->node = node;
- header->fif = fif;
- 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();
-
- // cache the page count
-
- header->page_count = FreeImage_InternalGetPageCount(bitmap.get());
-
- // allocate a continueus block to describe the bitmap
-
- header->m_blocks.push_back((BlockTypeS *)new BlockContinueus(0, header->page_count - 1));
-
- 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();
- }
- }
- tmp_io.release();
- header.release();
- return bitmap.release();
- }
- }
- }
- } catch (std::bad_alloc &) {
- /** @todo report error */
- }
- return NULL;
-}
-
-BOOL DLL_CALLCONV
-FreeImage_SaveMultiBitmapToHandle(FREE_IMAGE_FORMAT fif, FIMULTIBITMAP *bitmap, FreeImageIO *io, fi_handle handle, int flags) {
- if(!bitmap || !bitmap->data || !io || !handle) {
- return FALSE;
- }
-
- BOOL success = TRUE;
-
- // 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) {
- MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);
-
- // dst data
- void *data = FreeImage_Open(node, io, handle, FALSE);
- // src data
- void *data_read = NULL;
-
- if(header->handle) {
- // open src
- header->io->seek_proc(header->handle, 0, SEEK_SET);
- data_read = FreeImage_Open(header->node, header->io, header->handle, TRUE);
- }
-
- // write all the pages to the file using handle and io
-
- int count = 0;
-
- for (BlockListIterator i = header->m_blocks.begin(); i != header->m_blocks.end(); i++) {
- if (success) {
- switch((*i)->m_type) {
- case BLOCK_CONTINUEUS:
- {
- BlockContinueus *block = (BlockContinueus *)(*i);
-
- for (int j = block->m_start; j <= block->m_end; j++) {
-
- // load the original source data
- FIBITMAP *dib = header->node->m_plugin->load_proc(header->io, header->handle, j, header->load_flags, data_read);
-
- // save the data
- success = node->m_plugin->save_proc(io, dib, handle, count, flags, data);
- count++;
-
- FreeImage_Unload(dib);
- }
-
- break;
- }
-
- case BLOCK_REFERENCE:
- {
- BlockReference *ref = (BlockReference *)(*i);
-
- // read the compressed data
-
- BYTE *compressed_data = (BYTE*)malloc(ref->m_size * sizeof(BYTE));
-
- header->m_cachefile->readFile((BYTE *)compressed_data, ref->m_reference, ref->m_size);
-
- // uncompress the data
-
- FIMEMORY *hmem = FreeImage_OpenMemory(compressed_data, ref->m_size);
- FIBITMAP *dib = FreeImage_LoadFromMemory(header->cache_fif, hmem, 0);
- FreeImage_CloseMemory(hmem);
-
- // get rid of the buffer
- free(compressed_data);
-
- // save the data
-
- success = node->m_plugin->save_proc(io, dib, handle, count, flags, data);
- count++;
-
- // unload the dib
-
- FreeImage_Unload(dib);
-
- break;
- }
- }
- } else {
- break;
- }
- }
-
- // close the files
-
- FreeImage_Close(header->node, header->io, header->handle, data_read);
-
- FreeImage_Close(node, io, handle, data);
-
- return success;
- }
- }
-
- return FALSE;
-}
-
-
-BOOL DLL_CALLCONV
-FreeImage_CloseMultiBitmap(FIMULTIBITMAP *bitmap, int flags) {
- if (bitmap) {
- BOOL success = TRUE;
-
- if (bitmap->data) {
- MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);
-
- // saves changes only of images loaded directly from a file
- if (header->changed && header->m_filename) {
- try {
- // open a temp file
-
- std::string spool_name;
-
- ReplaceExtension(spool_name, header->m_filename, "fispool");
-
- // open the spool file and the source file
-
- FILE *f = fopen(spool_name.c_str(), "w+b");
-
- // saves changes
- if (f == NULL) {
- FreeImage_OutputMessageProc(header->fif, "Failed to open %s, %s", spool_name.c_str(), strerror(errno));
- success = FALSE;
- } else {
- success = FreeImage_SaveMultiBitmapToHandle(header->fif, bitmap, header->io, (fi_handle)f, flags);
-
- // close the files
-
- if (fclose(f) != 0) {
- success = FALSE;
- FreeImage_OutputMessageProc(header->fif, "Failed to close %s, %s", spool_name.c_str(), strerror(errno));
- }
- }
- if (header->handle) {
- fclose((FILE *)header->handle);
- }
-
- // applies changes to the destination file
-
- if (success) {
- remove(header->m_filename);
- success = (rename(spool_name.c_str(), header->m_filename) == 0) ? TRUE:FALSE;
- if(!success) {
- FreeImage_OutputMessageProc(header->fif, "Failed to rename %s to %s", spool_name.c_str(), header->m_filename);
- }
- } else {
- remove(spool_name.c_str());
- }
- } catch (std::bad_alloc &) {
- success = FALSE;
- }
-
- } else {
- if (header->handle && header->m_filename) {
- fclose((FILE *)header->handle);
- }
- }
-
- // clear the blocks list
-
- for (BlockListIterator i = header->m_blocks.begin(); i != header->m_blocks.end(); ++i) {
- delete *i;
- }
-
- // flush and dispose the cache
-
- if (header->m_cachefile) {
- header->m_cachefile->close();
- delete header->m_cachefile;
- }
-
- // delete the last open bitmaps
-
- while (!header->locked_pages.empty()) {
- FreeImage_Unload(header->locked_pages.begin()->first);
-
- header->locked_pages.erase(header->locked_pages.begin()->first);
- }
-
- // get rid of the IO structure
-
- delete header->io;
-
- // delete the filename
-
- if(header->m_filename) {
- delete[] header->m_filename;
- }
-
- // delete the FIMULTIBITMAPHEADER
-
- delete header;
- }
-
- delete bitmap;
-
- return success;
- }
-
- return FALSE;
-}
-
-int DLL_CALLCONV
-FreeImage_GetPageCount(FIMULTIBITMAP *bitmap) {
- if (bitmap) {
- MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);
-
- if (header->page_count == -1) {
- header->page_count = 0;
-
- for (BlockListIterator i = header->m_blocks.begin(); i != header->m_blocks.end(); ++i) {
- switch((*i)->m_type) {
- case BLOCK_CONTINUEUS :
- header->page_count += ((BlockContinueus *)(*i))->m_end - ((BlockContinueus *)(*i))->m_start + 1;
- break;
-
- case BLOCK_REFERENCE :
- header->page_count++;
- break;
- }
- }
- }
-
- return header->page_count;
- }
-
- return 0;
-}
-
-static BlockReference*
-FreeImage_SavePageToBlock(MULTIBITMAPHEADER *header, FIBITMAP *data) {
- if (header->read_only || !header->locked_pages.empty())
- return NULL;
-
- DWORD compressed_size = 0;
- BYTE *compressed_data = NULL;
-
- // compress the bitmap data
-
- // open a memory handle
- FIMEMORY *hmem = FreeImage_OpenMemory();
- if(hmem==NULL) return NULL;
- // save the file to memory
- if(!FreeImage_SaveToMemory(header->cache_fif, data, hmem, 0)) {
- FreeImage_CloseMemory(hmem);
- return NULL;
- }
- // get the buffer from the memory stream
- if(!FreeImage_AcquireMemory(hmem, &compressed_data, &compressed_size)) {
- FreeImage_CloseMemory(hmem);
- return NULL;
- }
-
- // write the compressed data to the cache
- int ref = header->m_cachefile->writeFile(compressed_data, compressed_size);
- // get rid of the compressed data
- FreeImage_CloseMemory(hmem);
-
- return new(std::nothrow) BlockReference(ref, compressed_size);
-}
-
-void DLL_CALLCONV
-FreeImage_AppendPage(FIMULTIBITMAP *bitmap, FIBITMAP *data) {
- if (!bitmap || !data)
- return;
-
- MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);
-
- BlockReference *block = FreeImage_SavePageToBlock(header, data);
- if(block==NULL) return;
-
- // add the block
- header->m_blocks.push_back((BlockTypeS *)block);
- header->changed = TRUE;
- header->page_count = -1;
-}
-
-void DLL_CALLCONV
-FreeImage_InsertPage(FIMULTIBITMAP *bitmap, int page, FIBITMAP *data) {
- if (!bitmap || !data)
- return;
-
- if (page >= FreeImage_GetPageCount(bitmap))
- return;
-
- MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);
-
- BlockReference *block = FreeImage_SavePageToBlock(header, data);
- if(block==NULL) return;
-
- // add a block
- if (page > 0) {
- BlockListIterator block_source = FreeImage_FindBlock(bitmap, page);
-
- header->m_blocks.insert(block_source, (BlockTypeS *)block);
- } else {
- header->m_blocks.push_front((BlockTypeS *)block);
- }
-
- header->changed = TRUE;
- header->page_count = -1;
-}
-
-void DLL_CALLCONV
-FreeImage_DeletePage(FIMULTIBITMAP *bitmap, int page) {
- if (bitmap) {
- MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);
-
- if ((!header->read_only) && (header->locked_pages.empty())) {
- if (FreeImage_GetPageCount(bitmap) > 1) {
- BlockListIterator i = FreeImage_FindBlock(bitmap, page);
-
- if (i != header->m_blocks.end()) {
- switch((*i)->m_type) {
- case BLOCK_CONTINUEUS :
- delete *i;
- header->m_blocks.erase(i);
- break;
-
- case BLOCK_REFERENCE :
- header->m_cachefile->deleteFile(((BlockReference *)(*i))->m_reference);
- delete *i;
- header->m_blocks.erase(i);
- break;
- }
-
- header->changed = TRUE;
- header->page_count = -1;
- }
- }
- }
- }
-}
-
-
-FIBITMAP * DLL_CALLCONV
-FreeImage_LockPage(FIMULTIBITMAP *bitmap, int page) {
- if (bitmap) {
- MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);
-
- // only lock if the page wasn't locked before...
-
- for (std::map<FIBITMAP *, int>::iterator i = header->locked_pages.begin(); i != header->locked_pages.end(); ++i) {
- if (i->second == page) {
- return NULL;
- }
- }
-
- // open the bitmap
-
- header->io->seek_proc(header->handle, 0, SEEK_SET);
-
- void *data = FreeImage_Open(header->node, header->io, header->handle, TRUE);
-
- // load the bitmap data
-
- if (data != NULL) {
- FIBITMAP *dib = (header->node->m_plugin->load_proc != NULL) ? header->node->m_plugin->load_proc(header->io, header->handle, page, header->load_flags, data) : NULL;
-
- // close the file
-
- FreeImage_Close(header->node, header->io, header->handle, data);
-
- // if there was still another bitmap open, get rid of it
-
- if (dib) {
- header->locked_pages[dib] = page;
-
- return dib;
- }
-
- return NULL;
- }
- }
-
- return NULL;
-}
-
-void DLL_CALLCONV
-FreeImage_UnlockPage(FIMULTIBITMAP *bitmap, FIBITMAP *page, BOOL changed) {
- if ((bitmap) && (page)) {
- MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);
-
- // find out if the page we try to unlock is actually locked...
-
- if (header->locked_pages.find(page) != header->locked_pages.end()) {
- // store the bitmap compressed in the cache for later writing
-
- if (changed && !header->read_only) {
- header->changed = TRUE;
-
- // cut loose the block from the rest
-
- BlockListIterator i = FreeImage_FindBlock(bitmap, header->locked_pages[page]);
-
- // compress the data
-
- DWORD compressed_size = 0;
- BYTE *compressed_data = NULL;
-
- // open a memory handle
- FIMEMORY *hmem = FreeImage_OpenMemory();
- // save the page to memory
- FreeImage_SaveToMemory(header->cache_fif, page, hmem, 0);
- // get the buffer from the memory stream
- FreeImage_AcquireMemory(hmem, &compressed_data, &compressed_size);
-
- // write the data to the cache
-
- switch ((*i)->m_type) {
- case BLOCK_CONTINUEUS :
- {
- int iPage = header->m_cachefile->writeFile(compressed_data, compressed_size);
-
- delete (*i);
-
- *i = (BlockTypeS *)new BlockReference(iPage, compressed_size);
-
- break;
- }
-
- case BLOCK_REFERENCE :
- {
- BlockReference *reference = (BlockReference *)(*i);
-
- header->m_cachefile->deleteFile(reference->m_reference);
-
- delete (*i);
-
- int iPage = header->m_cachefile->writeFile(compressed_data, compressed_size);
-
- *i = (BlockTypeS *)new BlockReference(iPage, compressed_size);
-
- break;
- }
- }
-
- // get rid of the compressed data
-
- FreeImage_CloseMemory(hmem);
- }
-
- // reset the locked page so that another page can be locked
-
- FreeImage_Unload(page);
-
- header->locked_pages.erase(page);
- }
- }
-}
-
-BOOL DLL_CALLCONV
-FreeImage_MovePage(FIMULTIBITMAP *bitmap, int target, int source) {
- if (bitmap) {
- MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);
-
- if ((!header->read_only) && (header->locked_pages.empty())) {
- if ((target != source) && ((target >= 0) && (target < FreeImage_GetPageCount(bitmap))) && ((source >= 0) && (source < FreeImage_GetPageCount(bitmap)))) {
- BlockListIterator block_source = FreeImage_FindBlock(bitmap, target);
- BlockListIterator block_target = FreeImage_FindBlock(bitmap, source);
-
- header->m_blocks.insert(block_target, *block_source);
- header->m_blocks.erase(block_source);
-
- header->changed = TRUE;
-
- return TRUE;
- }
- }
- }
-
- return FALSE;
-}
-
-BOOL DLL_CALLCONV
-FreeImage_GetLockedPageNumbers(FIMULTIBITMAP *bitmap, int *pages, int *count) {
- if ((bitmap) && (count)) {
- MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);
-
- if ((pages == NULL) || (*count == 0)) {
- *count = (int)header->locked_pages.size();
- } else {
- int c = 0;
-
- for (std::map<FIBITMAP *, int>::iterator i = header->locked_pages.begin(); i != header->locked_pages.end(); ++i) {
- pages[c] = i->second;
-
- c++;
-
- if (c == *count)
- break;
- }
- }
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-// =====================================================================
-// Memory IO Multipage functions
-// =====================================================================
-
-FIMULTIBITMAP * DLL_CALLCONV
-FreeImage_LoadMultiBitmapFromMemory(FREE_IMAGE_FORMAT fif, FIMEMORY *stream, int flags) {
- BOOL read_only = FALSE; // modifications (if any) will be stored into the memory cache
-
- // 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) {
- FreeImageIO *io = new(std::nothrow) FreeImageIO;
-
- if (io) {
- SetMemoryIO(io);
-
- FIMULTIBITMAP *bitmap = new(std::nothrow) FIMULTIBITMAP;
-
- if (bitmap) {
- MULTIBITMAPHEADER *header = new(std::nothrow) MULTIBITMAPHEADER;
-
- if (header) {
- header->m_filename = NULL;
- header->node = node;
- header->fif = fif;
- header->io = io;
- header->handle = (fi_handle)stream;
- 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;
-
- // cache the page count
-
- header->page_count = FreeImage_InternalGetPageCount(bitmap);
-
- // allocate a continueus block to describe the bitmap
-
- header->m_blocks.push_back((BlockTypeS *)new BlockContinueus(0, header->page_count - 1));
-
- if (!read_only) {
- // set up the cache
- CacheFile *cache_file = new(std::nothrow) CacheFile("", TRUE);
-
- if (cache_file && cache_file->open()) {
- header->m_cachefile = cache_file;
- }
- }
-
- return bitmap;
- }
-
- delete bitmap;
- }
-
- delete io;
- }
- }
- }
-
- return NULL;
-}
-
-BOOL DLL_CALLCONV
-FreeImage_SaveMultiBitmapToMemory(FREE_IMAGE_FORMAT fif, FIMULTIBITMAP *bitmap, FIMEMORY *stream, int flags) {
- if (stream && stream->data) {
- FreeImageIO io;
- SetMemoryIO(&io);
-
- return FreeImage_SaveMultiBitmapToHandle(fif, bitmap, &io, (fi_handle)stream, flags);
- }
-
- return FALSE;
-}
+// ==========================================================
+// Multi-Page functions
+//
+// Design and implementation by
+// - Floris van den Berg (flvdberg@wxs.nl)
+// - Laurent Rocher (rocherl@club-internet.fr)
+// - Steve Johnson (steve@parisgroup.net)
+// - Petr Pytelka (pyta@lightcomp.com)
+// - Hervé Drolon (drolon@infonie.fr)
+// - Vadim Alexandrov (vadimalexandrov@users.sourceforge.net
+// - Martin Dyring-Andersen (mda@spamfighter.com)
+// - Volodymyr Goncharov (volodymyr.goncharov@gmail.com)
+//
+// 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!
+// ==========================================================
+
+#ifdef _MSC_VER
+#pragma warning (disable : 4786) // identifier was truncated to 'number' characters
+#endif
+
+#include "CacheFile.h"
+#include "FreeImageIO.h"
+#include "Plugin.h"
+#include "Utilities.h"
+#include "FreeImage.h"
+
+// ----------------------------------------------------------
+
+enum BlockType { BLOCK_CONTINUEUS, BLOCK_REFERENCE };
+
+// ----------------------------------------------------------
+
+struct BlockTypeS {
+ BlockType m_type;
+
+ BlockTypeS(BlockType type) : m_type(type) {
+ }
+ virtual ~BlockTypeS() {}
+};
+
+struct BlockContinueus : public BlockTypeS {
+ int m_start;
+ int m_end;
+
+ BlockContinueus(int s, int e) : BlockTypeS(BLOCK_CONTINUEUS),
+ m_start(s),
+ m_end(e) {
+ }
+};
+
+struct BlockReference : public BlockTypeS {
+ int m_reference;
+ int m_size;
+
+ BlockReference(int r, int size) : BlockTypeS(BLOCK_REFERENCE),
+ m_reference(r),
+ m_size(size) {
+ }
+};
+
+// ----------------------------------------------------------
+
+typedef std::list<BlockTypeS *> BlockList;
+typedef std::list<BlockTypeS *>::iterator BlockListIterator;
+
+// ----------------------------------------------------------
+
+FI_STRUCT (MULTIBITMAPHEADER) {
+ PluginNode *node;
+ FREE_IMAGE_FORMAT fif;
+ FreeImageIO *io;
+ fi_handle handle;
+ CacheFile *m_cachefile;
+ std::map<FIBITMAP *, int> locked_pages;
+ BOOL changed;
+ int page_count;
+ BlockList m_blocks;
+ char *m_filename;
+ BOOL read_only;
+ FREE_IMAGE_FORMAT cache_fif;
+ int load_flags;
+};
+
+// =====================================================================
+// Helper functions
+// =====================================================================
+
+inline void
+ReplaceExtension(std::string& dst_filename, const std::string& src_filename, const std::string& dst_extension) {
+ size_t lastDot = src_filename.find_last_of('.');
+ if (lastDot == std::string::npos) {
+ dst_filename = src_filename;
+ dst_filename += ".";
+ dst_filename += dst_extension;
+ }
+ else {
+ dst_filename = src_filename.substr(0, lastDot + 1);
+ dst_filename += dst_extension;
+ }
+}
+
+// =====================================================================
+// Internal Multipage functions
+// =====================================================================
+
+inline MULTIBITMAPHEADER *
+FreeImage_GetMultiBitmapHeader(FIMULTIBITMAP *bitmap) {
+ return (MULTIBITMAPHEADER *)bitmap->data;
+}
+
+static BlockListIterator DLL_CALLCONV
+FreeImage_FindBlock(FIMULTIBITMAP *bitmap, int position) {
+ assert(NULL != bitmap);
+
+ MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);
+
+ // step 1: find the block that matches the given position
+
+ int prev_count = 0;
+ int count = 0;
+ BlockListIterator i;
+ BlockTypeS *current_block = NULL;
+
+ for (i = header->m_blocks.begin(); i != header->m_blocks.end(); ++i) {
+ prev_count = count;
+
+ switch((*i)->m_type) {
+ case BLOCK_CONTINUEUS :
+ count += ((BlockContinueus *)(*i))->m_end - ((BlockContinueus *)(*i))->m_start + 1;
+ break;
+
+ case BLOCK_REFERENCE :
+ count++;
+ break;
+ }
+
+ current_block = *i;
+
+ if (count > position)
+ break;
+ }
+
+ // step 2: make sure we found the node. from here it gets a little complicated:
+ // * if the block is there, just return it
+ // * if the block is a series of blocks, split it in max 3 new blocks
+ // and return the splitted block
+
+ if ((current_block) && (count > position)) {
+ switch(current_block->m_type) {
+ case BLOCK_REFERENCE :
+ return i;
+
+ case BLOCK_CONTINUEUS :
+ {
+ BlockContinueus *block = (BlockContinueus *)current_block;
+
+ if (block->m_start != block->m_end) {
+ int item = block->m_start + (position - prev_count);
+
+ // left part
+
+ if (item != block->m_start) {
+ BlockContinueus *block_a = new BlockContinueus(block->m_start, item - 1);
+ header->m_blocks.insert(i, (BlockTypeS *)block_a);
+ }
+
+ // middle part
+
+ BlockContinueus *block_b = new BlockContinueus(item, item);
+ BlockListIterator block_target = header->m_blocks.insert(i, (BlockTypeS *)block_b);
+
+ // right part
+
+ if (item != block->m_end) {
+ BlockContinueus *block_c = new BlockContinueus(item + 1, block->m_end);
+ header->m_blocks.insert(i, (BlockTypeS *)block_c);
+ }
+
+ // remove the old block that was just splitted
+
+ header->m_blocks.remove((BlockTypeS *)block);
+ delete block;
+
+ // return the splitted block
+
+ return block_target;
+ }
+
+ return i;
+ }
+ }
+ }
+ // we should never go here ...
+ assert(false);
+ return header->m_blocks.end();
+}
+
+int DLL_CALLCONV
+FreeImage_InternalGetPageCount(FIMULTIBITMAP *bitmap) {
+ if (bitmap) {
+ if (((MULTIBITMAPHEADER *)bitmap->data)->handle) {
+ MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);
+
+ header->io->seek_proc(header->handle, 0, SEEK_SET);
+
+ void *data = FreeImage_Open(header->node, header->io, header->handle, TRUE);
+
+ int page_count = (header->node->m_plugin->pagecount_proc != NULL) ? header->node->m_plugin->pagecount_proc(header->io, header->handle, data) : 1;
+
+ FreeImage_Close(header->node, header->io, header->handle, data);
+
+ return page_count;
+ }
+ }
+
+ return 0;
+}
+
+// =====================================================================
+// Multipage functions
+// =====================================================================
+
+FIMULTIBITMAP * DLL_CALLCONV
+FreeImage_OpenMultiBitmap(FREE_IMAGE_FORMAT fif, const char *filename, BOOL create_new, BOOL read_only, BOOL keep_cache_in_memory, int flags) {
+
+ FILE *handle = NULL;
+ try {
+ // sanity check on the parameters
+
+ if (create_new) {
+ read_only = FALSE;
+ }
+
+ // 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<FreeImageIO> io (new FreeImageIO);
+
+ SetDefaultIO(io.get());
+
+ if (!create_new) {
+ handle = fopen(filename, "rb");
+ if (handle == NULL) {
+ return NULL;
+ }
+ }
+
+ std::auto_ptr<FIMULTIBITMAP> bitmap (new FIMULTIBITMAP);
+ std::auto_ptr<MULTIBITMAPHEADER> header (new MULTIBITMAPHEADER);
+ header->m_filename = new char[strlen(filename) + 1];
+ strcpy(header->m_filename, filename);
+ header->node = node;
+ header->fif = fif;
+ header->io = io.get ();
+ 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();
+
+ // cache the page count
+
+ header->page_count = FreeImage_InternalGetPageCount(bitmap.get());
+
+ // allocate a continueus block to describe the bitmap
+
+ if (!create_new) {
+ header->m_blocks.push_back((BlockTypeS *)new BlockContinueus(0, header->page_count - 1));
+ }
+
+ // set up the cache
+
+ if (!read_only) {
+ std::string cache_name;
+ ReplaceExtension(cache_name, filename, "ficache");
+
+ std::auto_ptr<CacheFile> cache_file (new CacheFile(cache_name, keep_cache_in_memory));
+
+ if (cache_file->open()) {
+ // we can use release() as std::bad_alloc won't be thrown from here on
+ header->m_cachefile = cache_file.release();
+ } else {
+ // an error occured ...
+ fclose(handle);
+ return NULL;
+ }
+ }
+ // return the multibitmap
+ // std::bad_alloc won't be thrown from here on
+ header.release(); // now owned by bitmap
+ io.release(); // now owned by bitmap
+ return bitmap.release(); // now owned by caller
+ }
+ }
+ } catch (std::bad_alloc &) {
+ /** @todo report error */
+ }
+ if (handle)
+ fclose(handle);
+ return NULL;
+}
+
+FIMULTIBITMAP * DLL_CALLCONV
+FreeImage_OpenMultiBitmapU(FREE_IMAGE_FORMAT fif, const wchar_t *filename, BOOL create_new, BOOL read_only, BOOL keep_cache_in_memory, int flags) {
+
+ // convert to single character - no national chars in extensions
+ char *extension = (char *)malloc(wcslen(filename)+1);
+ unsigned int i=0;
+ for (; i < wcslen(filename); i++) // convert 16-bit to 8-bit
+ extension[i] = (char)(filename[i] & 0x00FF);
+ // set terminating 0
+ extension[i]=0;
+ FIMULTIBITMAP *fRet = FreeImage_OpenMultiBitmap(fif, extension, create_new, read_only, keep_cache_in_memory, flags);
+ free(extension);
+
+ return fRet;
+}
+
+FIMULTIBITMAP * DLL_CALLCONV
+FreeImage_OpenMultiBitmapFromHandle(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_handle handle, int flags) {
+ try {
+ 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);
+ std::auto_ptr<FreeImageIO> tmp_io (new FreeImageIO (*io));
+ header->io = tmp_io.get();
+ header->m_filename = NULL;
+ header->node = node;
+ header->fif = fif;
+ 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();
+
+ // cache the page count
+
+ header->page_count = FreeImage_InternalGetPageCount(bitmap.get());
+
+ // allocate a continueus block to describe the bitmap
+
+ header->m_blocks.push_back((BlockTypeS *)new BlockContinueus(0, header->page_count - 1));
+
+ 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();
+ }
+ }
+ tmp_io.release();
+ header.release();
+ return bitmap.release();
+ }
+ }
+ }
+ } catch (std::bad_alloc &) {
+ /** @todo report error */
+ }
+ return NULL;
+}
+
+BOOL DLL_CALLCONV
+FreeImage_SaveMultiBitmapToHandle(FREE_IMAGE_FORMAT fif, FIMULTIBITMAP *bitmap, FreeImageIO *io, fi_handle handle, int flags) {
+ if(!bitmap || !bitmap->data || !io || !handle) {
+ return FALSE;
+ }
+
+ BOOL success = TRUE;
+
+ // 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) {
+ MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);
+
+ // dst data
+ void *data = FreeImage_Open(node, io, handle, FALSE);
+ // src data
+ void *data_read = NULL;
+
+ if(header->handle) {
+ // open src
+ header->io->seek_proc(header->handle, 0, SEEK_SET);
+ data_read = FreeImage_Open(header->node, header->io, header->handle, TRUE);
+ }
+
+ // write all the pages to the file using handle and io
+
+ int count = 0;
+
+ for (BlockListIterator i = header->m_blocks.begin(); i != header->m_blocks.end(); i++) {
+ if (success) {
+ switch((*i)->m_type) {
+ case BLOCK_CONTINUEUS:
+ {
+ BlockContinueus *block = (BlockContinueus *)(*i);
+
+ for (int j = block->m_start; j <= block->m_end; j++) {
+
+ // load the original source data
+ FIBITMAP *dib = header->node->m_plugin->load_proc(header->io, header->handle, j, header->load_flags, data_read);
+
+ // save the data
+ success = node->m_plugin->save_proc(io, dib, handle, count, flags, data);
+ count++;
+
+ FreeImage_Unload(dib);
+ }
+
+ break;
+ }
+
+ case BLOCK_REFERENCE:
+ {
+ BlockReference *ref = (BlockReference *)(*i);
+
+ // read the compressed data
+
+ BYTE *compressed_data = (BYTE*)malloc(ref->m_size * sizeof(BYTE));
+
+ header->m_cachefile->readFile((BYTE *)compressed_data, ref->m_reference, ref->m_size);
+
+ // uncompress the data
+
+ FIMEMORY *hmem = FreeImage_OpenMemory(compressed_data, ref->m_size);
+ FIBITMAP *dib = FreeImage_LoadFromMemory(header->cache_fif, hmem, 0);
+ FreeImage_CloseMemory(hmem);
+
+ // get rid of the buffer
+ free(compressed_data);
+
+ // save the data
+
+ success = node->m_plugin->save_proc(io, dib, handle, count, flags, data);
+ count++;
+
+ // unload the dib
+
+ FreeImage_Unload(dib);
+
+ break;
+ }
+ }
+ } else {
+ break;
+ }
+ }
+
+ // close the files
+
+ FreeImage_Close(header->node, header->io, header->handle, data_read);
+
+ FreeImage_Close(node, io, handle, data);
+
+ return success;
+ }
+ }
+
+ return FALSE;
+}
+
+
+BOOL DLL_CALLCONV
+FreeImage_CloseMultiBitmap(FIMULTIBITMAP *bitmap, int flags) {
+ if (bitmap) {
+ BOOL success = TRUE;
+
+ if (bitmap->data) {
+ MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);
+
+ // saves changes only of images loaded directly from a file
+ if (header->changed && header->m_filename) {
+ try {
+ // open a temp file
+
+ std::string spool_name;
+
+ ReplaceExtension(spool_name, header->m_filename, "fispool");
+
+ // open the spool file and the source file
+
+ FILE *f = fopen(spool_name.c_str(), "w+b");
+
+ // saves changes
+ if (f == NULL) {
+ FreeImage_OutputMessageProc(header->fif, "Failed to open %s, %s", spool_name.c_str(), strerror(errno));
+ success = FALSE;
+ } else {
+ success = FreeImage_SaveMultiBitmapToHandle(header->fif, bitmap, header->io, (fi_handle)f, flags);
+
+ // close the files
+
+ if (fclose(f) != 0) {
+ success = FALSE;
+ FreeImage_OutputMessageProc(header->fif, "Failed to close %s, %s", spool_name.c_str(), strerror(errno));
+ }
+ }
+ if (header->handle) {
+ fclose((FILE *)header->handle);
+ }
+
+ // applies changes to the destination file
+
+ if (success) {
+ remove(header->m_filename);
+ success = (rename(spool_name.c_str(), header->m_filename) == 0) ? TRUE:FALSE;
+ if(!success) {
+ FreeImage_OutputMessageProc(header->fif, "Failed to rename %s to %s", spool_name.c_str(), header->m_filename);
+ }
+ } else {
+ remove(spool_name.c_str());
+ }
+ } catch (std::bad_alloc &) {
+ success = FALSE;
+ }
+
+ } else {
+ if (header->handle && header->m_filename) {
+ fclose((FILE *)header->handle);
+ }
+ }
+
+ // clear the blocks list
+
+ for (BlockListIterator i = header->m_blocks.begin(); i != header->m_blocks.end(); ++i) {
+ delete *i;
+ }
+
+ // flush and dispose the cache
+
+ if (header->m_cachefile) {
+ header->m_cachefile->close();
+ delete header->m_cachefile;
+ }
+
+ // delete the last open bitmaps
+
+ while (!header->locked_pages.empty()) {
+ FreeImage_Unload(header->locked_pages.begin()->first);
+
+ header->locked_pages.erase(header->locked_pages.begin()->first);
+ }
+
+ // get rid of the IO structure
+
+ delete header->io;
+
+ // delete the filename
+
+ if(header->m_filename) {
+ delete[] header->m_filename;
+ }
+
+ // delete the FIMULTIBITMAPHEADER
+
+ delete header;
+ }
+
+ delete bitmap;
+
+ return success;
+ }
+
+ return FALSE;
+}
+
+int DLL_CALLCONV
+FreeImage_GetPageCount(FIMULTIBITMAP *bitmap) {
+ if (bitmap) {
+ MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);
+
+ if (header->page_count == -1) {
+ header->page_count = 0;
+
+ for (BlockListIterator i = header->m_blocks.begin(); i != header->m_blocks.end(); ++i) {
+ switch((*i)->m_type) {
+ case BLOCK_CONTINUEUS :
+ header->page_count += ((BlockContinueus *)(*i))->m_end - ((BlockContinueus *)(*i))->m_start + 1;
+ break;
+
+ case BLOCK_REFERENCE :
+ header->page_count++;
+ break;
+ }
+ }
+ }
+
+ return header->page_count;
+ }
+
+ return 0;
+}
+
+static BlockReference*
+FreeImage_SavePageToBlock(MULTIBITMAPHEADER *header, FIBITMAP *data) {
+ if (header->read_only || !header->locked_pages.empty())
+ return NULL;
+
+ DWORD compressed_size = 0;
+ BYTE *compressed_data = NULL;
+
+ // compress the bitmap data
+
+ // open a memory handle
+ FIMEMORY *hmem = FreeImage_OpenMemory();
+ if(hmem==NULL) return NULL;
+ // save the file to memory
+ if(!FreeImage_SaveToMemory(header->cache_fif, data, hmem, 0)) {
+ FreeImage_CloseMemory(hmem);
+ return NULL;
+ }
+ // get the buffer from the memory stream
+ if(!FreeImage_AcquireMemory(hmem, &compressed_data, &compressed_size)) {
+ FreeImage_CloseMemory(hmem);
+ return NULL;
+ }
+
+ // write the compressed data to the cache
+ int ref = header->m_cachefile->writeFile(compressed_data, compressed_size);
+ // get rid of the compressed data
+ FreeImage_CloseMemory(hmem);
+
+ return new(std::nothrow) BlockReference(ref, compressed_size);
+}
+
+void DLL_CALLCONV
+FreeImage_AppendPage(FIMULTIBITMAP *bitmap, FIBITMAP *data) {
+ if (!bitmap || !data)
+ return;
+
+ MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);
+
+ BlockReference *block = FreeImage_SavePageToBlock(header, data);
+ if(block==NULL) return;
+
+ // add the block
+ header->m_blocks.push_back((BlockTypeS *)block);
+ header->changed = TRUE;
+ header->page_count = -1;
+}
+
+void DLL_CALLCONV
+FreeImage_InsertPage(FIMULTIBITMAP *bitmap, int page, FIBITMAP *data) {
+ if (!bitmap || !data)
+ return;
+
+ if (page >= FreeImage_GetPageCount(bitmap))
+ return;
+
+ MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);
+
+ BlockReference *block = FreeImage_SavePageToBlock(header, data);
+ if(block==NULL) return;
+
+ // add a block
+ if (page > 0) {
+ BlockListIterator block_source = FreeImage_FindBlock(bitmap, page);
+
+ header->m_blocks.insert(block_source, (BlockTypeS *)block);
+ } else {
+ header->m_blocks.push_front((BlockTypeS *)block);
+ }
+
+ header->changed = TRUE;
+ header->page_count = -1;
+}
+
+void DLL_CALLCONV
+FreeImage_DeletePage(FIMULTIBITMAP *bitmap, int page) {
+ if (bitmap) {
+ MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);
+
+ if ((!header->read_only) && (header->locked_pages.empty())) {
+ if (FreeImage_GetPageCount(bitmap) > 1) {
+ BlockListIterator i = FreeImage_FindBlock(bitmap, page);
+
+ if (i != header->m_blocks.end()) {
+ switch((*i)->m_type) {
+ case BLOCK_CONTINUEUS :
+ delete *i;
+ header->m_blocks.erase(i);
+ break;
+
+ case BLOCK_REFERENCE :
+ header->m_cachefile->deleteFile(((BlockReference *)(*i))->m_reference);
+ delete *i;
+ header->m_blocks.erase(i);
+ break;
+ }
+
+ header->changed = TRUE;
+ header->page_count = -1;
+ }
+ }
+ }
+ }
+}
+
+
+FIBITMAP * DLL_CALLCONV
+FreeImage_LockPage(FIMULTIBITMAP *bitmap, int page) {
+ if (bitmap) {
+ MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);
+
+ // only lock if the page wasn't locked before...
+
+ for (std::map<FIBITMAP *, int>::iterator i = header->locked_pages.begin(); i != header->locked_pages.end(); ++i) {
+ if (i->second == page) {
+ return NULL;
+ }
+ }
+
+ // open the bitmap
+
+ header->io->seek_proc(header->handle, 0, SEEK_SET);
+
+ void *data = FreeImage_Open(header->node, header->io, header->handle, TRUE);
+
+ // load the bitmap data
+
+ if (data != NULL) {
+ FIBITMAP *dib = (header->node->m_plugin->load_proc != NULL) ? header->node->m_plugin->load_proc(header->io, header->handle, page, header->load_flags, data) : NULL;
+
+ // close the file
+
+ FreeImage_Close(header->node, header->io, header->handle, data);
+
+ // if there was still another bitmap open, get rid of it
+
+ if (dib) {
+ header->locked_pages[dib] = page;
+
+ return dib;
+ }
+
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+void DLL_CALLCONV
+FreeImage_UnlockPage(FIMULTIBITMAP *bitmap, FIBITMAP *page, BOOL changed) {
+ if ((bitmap) && (page)) {
+ MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);
+
+ // find out if the page we try to unlock is actually locked...
+
+ if (header->locked_pages.find(page) != header->locked_pages.end()) {
+ // store the bitmap compressed in the cache for later writing
+
+ if (changed && !header->read_only) {
+ header->changed = TRUE;
+
+ // cut loose the block from the rest
+
+ BlockListIterator i = FreeImage_FindBlock(bitmap, header->locked_pages[page]);
+
+ // compress the data
+
+ DWORD compressed_size = 0;
+ BYTE *compressed_data = NULL;
+
+ // open a memory handle
+ FIMEMORY *hmem = FreeImage_OpenMemory();
+ // save the page to memory
+ FreeImage_SaveToMemory(header->cache_fif, page, hmem, 0);
+ // get the buffer from the memory stream
+ FreeImage_AcquireMemory(hmem, &compressed_data, &compressed_size);
+
+ // write the data to the cache
+
+ switch ((*i)->m_type) {
+ case BLOCK_CONTINUEUS :
+ {
+ int iPage = header->m_cachefile->writeFile(compressed_data, compressed_size);
+
+ delete (*i);
+
+ *i = (BlockTypeS *)new BlockReference(iPage, compressed_size);
+
+ break;
+ }
+
+ case BLOCK_REFERENCE :
+ {
+ BlockReference *reference = (BlockReference *)(*i);
+
+ header->m_cachefile->deleteFile(reference->m_reference);
+
+ delete (*i);
+
+ int iPage = header->m_cachefile->writeFile(compressed_data, compressed_size);
+
+ *i = (BlockTypeS *)new BlockReference(iPage, compressed_size);
+
+ break;
+ }
+ }
+
+ // get rid of the compressed data
+
+ FreeImage_CloseMemory(hmem);
+ }
+
+ // reset the locked page so that another page can be locked
+
+ FreeImage_Unload(page);
+
+ header->locked_pages.erase(page);
+ }
+ }
+}
+
+BOOL DLL_CALLCONV
+FreeImage_MovePage(FIMULTIBITMAP *bitmap, int target, int source) {
+ if (bitmap) {
+ MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);
+
+ if ((!header->read_only) && (header->locked_pages.empty())) {
+ if ((target != source) && ((target >= 0) && (target < FreeImage_GetPageCount(bitmap))) && ((source >= 0) && (source < FreeImage_GetPageCount(bitmap)))) {
+ BlockListIterator block_source = FreeImage_FindBlock(bitmap, target);
+ BlockListIterator block_target = FreeImage_FindBlock(bitmap, source);
+
+ header->m_blocks.insert(block_target, *block_source);
+ header->m_blocks.erase(block_source);
+
+ header->changed = TRUE;
+
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+BOOL DLL_CALLCONV
+FreeImage_GetLockedPageNumbers(FIMULTIBITMAP *bitmap, int *pages, int *count) {
+ if ((bitmap) && (count)) {
+ MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);
+
+ if ((pages == NULL) || (*count == 0)) {
+ *count = (int)header->locked_pages.size();
+ } else {
+ int c = 0;
+
+ for (std::map<FIBITMAP *, int>::iterator i = header->locked_pages.begin(); i != header->locked_pages.end(); ++i) {
+ pages[c] = i->second;
+
+ c++;
+
+ if (c == *count)
+ break;
+ }
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// =====================================================================
+// Memory IO Multipage functions
+// =====================================================================
+
+FIMULTIBITMAP * DLL_CALLCONV
+FreeImage_LoadMultiBitmapFromMemory(FREE_IMAGE_FORMAT fif, FIMEMORY *stream, int flags) {
+ BOOL read_only = FALSE; // modifications (if any) will be stored into the memory cache
+
+ // 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) {
+ FreeImageIO *io = new(std::nothrow) FreeImageIO;
+
+ if (io) {
+ SetMemoryIO(io);
+
+ FIMULTIBITMAP *bitmap = new(std::nothrow) FIMULTIBITMAP;
+
+ if (bitmap) {
+ MULTIBITMAPHEADER *header = new(std::nothrow) MULTIBITMAPHEADER;
+
+ if (header) {
+ header->m_filename = NULL;
+ header->node = node;
+ header->fif = fif;
+ header->io = io;
+ header->handle = (fi_handle)stream;
+ 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;
+
+ // cache the page count
+
+ header->page_count = FreeImage_InternalGetPageCount(bitmap);
+
+ // allocate a continueus block to describe the bitmap
+
+ header->m_blocks.push_back((BlockTypeS *)new BlockContinueus(0, header->page_count - 1));
+
+ if (!read_only) {
+ // set up the cache
+ CacheFile *cache_file = new(std::nothrow) CacheFile("", TRUE);
+
+ if (cache_file && cache_file->open()) {
+ header->m_cachefile = cache_file;
+ }
+ }
+
+ return bitmap;
+ }
+
+ delete bitmap;
+ }
+
+ delete io;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+BOOL DLL_CALLCONV
+FreeImage_SaveMultiBitmapToMemory(FREE_IMAGE_FORMAT fif, FIMULTIBITMAP *bitmap, FIMEMORY *stream, int flags) {
+ if (stream && stream->data) {
+ FreeImageIO io;
+ SetMemoryIO(&io);
+
+ return FreeImage_SaveMultiBitmapToHandle(fif, bitmap, &io, (fi_handle)stream, flags);
+ }
+
+ return FALSE;
+}
diff --git a/plugins/AdvaImg/src/FreeImage/PSDParser.cpp b/plugins/AdvaImg/src/FreeImage/PSDParser.cpp
index 57c703a06f..fba54c2421 100644
--- a/plugins/AdvaImg/src/FreeImage/PSDParser.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PSDParser.cpp
@@ -506,6 +506,10 @@ bool psdParser::ReadImageResources(FreeImageIO *io, fi_handle handle, LONG lengt
oResource.Reset();
n = (int)io->read_proc(&oResource._OSType, sizeof(oResource._OSType), 1, handle);
+ if(n != 1) {
+ FreeImage_OutputMessageProc(_fi_format_id, "This file contains damaged data causing an unexpected end-of-file - stop reading resources");
+ return false;
+ }
nBytes += n * sizeof(oResource._OSType);
if( (nBytes % 2) != 0 ) {
diff --git a/plugins/AdvaImg/src/FreeImage/PixelAccess.cpp b/plugins/AdvaImg/src/FreeImage/PixelAccess.cpp
index e3dccfe1c9..c69463c316 100644
--- a/plugins/AdvaImg/src/FreeImage/PixelAccess.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PixelAccess.cpp
@@ -1,210 +1,210 @@
-// ==========================================================
-// Pixel access functions
-//
-// Design and implementation by
-// - Floris van den Berg (flvdberg@wxs.nl)
-// - Hervé Drolon (drolon@infonie.fr)
-// - Ryan Rubley (ryan@lostreality.org)
-// - Riley McNiff (rmcniff@marexgroup.com)
-//
-// 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 "FreeImage.h"
-#include "Utilities.h"
-
-// ----------------------------------------------------------
-
-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;
- }
- return CalculateScanLine(FreeImage_GetBits(dib), FreeImage_GetPitch(dib), scanline);
-}
-
-BOOL DLL_CALLCONV
-FreeImage_GetPixelIndex(FIBITMAP *dib, unsigned x, unsigned y, BYTE *value) {
- BYTE shift;
-
- if(!FreeImage_HasPixels(dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP))
- return FALSE;
-
- if((x < FreeImage_GetWidth(dib)) && (y < FreeImage_GetHeight(dib))) {
- BYTE *bits = FreeImage_GetScanLine(dib, y);
-
- switch(FreeImage_GetBPP(dib)) {
- case 1:
- *value = (bits[x >> 3] & (0x80 >> (x & 0x07))) != 0;
- break;
- case 4:
- shift = (BYTE)((1 - x % 2) << 2);
- *value = (bits[x >> 1] & (0x0F << shift)) >> shift;
- break;
- case 8:
- *value = bits[x];
- break;
- default:
- return FALSE;
- }
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-BOOL DLL_CALLCONV
-FreeImage_GetPixelColor(FIBITMAP *dib, unsigned x, unsigned y, RGBQUAD *value) {
- if(!FreeImage_HasPixels(dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP))
- return FALSE;
-
- if((x < FreeImage_GetWidth(dib)) && (y < FreeImage_GetHeight(dib))) {
- BYTE *bits = FreeImage_GetScanLine(dib, y);
-
- switch(FreeImage_GetBPP(dib)) {
- case 16:
- {
- bits += 2*x;
- WORD *pixel = (WORD *)bits;
- if((FreeImage_GetRedMask(dib) == FI16_565_RED_MASK) && (FreeImage_GetGreenMask(dib) == FI16_565_GREEN_MASK) && (FreeImage_GetBlueMask(dib) == FI16_565_BLUE_MASK)) {
- value->rgbBlue = (BYTE)((((*pixel & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) * 0xFF) / 0x1F);
- value->rgbGreen = (BYTE)((((*pixel & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) * 0xFF) / 0x3F);
- value->rgbRed = (BYTE)((((*pixel & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) * 0xFF) / 0x1F);
- value->rgbReserved = 0;
- } else {
- value->rgbBlue = (BYTE)((((*pixel & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) * 0xFF) / 0x1F);
- value->rgbGreen = (BYTE)((((*pixel & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) * 0xFF) / 0x1F);
- value->rgbRed = (BYTE)((((*pixel & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) * 0xFF) / 0x1F);
- value->rgbReserved = 0;
- }
- break;
- }
- case 24:
- bits += 3*x;
- value->rgbBlue = bits[FI_RGBA_BLUE]; // B
- value->rgbGreen = bits[FI_RGBA_GREEN]; // G
- value->rgbRed = bits[FI_RGBA_RED]; // R
- value->rgbReserved = 0;
- break;
- case 32:
- bits += 4*x;
- value->rgbBlue = bits[FI_RGBA_BLUE]; // B
- value->rgbGreen = bits[FI_RGBA_GREEN]; // G
- value->rgbRed = bits[FI_RGBA_RED]; // R
- value->rgbReserved = bits[FI_RGBA_ALPHA]; // A
- break;
- default:
- return FALSE;
- }
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-BOOL DLL_CALLCONV
-FreeImage_SetPixelIndex(FIBITMAP *dib, unsigned x, unsigned y, BYTE *value) {
- BYTE shift;
-
- if(!FreeImage_HasPixels(dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP))
- return FALSE;
-
- if((x < FreeImage_GetWidth(dib)) && (y < FreeImage_GetHeight(dib))) {
- BYTE *bits = FreeImage_GetScanLine(dib, y);
-
- switch(FreeImage_GetBPP(dib)) {
- case 1:
- *value ? bits[x >> 3] |= (0x80 >> (x & 0x7)) : bits[x >> 3] &= (0xFF7F >> (x & 0x7));
- break;
- case 4:
- shift = (BYTE)((1 - x % 2) << 2);
- bits[x >> 1] &= ~(0x0F << shift);
- bits[x >> 1] |= ((*value & 0x0F) << shift);
- break;
- case 8:
- bits[x] = *value;
- break;
- default:
- return FALSE;
- }
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-BOOL DLL_CALLCONV
-FreeImage_SetPixelColor(FIBITMAP *dib, unsigned x, unsigned y, RGBQUAD *value) {
- if(!FreeImage_HasPixels(dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP))
- return FALSE;
-
- if((x < FreeImage_GetWidth(dib)) && (y < FreeImage_GetHeight(dib))) {
- BYTE *bits = FreeImage_GetScanLine(dib, y);
-
- switch(FreeImage_GetBPP(dib)) {
- case 16:
- {
- bits += 2*x;
- WORD *pixel = (WORD *)bits;
- if((FreeImage_GetRedMask(dib) == FI16_565_RED_MASK) && (FreeImage_GetGreenMask(dib) == FI16_565_GREEN_MASK) && (FreeImage_GetBlueMask(dib) == FI16_565_BLUE_MASK)) {
- *pixel = ((value->rgbBlue >> 3) << FI16_565_BLUE_SHIFT) |
- ((value->rgbGreen >> 2) << FI16_565_GREEN_SHIFT) |
- ((value->rgbRed >> 3) << FI16_565_RED_SHIFT);
- } else {
- *pixel = ((value->rgbBlue >> 3) << FI16_555_BLUE_SHIFT) |
- ((value->rgbGreen >> 3) << FI16_555_GREEN_SHIFT) |
- ((value->rgbRed >> 3) << FI16_555_RED_SHIFT);
- }
- break;
- }
- case 24:
- bits += 3*x;
- bits[FI_RGBA_BLUE] = value->rgbBlue; // B
- bits[FI_RGBA_GREEN] = value->rgbGreen; // G
- bits[FI_RGBA_RED] = value->rgbRed; // R
- break;
- case 32:
- bits += 4*x;
- bits[FI_RGBA_BLUE] = value->rgbBlue; // B
- bits[FI_RGBA_GREEN] = value->rgbGreen; // G
- bits[FI_RGBA_RED] = value->rgbRed; // R
- bits[FI_RGBA_ALPHA] = value->rgbReserved; // A
- break;
- default:
- return FALSE;
- }
-
- return TRUE;
- }
-
- return FALSE;
-}
-
+// ==========================================================
+// Pixel access functions
+//
+// Design and implementation by
+// - Floris van den Berg (flvdberg@wxs.nl)
+// - Hervé Drolon (drolon@infonie.fr)
+// - Ryan Rubley (ryan@lostreality.org)
+// - Riley McNiff (rmcniff@marexgroup.com)
+//
+// 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 "FreeImage.h"
+#include "Utilities.h"
+
+// ----------------------------------------------------------
+
+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;
+ }
+ return CalculateScanLine(FreeImage_GetBits(dib), FreeImage_GetPitch(dib), scanline);
+}
+
+BOOL DLL_CALLCONV
+FreeImage_GetPixelIndex(FIBITMAP *dib, unsigned x, unsigned y, BYTE *value) {
+ BYTE shift;
+
+ if(!FreeImage_HasPixels(dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP))
+ return FALSE;
+
+ if((x < FreeImage_GetWidth(dib)) && (y < FreeImage_GetHeight(dib))) {
+ BYTE *bits = FreeImage_GetScanLine(dib, y);
+
+ switch(FreeImage_GetBPP(dib)) {
+ case 1:
+ *value = (bits[x >> 3] & (0x80 >> (x & 0x07))) != 0;
+ break;
+ case 4:
+ shift = (BYTE)((1 - x % 2) << 2);
+ *value = (bits[x >> 1] & (0x0F << shift)) >> shift;
+ break;
+ case 8:
+ *value = bits[x];
+ break;
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOL DLL_CALLCONV
+FreeImage_GetPixelColor(FIBITMAP *dib, unsigned x, unsigned y, RGBQUAD *value) {
+ if(!FreeImage_HasPixels(dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP))
+ return FALSE;
+
+ if((x < FreeImage_GetWidth(dib)) && (y < FreeImage_GetHeight(dib))) {
+ BYTE *bits = FreeImage_GetScanLine(dib, y);
+
+ switch(FreeImage_GetBPP(dib)) {
+ case 16:
+ {
+ bits += 2*x;
+ WORD *pixel = (WORD *)bits;
+ if((FreeImage_GetRedMask(dib) == FI16_565_RED_MASK) && (FreeImage_GetGreenMask(dib) == FI16_565_GREEN_MASK) && (FreeImage_GetBlueMask(dib) == FI16_565_BLUE_MASK)) {
+ value->rgbBlue = (BYTE)((((*pixel & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) * 0xFF) / 0x1F);
+ value->rgbGreen = (BYTE)((((*pixel & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) * 0xFF) / 0x3F);
+ value->rgbRed = (BYTE)((((*pixel & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) * 0xFF) / 0x1F);
+ value->rgbReserved = 0;
+ } else {
+ value->rgbBlue = (BYTE)((((*pixel & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) * 0xFF) / 0x1F);
+ value->rgbGreen = (BYTE)((((*pixel & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) * 0xFF) / 0x1F);
+ value->rgbRed = (BYTE)((((*pixel & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) * 0xFF) / 0x1F);
+ value->rgbReserved = 0;
+ }
+ break;
+ }
+ case 24:
+ bits += 3*x;
+ value->rgbBlue = bits[FI_RGBA_BLUE]; // B
+ value->rgbGreen = bits[FI_RGBA_GREEN]; // G
+ value->rgbRed = bits[FI_RGBA_RED]; // R
+ value->rgbReserved = 0;
+ break;
+ case 32:
+ bits += 4*x;
+ value->rgbBlue = bits[FI_RGBA_BLUE]; // B
+ value->rgbGreen = bits[FI_RGBA_GREEN]; // G
+ value->rgbRed = bits[FI_RGBA_RED]; // R
+ value->rgbReserved = bits[FI_RGBA_ALPHA]; // A
+ break;
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOL DLL_CALLCONV
+FreeImage_SetPixelIndex(FIBITMAP *dib, unsigned x, unsigned y, BYTE *value) {
+ BYTE shift;
+
+ if(!FreeImage_HasPixels(dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP))
+ return FALSE;
+
+ if((x < FreeImage_GetWidth(dib)) && (y < FreeImage_GetHeight(dib))) {
+ BYTE *bits = FreeImage_GetScanLine(dib, y);
+
+ switch(FreeImage_GetBPP(dib)) {
+ case 1:
+ *value ? bits[x >> 3] |= (0x80 >> (x & 0x7)) : bits[x >> 3] &= (0xFF7F >> (x & 0x7));
+ break;
+ case 4:
+ shift = (BYTE)((1 - x % 2) << 2);
+ bits[x >> 1] &= ~(0x0F << shift);
+ bits[x >> 1] |= ((*value & 0x0F) << shift);
+ break;
+ case 8:
+ bits[x] = *value;
+ break;
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOL DLL_CALLCONV
+FreeImage_SetPixelColor(FIBITMAP *dib, unsigned x, unsigned y, RGBQUAD *value) {
+ if(!FreeImage_HasPixels(dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP))
+ return FALSE;
+
+ if((x < FreeImage_GetWidth(dib)) && (y < FreeImage_GetHeight(dib))) {
+ BYTE *bits = FreeImage_GetScanLine(dib, y);
+
+ switch(FreeImage_GetBPP(dib)) {
+ case 16:
+ {
+ bits += 2*x;
+ WORD *pixel = (WORD *)bits;
+ if((FreeImage_GetRedMask(dib) == FI16_565_RED_MASK) && (FreeImage_GetGreenMask(dib) == FI16_565_GREEN_MASK) && (FreeImage_GetBlueMask(dib) == FI16_565_BLUE_MASK)) {
+ *pixel = ((value->rgbBlue >> 3) << FI16_565_BLUE_SHIFT) |
+ ((value->rgbGreen >> 2) << FI16_565_GREEN_SHIFT) |
+ ((value->rgbRed >> 3) << FI16_565_RED_SHIFT);
+ } else {
+ *pixel = ((value->rgbBlue >> 3) << FI16_555_BLUE_SHIFT) |
+ ((value->rgbGreen >> 3) << FI16_555_GREEN_SHIFT) |
+ ((value->rgbRed >> 3) << FI16_555_RED_SHIFT);
+ }
+ break;
+ }
+ case 24:
+ bits += 3*x;
+ bits[FI_RGBA_BLUE] = value->rgbBlue; // B
+ bits[FI_RGBA_GREEN] = value->rgbGreen; // G
+ bits[FI_RGBA_RED] = value->rgbRed; // R
+ break;
+ case 32:
+ bits += 4*x;
+ bits[FI_RGBA_BLUE] = value->rgbBlue; // B
+ bits[FI_RGBA_GREEN] = value->rgbGreen; // G
+ bits[FI_RGBA_RED] = value->rgbRed; // R
+ bits[FI_RGBA_ALPHA] = value->rgbReserved; // A
+ break;
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
diff --git a/plugins/AdvaImg/src/FreeImage/Plugin.cpp b/plugins/AdvaImg/src/FreeImage/Plugin.cpp
index 7ded36ebc2..6f88e47e68 100644
--- a/plugins/AdvaImg/src/FreeImage/Plugin.cpp
+++ b/plugins/AdvaImg/src/FreeImage/Plugin.cpp
@@ -218,7 +218,12 @@ 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
+ */
+
// initialise the TagLib singleton
TagLib& s = TagLib::instance();
@@ -257,7 +262,7 @@ FreeImage_Initialise(BOOL load_local_plugins_only) {
//s_plugins->AddNode(InitXPM);
//s_plugins->AddNode(InitDDS);
s_plugins->AddNode(InitGIF);
- //s_plugins->AddNode(InitHDR);
+ //s_plugins->AddNode(InitHDR);
//s_plugins->AddNode(InitG3);
//s_plugins->AddNode(InitSGI);
//s_plugins->AddNode(InitEXR);
@@ -266,6 +271,74 @@ FreeImage_Initialise(BOOL load_local_plugins_only) {
//s_plugins->AddNode(InitPFM);
//s_plugins->AddNode(InitPICT);
//s_plugins->AddNode(InitRAW);
+ //s_plugins->AddNode(InitWEBP);
+//#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];
+ 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 (last_point) {
+ *last_point = '\0';
+
+ bOk = SetCurrentDirectoryA(module);
+ }
+ }
+ }
+
+ // search for plugins
+
+ while (count < s_search_list_size) {
+ _finddata_t find_data;
+ long find_handle;
+
+ strcpy(buffer, s_search_list[count]);
+ strcat(buffer, "*.fip");
+
+ if ((find_handle = (long)_findfirst(buffer, &find_data)) != -1L) {
+ do {
+ strcpy(buffer, s_search_list[count]);
+ strncat(buffer, find_data.name, MAX_PATH + 200);
+
+ HINSTANCE instance = LoadLibraryA(buffer);
+
+ if (instance != NULL) {
+ FARPROC proc_address = GetProcAddress(instance, "_Init@8");
+
+ if (proc_address != NULL) {
+ s_plugins->AddNode((FI_InitProc)proc_address, (void *)instance);
+ } else {
+ FreeLibrary(instance);
+ }
+ }
+ } while (_findnext(find_handle, &find_data) != -1L);
+
+ _findclose(find_handle);
+ }
+
+ count++;
+ }
+
+ // restore the current directory
+
+ if (bOk) {
+ SetCurrentDirectoryA(current_dir);
+ }
+ }
+#endif // _WIN32
}
}
}
diff --git a/plugins/AdvaImg/src/FreeImage/PluginBMP.cpp b/plugins/AdvaImg/src/FreeImage/PluginBMP.cpp
index 4041d859fa..0ee1c5db30 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginBMP.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginBMP.cpp
@@ -35,10 +35,13 @@ static const BYTE RLE_ENDOFLINE = 0;
static const BYTE RLE_ENDOFBITMAP = 1;
static const BYTE RLE_DELTA = 2;
-static const BYTE BI_RGB = 0;
-static const BYTE BI_RLE8 = 1;
-static const BYTE BI_RLE4 = 2;
-static const BYTE BI_BITFIELDS = 3;
+static const BYTE BI_RGB = 0; // compression: none
+static const BYTE BI_RLE8 = 1; // compression: RLE 8-bit/pixel
+static const BYTE BI_RLE4 = 2; // compression: RLE 4-bit/pixel
+static const BYTE BI_BITFIELDS = 3; // compression: Bit field or Huffman 1D compression for BITMAPCOREHEADER2
+static const BYTE BI_JPEG = 4; // compression: JPEG or RLE-24 compression for BITMAPCOREHEADER2
+static const BYTE BI_PNG = 5; // compression: PNG
+static const BYTE BI_ALPHABITFIELDS = 6; // compression: Bit field (this value is valid in Windows CE .NET 4.0 and later)
// ----------------------------------------------------------
@@ -65,11 +68,11 @@ typedef struct tagBITMAPINFOOS2_1X_HEADER {
} BITMAPINFOOS2_1X_HEADER, *PBITMAPINFOOS2_1X_HEADER;
typedef struct tagBITMAPFILEHEADER {
- WORD bfType;
- DWORD bfSize;
- WORD bfReserved1;
- WORD bfReserved2;
- DWORD bfOffBits;
+ WORD bfType; //! The file type
+ DWORD bfSize; //! The size, in bytes, of the bitmap file
+ WORD bfReserved1; //! Reserved; must be zero
+ WORD bfReserved2; //! Reserved; must be zero
+ DWORD bfOffBits; //! The offset, in bytes, from the beginning of the BITMAPFILEHEADER structure to the bitmap bits
} BITMAPFILEHEADER, *PBITMAPFILEHEADER;
#ifdef _WIN32
@@ -452,7 +455,7 @@ LoadPixelDataRLE8(FreeImageIO *io, fi_handle handle, int width, int height, FIBI
// --------------------------------------------------------------------------
static FIBITMAP *
-LoadWindowsBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bits_offset) {
+LoadWindowsBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bits_offset, int type) {
FIBITMAP *dib = NULL;
try {
@@ -481,8 +484,9 @@ LoadWindowsBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bit
case 4 :
case 8 :
{
- if ((used_colors == 0) || (used_colors > CalculateUsedPaletteEntries(bit_count)))
+ if ((used_colors == 0) || (used_colors > CalculateUsedPaletteEntries(bit_count))) {
used_colors = CalculateUsedPaletteEntries(bit_count);
+ }
// allocate enough memory to hold the bitmap (header, palette, pixels) and read the palette
@@ -494,6 +498,19 @@ LoadWindowsBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bit
// set resolution information
FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);
+
+ // seek to the end of the header (depending on the BMP header version)
+ // type == sizeof(BITMAPVxINFOHEADER)
+ switch(type) {
+ case 40: // sizeof(BITMAPINFOHEADER) - all Windows versions since Windows 3.0
+ break;
+ case 52: // sizeof(BITMAPV2INFOHEADER) (undocumented)
+ case 56: // sizeof(BITMAPV3INFOHEADER) (undocumented)
+ case 108: // sizeof(BITMAPV4HEADER) - all Windows versions since Windows 95/NT4 (not supported)
+ case 124: // sizeof(BITMAPV5HEADER) - Windows 98/2000 and newer (not supported)
+ io->seek_proc(handle, (long)(type - sizeof(BITMAPINFOHEADER)), SEEK_CUR);
+ break;
+ }
// load the palette
@@ -512,10 +529,8 @@ LoadWindowsBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bit
// seek to the actual pixel data.
// this is needed because sometimes the palette is larger than the entries it contains predicts
+ io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
- if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * sizeof(RGBQUAD))))
- io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
-
// read the pixel data
switch (compression) {
@@ -551,11 +566,15 @@ LoadWindowsBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bit
case 16 :
{
- if (bih.biCompression == BI_BITFIELDS) {
- DWORD bitfields[3];
-
- io->read_proc(bitfields, 3 * sizeof(DWORD), 1, handle);
-
+ int use_bitfields = 0;
+ if (bih.biCompression == BI_BITFIELDS) use_bitfields = 3;
+ else if (bih.biCompression == BI_ALPHABITFIELDS) use_bitfields = 4;
+ else if (type == 52) use_bitfields = 3;
+ else if (type >= 56) use_bitfields = 4;
+
+ if (use_bitfields > 0) {
+ DWORD bitfields[4];
+ io->read_proc(bitfields, use_bitfields * sizeof(DWORD), 1, handle);
dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, bitfields[0], bitfields[1], bitfields[2]);
} else {
dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI16_555_RED_MASK, FI16_555_GREEN_MASK, FI16_555_BLUE_MASK);
@@ -573,14 +592,11 @@ LoadWindowsBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bit
// header only mode
return dib;
}
+
+ // seek to the actual pixel data
+ io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
// load pixel data and swap as needed if OS is Big Endian
-
- if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER))) {
- // seek to the actual pixel data
- io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
- }
-
LoadPixelData(io, handle, dib, height, pitch, bit_count);
return dib;
@@ -590,11 +606,15 @@ LoadWindowsBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bit
case 24 :
case 32 :
{
- if (bih.biCompression == BI_BITFIELDS) {
- DWORD bitfields[3];
-
- io->read_proc(bitfields, 3 * sizeof(DWORD), 1, handle);
-
+ int use_bitfields = 0;
+ if (bih.biCompression == BI_BITFIELDS) use_bitfields = 3;
+ else if (bih.biCompression == BI_ALPHABITFIELDS) use_bitfields = 4;
+ else if (type == 52) use_bitfields = 3;
+ else if (type >= 56) use_bitfields = 4;
+
+ if (use_bitfields > 0) {
+ DWORD bitfields[4];
+ io->read_proc(bitfields, use_bitfields * sizeof(DWORD), 1, handle);
dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, bitfields[0], bitfields[1], bitfields[2]);
} else {
if( bit_count == 32 ) {
@@ -619,12 +639,10 @@ LoadWindowsBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bit
// Skip over the optional palette
// A 24 or 32 bit DIB may contain a palette for faster color reduction
+ // i.e. you can have (FreeImage_GetColorsUsed(dib) > 0)
- if (FreeImage_GetColorsUsed(dib) > 0) {
- io->seek_proc(handle, FreeImage_GetColorsUsed(dib) * sizeof(RGBQUAD), SEEK_CUR);
- } else if ((bih.biCompression != BI_BITFIELDS) && (bitmap_bits_offset > sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER))) {
- io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
- }
+ // seek to the actual pixel data
+ io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
// read in the bitmap bits
// load pixel data and swap as needed if OS is Big Endian
@@ -735,8 +753,9 @@ LoadOS22XBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bits_
// seek to the actual pixel data.
// this is needed because sometimes the palette is larger than the entries it contains predicts
- if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3)))
+ if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3))) {
io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
+ }
// read the pixel data
@@ -827,8 +846,9 @@ LoadOS22XBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bits_
// Skip over the optional palette
// A 24 or 32 bit DIB may contain a palette for faster color reduction
- if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3)))
+ if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3))) {
io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
+ }
// read in the bitmap bits
// load pixel data and swap as needed if OS is Big Endian
@@ -1101,24 +1121,18 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
case 12:
// OS/2 and also all Windows versions since Windows 3.0
return LoadOS21XBMP(io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits);
+
case 64:
// OS/2
return LoadOS22XBMP(io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits);
- case 40:
- // BITMAPINFOHEADER - all Windows versions since Windows 3.0
- return LoadWindowsBMP(io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits);
- case 52:
- // BITMAPV2INFOHEADER (undocumented)
- break;
- case 56:
- // BITMAPV3INFOHEADER (undocumented)
- break;
- case 108:
- // BITMAPV4HEADER - all Windows versions since Windows 95/NT4 (not supported)
- break;
- case 124:
- // BITMAPV5HEADER - Windows 98/2000 and newer (not supported)
- break;
+
+ case 40: // BITMAPINFOHEADER - all Windows versions since Windows 3.0
+ case 52: // BITMAPV2INFOHEADER (undocumented, partially supported)
+ case 56: // BITMAPV3INFOHEADER (undocumented, partially supported)
+ case 108: // BITMAPV4HEADER - all Windows versions since Windows 95/NT4 (partially supported)
+ case 124: // BITMAPV5HEADER - Windows 98/2000 and newer (partially supported)
+ return LoadWindowsBMP(io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits, type);
+
default:
break;
}
diff --git a/plugins/AdvaImg/src/FreeImage/PluginGIF.cpp b/plugins/AdvaImg/src/FreeImage/PluginGIF.cpp
index e8d84afac4..87c0185865 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginGIF.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginGIF.cpp
@@ -376,7 +376,7 @@ bool StringTable::Decompress(BYTE *buf, int *len)
m_partial >>= m_codeSize;
m_partialSize -= m_codeSize;
- if( code > m_nextCode || (m_nextCode == MAX_LZW_CODE && code != m_clearCode) || code == m_endCode ) {
+ if( code > m_nextCode || /*(m_nextCode == MAX_LZW_CODE && code != m_clearCode) || */code == m_endCode ) {
m_done = true;
*len = (int)(bufpos - buf);
return true;
@@ -387,7 +387,7 @@ bool StringTable::Decompress(BYTE *buf, int *len)
}
//add new string to string table, if not the first pass since a clear code
- if( m_oldCode != MAX_LZW_CODE ) {
+ if( m_oldCode != MAX_LZW_CODE && m_nextCode < MAX_LZW_CODE) {
m_strings[m_nextCode] = m_strings[m_oldCode] + m_strings[code == m_nextCode ? m_oldCode : code][0];
}
diff --git a/plugins/AdvaImg/src/FreeImage/PluginHDR.cpp b/plugins/AdvaImg/src/FreeImage/PluginHDR.cpp
index d8c24adc31..0cde6139db 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginHDR.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginHDR.cpp
@@ -73,7 +73,7 @@ typedef enum {
rgbe_read_error,
rgbe_write_error,
rgbe_format_error,
- rgbe_memory_error,
+ rgbe_memory_error
} rgbe_error_code;
// ----------------------------------------------------------
diff --git a/plugins/AdvaImg/src/FreeImage/PluginICO.cpp b/plugins/AdvaImg/src/FreeImage/PluginICO.cpp
index 7f41a0d841..df5ecee91d 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginICO.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginICO.cpp
@@ -339,7 +339,8 @@ LoadStandardIcon(FreeImageIO *io, fi_handle handle, int flags, BOOL header_only)
// bitmap has been loaded successfully!
// convert to 32bpp and generate an alpha channel
- if((flags & ICO_MAKEALPHA) == ICO_MAKEALPHA) {
+ // apply the AND mask only if the image is not 32 bpp
+ if(((flags & ICO_MAKEALPHA) == ICO_MAKEALPHA) && (bit_count < 32)) {
FIBITMAP *dib32 = FreeImage_ConvertTo32Bits(dib);
FreeImage_Unload(dib);
diff --git a/plugins/AdvaImg/src/FreeImage/PluginJ2K.cpp b/plugins/AdvaImg/src/FreeImage/PluginJ2K.cpp
index ae8a6ae88a..5c23a7c6e1 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginJ2K.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginJ2K.cpp
@@ -1,339 +1,327 @@
-// ==========================================================
-// JPEG2000 J2K codestream Loader and Writer
-//
-// Design and implementation by
-// - Hervé Drolon (drolon@infonie.fr)
-//
-// 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 "FreeImage.h"
-#include "Utilities.h"
-#include "../LibOpenJPEG/openjpeg.h"
-
-// ==========================================================
-// Plugin Interface
-// ==========================================================
-
-static int s_format_id;
-
-// ==========================================================
-// Helper functions (see J2KHelper.cpp)
-// ==========================================================
-
-FIBITMAP* J2KImageToFIBITMAP(int format_id, const opj_image_t *image);
-opj_image_t* FIBITMAPToJ2KImage(int format_id, FIBITMAP *dib, const opj_cparameters_t *parameters);
-
-// ==========================================================
-// Internal functions
-// ==========================================================
-
-/**
-OpenJPEG Error callback
-*/
-static void j2k_error_callback(const char *msg, void *client_data) {
- FreeImage_OutputMessageProc(s_format_id, "Error: %s", msg);
-}
-/**
-OpenJPEG Warning callback
-*/
-static void j2k_warning_callback(const char *msg, void *client_data) {
- FreeImage_OutputMessageProc(s_format_id, "Warning: %s", msg);
-}
-
-// ==========================================================
-// Plugin Implementation
-// ==========================================================
-
-static const char * DLL_CALLCONV
-Format() {
- return "J2K";
-}
-
-static const char * DLL_CALLCONV
-Description() {
- return "JPEG-2000 codestream";
-}
-
-static const char * DLL_CALLCONV
-Extension() {
- return "j2k,j2c";
-}
-
-static const char * DLL_CALLCONV
-RegExpr() {
- return NULL;
-}
-
-static const char * DLL_CALLCONV
-MimeType() {
- return "image/j2k";
-}
-
-static BOOL DLL_CALLCONV
-Validate(FreeImageIO *io, fi_handle handle) {
- BYTE jpc_signature[] = { 0xFF, 0x4F };
- BYTE signature[2] = { 0, 0 };
-
- long tell = io->tell_proc(handle);
- io->read_proc(signature, 1, sizeof(jpc_signature), handle);
- io->seek_proc(handle, tell, SEEK_SET);
-
- return (memcmp(jpc_signature, signature, sizeof(jpc_signature)) == 0);
-}
-
-static BOOL DLL_CALLCONV
-SupportsExportDepth(int depth) {
- return (
- (depth == 8) ||
- (depth == 24) ||
- (depth == 32)
- );
-}
-
-static BOOL DLL_CALLCONV
-SupportsExportType(FREE_IMAGE_TYPE type) {
- return (
- (type == FIT_BITMAP) ||
- (type == FIT_UINT16) ||
- (type == FIT_RGB16) ||
- (type == FIT_RGBA16)
- );
-}
-
-// ----------------------------------------------------------
-
-static void * DLL_CALLCONV
-Open(FreeImageIO *io, fi_handle handle, BOOL read) {
- return NULL;
-}
-
-static void DLL_CALLCONV
-Close(FreeImageIO *io, fi_handle handle, void *data) {
-}
-
-// ----------------------------------------------------------
-
-static FIBITMAP * DLL_CALLCONV
-Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
- if (handle) {
- opj_dparameters_t parameters; // decompression parameters
- opj_event_mgr_t event_mgr; // event manager
- opj_image_t *image = NULL; // decoded image
-
- BYTE *src = NULL;
- long file_length;
-
- opj_dinfo_t* dinfo = NULL; // handle to a decompressor
- opj_cio_t *cio = NULL;
-
- FIBITMAP *dib = NULL;
-
- // check the file format
- if(!Validate(io, handle)) {
- return NULL;
- }
-
- // configure the event callbacks
- memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
- event_mgr.error_handler = j2k_error_callback;
- event_mgr.warning_handler = j2k_warning_callback;
- event_mgr.info_handler = NULL;
-
- // set decoding parameters to default values
- opj_set_default_decoder_parameters(&parameters);
-
- try {
- // read the input file and put it in memory
-
- long start_pos = io->tell_proc(handle);
- io->seek_proc(handle, 0, SEEK_END);
- file_length = io->tell_proc(handle) - start_pos;
- io->seek_proc(handle, start_pos, SEEK_SET);
- src = (BYTE*)malloc(file_length * sizeof(BYTE));
- if(!src) {
- throw FI_MSG_ERROR_MEMORY;
- }
- if(io->read_proc(src, 1, file_length, handle) < 1) {
- throw "Error while reading input stream";
- }
-
- // decode the JPEG-2000 codestream
-
- // get a decoder handle
- dinfo = opj_create_decompress(CODEC_J2K);
-
- // catch events using our callbacks
- opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, NULL);
-
- // setup the decoder decoding parameters using user parameters
- opj_setup_decoder(dinfo, &parameters);
-
- // open a byte stream
- cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length);
-
- // decode the stream and fill the image structure
- image = opj_decode(dinfo, cio);
- if(!image) {
- throw "Failed to decode image!\n";
- }
-
- // close the byte stream
- opj_cio_close(cio);
- cio = NULL;
-
- // free the memory containing the code-stream
- free(src);
- src = NULL;
-
- // free the codec context
- opj_destroy_decompress(dinfo);
-
- // create output image
- dib = J2KImageToFIBITMAP(s_format_id, image);
- if(!dib) throw "Failed to import JPEG2000 image";
-
- // free image data structure
- opj_image_destroy(image);
-
- return dib;
-
- } catch (const char *text) {
- if(src) free(src);
- if(dib) FreeImage_Unload(dib);
- // free remaining structures
- opj_destroy_decompress(dinfo);
- opj_image_destroy(image);
- // close the byte stream
- if(cio) opj_cio_close(cio);
-
- FreeImage_OutputMessageProc(s_format_id, text);
-
- return NULL;
- }
- }
-
- return NULL;
-}
-
-static BOOL DLL_CALLCONV
-Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
- if ((dib) && (handle)) {
- BOOL bSuccess;
- opj_cparameters_t parameters; // compression parameters
- opj_event_mgr_t event_mgr; // event manager
- opj_image_t *image = NULL; // image to encode
- opj_cinfo_t* cinfo = NULL; // codec context
- opj_cio_t *cio = NULL; // memory byte stream
-
- // configure the event callbacks
- memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
- event_mgr.error_handler = j2k_error_callback;
- event_mgr.warning_handler = j2k_warning_callback;
- event_mgr.info_handler = NULL;
-
- // set encoding parameters to default values
- opj_set_default_encoder_parameters(&parameters);
-
- 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_numlayers++;
- parameters.cp_disto_alloc = 1;
-
- try {
- // convert the dib to a OpenJPEG image
- image = FIBITMAPToJ2KImage(s_format_id, dib, &parameters);
- if(!image) return FALSE;
-
- // decide if MCT should be used
- parameters.tcp_mct = (image->numcomps == 3) ? 1 : 0;
-
- // encode the destination image
-
- // get a J2K compressor handle
- cinfo = opj_create_compress(CODEC_J2K);
-
- // catch events using our callbacks
- opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, NULL);
-
- // setup the encoder parameters using the current image and using user parameters
- opj_setup_encoder(cinfo, &parameters, image);
-
- // open a byte stream for writing, allocate memory for all tiles
- cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0);
-
- // encode the image
- bSuccess = opj_encode(cinfo, cio, image, NULL/*parameters.index*/);
- if (!bSuccess) {
- throw "Failed to encode image";
- }
- int codestream_length = cio_tell(cio);
-
- // write the buffer to user's IO handle
- io->write_proc(cio->buffer, 1, codestream_length, handle);
-
- // close and free the byte stream
- opj_cio_close(cio);
-
- // free remaining compression structures
- opj_destroy_compress(cinfo);
-
- // free image data
- opj_image_destroy(image);
-
- return TRUE;
-
- } catch (const char *text) {
- if(cio) opj_cio_close(cio);
- if(cinfo) opj_destroy_compress(cinfo);
- if(image) opj_image_destroy(image);
- FreeImage_OutputMessageProc(s_format_id, text);
- return FALSE;
- }
- }
-
- return FALSE;
-}
-
-// ==========================================================
-// Init
-// ==========================================================
-
-void DLL_CALLCONV
-InitJ2K(Plugin *plugin, int format_id) {
- s_format_id = format_id;
-
- plugin->format_proc = Format;
- plugin->description_proc = Description;
- plugin->extension_proc = Extension;
- plugin->regexpr_proc = RegExpr;
- plugin->open_proc = Open;
- plugin->close_proc = Close;
- plugin->pagecount_proc = NULL;
- plugin->pagecapability_proc = NULL;
- plugin->load_proc = Load;
- plugin->save_proc = Save;
- plugin->validate_proc = Validate;
- plugin->mime_proc = MimeType;
- plugin->supports_export_bpp_proc = SupportsExportDepth;
- plugin->supports_export_type_proc = SupportsExportType;
- plugin->supports_icc_profiles_proc = NULL;
-}
+// ==========================================================
+// JPEG2000 J2K codestream Loader and Writer
+//
+// Design and implementation by
+// - Hervé Drolon (drolon@infonie.fr)
+//
+// 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 "FreeImage.h"
+#include "Utilities.h"
+#include "../LibOpenJPEG/openjpeg.h"
+#include "J2KHelper.h"
+
+// ==========================================================
+// Plugin Interface
+// ==========================================================
+
+static int s_format_id;
+
+// ==========================================================
+// Internal functions
+// ==========================================================
+
+/**
+OpenJPEG Error callback
+*/
+static void j2k_error_callback(const char *msg, void *client_data) {
+ FreeImage_OutputMessageProc(s_format_id, "Error: %s", msg);
+}
+/**
+OpenJPEG Warning callback
+*/
+static void j2k_warning_callback(const char *msg, void *client_data) {
+ FreeImage_OutputMessageProc(s_format_id, "Warning: %s", msg);
+}
+
+// ==========================================================
+// Plugin Implementation
+// ==========================================================
+
+static const char * DLL_CALLCONV
+Format() {
+ return "J2K";
+}
+
+static const char * DLL_CALLCONV
+Description() {
+ return "JPEG-2000 codestream";
+}
+
+static const char * DLL_CALLCONV
+Extension() {
+ return "j2k,j2c";
+}
+
+static const char * DLL_CALLCONV
+RegExpr() {
+ return NULL;
+}
+
+static const char * DLL_CALLCONV
+MimeType() {
+ return "image/j2k";
+}
+
+static BOOL DLL_CALLCONV
+Validate(FreeImageIO *io, fi_handle handle) {
+ BYTE jpc_signature[] = { 0xFF, 0x4F };
+ BYTE signature[2] = { 0, 0 };
+
+ long tell = io->tell_proc(handle);
+ io->read_proc(signature, 1, sizeof(jpc_signature), handle);
+ io->seek_proc(handle, tell, SEEK_SET);
+
+ return (memcmp(jpc_signature, signature, sizeof(jpc_signature)) == 0);
+}
+
+static BOOL DLL_CALLCONV
+SupportsExportDepth(int depth) {
+ return (
+ (depth == 8) ||
+ (depth == 24) ||
+ (depth == 32)
+ );
+}
+
+static BOOL DLL_CALLCONV
+SupportsExportType(FREE_IMAGE_TYPE type) {
+ return (
+ (type == FIT_BITMAP) ||
+ (type == FIT_UINT16) ||
+ (type == FIT_RGB16) ||
+ (type == FIT_RGBA16)
+ );
+}
+
+// ----------------------------------------------------------
+
+static void * DLL_CALLCONV
+Open(FreeImageIO *io, fi_handle handle, BOOL read) {
+ // create the stream wrapper
+ J2KFIO_t *fio = opj_freeimage_stream_create(io, handle, read);
+ return fio;
+}
+
+static void DLL_CALLCONV
+Close(FreeImageIO *io, fi_handle handle, void *data) {
+ // destroy the stream wrapper
+ J2KFIO_t *fio = (J2KFIO_t*)data;
+ opj_freeimage_stream_destroy(fio);
+}
+
+// ----------------------------------------------------------
+
+static FIBITMAP * DLL_CALLCONV
+Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
+ J2KFIO_t *fio = (J2KFIO_t*)data;
+ if (handle && fio) {
+ opj_codec_t *d_codec = NULL; // handle to a decompressor
+ opj_dparameters_t parameters; // decompression parameters
+ opj_image_t *image = NULL; // decoded image
+
+ FIBITMAP *dib = NULL;
+
+ // check the file format
+ if(!Validate(io, handle)) {
+ return NULL;
+ }
+
+ BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
+
+ // get the OpenJPEG stream
+ opj_stream_t *d_stream = fio->stream;
+
+ // set decoding parameters to default values
+ opj_set_default_decoder_parameters(&parameters);
+
+ try {
+ // decode the JPEG-2000 codestream
+
+ // get a decoder handle
+ d_codec = opj_create_decompress(OPJ_CODEC_J2K);
+
+ // configure the event callbacks
+ // catch events using our callbacks (no local context needed here)
+ opj_set_info_handler(d_codec, NULL, NULL);
+ opj_set_warning_handler(d_codec, j2k_warning_callback, NULL);
+ opj_set_error_handler(d_codec, j2k_error_callback, NULL);
+
+ // setup the decoder decoding parameters using user parameters
+ if( !opj_setup_decoder(d_codec, &parameters) ) {
+ throw "Failed to setup the decoder\n";
+ }
+
+ // read the main header of the codestream and if necessary the JP2 boxes
+ if( !opj_read_header(d_stream, d_codec, &image)) {
+ throw "Failed to read the header\n";
+ }
+
+ // --- header only mode
+
+ if (header_only) {
+ // create output image
+ dib = J2KImageToFIBITMAP(s_format_id, image, header_only);
+ if(!dib) throw "Failed to import JPEG2000 image";
+ // clean-up and return header data
+ opj_destroy_codec(d_codec);
+ opj_image_destroy(image);
+ return dib;
+ }
+
+ // decode the stream and fill the image structure
+ if( !( opj_decode(d_codec, d_stream, image) && opj_end_decompress(d_codec, d_stream) ) ) {
+ throw "Failed to decode image!\n";
+ }
+
+ // free the codec context
+ opj_destroy_codec(d_codec);
+ d_codec = NULL;
+
+ // create output image
+ dib = J2KImageToFIBITMAP(s_format_id, image, header_only);
+ if(!dib) throw "Failed to import JPEG2000 image";
+
+ // free image data structure
+ opj_image_destroy(image);
+
+ return dib;
+
+ } catch (const char *text) {
+ if(dib) FreeImage_Unload(dib);
+ // free remaining structures
+ opj_destroy_codec(d_codec);
+ opj_image_destroy(image);
+
+ FreeImage_OutputMessageProc(s_format_id, text);
+
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+static BOOL DLL_CALLCONV
+Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
+ J2KFIO_t *fio = (J2KFIO_t*)data;
+ if (dib && handle && fio) {
+ BOOL bSuccess;
+ opj_codec_t *c_codec = NULL; // handle to a compressor
+ opj_cparameters_t parameters; // compression parameters
+ opj_image_t *image = NULL; // image to encode
+
+ // get the OpenJPEG stream
+ opj_stream_t *c_stream = fio->stream;
+
+ // set encoding parameters to default values
+ opj_set_default_encoder_parameters(&parameters);
+
+ 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;
+ // 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_numlayers++;
+ parameters.cp_disto_alloc = 1;
+
+ // convert the dib to a OpenJPEG image
+ image = FIBITMAPToJ2KImage(s_format_id, dib, &parameters);
+ if(!image) return FALSE;
+
+ // decide if MCT should be used
+ parameters.tcp_mct = (image->numcomps == 3) ? 1 : 0;
+
+ // encode the destination image
+
+ // get a J2K compressor handle
+ c_codec = opj_create_compress(OPJ_CODEC_J2K);
+
+ // configure the event callbacks
+ // catch events using our callbacks (no local context needed here)
+ opj_set_info_handler(c_codec, NULL, NULL);
+ opj_set_warning_handler(c_codec, j2k_warning_callback, NULL);
+ opj_set_error_handler(c_codec, j2k_error_callback, NULL);
+
+ // setup the encoder parameters using the current image and using user parameters
+ opj_setup_encoder(c_codec, &parameters, image);
+
+ // encode the image
+ bSuccess = opj_start_compress(c_codec, image, c_stream);
+ if(bSuccess) {
+ bSuccess = bSuccess && opj_encode(c_codec, c_stream);
+ if(bSuccess) {
+ bSuccess = bSuccess && opj_end_compress(c_codec, c_stream);
+ }
+ }
+ if (!bSuccess) {
+ throw "Failed to encode image";
+ }
+
+ // free remaining compression structures
+ opj_destroy_codec(c_codec);
+
+ // free image data
+ opj_image_destroy(image);
+
+ return TRUE;
+
+ } catch (const char *text) {
+ if(c_codec) opj_destroy_codec(c_codec);
+ if(image) opj_image_destroy(image);
+ FreeImage_OutputMessageProc(s_format_id, text);
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
+// ==========================================================
+// Init
+// ==========================================================
+
+void DLL_CALLCONV
+InitJ2K(Plugin *plugin, int format_id) {
+ s_format_id = format_id;
+
+ plugin->format_proc = Format;
+ plugin->description_proc = Description;
+ plugin->extension_proc = Extension;
+ plugin->regexpr_proc = RegExpr;
+ plugin->open_proc = Open;
+ plugin->close_proc = Close;
+ plugin->pagecount_proc = NULL;
+ plugin->pagecapability_proc = NULL;
+ plugin->load_proc = Load;
+ plugin->save_proc = Save;
+ plugin->validate_proc = Validate;
+ plugin->mime_proc = MimeType;
+ plugin->supports_export_bpp_proc = SupportsExportDepth;
+ plugin->supports_export_type_proc = SupportsExportType;
+ plugin->supports_icc_profiles_proc = NULL;
+}
diff --git a/plugins/AdvaImg/src/FreeImage/PluginJP2.cpp b/plugins/AdvaImg/src/FreeImage/PluginJP2.cpp
index 261697fb5c..edf5b396c3 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginJP2.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginJP2.cpp
@@ -1,339 +1,327 @@
-// ==========================================================
-// JPEG2000 JP2 file format Loader and Writer
-//
-// Design and implementation by
-// - Hervé Drolon (drolon@infonie.fr)
-//
-// 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 "FreeImage.h"
-#include "Utilities.h"
-#include "../LibOpenJPEG/openjpeg.h"
-
-// ==========================================================
-// Plugin Interface
-// ==========================================================
-
-static int s_format_id;
-
-// ==========================================================
-// Helper functions (see J2KHelper.cpp)
-// ==========================================================
-
-FIBITMAP* J2KImageToFIBITMAP(int format_id, const opj_image_t *image);
-opj_image_t* FIBITMAPToJ2KImage(int format_id, FIBITMAP *dib, const opj_cparameters_t *parameters);
-
-// ==========================================================
-// Internal functions
-// ==========================================================
-
-/**
-OpenJPEG Error callback
-*/
-static void jp2_error_callback(const char *msg, void *client_data) {
- FreeImage_OutputMessageProc(s_format_id, "Error: %s", msg);
-}
-/**
-OpenJPEG Warning callback
-*/
-static void jp2_warning_callback(const char *msg, void *client_data) {
- FreeImage_OutputMessageProc(s_format_id, "Warning: %s", msg);
-}
-
-// ==========================================================
-// Plugin Implementation
-// ==========================================================
-
-static const char * DLL_CALLCONV
-Format() {
- return "JP2";
-}
-
-static const char * DLL_CALLCONV
-Description() {
- return "JPEG-2000 File Format";
-}
-
-static const char * DLL_CALLCONV
-Extension() {
- return "jp2";
-}
-
-static const char * DLL_CALLCONV
-RegExpr() {
- return NULL;
-}
-
-static const char * DLL_CALLCONV
-MimeType() {
- return "image/jp2";
-}
-
-static BOOL DLL_CALLCONV
-Validate(FreeImageIO *io, fi_handle handle) {
- BYTE jp2_signature[] = { 0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50, 0x20, 0x20, 0x0D, 0x0A, 0x87, 0x0A };
- BYTE signature[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-
- long tell = io->tell_proc(handle);
- io->read_proc(signature, 1, sizeof(jp2_signature), handle);
- io->seek_proc(handle, tell, SEEK_SET);
-
- return (memcmp(jp2_signature, signature, sizeof(jp2_signature)) == 0);
-}
-
-static BOOL DLL_CALLCONV
-SupportsExportDepth(int depth) {
- return (
- (depth == 8) ||
- (depth == 24) ||
- (depth == 32)
- );
-}
-
-static BOOL DLL_CALLCONV
-SupportsExportType(FREE_IMAGE_TYPE type) {
- return (
- (type == FIT_BITMAP) ||
- (type == FIT_UINT16) ||
- (type == FIT_RGB16) ||
- (type == FIT_RGBA16)
- );
-}
-
-// ----------------------------------------------------------
-
-static void * DLL_CALLCONV
-Open(FreeImageIO *io, fi_handle handle, BOOL read) {
- return NULL;
-}
-
-static void DLL_CALLCONV
-Close(FreeImageIO *io, fi_handle handle, void *data) {
-}
-
-// ----------------------------------------------------------
-
-static FIBITMAP * DLL_CALLCONV
-Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
- if (handle) {
- opj_dparameters_t parameters; // decompression parameters
- opj_event_mgr_t event_mgr; // event manager
- opj_image_t *image = NULL; // decoded image
-
- BYTE *src = NULL;
- long file_length;
-
- opj_dinfo_t* dinfo = NULL; // handle to a decompressor
- opj_cio_t *cio = NULL;
-
- FIBITMAP *dib = NULL;
-
- // check the file format
- if(!Validate(io, handle)) {
- return NULL;
- }
-
- // configure the event callbacks
- memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
- event_mgr.error_handler = jp2_error_callback;
- event_mgr.warning_handler = jp2_warning_callback;
- event_mgr.info_handler = NULL;
-
- // set decoding parameters to default values
- opj_set_default_decoder_parameters(&parameters);
-
- try {
- // read the input file and put it in memory
-
- long start_pos = io->tell_proc(handle);
- io->seek_proc(handle, 0, SEEK_END);
- file_length = io->tell_proc(handle) - start_pos;
- io->seek_proc(handle, start_pos, SEEK_SET);
- src = (BYTE*)malloc(file_length * sizeof(BYTE));
- if(!src) {
- throw FI_MSG_ERROR_MEMORY;
- }
- if(io->read_proc(src, 1, file_length, handle) < 1) {
- throw "Error while reading input stream";
- }
-
- // decode the JPEG-2000 file
-
- // get a decoder handle
- dinfo = opj_create_decompress(CODEC_JP2);
-
- // catch events using our callbacks
- opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, NULL);
-
- // setup the decoder decoding parameters using user parameters
- opj_setup_decoder(dinfo, &parameters);
-
- // open a byte stream
- cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length);
-
- // decode the stream and fill the image structure
- image = opj_decode(dinfo, cio);
- if(!image) {
- throw "Failed to decode image!\n";
- }
-
- // close the byte stream
- opj_cio_close(cio);
- cio = NULL;
-
- // free the memory containing the code-stream
- free(src);
- src = NULL;
-
- // free the codec context
- opj_destroy_decompress(dinfo);
-
- // create output image
- dib = J2KImageToFIBITMAP(s_format_id, image);
- if(!dib) throw "Failed to import JPEG2000 image";
-
- // free image data structure
- opj_image_destroy(image);
-
- return dib;
-
- } catch (const char *text) {
- if(src) free(src);
- if(dib) FreeImage_Unload(dib);
- // free remaining structures
- opj_destroy_decompress(dinfo);
- opj_image_destroy(image);
- // close the byte stream
- if(cio) opj_cio_close(cio);
-
- FreeImage_OutputMessageProc(s_format_id, text);
-
- return NULL;
- }
- }
-
- return NULL;
-}
-
-static BOOL DLL_CALLCONV
-Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
- if ((dib) && (handle)) {
- BOOL bSuccess;
- opj_cparameters_t parameters; // compression parameters
- opj_event_mgr_t event_mgr; // event manager
- opj_image_t *image = NULL; // image to encode
- opj_cinfo_t* cinfo = NULL; // codec context
- opj_cio_t *cio = NULL; // memory byte stream
-
- // configure the event callbacks
- memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
- event_mgr.error_handler = jp2_error_callback;
- event_mgr.warning_handler = jp2_warning_callback;
- event_mgr.info_handler = NULL;
-
- // set encoding parameters to default values
- opj_set_default_encoder_parameters(&parameters);
-
- parameters.tcp_numlayers = 0;
- // if no rate entered, apply a 16:1 rate by 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_numlayers++;
- parameters.cp_disto_alloc = 1;
-
- try {
- // convert the dib to a OpenJPEG image
- image = FIBITMAPToJ2KImage(s_format_id, dib, &parameters);
- if(!image) return FALSE;
-
- // decide if MCT should be used
- parameters.tcp_mct = (image->numcomps == 3) ? 1 : 0;
-
- // encode the destination image
-
- // get a J2K compressor handle
- cinfo = opj_create_compress(CODEC_JP2);
-
- // catch events using our callbacks
- opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, NULL);
-
- // setup the encoder parameters using the current image and using user parameters
- opj_setup_encoder(cinfo, &parameters, image);
-
- // open a byte stream for writing, allocate memory for all tiles
- cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0);
-
- // encode the image
- bSuccess = opj_encode(cinfo, cio, image, NULL/*parameters.index*/);
- if (!bSuccess) {
- throw "Failed to encode image";
- }
- int codestream_length = cio_tell(cio);
-
- // write the buffer to user's IO handle
- io->write_proc(cio->buffer, 1, codestream_length, handle);
-
- // close and free the byte stream
- opj_cio_close(cio);
-
- // free remaining compression structures
- opj_destroy_compress(cinfo);
-
- // free image data
- opj_image_destroy(image);
-
- return TRUE;
-
- } catch (const char *text) {
- if(cio) opj_cio_close(cio);
- if(cinfo) opj_destroy_compress(cinfo);
- if(image) opj_image_destroy(image);
- FreeImage_OutputMessageProc(s_format_id, text);
- return FALSE;
- }
- }
-
- return FALSE;
-}
-
-// ==========================================================
-// Init
-// ==========================================================
-
-void DLL_CALLCONV
-InitJP2(Plugin *plugin, int format_id) {
- s_format_id = format_id;
-
- plugin->format_proc = Format;
- plugin->description_proc = Description;
- plugin->extension_proc = Extension;
- plugin->regexpr_proc = RegExpr;
- plugin->open_proc = Open;
- plugin->close_proc = Close;
- plugin->pagecount_proc = NULL;
- plugin->pagecapability_proc = NULL;
- plugin->load_proc = Load;
- plugin->save_proc = Save;
- plugin->validate_proc = Validate;
- plugin->mime_proc = MimeType;
- plugin->supports_export_bpp_proc = SupportsExportDepth;
- plugin->supports_export_type_proc = SupportsExportType;
- plugin->supports_icc_profiles_proc = NULL;
-}
+// ==========================================================
+// JPEG2000 JP2 file format Loader and Writer
+//
+// Design and implementation by
+// - Hervé Drolon (drolon@infonie.fr)
+//
+// 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 "FreeImage.h"
+#include "Utilities.h"
+#include "../LibOpenJPEG/openjpeg.h"
+#include "J2KHelper.h"
+
+// ==========================================================
+// Plugin Interface
+// ==========================================================
+
+static int s_format_id;
+
+// ==========================================================
+// Internal functions
+// ==========================================================
+
+/**
+OpenJPEG Error callback
+*/
+static void jp2_error_callback(const char *msg, void *client_data) {
+ FreeImage_OutputMessageProc(s_format_id, "Error: %s", msg);
+}
+/**
+OpenJPEG Warning callback
+*/
+static void jp2_warning_callback(const char *msg, void *client_data) {
+ FreeImage_OutputMessageProc(s_format_id, "Warning: %s", msg);
+}
+
+// ==========================================================
+// Plugin Implementation
+// ==========================================================
+
+static const char * DLL_CALLCONV
+Format() {
+ return "JP2";
+}
+
+static const char * DLL_CALLCONV
+Description() {
+ return "JPEG-2000 File Format";
+}
+
+static const char * DLL_CALLCONV
+Extension() {
+ return "jp2";
+}
+
+static const char * DLL_CALLCONV
+RegExpr() {
+ return NULL;
+}
+
+static const char * DLL_CALLCONV
+MimeType() {
+ return "image/jp2";
+}
+
+static BOOL DLL_CALLCONV
+Validate(FreeImageIO *io, fi_handle handle) {
+ BYTE jp2_signature[] = { 0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50, 0x20, 0x20, 0x0D, 0x0A, 0x87, 0x0A };
+ BYTE signature[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ long tell = io->tell_proc(handle);
+ io->read_proc(signature, 1, sizeof(jp2_signature), handle);
+ io->seek_proc(handle, tell, SEEK_SET);
+
+ return (memcmp(jp2_signature, signature, sizeof(jp2_signature)) == 0);
+}
+
+static BOOL DLL_CALLCONV
+SupportsExportDepth(int depth) {
+ return (
+ (depth == 8) ||
+ (depth == 24) ||
+ (depth == 32)
+ );
+}
+
+static BOOL DLL_CALLCONV
+SupportsExportType(FREE_IMAGE_TYPE type) {
+ return (
+ (type == FIT_BITMAP) ||
+ (type == FIT_UINT16) ||
+ (type == FIT_RGB16) ||
+ (type == FIT_RGBA16)
+ );
+}
+
+// ----------------------------------------------------------
+
+static void * DLL_CALLCONV
+Open(FreeImageIO *io, fi_handle handle, BOOL read) {
+ // create the stream wrapper
+ J2KFIO_t *fio = opj_freeimage_stream_create(io, handle, read);
+ return fio;
+}
+
+static void DLL_CALLCONV
+Close(FreeImageIO *io, fi_handle handle, void *data) {
+ // destroy the stream wrapper
+ J2KFIO_t *fio = (J2KFIO_t*)data;
+ opj_freeimage_stream_destroy(fio);
+}
+
+// ----------------------------------------------------------
+
+static FIBITMAP * DLL_CALLCONV
+Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
+ J2KFIO_t *fio = (J2KFIO_t*)data;
+ if (handle && fio) {
+ opj_codec_t *d_codec = NULL; // handle to a decompressor
+ opj_dparameters_t parameters; // decompression parameters
+ opj_image_t *image = NULL; // decoded image
+
+ FIBITMAP *dib = NULL;
+
+ // check the file format
+ if(!Validate(io, handle)) {
+ return NULL;
+ }
+
+ BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
+
+ // get the OpenJPEG stream
+ opj_stream_t *d_stream = fio->stream;
+
+ // set decoding parameters to default values
+ opj_set_default_decoder_parameters(&parameters);
+
+ try {
+ // decode the JPEG-2000 file
+
+ // get a decoder handle
+ d_codec = opj_create_decompress(OPJ_CODEC_JP2);
+
+ // configure the event callbacks
+ // catch events using our callbacks (no local context needed here)
+ opj_set_info_handler(d_codec, NULL, NULL);
+ opj_set_warning_handler(d_codec, jp2_warning_callback, NULL);
+ opj_set_error_handler(d_codec, jp2_error_callback, NULL);
+
+ // setup the decoder decoding parameters using user parameters
+ if( !opj_setup_decoder(d_codec, &parameters) ) {
+ throw "Failed to setup the decoder\n";
+ }
+
+ // read the main header of the codestream and if necessary the JP2 boxes
+ if( !opj_read_header(d_stream, d_codec, &image)) {
+ throw "Failed to read the header\n";
+ }
+
+ // --- header only mode
+
+ if (header_only) {
+ // create output image
+ dib = J2KImageToFIBITMAP(s_format_id, image, header_only);
+ if(!dib) throw "Failed to import JPEG2000 image";
+ // clean-up and return header data
+ opj_destroy_codec(d_codec);
+ opj_image_destroy(image);
+ return dib;
+ }
+
+ // decode the stream and fill the image structure
+ if( !( opj_decode(d_codec, d_stream, image) && opj_end_decompress(d_codec, d_stream) ) ) {
+ throw "Failed to decode image!\n";
+ }
+
+ // free the codec context
+ opj_destroy_codec(d_codec);
+ d_codec = NULL;
+
+ // create output image
+ dib = J2KImageToFIBITMAP(s_format_id, image, header_only);
+ if(!dib) throw "Failed to import JPEG2000 image";
+
+ // free image data structure
+ opj_image_destroy(image);
+
+ return dib;
+
+ } catch (const char *text) {
+ if(dib) FreeImage_Unload(dib);
+ // free remaining structures
+ opj_destroy_codec(d_codec);
+ opj_image_destroy(image);
+
+ FreeImage_OutputMessageProc(s_format_id, text);
+
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+static BOOL DLL_CALLCONV
+Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
+ J2KFIO_t *fio = (J2KFIO_t*)data;
+ if (dib && handle && fio) {
+ BOOL bSuccess;
+ opj_codec_t *c_codec = NULL; // handle to a compressor
+ opj_cparameters_t parameters; // compression parameters
+ opj_image_t *image = NULL; // image to encode
+
+ // get the OpenJPEG stream
+ opj_stream_t *c_stream = fio->stream;
+
+ // set encoding parameters to default values
+ opj_set_default_encoder_parameters(&parameters);
+
+ 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;
+ // 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_numlayers++;
+ parameters.cp_disto_alloc = 1;
+
+ // convert the dib to a OpenJPEG image
+ image = FIBITMAPToJ2KImage(s_format_id, dib, &parameters);
+ if(!image) return FALSE;
+
+ // decide if MCT should be used
+ parameters.tcp_mct = (image->numcomps == 3) ? 1 : 0;
+
+ // encode the destination image
+
+ // get a JP2 compressor handle
+ c_codec = opj_create_compress(OPJ_CODEC_JP2);
+
+ // configure the event callbacks
+ // catch events using our callbacks (no local context needed here)
+ opj_set_info_handler(c_codec, NULL, NULL);
+ opj_set_warning_handler(c_codec, jp2_warning_callback, NULL);
+ opj_set_error_handler(c_codec, jp2_error_callback, NULL);
+
+ // setup the encoder parameters using the current image and using user parameters
+ opj_setup_encoder(c_codec, &parameters, image);
+
+ // encode the image
+ bSuccess = opj_start_compress(c_codec, image, c_stream);
+ if(bSuccess) {
+ bSuccess = bSuccess && opj_encode(c_codec, c_stream);
+ if(bSuccess) {
+ bSuccess = bSuccess && opj_end_compress(c_codec, c_stream);
+ }
+ }
+ if (!bSuccess) {
+ throw "Failed to encode image";
+ }
+
+ // free remaining compression structures
+ opj_destroy_codec(c_codec);
+
+ // free image data
+ opj_image_destroy(image);
+
+ return TRUE;
+
+ } catch (const char *text) {
+ if(c_codec) opj_destroy_codec(c_codec);
+ if(image) opj_image_destroy(image);
+ FreeImage_OutputMessageProc(s_format_id, text);
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
+// ==========================================================
+// Init
+// ==========================================================
+
+void DLL_CALLCONV
+InitJP2(Plugin *plugin, int format_id) {
+ s_format_id = format_id;
+
+ plugin->format_proc = Format;
+ plugin->description_proc = Description;
+ plugin->extension_proc = Extension;
+ plugin->regexpr_proc = RegExpr;
+ plugin->open_proc = Open;
+ plugin->close_proc = Close;
+ plugin->pagecount_proc = NULL;
+ plugin->pagecapability_proc = NULL;
+ plugin->load_proc = Load;
+ plugin->save_proc = Save;
+ plugin->validate_proc = Validate;
+ plugin->mime_proc = MimeType;
+ plugin->supports_export_bpp_proc = SupportsExportDepth;
+ plugin->supports_export_type_proc = SupportsExportType;
+ plugin->supports_icc_profiles_proc = NULL;
+}
diff --git a/plugins/AdvaImg/src/FreeImage/PluginJPEG.cpp b/plugins/AdvaImg/src/FreeImage/PluginJPEG.cpp
index 1e0237d115..c1b45e6347 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginJPEG.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginJPEG.cpp
@@ -656,46 +656,6 @@ jpeg_read_xmp_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned int datalen)
}
/**
- Read JPEG_APP1 marker (Exif profile)
- @param dib Input FIBITMAP
- @param dataptr Pointer to the APP1 marker
- @param datalen APP1 marker length
- @return Returns TRUE if successful, FALSE otherwise
-*/
-static BOOL
-jpeg_read_exif_profile_raw(FIBITMAP *dib, const BYTE *profile, unsigned int length) {
- // marker identifying string for Exif = "Exif\0\0"
- BYTE exif_signature[6] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 };
-
- // verify the identifying string
- if(memcmp(exif_signature, profile, sizeof(exif_signature)) != 0) {
- // not an Exif profile
- return FALSE;
- }
-
- // create a tag
- FITAG *tag = FreeImage_CreateTag();
- if(tag) {
- FreeImage_SetTagID(tag, EXIF_MARKER); // (JPEG_APP0 + 1) => EXIF marker / Adobe XMP marker
- FreeImage_SetTagKey(tag, g_TagLib_ExifRawFieldName);
- FreeImage_SetTagLength(tag, (DWORD)length);
- FreeImage_SetTagCount(tag, (DWORD)length);
- FreeImage_SetTagType(tag, FIDT_BYTE);
- FreeImage_SetTagValue(tag, profile);
-
- // store the tag
- FreeImage_SetMetadata(FIMD_EXIF_RAW, dib, FreeImage_GetTagKey(tag), tag);
-
- // destroy the tag
- FreeImage_DeleteTag(tag);
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
Read JFIF "JFXX" extension APP0 marker
@param dib Input FIBITMAP
@param dataptr Pointer to the APP0 marker
@@ -976,14 +936,14 @@ jpeg_write_exif_profile_raw(j_compress_ptr cinfo, FIBITMAP *dib) {
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);
- return TRUE;
+ return TRUE;
}
return FALSE;
@@ -1126,66 +1086,6 @@ store_size_info(FIBITMAP *dib, JDIMENSION width, JDIMENSION height) {
}
}
-// ------------------------------------------------------------
-// Rotate a dib according to Exif info
-// ------------------------------------------------------------
-
-static void
-rotate_exif(FIBITMAP **dib) {
- // check for Exif rotation
- if(FreeImage_GetMetadataCount(FIMD_EXIF_MAIN, *dib)) {
- FIBITMAP *rotated = NULL;
- // process Exif rotation
- FITAG *tag = NULL;
- FreeImage_GetMetadata(FIMD_EXIF_MAIN, *dib, "Orientation", &tag);
- if(tag != NULL) {
- if(FreeImage_GetTagID(tag) == TAG_ORIENTATION) {
- unsigned short orientation = *((unsigned short *)FreeImage_GetTagValue(tag));
- switch (orientation) {
- case 1: // "top, left side" => 0°
- break;
- case 2: // "top, right side" => flip left-right
- FreeImage_FlipHorizontal(*dib);
- break;
- case 3: // "bottom, right side"; => -180°
- rotated = FreeImage_Rotate(*dib, 180);
- FreeImage_Unload(*dib);
- *dib = rotated;
- break;
- case 4: // "bottom, left side" => flip up-down
- FreeImage_FlipVertical(*dib);
- break;
- case 5: // "left side, top" => +90° + flip up-down
- rotated = FreeImage_Rotate(*dib, 90);
- FreeImage_Unload(*dib);
- *dib = rotated;
- FreeImage_FlipVertical(*dib);
- break;
- case 6: // "right side, top" => -90°
- rotated = FreeImage_Rotate(*dib, -90);
- FreeImage_Unload(*dib);
- *dib = rotated;
- break;
- case 7: // "right side, bottom" => -90° + flip up-down
- rotated = FreeImage_Rotate(*dib, -90);
- FreeImage_Unload(*dib);
- *dib = rotated;
- FreeImage_FlipVertical(*dib);
- break;
- case 8: // "left side, bottom" => +90°
- rotated = FreeImage_Rotate(*dib, 90);
- FreeImage_Unload(*dib);
- *dib = rotated;
- break;
- default:
- break;
- }
- }
- }
- }
-}
-
-
// ==========================================================
// Plugin Implementation
// ==========================================================
@@ -1473,7 +1373,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
// check for automatic Exif rotation
if(!header_only && ((flags & JPEG_EXIFROTATE) == JPEG_EXIFROTATE)) {
- rotate_exif(&dib);
+ RotateExif(&dib);
}
// everything went well. return the loaded dib
diff --git a/plugins/AdvaImg/src/FreeImage/PluginJXR.cpp b/plugins/AdvaImg/src/FreeImage/PluginJXR.cpp
new file mode 100644
index 0000000000..f5e4878c1d
--- /dev/null
+++ b/plugins/AdvaImg/src/FreeImage/PluginJXR.cpp
@@ -0,0 +1,1309 @@
+// ==========================================================
+// JPEG XR Loader & Writer
+//
+// Design and implementation by
+// - Herve Drolon (drolon@infonie.fr)
+//
+// 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 "FreeImage.h"
+#include "Utilities.h"
+#include "../Metadata/FreeImageTag.h"
+
+#include "../LibJXR/jxrgluelib/JXRGlue.h"
+
+// ==========================================================
+// Plugin Interface
+// ==========================================================
+
+static int s_format_id;
+
+// ==========================================================
+// FreeImageIO interface (I/O streaming functions)
+// ==========================================================
+
+/**
+JXR wrapper for FreeImage I/O handle
+*/
+typedef struct tagFreeImageJXRIO {
+ FreeImageIO *io;
+ fi_handle handle;
+} FreeImageJXRIO;
+
+static ERR
+_jxr_io_Read(WMPStream* pWS, void* pv, size_t cb) {
+ FreeImageJXRIO *fio = (FreeImageJXRIO*)pWS->state.pvObj;
+ return (fio->io->read_proc(pv, (unsigned)cb, 1, fio->handle) == 1) ? WMP_errSuccess : WMP_errFileIO;
+}
+
+static ERR
+_jxr_io_Write(WMPStream* pWS, const void* pv, size_t cb) {
+ FreeImageJXRIO *fio = (FreeImageJXRIO*)pWS->state.pvObj;
+ if(0 != cb) {
+ return (fio->io->write_proc((void*)pv, (unsigned)cb, 1, fio->handle) == 1) ? WMP_errSuccess : WMP_errFileIO;
+ }
+ return WMP_errFileIO;
+}
+
+static ERR
+_jxr_io_SetPos(WMPStream* pWS, size_t offPos) {
+ FreeImageJXRIO *fio = (FreeImageJXRIO*)pWS->state.pvObj;
+ return (fio->io->seek_proc(fio->handle, (long)offPos, SEEK_SET) == 0) ? WMP_errSuccess : WMP_errFileIO;
+}
+
+static ERR
+_jxr_io_GetPos(WMPStream* pWS, size_t* poffPos) {
+ FreeImageJXRIO *fio = (FreeImageJXRIO*)pWS->state.pvObj;
+ long lOff = fio->io->tell_proc(fio->handle);
+ if(lOff == -1) {
+ return WMP_errFileIO;
+ }
+ *poffPos = (size_t)lOff;
+ return WMP_errSuccess;
+}
+
+static Bool
+_jxr_io_EOS(WMPStream* pWS) {
+ FreeImageJXRIO *fio = (FreeImageJXRIO*)pWS->state.pvObj;
+ long currentPos = fio->io->tell_proc(fio->handle);
+ fio->io->seek_proc(fio->handle, 0, SEEK_END);
+ long fileRemaining = fio->io->tell_proc(fio->handle) - currentPos;
+ fio->io->seek_proc(fio->handle, currentPos, SEEK_SET);
+ return (fileRemaining > 0);
+}
+
+static ERR
+_jxr_io_Close(WMPStream** ppWS) {
+ WMPStream *pWS = *ppWS;
+ // HACK : we use fMem to avoid a stream destruction by the library
+ // because FreeImage MUST HAVE the ownership of the stream
+ // see _jxr_io_Create
+ if(pWS && pWS->fMem) {
+ free(pWS);
+ *ppWS = NULL;
+ }
+ return WMP_errSuccess;
+}
+
+static ERR
+_jxr_io_Create(WMPStream **ppWS, FreeImageJXRIO *jxr_io) {
+ *ppWS = (WMPStream*)calloc(1, sizeof(**ppWS));
+ if(*ppWS) {
+ WMPStream *pWS = *ppWS;
+
+ pWS->state.pvObj = jxr_io;
+ pWS->Close = _jxr_io_Close;
+ pWS->EOS = _jxr_io_EOS;
+ pWS->Read = _jxr_io_Read;
+ pWS->Write = _jxr_io_Write;
+ pWS->SetPos = _jxr_io_SetPos;
+ pWS->GetPos = _jxr_io_GetPos;
+
+ // HACK : we use fMem to avoid a stream destruction by the library
+ // because FreeImage MUST HAVE the ownership of the stream
+ // see _jxr_io_Close
+ pWS->fMem = FALSE;
+
+ return WMP_errSuccess;
+ }
+ return WMP_errOutOfMemory;
+}
+
+// ==========================================================
+// JPEG XR Error handling
+// ==========================================================
+
+static const char*
+JXR_ErrorMessage(const int error) {
+ switch(error) {
+ case WMP_errNotYetImplemented:
+ case WMP_errAbstractMethod:
+ return "Not yet implemented";
+ case WMP_errOutOfMemory:
+ return "Out of memory";
+ case WMP_errFileIO:
+ return "File I/O error";
+ case WMP_errBufferOverflow:
+ return "Buffer overflow";
+ case WMP_errInvalidParameter:
+ return "Invalid parameter";
+ case WMP_errInvalidArgument:
+ return "Invalid argument";
+ case WMP_errUnsupportedFormat:
+ return "Unsupported format";
+ case WMP_errIncorrectCodecVersion:
+ return "Incorrect codec version";
+ case WMP_errIndexNotFound:
+ return "Format converter: Index not found";
+ case WMP_errOutOfSequence:
+ return "Metadata: Out of sequence";
+ case WMP_errMustBeMultipleOf16LinesUntilLastCall:
+ return "Must be multiple of 16 lines until last call";
+ case WMP_errPlanarAlphaBandedEncRequiresTempFile:
+ return "Planar alpha banded encoder requires temp files";
+ case WMP_errAlphaModeCannotBeTranscoded:
+ return "Alpha mode cannot be transcoded";
+ case WMP_errIncorrectCodecSubVersion:
+ return "Incorrect codec subversion";
+ case WMP_errFail:
+ case WMP_errNotInitialized:
+ default:
+ return "Invalid instruction - please contact the FreeImage team";
+ }
+
+ return NULL;
+}
+
+// ==========================================================
+// Helper functions & macro
+// ==========================================================
+
+#define JXR_CHECK(error_code) \
+ if(error_code < 0) { \
+ const char *error_message = JXR_ErrorMessage(error_code); \
+ throw error_message; \
+ }
+
+// --------------------------------------------------------------------------
+
+/**
+Input conversions natively understood by FreeImage
+@see GetNativePixelFormat
+*/
+typedef struct tagJXRInputConversion {
+ BITDEPTH_BITS bdBitDepth;
+ U32 cbitUnit;
+ FREE_IMAGE_TYPE image_type;
+ unsigned red_mask;
+ unsigned green_mask;
+ unsigned blue_mask;
+} JXRInputConversion;
+
+/**
+Conversion table for native FreeImage formats
+@see GetNativePixelFormat
+*/
+static JXRInputConversion s_FreeImagePixelInfo[] = {
+ // 1-bit bitmap
+ { BD_1, 1, FIT_BITMAP, 0, 0, 0 },
+ // 8-, 24-, 32-bit bitmap
+ { BD_8, 8, FIT_BITMAP, 0, 0, 0 },
+ { BD_8, 24, FIT_BITMAP, 0, 0, 0 },
+ { BD_8, 32, FIT_BITMAP, 0, 0, 0 },
+ // 16-bit RGB 565
+ { BD_565, 16, FIT_BITMAP, FI16_565_RED_MASK, FI16_565_GREEN_MASK, FI16_565_BLUE_MASK },
+ // 16-bit RGB 555
+ { BD_5, 16, FIT_BITMAP, FI16_555_RED_MASK, FI16_555_GREEN_MASK, FI16_555_BLUE_MASK },
+ // 16-bit greyscale, RGB16, RGBA16 bitmap
+ { BD_16, 16, FIT_UINT16, 0, 0, 0 },
+ { BD_16, 48, FIT_RGB16, 0, 0, 0 },
+ { BD_16, 64, FIT_RGBA16, 0, 0, 0 },
+ // 32-bit float, RGBF, RGBAF bitmap
+ { BD_32F, 32, FIT_FLOAT, 0, 0, 0 },
+ { BD_32F, 96, FIT_RGBF, 0, 0, 0 },
+ { BD_32F, 128, FIT_RGBAF, 0, 0, 0 }
+};
+
+/**
+Scan input pixelInfo specifications and return the equivalent FreeImage info for loading
+@param pixelInfo Image specifications
+@param out_guid_format (returned value) output pixel format
+@param image_type (returned value) Image type
+@param bpp (returned value) Image bit depth
+@param red_mask (returned value) RGB mask
+@param green_mask (returned value) RGB mask
+@param blue_mask (returned value) RGB mask
+@return Returns WMP_errSuccess if successful, returns WMP_errFail otherwise
+@see GetInputPixelFormat
+*/
+static ERR
+GetNativePixelFormat(const PKPixelInfo *pixelInfo, PKPixelFormatGUID *out_guid_format, FREE_IMAGE_TYPE *image_type, unsigned *bpp, unsigned *red_mask, unsigned *green_mask, unsigned *blue_mask) {
+ const unsigned s_FreeImagePixelInfoSize = (unsigned)sizeof(s_FreeImagePixelInfo) / sizeof(*(s_FreeImagePixelInfo));
+
+ for(unsigned i = 0; i < s_FreeImagePixelInfoSize; i++) {
+ if(pixelInfo->bdBitDepth == s_FreeImagePixelInfo[i].bdBitDepth) {
+ if(pixelInfo->cbitUnit == s_FreeImagePixelInfo[i].cbitUnit) {
+ // found ! now get dst image format specifications
+ memcpy(out_guid_format, pixelInfo->pGUIDPixFmt, sizeof(PKPixelFormatGUID));
+ *image_type = s_FreeImagePixelInfo[i].image_type;
+ *bpp = s_FreeImagePixelInfo[i].cbitUnit;
+ *red_mask = s_FreeImagePixelInfo[i].red_mask;
+ *green_mask = s_FreeImagePixelInfo[i].green_mask;
+ *blue_mask = s_FreeImagePixelInfo[i].blue_mask;
+ return WMP_errSuccess;
+ }
+ }
+ }
+
+ // not found : need pixel format conversion
+ return WMP_errFail;
+}
+
+/**
+Scan input file guid format and return the equivalent FreeImage info & target guid format for loading
+@param pDecoder Decoder handle
+@param guid_format (returned value) Output pixel format
+@param image_type (returned value) Image type
+@param bpp (returned value) Image bit depth
+@param red_mask (returned value) RGB mask
+@param green_mask (returned value) RGB mask
+@param blue_mask (returned value) RGB mask
+@return Returns TRUE if successful, returns FALSE otherwise
+*/
+static ERR
+GetInputPixelFormat(PKImageDecode *pDecoder, PKPixelFormatGUID *guid_format, FREE_IMAGE_TYPE *image_type, unsigned *bpp, unsigned *red_mask, unsigned *green_mask, unsigned *blue_mask) {
+ ERR error_code = 0; // error code as returned by the interface
+ PKPixelInfo pixelInfo; // image specifications
+
+ try {
+ // get input file pixel format ...
+ PKPixelFormatGUID pguidSourcePF;
+ error_code = pDecoder->GetPixelFormat(pDecoder, &pguidSourcePF);
+ JXR_CHECK(error_code);
+ pixelInfo.pGUIDPixFmt = &pguidSourcePF;
+ // ... check for a supported format and get the format specifications
+ error_code = PixelFormatLookup(&pixelInfo, LOOKUP_FORWARD);
+ JXR_CHECK(error_code);
+
+ // search for an equivalent native FreeImage format
+ error_code = GetNativePixelFormat(&pixelInfo, guid_format, image_type, bpp, red_mask, green_mask, blue_mask);
+
+ if(error_code != WMP_errSuccess) {
+ // try to find a suitable conversion function ...
+ const PKPixelFormatGUID *ppguidTargetPF = NULL; // target pixel format
+ unsigned iIndex = 0; // first available conversion function
+ do {
+ error_code = PKFormatConverter_EnumConversions(&pguidSourcePF, iIndex, &ppguidTargetPF);
+ if(error_code == WMP_errSuccess) {
+ // found a conversion function, is the converted format a native FreeImage format ?
+ pixelInfo.pGUIDPixFmt = ppguidTargetPF;
+ error_code = PixelFormatLookup(&pixelInfo, LOOKUP_FORWARD);
+ JXR_CHECK(error_code);
+ error_code = GetNativePixelFormat(&pixelInfo, guid_format, image_type, bpp, red_mask, green_mask, blue_mask);
+ if(error_code == WMP_errSuccess) {
+ break;
+ }
+ }
+ // try next conversion function
+ iIndex++;
+ } while(error_code != WMP_errIndexNotFound);
+
+ }
+
+ return (error_code == WMP_errSuccess) ? WMP_errSuccess : WMP_errUnsupportedFormat;
+
+ } catch(...) {
+ return error_code;
+ }
+}
+
+// --------------------------------------------------------------------------
+
+/**
+Scan input dib format and return the equivalent PKPixelFormatGUID format for saving
+@param dib Image to be saved
+@param guid_format (returned value) GUID format
+@param bHasAlpha (returned value) TRUE if an alpha layer is present
+@return Returns TRUE if successful, returns FALSE otherwise
+*/
+static ERR
+GetOutputPixelFormat(FIBITMAP *dib, PKPixelFormatGUID *guid_format, BOOL *bHasAlpha) {
+ const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
+ const unsigned bpp = FreeImage_GetBPP(dib);
+ const FREE_IMAGE_COLOR_TYPE color_type = FreeImage_GetColorType(dib);
+
+ *guid_format = GUID_PKPixelFormatDontCare;
+ *bHasAlpha = FALSE;
+
+ switch(image_type) {
+ case FIT_BITMAP: // standard image : 1-, 4-, 8-, 16-, 24-, 32-bit
+ switch(bpp) {
+ case 1:
+ // assume FIC_MINISBLACK
+ if(color_type == FIC_MINISBLACK) {
+ *guid_format = GUID_PKPixelFormatBlackWhite;
+ }
+ break;
+ case 8:
+ // assume FIC_MINISBLACK
+ if(color_type == FIC_MINISBLACK) {
+ *guid_format = GUID_PKPixelFormat8bppGray;
+ }
+ break;
+ case 16:
+ if ((FreeImage_GetRedMask(dib) == FI16_565_RED_MASK) && (FreeImage_GetGreenMask(dib) == FI16_565_GREEN_MASK) && (FreeImage_GetBlueMask(dib) == FI16_565_BLUE_MASK)) {
+ *guid_format = GUID_PKPixelFormat16bppRGB565;
+ } else {
+ // includes case where all the masks are 0
+ *guid_format = GUID_PKPixelFormat16bppRGB555;
+ }
+ break;
+#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
+ case 24:
+ *guid_format = GUID_PKPixelFormat24bppBGR;
+ break;
+ case 32:
+ *guid_format = GUID_PKPixelFormat32bppBGRA;
+ *bHasAlpha = TRUE;
+ break;
+#elif FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
+ case 24:
+ *guid_format = GUID_PKPixelFormat24bppRGB;
+ break;
+ case 32:
+ *guid_format = GUID_PKPixelFormat32bppRGBA;
+ *bHasAlpha = TRUE;
+ break;
+#endif
+ case 4:
+ default:
+ // not supported
+ break;
+ }
+ break;
+ case FIT_UINT16: // array of unsigned short : unsigned 16-bit
+ *guid_format = GUID_PKPixelFormat16bppGray;
+ break;
+ case FIT_FLOAT: // array of float : 32-bit IEEE floating point
+ *guid_format = GUID_PKPixelFormat32bppGrayFloat;
+ break;
+ case FIT_RGB16: // 48-bit RGB image : 3 x 16-bit
+ *guid_format = GUID_PKPixelFormat48bppRGB;
+ break;
+ case FIT_RGBA16: // 64-bit RGBA image : 4 x 16-bit
+ *guid_format = GUID_PKPixelFormat64bppRGBA;
+ *bHasAlpha = TRUE;
+ break;
+ case FIT_RGBF: // 96-bit RGB float image : 3 x 32-bit IEEE floating point
+ *guid_format = GUID_PKPixelFormat96bppRGBFloat;
+ break;
+ case FIT_RGBAF: // 128-bit RGBA float image : 4 x 32-bit IEEE floating point
+ *guid_format = GUID_PKPixelFormat128bppRGBAFloat;
+ *bHasAlpha = TRUE;
+ break;
+
+ case FIT_INT16: // array of short : signed 16-bit
+ case FIT_UINT32: // array of unsigned long : unsigned 32-bit
+ case FIT_INT32: // array of long : signed 32-bit
+ case FIT_DOUBLE: // array of double : 64-bit IEEE floating point
+ case FIT_COMPLEX: // array of FICOMPLEX : 2 x 64-bit IEEE floating point
+
+ default:
+ // unsupported format
+ break;
+ }
+
+ return (*guid_format != GUID_PKPixelFormatDontCare) ? WMP_errSuccess : WMP_errUnsupportedFormat;
+}
+
+// ==========================================================
+// Metadata loading & saving
+// ==========================================================
+
+/**
+Read a JPEG-XR IFD as a buffer
+*/
+static ERR
+ReadProfile(WMPStream* pStream, unsigned cbByteCount, unsigned uOffset, BYTE **ppbProfile) {
+ // (re-)allocate profile buffer
+ BYTE *pbProfile = *ppbProfile;
+ pbProfile = (BYTE*)realloc(pbProfile, cbByteCount);
+ if(!pbProfile) {
+ return WMP_errOutOfMemory;
+ }
+ // read the profile
+ if(WMP_errSuccess == pStream->SetPos(pStream, uOffset)) {
+ if(WMP_errSuccess == pStream->Read(pStream, pbProfile, cbByteCount)) {
+ *ppbProfile = pbProfile;
+ return WMP_errSuccess;
+ }
+ }
+ return WMP_errFileIO;
+}
+
+/**
+Convert a DPKPROPVARIANT to a FITAG, then store the tag as FIMD_EXIF_MAIN
+*/
+static BOOL
+ReadPropVariant(WORD tag_id, const DPKPROPVARIANT & varSrc, FIBITMAP *dib) {
+ DWORD dwSize;
+
+ if(varSrc.vt == DPKVT_EMPTY) {
+ return FALSE;
+ }
+
+ // get the tag key
+ TagLib& s = TagLib::instance();
+ const char *key = s.getTagFieldName(TagLib::EXIF_MAIN, tag_id, NULL);
+ if(!key) {
+ return FALSE;
+ }
+
+ // create a tag
+ FITAG *tag = FreeImage_CreateTag();
+ if(tag) {
+ // set tag ID
+ FreeImage_SetTagID(tag, tag_id);
+ // set tag type, count, length and value
+ switch (varSrc.vt) {
+ case DPKVT_LPSTR:
+ FreeImage_SetTagType(tag, FIDT_ASCII);
+ dwSize = (DWORD)strlen(varSrc.VT.pszVal) + 1;
+ FreeImage_SetTagCount(tag, dwSize);
+ FreeImage_SetTagLength(tag, dwSize);
+ FreeImage_SetTagValue(tag, varSrc.VT.pszVal);
+ break;
+
+ 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_SetTagLength(tag, dwSize);
+ FreeImage_SetTagValue(tag, varSrc.VT.pwszVal);
+ break;
+
+ case DPKVT_UI2:
+ FreeImage_SetTagType(tag, FIDT_SHORT);
+ FreeImage_SetTagCount(tag, 1);
+ FreeImage_SetTagLength(tag, 2);
+ FreeImage_SetTagValue(tag, &varSrc.VT.uiVal);
+ break;
+
+ case DPKVT_UI4:
+ FreeImage_SetTagType(tag, FIDT_LONG);
+ FreeImage_SetTagCount(tag, 1);
+ FreeImage_SetTagLength(tag, 4);
+ FreeImage_SetTagValue(tag, &varSrc.VT.ulVal);
+ break;
+
+ default:
+ assert(FALSE); // This case is not handled
+ break;
+ }
+ // get the tag desctiption
+ const char *description = s.getTagDescription(TagLib::EXIF_MAIN, tag_id);
+ FreeImage_SetTagDescription(tag, description);
+
+ // store the tag
+ FreeImage_SetMetadata(FIMD_EXIF_MAIN, dib, key, tag);
+
+ FreeImage_DeleteTag(tag);
+ }
+ return TRUE;
+}
+
+/**
+Read JPEG-XR descriptive metadata and store as EXIF_MAIN metadata
+@see ReadPropVariant
+*/
+static ERR
+ReadDescriptiveMetadata(PKImageDecode *pID, FIBITMAP *dib) {
+ // get Exif TIFF metadata
+ const DESCRIPTIVEMETADATA *pDescMetadata = &pID->WMP.sDescMetadata;
+ // convert metadata to FITAG and store into the EXIF_MAIN metadata model
+ ReadPropVariant(WMP_tagImageDescription, pDescMetadata->pvarImageDescription, dib);
+ ReadPropVariant(WMP_tagCameraMake, pDescMetadata->pvarCameraMake, dib);
+ ReadPropVariant(WMP_tagCameraModel, pDescMetadata->pvarCameraModel, dib);
+ ReadPropVariant(WMP_tagSoftware, pDescMetadata->pvarSoftware, dib);
+ ReadPropVariant(WMP_tagDateTime, pDescMetadata->pvarDateTime, dib);
+ ReadPropVariant(WMP_tagArtist, pDescMetadata->pvarArtist, dib);
+ ReadPropVariant(WMP_tagCopyright, pDescMetadata->pvarCopyright, dib);
+ ReadPropVariant(WMP_tagRatingStars, pDescMetadata->pvarRatingStars, dib);
+ ReadPropVariant(WMP_tagRatingValue, pDescMetadata->pvarRatingValue, dib);
+ ReadPropVariant(WMP_tagCaption, pDescMetadata->pvarCaption, dib);
+ ReadPropVariant(WMP_tagDocumentName, pDescMetadata->pvarDocumentName, dib);
+ ReadPropVariant(WMP_tagPageName, pDescMetadata->pvarPageName, dib);
+ ReadPropVariant(WMP_tagPageNumber, pDescMetadata->pvarPageNumber, dib);
+ ReadPropVariant(WMP_tagHostComputer, pDescMetadata->pvarHostComputer, dib);
+ return WMP_errSuccess;
+}
+
+/**
+Read ICC, XMP, Exif, Exif-GPS, IPTC, descriptive (i.e. Exif-TIFF) metadata
+*/
+static ERR
+ReadMetadata(PKImageDecode *pID, FIBITMAP *dib) {
+ ERR error_code = 0; // error code as returned by the interface
+ size_t currentPos = 0; // current stream position
+
+ WMPStream *pStream = pID->pStream;
+ WmpDEMisc *wmiDEMisc = &pID->WMP.wmiDEMisc;
+ BYTE *pbProfile = NULL;
+
+ try {
+ // save current position
+ error_code = pStream->GetPos(pStream, &currentPos);
+ JXR_CHECK(error_code);
+
+ // ICC profile
+ if(0 != wmiDEMisc->uColorProfileByteCount) {
+ unsigned cbByteCount = wmiDEMisc->uColorProfileByteCount;
+ unsigned uOffset = wmiDEMisc->uColorProfileOffset;
+ error_code = ReadProfile(pStream, cbByteCount, uOffset, &pbProfile);
+ JXR_CHECK(error_code);
+ FreeImage_CreateICCProfile(dib, pbProfile, cbByteCount);
+ }
+
+ // XMP metadata
+ if(0 != wmiDEMisc->uXMPMetadataByteCount) {
+ unsigned cbByteCount = wmiDEMisc->uXMPMetadataByteCount;
+ unsigned uOffset = wmiDEMisc->uXMPMetadataOffset;
+ error_code = ReadProfile(pStream, cbByteCount, uOffset, &pbProfile);
+ JXR_CHECK(error_code);
+ // store the tag as XMP
+ FITAG *tag = FreeImage_CreateTag();
+ if(tag) {
+ FreeImage_SetTagLength(tag, cbByteCount);
+ FreeImage_SetTagCount(tag, cbByteCount);
+ FreeImage_SetTagType(tag, FIDT_ASCII);
+ FreeImage_SetTagValue(tag, pbProfile);
+ FreeImage_SetTagKey(tag, g_TagLib_XMPFieldName);
+ FreeImage_SetMetadata(FIMD_XMP, dib, FreeImage_GetTagKey(tag), tag);
+ FreeImage_DeleteTag(tag);
+ }
+ }
+
+ // IPTC metadata
+ if(0 != wmiDEMisc->uIPTCNAAMetadataByteCount) {
+ unsigned cbByteCount = wmiDEMisc->uIPTCNAAMetadataByteCount;
+ unsigned uOffset = wmiDEMisc->uIPTCNAAMetadataOffset;
+ error_code = ReadProfile(pStream, cbByteCount, uOffset, &pbProfile);
+ JXR_CHECK(error_code);
+ // decode the IPTC profile
+ read_iptc_profile(dib, pbProfile, cbByteCount);
+ }
+
+ // Exif metadata
+ if(0 != wmiDEMisc->uEXIFMetadataByteCount) {
+ unsigned cbByteCount = wmiDEMisc->uEXIFMetadataByteCount;
+ unsigned uOffset = wmiDEMisc->uEXIFMetadataOffset;
+ error_code = ReadProfile(pStream, cbByteCount, uOffset, &pbProfile);
+ JXR_CHECK(error_code);
+ // decode the Exif profile
+ jpegxr_read_exif_profile(dib, pbProfile, cbByteCount);
+ }
+
+ // Exif-GPS metadata
+ if(0 != wmiDEMisc->uGPSInfoMetadataByteCount) {
+ unsigned cbByteCount = wmiDEMisc->uGPSInfoMetadataByteCount;
+ unsigned uOffset = wmiDEMisc->uGPSInfoMetadataOffset;
+ error_code = ReadProfile(pStream, cbByteCount, uOffset, &pbProfile);
+ JXR_CHECK(error_code);
+ // decode the Exif-GPS profile
+ jpegxr_read_exif_gps_profile(dib, pbProfile, cbByteCount);
+ }
+
+ // free profile buffer
+ free(pbProfile);
+ // restore initial position
+ error_code = pID->pStream->SetPos(pID->pStream, currentPos);
+ JXR_CHECK(error_code);
+
+ // as a LAST STEP, read descriptive metadata
+ // these metadata overwrite possible identical Exif-TIFF metadata
+ // that could have been read inside the Exif IFD
+
+ return ReadDescriptiveMetadata(pID, dib);
+
+ } catch(...) {
+ // free profile buffer
+ free(pbProfile);
+ if(currentPos) {
+ // restore initial position
+ pStream->SetPos(pStream, currentPos);
+ }
+ return error_code;
+ }
+}
+
+// ==========================================================
+// Quantization tables (Y, U, V, YHP, UHP, VHP),
+// optimized for PSNR
+// ==========================================================
+
+static const int DPK_QPS_420[11][6] = { // for 8 bit only
+ { 66, 65, 70, 72, 72, 77 },
+ { 59, 58, 63, 64, 63, 68 },
+ { 52, 51, 57, 56, 56, 61 },
+ { 48, 48, 54, 51, 50, 55 },
+ { 43, 44, 48, 46, 46, 49 },
+ { 37, 37, 42, 38, 38, 43 },
+ { 26, 28, 31, 27, 28, 31 },
+ { 16, 17, 22, 16, 17, 21 },
+ { 10, 11, 13, 10, 10, 13 },
+ { 5, 5, 6, 5, 5, 6 },
+ { 2, 2, 3, 2, 2, 2 }
+};
+
+static const int DPK_QPS_8[12][6] = {
+ { 67, 79, 86, 72, 90, 98 },
+ { 59, 74, 80, 64, 83, 89 },
+ { 53, 68, 75, 57, 76, 83 },
+ { 49, 64, 71, 53, 70, 77 },
+ { 45, 60, 67, 48, 67, 74 },
+ { 40, 56, 62, 42, 59, 66 },
+ { 33, 49, 55, 35, 51, 58 },
+ { 27, 44, 49, 28, 45, 50 },
+ { 20, 36, 42, 20, 38, 44 },
+ { 13, 27, 34, 13, 28, 34 },
+ { 7, 17, 21, 8, 17, 21 }, // Photoshop 100%
+ { 2, 5, 6, 2, 5, 6 }
+};
+
+static const int DPK_QPS_16[11][6] = {
+ { 197, 203, 210, 202, 207, 213 },
+ { 174, 188, 193, 180, 189, 196 },
+ { 152, 167, 173, 156, 169, 174 },
+ { 135, 152, 157, 137, 153, 158 },
+ { 119, 137, 141, 119, 138, 142 },
+ { 102, 120, 125, 100, 120, 124 },
+ { 82, 98, 104, 79, 98, 103 },
+ { 60, 76, 81, 58, 76, 81 },
+ { 39, 52, 58, 36, 52, 58 },
+ { 16, 27, 33, 14, 27, 33 },
+ { 5, 8, 9, 4, 7, 8 }
+};
+
+static const int DPK_QPS_16f[11][6] = {
+ { 148, 177, 171, 165, 187, 191 },
+ { 133, 155, 153, 147, 172, 181 },
+ { 114, 133, 138, 130, 157, 167 },
+ { 97, 118, 120, 109, 137, 144 },
+ { 76, 98, 103, 85, 115, 121 },
+ { 63, 86, 91, 62, 96, 99 },
+ { 46, 68, 71, 43, 73, 75 },
+ { 29, 48, 52, 27, 48, 51 },
+ { 16, 30, 35, 14, 29, 34 },
+ { 8, 14, 17, 7, 13, 17 },
+ { 3, 5, 7, 3, 5, 6 }
+};
+
+static const int DPK_QPS_32f[11][6] = {
+ { 194, 206, 209, 204, 211, 217 },
+ { 175, 187, 196, 186, 193, 205 },
+ { 157, 170, 177, 167, 180, 190 },
+ { 133, 152, 156, 144, 163, 168 },
+ { 116, 138, 142, 117, 143, 148 },
+ { 98, 120, 123, 96, 123, 126 },
+ { 80, 99, 102, 78, 99, 102 },
+ { 65, 79, 84, 63, 79, 84 },
+ { 48, 61, 67, 45, 60, 66 },
+ { 27, 41, 46, 24, 40, 45 },
+ { 3, 22, 24, 2, 21, 22 }
+};
+
+// ==========================================================
+// Plugin Implementation
+// ==========================================================
+
+static const char * DLL_CALLCONV
+Format() {
+ return "JPEG-XR";
+}
+
+static const char * DLL_CALLCONV
+Description() {
+ return "JPEG XR image format";
+}
+
+static const char * DLL_CALLCONV
+Extension() {
+ return "jxr,wdp,hdp";
+}
+
+static const char * DLL_CALLCONV
+RegExpr() {
+ return NULL;
+}
+
+static const char * DLL_CALLCONV
+MimeType() {
+ return "image/vnd.ms-photo";
+}
+
+static BOOL DLL_CALLCONV
+Validate(FreeImageIO *io, fi_handle handle) {
+ BYTE jxr_signature[3] = { 0x49, 0x49, 0xBC };
+ BYTE signature[3] = { 0, 0, 0 };
+
+ io->read_proc(&signature, 1, 3, handle);
+
+ return (memcmp(jxr_signature, signature, 3) == 0);
+}
+
+static BOOL DLL_CALLCONV
+SupportsExportDepth(int depth) {
+ return (
+ (depth == 1) ||
+ (depth == 8) ||
+ (depth == 16) ||
+ (depth == 24) ||
+ (depth == 32)
+ );
+}
+
+static BOOL DLL_CALLCONV
+SupportsExportType(FREE_IMAGE_TYPE type) {
+ return (
+ (type == FIT_BITMAP) ||
+ (type == FIT_UINT16) ||
+ (type == FIT_RGB16) ||
+ (type == FIT_RGBA16) ||
+ (type == FIT_FLOAT) ||
+ (type == FIT_RGBF) ||
+ (type == FIT_RGBAF)
+ );
+}
+
+static BOOL DLL_CALLCONV
+SupportsICCProfiles() {
+ return TRUE;
+}
+
+static BOOL DLL_CALLCONV
+SupportsNoPixels() {
+ return TRUE;
+}
+
+// ==========================================================
+// Open & Close
+// ==========================================================
+
+static void * DLL_CALLCONV
+Open(FreeImageIO *io, fi_handle handle, BOOL read) {
+ WMPStream *pStream = NULL; // stream interface
+ if(io && handle) {
+ // allocate the FreeImageIO stream wrapper
+ FreeImageJXRIO *jxr_io = (FreeImageJXRIO*)malloc(sizeof(FreeImageJXRIO));
+ if(jxr_io) {
+ jxr_io->io = io;
+ jxr_io->handle = handle;
+ // create a JXR stream wrapper
+ if(_jxr_io_Create(&pStream, jxr_io) != WMP_errSuccess) {
+ free(jxr_io);
+ return NULL;
+ }
+ }
+ }
+ return pStream;
+}
+
+static void DLL_CALLCONV
+Close(FreeImageIO *io, fi_handle handle, void *data) {
+ WMPStream *pStream = (WMPStream*)data;
+ if(pStream) {
+ // free the FreeImageIO stream wrapper
+ FreeImageJXRIO *jxr_io = (FreeImageJXRIO*)pStream->state.pvObj;
+ free(jxr_io);
+ // free the JXR stream wrapper
+ pStream->fMem = TRUE;
+ _jxr_io_Close(&pStream);
+ }
+}
+
+// ==========================================================
+// Load
+// ==========================================================
+
+/**
+Set decoder parameters
+@param pDecoder Decoder handle
+@param flags FreeImage load flags
+*/
+static void
+SetDecoderParameters(PKImageDecode *pDecoder, int flags) {
+ // load image & alpha for formats with alpha
+ pDecoder->WMP.wmiSCP.uAlphaMode = 2;
+ // more options to come ...
+}
+
+/**
+Copy or convert & copy decoded pixels into the dib
+@param pDecoder Decoder handle
+@param out_guid_format Target guid format
+@param dib Output dib
+@param width Image width
+@param height Image height
+@return Returns 0 if successful, returns ERR otherwise
+*/
+static ERR
+CopyPixels(PKImageDecode *pDecoder, PKPixelFormatGUID out_guid_format, FIBITMAP *dib, int width, int height) {
+ PKFormatConverter *pConverter = NULL; // pixel format converter
+ ERR error_code = 0; // error code as returned by the interface
+ BYTE *pb = NULL; // local buffer used for pixel format conversion
+
+ // image dimensions
+ const PKRect rect = {0, 0, width, height};
+
+ try {
+ // get input file pixel format ...
+ PKPixelFormatGUID in_guid_format;
+ error_code = pDecoder->GetPixelFormat(pDecoder, &in_guid_format);
+ JXR_CHECK(error_code);
+
+ // is a format conversion needed ?
+
+ if(IsEqualGUID(out_guid_format, in_guid_format)) {
+ // no conversion, load bytes "as is" ...
+
+ // get a pointer to dst pixel data
+ BYTE *dib_bits = FreeImage_GetBits(dib);
+
+ // get dst pitch (count of BYTE for stride)
+ const unsigned cbStride = FreeImage_GetPitch(dib);
+
+ // decode and copy bits to dst array
+ error_code = pDecoder->Copy(pDecoder, &rect, dib_bits, cbStride);
+ JXR_CHECK(error_code);
+ }
+ else {
+ // we need to use the conversion API ...
+
+ // allocate the pixel format converter
+ error_code = PKCodecFactory_CreateFormatConverter(&pConverter);
+ JXR_CHECK(error_code);
+
+ // set the conversion function
+ error_code = pConverter->Initialize(pConverter, pDecoder, NULL, out_guid_format);
+ JXR_CHECK(error_code);
+
+ // get the maximum stride
+ unsigned cbStride = 0;
+ {
+ PKPixelInfo pPIFrom;
+ PKPixelInfo pPITo;
+
+ pPIFrom.pGUIDPixFmt = &in_guid_format;
+ error_code = PixelFormatLookup(&pPIFrom, LOOKUP_FORWARD);
+ JXR_CHECK(error_code);
+
+ pPITo.pGUIDPixFmt = &out_guid_format;
+ error_code = PixelFormatLookup(&pPITo, LOOKUP_FORWARD);
+ JXR_CHECK(error_code);
+
+ unsigned cbStrideFrom = ((pPIFrom.cbitUnit + 7) >> 3) * width;
+ unsigned cbStrideTo = ((pPITo.cbitUnit + 7) >> 3) * width;
+ cbStride = MAX(cbStrideFrom, cbStrideTo);
+ }
+
+ // allocate a local decoder / encoder buffer
+ error_code = PKAllocAligned((void **) &pb, cbStride * height, 128);
+ JXR_CHECK(error_code);
+
+ // copy / convert pixels
+ error_code = pConverter->Copy(pConverter, &rect, pb, cbStride);
+ JXR_CHECK(error_code);
+
+ // now copy pixels into the dib
+ const size_t line_size = FreeImage_GetLine(dib);
+ for(int y = 0; y < height; y++) {
+ BYTE *src_bits = (BYTE*)(pb + y * cbStride);
+ BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, y);
+ memcpy(dst_bits, src_bits, line_size);
+ }
+
+ // free the local buffer
+ PKFreeAligned((void **) &pb);
+
+ // free the pixel format converter
+ PKFormatConverter_Release(&pConverter);
+ }
+
+ // FreeImage DIB are upside-down relative to usual graphic conventions
+ FreeImage_FlipVertical(dib);
+
+ // post-processing ...
+ // -------------------
+
+ // swap RGB as needed
+
+#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
+ if(IsEqualGUID(out_guid_format, GUID_PKPixelFormat24bppRGB) || IsEqualGUID(out_guid_format, GUID_PKPixelFormat32bppRGB)) {
+ SwapRedBlue32(dib);
+ }
+#elif FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
+ if(IsEqualGUID(out_guid_format, GUID_PKPixelFormat24bppBGR) || IsEqualGUID(out_guid_format, GUID_PKPixelFormat32bppBGR)) {
+ SwapRedBlue32(dib);
+ }
+#endif
+
+ return WMP_errSuccess;
+
+ } catch(...) {
+ // free the local buffer
+ PKFreeAligned((void **) &pb);
+ // free the pixel format converter
+ PKFormatConverter_Release(&pConverter);
+
+ return error_code;
+ }
+}
+
+// --------------------------------------------------------------------------
+
+static FIBITMAP * DLL_CALLCONV
+Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
+ PKImageDecode *pDecoder = NULL; // decoder interface
+ ERR error_code = 0; // error code as returned by the interface
+ PKPixelFormatGUID guid_format; // loaded pixel format (== input file pixel format if no conversion needed)
+
+ FREE_IMAGE_TYPE image_type = FIT_UNKNOWN; // input image type
+ unsigned bpp = 0; // input image bit depth
+ FIBITMAP *dib = NULL;
+
+ // get the I/O stream wrapper
+ WMPStream *pDecodeStream = (WMPStream*)data;
+
+ if(!handle || !pDecodeStream) {
+ return NULL;
+ }
+
+ BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
+
+ try {
+ int width, height; // image dimensions (in pixels)
+
+ // create a JXR decoder interface and initialize function pointers with *_WMP functions
+ error_code = PKImageDecode_Create_WMP(&pDecoder);
+ JXR_CHECK(error_code);
+
+ // attach the stream to the decoder ...
+ // ... then read the image container and the metadata
+ error_code = pDecoder->Initialize(pDecoder, pDecodeStream);
+ JXR_CHECK(error_code);
+
+ // set decoder parameters
+ SetDecoderParameters(pDecoder, flags);
+
+ // get dst image format specifications
+ unsigned red_mask = 0, green_mask = 0, blue_mask = 0;
+ error_code = GetInputPixelFormat(pDecoder, &guid_format, &image_type, &bpp, &red_mask, &green_mask, &blue_mask);
+ JXR_CHECK(error_code);
+
+ // get image dimensions
+ pDecoder->GetSize(pDecoder, &width, &height);
+
+ // allocate dst image
+ {
+ dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, bpp, red_mask, green_mask, blue_mask);
+ if(!dib) {
+ throw FI_MSG_ERROR_DIB_MEMORY;
+ }
+ if(FreeImage_GetBPP(dib) == 1) {
+ // BD_1 - build a FIC_MINISBLACK palette
+ RGBQUAD *pal = FreeImage_GetPalette(dib);
+ pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0;
+ pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255;
+ }
+ }
+
+ // get image resolution
+ {
+ float resX, resY; // image resolution (in dots per inch)
+ // convert from English units, i.e. dots per inch to universal units, i.e. dots per meter
+ pDecoder->GetResolution(pDecoder, &resX, &resY);
+ FreeImage_SetDotsPerMeterX(dib, (unsigned)(resX / 0.0254F + 0.5F));
+ FreeImage_SetDotsPerMeterY(dib, (unsigned)(resY / 0.0254F + 0.5F));
+ }
+
+ // get metadata & ICC profile
+ error_code = ReadMetadata(pDecoder, dib);
+ JXR_CHECK(error_code);
+
+ if(header_only) {
+ // header only mode ...
+
+ // free the decoder
+ pDecoder->Release(&pDecoder);
+ assert(pDecoder == NULL);
+
+ return dib;
+ }
+
+ // copy pixels into the dib, perform pixel conversion if needed
+ error_code = CopyPixels(pDecoder, guid_format, dib, width, height);
+ JXR_CHECK(error_code);
+
+ // free the decoder
+ pDecoder->Release(&pDecoder);
+ assert(pDecoder == NULL);
+
+ return dib;
+
+ } catch (const char *message) {
+ // unload the dib
+ FreeImage_Unload(dib);
+ // free the decoder
+ pDecoder->Release(&pDecoder);
+
+ if(NULL != message) {
+ FreeImage_OutputMessageProc(s_format_id, message);
+ }
+ }
+
+ return NULL;
+}
+
+// ==========================================================
+// Save
+// ==========================================================
+
+/**
+Configure compression parameters
+
+ImageQuality Q (BD==1) Q (BD==8) Q (BD==16) Q (BD==32F) Subsample Overlap
+[0.0, 0.4] 8-IQ*5 (see table) (see table) (see table) 4:4:4 2
+(0.4, 0.8) 8-IQ*5 (see table) (see table) (see table) 4:4:4 1
+[0.8, 1.0) 8-IQ*5 (see table) (see table) (see table) 4:4:4 1
+[1.0, 1.0] 1 1 1 1 4:4:4 0
+
+@param wmiSCP Encoder parameters
+@param pixelInfo Image specifications
+@param fltImageQuality Image output quality in [0..1), 1 means lossless
+*/
+static void
+SetCompression(CWMIStrCodecParam *wmiSCP, const PKPixelInfo *pixelInfo, float fltImageQuality) {
+ if(fltImageQuality < 1.0F) {
+ // overlap
+ if(fltImageQuality >= 0.5F) {
+ wmiSCP->olOverlap = OL_ONE;
+ } else {
+ wmiSCP->olOverlap = OL_TWO;
+ }
+ // chroma sub-sampling
+ if(fltImageQuality >= 0.5F || pixelInfo->uBitsPerSample > 8) {
+ wmiSCP->cfColorFormat = YUV_444;
+ } else {
+ wmiSCP->cfColorFormat = YUV_420;
+ }
+
+ // bit depth
+ if(pixelInfo->bdBitDepth == BD_1) {
+ wmiSCP->uiDefaultQPIndex = (U8)(8 - 5.0F * fltImageQuality + 0.5F);
+ }
+ else {
+ // remap [0.8, 0.866, 0.933, 1.0] to [0.8, 0.9, 1.0, 1.1]
+ // to use 8-bit DPK QP table (0.933 == Photoshop JPEG 100)
+ if(fltImageQuality > 0.8F && pixelInfo->bdBitDepth == BD_8 && wmiSCP->cfColorFormat != YUV_420 && wmiSCP->cfColorFormat != YUV_422) {
+ fltImageQuality = 0.8F + (fltImageQuality - 0.8F) * 1.5F;
+ }
+
+ const int qi = (int) (10.0F * fltImageQuality);
+ const float qf = 10.0F * fltImageQuality - (float)qi;
+
+ const int *pQPs =
+ (wmiSCP->cfColorFormat == YUV_420 || wmiSCP->cfColorFormat == YUV_422) ?
+ DPK_QPS_420[qi] :
+ (pixelInfo->bdBitDepth == BD_8 ? DPK_QPS_8[qi] :
+ (pixelInfo->bdBitDepth == BD_16 ? DPK_QPS_16[qi] :
+ (pixelInfo->bdBitDepth == BD_16F ? DPK_QPS_16f[qi] :
+ DPK_QPS_32f[qi])));
+
+ wmiSCP->uiDefaultQPIndex = (U8) (0.5F + (float) pQPs[0] * (1.0F - qf) + (float) (pQPs + 6)[0] * qf);
+ wmiSCP->uiDefaultQPIndexU = (U8) (0.5F + (float) pQPs[1] * (1.0F - qf) + (float) (pQPs + 6)[1] * qf);
+ wmiSCP->uiDefaultQPIndexV = (U8) (0.5F + (float) pQPs[2] * (1.0F - qf) + (float) (pQPs + 6)[2] * qf);
+ wmiSCP->uiDefaultQPIndexYHP = (U8) (0.5F + (float) pQPs[3] * (1.0F - qf) + (float) (pQPs + 6)[3] * qf);
+ wmiSCP->uiDefaultQPIndexUHP = (U8) (0.5F + (float) pQPs[4] * (1.0F - qf) + (float) (pQPs + 6)[4] * qf);
+ wmiSCP->uiDefaultQPIndexVHP = (U8) (0.5F + (float) pQPs[5] * (1.0F - qf) + (float) (pQPs + 6)[5] * qf);
+ }
+ } // fltImageQuality < 1.0F
+ else {
+ // lossless mode
+ wmiSCP->uiDefaultQPIndex = 1;
+ }
+}
+
+/**
+Set encoder parameters
+@param wmiSCP Encoder parameters
+@param pixelInfo Image specifications
+@param flags FreeImage save flags
+@param bHasAlpha TRUE if an alpha layer is present
+*/
+static void
+SetEncoderParameters(CWMIStrCodecParam *wmiSCP, const PKPixelInfo *pixelInfo, int flags, BOOL bHasAlpha) {
+ float fltImageQuality = 1.0F;
+
+ // all values have been set to zero by the API
+ // update default values for some attributes
+ wmiSCP->cfColorFormat = YUV_444; // color format
+ wmiSCP->bdBitDepth = BD_LONG; // internal bit depth
+ wmiSCP->bfBitstreamFormat = SPATIAL; // compressed image data in spatial order
+ wmiSCP->bProgressiveMode = FALSE; // sequential mode
+ wmiSCP->olOverlap = OL_ONE; // single level overlap processing
+ wmiSCP->cNumOfSliceMinus1H = 0; // # of horizontal slices
+ wmiSCP->cNumOfSliceMinus1V = 0; // # of vertical slices
+ wmiSCP->sbSubband = SB_ALL; // keep all subbands
+ wmiSCP->uAlphaMode = 0; // 0:no alpha 1: alpha only else: something + alpha
+ wmiSCP->uiDefaultQPIndex = 1; // quantization for grey or rgb layer(s), 1: lossless
+ wmiSCP->uiDefaultQPIndexAlpha = 1; // quantization for alpha layer, 1: lossless
+
+ // process the flags
+ // -----------------
+
+ // progressive mode
+ if((flags & JXR_PROGRESSIVE) == JXR_PROGRESSIVE) {
+ // turn on progressive mode (instead of sequential mode)
+ wmiSCP->bProgressiveMode = TRUE;
+ }
+
+ // quality in [0.01 - 1.0), 1.0 means lossless - default is 0.80
+ int quality = flags & 0x7F;
+ if(quality == 0) {
+ // defaut to 0.80
+ fltImageQuality = 0.8F;
+ } else if((flags & JXR_LOSSLESS) == JXR_LOSSLESS) {
+ fltImageQuality = 1.0F;
+ } else {
+ quality = (quality >= 100) ? 100 : quality;
+ fltImageQuality = quality / 100.0F;
+ }
+ SetCompression(wmiSCP, pixelInfo, fltImageQuality);
+
+ // alpha compression
+ if(bHasAlpha) {
+ wmiSCP->uAlphaMode = 2; // encode with a planar alpha channel
+ }
+}
+
+// --------------------------------------------------------------------------
+
+static BOOL DLL_CALLCONV
+Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
+ BOOL bIsFlipped = FALSE; // FreeImage DIB are upside-down relative to usual graphic conventions
+ PKPixelFormatGUID guid_format; // image format
+ PKPixelInfo pixelInfo; // image specifications
+ BOOL bHasAlpha = FALSE; // is alpha layer present ?
+
+ PKImageEncode *pEncoder = NULL; // encoder interface
+ ERR error_code = 0; // error code as returned by the interface
+
+ // get the I/O stream wrapper
+ WMPStream *pEncodeStream = (WMPStream*)data;
+
+ if(!dib || !handle || !pEncodeStream) {
+ return FALSE;
+ }
+
+ try {
+ // get image dimensions
+ unsigned width = FreeImage_GetWidth(dib);
+ unsigned height = FreeImage_GetHeight(dib);
+
+ // check JPEG-XR limits
+ if((width < MB_WIDTH_PIXEL) || (height < MB_HEIGHT_PIXEL)) {
+ FreeImage_OutputMessageProc(s_format_id, "Unsupported image size: width x height = %d x %d", width, height);
+ throw (const char*)NULL;
+ }
+
+ // get output pixel format
+ error_code = GetOutputPixelFormat(dib, &guid_format, &bHasAlpha);
+ JXR_CHECK(error_code);
+ pixelInfo.pGUIDPixFmt = &guid_format;
+ error_code = PixelFormatLookup(&pixelInfo, LOOKUP_FORWARD);
+ JXR_CHECK(error_code);
+
+ // create a JXR encoder interface and initialize function pointers with *_WMP functions
+ error_code = PKImageEncode_Create_WMP(&pEncoder);
+ JXR_CHECK(error_code);
+
+ // attach the stream to the encoder and set all encoder parameters to zero ...
+ error_code = pEncoder->Initialize(pEncoder, pEncodeStream, &pEncoder->WMP.wmiSCP, sizeof(CWMIStrCodecParam));
+ JXR_CHECK(error_code);
+
+ // ... then configure the encoder
+ SetEncoderParameters(&pEncoder->WMP.wmiSCP, &pixelInfo, flags, bHasAlpha);
+
+ // set pixel format
+ pEncoder->SetPixelFormat(pEncoder, guid_format);
+
+ // set image size
+ pEncoder->SetSize(pEncoder, width, height);
+
+ // set resolution (convert from universal units to English units)
+ float resX = (float)(unsigned)(0.5F + 0.0254F * FreeImage_GetDotsPerMeterX(dib));
+ float resY = (float)(unsigned)(0.5F + 0.0254F * FreeImage_GetDotsPerMeterY(dib));
+ pEncoder->SetResolution(pEncoder, resX, resY);
+
+ // write pixels
+ // --------------
+
+ // dib coordinates are upside-down relative to usual conventions
+ bIsFlipped = FreeImage_FlipVertical(dib);
+
+ // get a pointer to dst pixel data
+ BYTE *dib_bits = FreeImage_GetBits(dib);
+
+ // get dst pitch (count of BYTE for stride)
+ const unsigned cbStride = FreeImage_GetPitch(dib);
+
+ // write pixels on output
+ error_code = pEncoder->WritePixels(pEncoder, height, dib_bits, cbStride);
+ JXR_CHECK(error_code);
+
+ // recover dib coordinates
+ FreeImage_FlipVertical(dib);
+
+ // free the encoder
+ pEncoder->Release(&pEncoder);
+ assert(pEncoder == NULL);
+
+ return TRUE;
+
+ } catch (const char *message) {
+ if(bIsFlipped) {
+ // recover dib coordinates
+ FreeImage_FlipVertical(dib);
+ }
+ if(pEncoder) {
+ // free the encoder
+ pEncoder->Release(&pEncoder);
+ assert(pEncoder == NULL);
+ }
+ if(NULL != message) {
+ FreeImage_OutputMessageProc(s_format_id, message);
+ }
+ }
+
+ return FALSE;
+}
+
+// ==========================================================
+// Init
+// ==========================================================
+
+void DLL_CALLCONV
+InitJXR(Plugin *plugin, int format_id) {
+ s_format_id = format_id;
+
+ plugin->format_proc = Format;
+ plugin->description_proc = Description;
+ plugin->extension_proc = Extension;
+ plugin->regexpr_proc = RegExpr;
+ plugin->open_proc = Open;
+ plugin->close_proc = Close;
+ plugin->pagecount_proc = NULL;
+ plugin->pagecapability_proc = NULL;
+ plugin->load_proc = Load;
+ plugin->save_proc = Save;
+ plugin->validate_proc = Validate;
+ plugin->mime_proc = MimeType;
+ plugin->supports_export_bpp_proc = SupportsExportDepth;
+ plugin->supports_export_type_proc = SupportsExportType;
+ plugin->supports_icc_profiles_proc = SupportsICCProfiles;
+ plugin->supports_no_pixels_proc = SupportsNoPixels;
+}
+
diff --git a/plugins/AdvaImg/src/FreeImage/PluginPNG.cpp b/plugins/AdvaImg/src/FreeImage/PluginPNG.cpp
index 7a74fe5e81..f6b59e299b 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginPNG.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginPNG.cpp
@@ -35,6 +35,8 @@
#define PNG_BYTES_TO_CHECK 8
+#undef PNG_Z_DEFAULT_COMPRESSION // already used in ../LibPNG/pnglibconf.h
+
// ----------------------------------------------------------
#include "zlib.h"
diff --git a/plugins/AdvaImg/src/FreeImage/PluginSGI.cpp b/plugins/AdvaImg/src/FreeImage/PluginSGI.cpp
index 0fd162b1d4..35fd2ec611 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginSGI.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginSGI.cpp
@@ -178,7 +178,7 @@ Description() {
static const char * DLL_CALLCONV
Extension() {
- return "sgi";
+ return "sgi,rgb,rgba,bw";
}
static const char * DLL_CALLCONV
diff --git a/plugins/AdvaImg/src/FreeImage/PluginTARGA.cpp b/plugins/AdvaImg/src/FreeImage/PluginTARGA.cpp
index 5fb1f53ee0..f12d7286ce 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginTARGA.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginTARGA.cpp
@@ -358,6 +358,7 @@ MimeType() {
static BOOL
isTARGA20(FreeImageIO *io, fi_handle handle) {
const unsigned sizeofSig = 18;
+ BYTE signature[sizeofSig];
// tga_signature = "TRUEVISION-XFILE." (TGA 2.0 only)
BYTE tga_signature[sizeofSig] = { 84, 82, 85, 69, 86, 73, 83, 73, 79, 78, 45, 88, 70, 73, 76, 69, 46, 0 };
// get the start offset
@@ -366,13 +367,10 @@ isTARGA20(FreeImageIO *io, fi_handle handle) {
io->seek_proc(handle, 0, SEEK_END);
const long eof = io->tell_proc(handle);
// read the signature
-
io->seek_proc(handle, start_offset + eof - sizeofSig, SEEK_SET);
- BYTE signature[sizeofSig];
- io->read_proc(&signature, 1, sizeofSig, handle);
-
- // rewind
- io->seek_proc(handle, start_offset, SEEK_SET);
+ io->read_proc(&signature, 1, sizeofSig, handle);
+ // rewind
+ io->seek_proc(handle, start_offset, SEEK_SET);
return (memcmp(tga_signature, signature, sizeofSig) == 0);
}
@@ -384,41 +382,61 @@ Validate(FreeImageIO *io, fi_handle handle) {
}
// not a 2.0 image, try testing if it's a valid TGA anyway (not robust)
- BOOL bResult = FALSE;
-
- const long start_offset = io->tell_proc(handle);
-
- TGAHEADER header;
- io->read_proc(&header, sizeof(tagTGAHEADER), 1, handle);
-
- // rewind
- io->seek_proc(handle, start_offset, SEEK_SET);
+ {
+ const long start_offset = io->tell_proc(handle);
+
+ // get the header
+ TGAHEADER header;
+ io->read_proc(&header, sizeof(tagTGAHEADER), 1, handle);
+#ifdef FREEIMAGE_BIGENDIAN
+ SwapHeader(&header);
+#endif
+ // rewind
+ io->seek_proc(handle, start_offset, SEEK_SET);
- switch(header.image_type) {
- case TGA_CMAP :
- case TGA_RGB:
- case TGA_MONO :
- case TGA_RLECMAP:
- case TGA_RLERGB:
- case TGA_RLEMONO:
- switch(header.is_pixel_depth) {
- case 8 :
- case 16:
- case 24:
- case 32:
- bResult = TRUE;
- break;
- default:
- bResult = FALSE;
- break;
+ // the color map type should be a 0 or a 1...
+ if(header.color_map_type != 0 && header.color_map_type != 1) {
+ return FALSE;
+ }
+ // 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
+ if(header.cm_first_entry >= header.cm_length) {
+ return FALSE;
}
- break;
- default:
- bResult = FALSE;
- break;
+ }
+ // 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) {
+ return FALSE;
+ }
+ // 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_RGB:
+ case TGA_MONO :
+ case TGA_RLECMAP:
+ case TGA_RLERGB:
+ case TGA_RLEMONO:
+ switch(header.is_pixel_depth) {
+ case 8 :
+ case 16:
+ case 24:
+ case 32:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+ break;
+ default:
+ return FALSE;
+ }
}
-
- return bResult;
+
+ return FALSE;
}
static BOOL DLL_CALLCONV
@@ -731,8 +749,12 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
// calculate the color map size
csize = header.cm_length * header.cm_size / 8;
+
+ // read the color map
BYTE *cmap = (BYTE*)malloc(csize * sizeof(BYTE));
-
+ if (cmap == NULL) {
+ throw FI_MSG_ERROR_DIB_MEMORY;
+ }
io->read_proc(cmap, sizeof(BYTE), csize, handle);
// build the palette
@@ -740,8 +762,10 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
switch (header.cm_size) {
case 16: {
WORD *rgb555 = (WORD*)&cmap[0];
+ unsigned start = (unsigned)header.cm_first_entry;
+ unsigned stop = MIN((unsigned)256, (unsigned)header.cm_length);
- for (count = header.cm_first_entry; count < header.cm_length; count++) {
+ for (count = start; count < stop; count++) {
palette[count].rgbRed = (BYTE)((((*rgb555 & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) * 0xFF) / 0x1F);
palette[count].rgbGreen = (BYTE)((((*rgb555 & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) * 0xFF) / 0x1F);
palette[count].rgbBlue = (BYTE)((((*rgb555 & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) * 0xFF) / 0x1F);
@@ -752,8 +776,10 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
case 24: {
FILE_BGR *bgr = (FILE_BGR*)&cmap[0];
+ unsigned start = (unsigned)header.cm_first_entry;
+ unsigned stop = MIN((unsigned)256, (unsigned)header.cm_length);
- for (count = header.cm_first_entry; count < header.cm_length; count++) {
+ for (count = start; count < stop; count++) {
palette[count].rgbBlue = bgr->b;
palette[count].rgbGreen = bgr->g;
palette[count].rgbRed = bgr->r;
@@ -769,8 +795,10 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
memset(trns, 0xFF, 256);
FILE_BGRA *bgra = (FILE_BGRA*)&cmap[0];
+ unsigned start = (unsigned)header.cm_first_entry;
+ unsigned stop = MIN((unsigned)256, (unsigned)header.cm_length);
- for (count = header.cm_first_entry; count < header.cm_length; count++) {
+ for (count = start; count < stop; count++) {
palette[count].rgbBlue = bgra->b;
palette[count].rgbGreen = bgra->g;
palette[count].rgbRed = bgra->r;
diff --git a/plugins/AdvaImg/src/FreeImage/PluginTIFF.cpp b/plugins/AdvaImg/src/FreeImage/PluginTIFF.cpp
index 72218a2564..4e502c56e8 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginTIFF.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginTIFF.cpp
@@ -193,9 +193,6 @@ TIFF *
TIFFFdOpen(thandle_t handle, const char *name, const char *mode) {
TIFF *tif;
- // Set up the callback for extended TIFF directory tag support
- // (see XTIFF.cpp)
- XTIFFInitialize();
// Open the file; the callback will set everything up
tif = TIFFClientOpen(name, mode, handle,
@@ -1894,6 +1891,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
if(buf == NULL) {
throw FI_MSG_ERROR_MEMORY;
}
+ memset(buf, 0, TIFFStripSize(tif) * sizeof(BYTE));
BOOL bThrowMessage = FALSE;
@@ -2622,6 +2620,10 @@ void DLL_CALLCONV
InitTIFF(Plugin *plugin, int format_id) {
s_format_id = format_id;
+ // Set up the callback for extended TIFF directory tag support (see XTIFF.cpp)
+ // Must be called before using libtiff
+ XTIFFInitialize();
+
plugin->format_proc = Format;
plugin->description_proc = Description;
plugin->extension_proc = Extension;
diff --git a/plugins/AdvaImg/src/FreeImage/PluginWebP.cpp b/plugins/AdvaImg/src/FreeImage/PluginWebP.cpp
new file mode 100644
index 0000000000..9fb0b69447
--- /dev/null
+++ b/plugins/AdvaImg/src/FreeImage/PluginWebP.cpp
@@ -0,0 +1,698 @@
+// ==========================================================
+// Google WebP Loader & Writer
+//
+// Design and implementation by
+// - Herve Drolon (drolon@infonie.fr)
+//
+// 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 "FreeImage.h"
+#include "Utilities.h"
+
+#include "../Metadata/FreeImageTag.h"
+
+#include "../LibWebP/src/webp/decode.h"
+#include "../LibWebP/src/webp/encode.h"
+#include "../LibWebP/src/enc/vp8enci.h"
+#include "../LibWebP/src/webp/mux.h"
+
+// ==========================================================
+// Plugin Interface
+// ==========================================================
+
+static int s_format_id;
+
+// ----------------------------------------------------------
+// Helpers for the load function
+// ----------------------------------------------------------
+
+/**
+Read the whole file into memory
+*/
+static BOOL
+ReadFileToWebPData(FreeImageIO *io, fi_handle handle, WebPData * const bitstream) {
+ uint8_t *raw_data = NULL;
+
+ try {
+ // Read the input file and put it in memory
+ long start_pos = io->tell_proc(handle);
+ io->seek_proc(handle, 0, SEEK_END);
+ size_t file_length = (size_t)(io->tell_proc(handle) - start_pos);
+ io->seek_proc(handle, start_pos, SEEK_SET);
+ raw_data = (uint8_t*)malloc(file_length * sizeof(uint8_t));
+ if(!raw_data) {
+ throw FI_MSG_ERROR_MEMORY;
+ }
+ if(io->read_proc(raw_data, 1, (unsigned)file_length, handle) != file_length) {
+ throw "Error while reading input stream";
+ }
+
+ // copy pointers (must be released later using free)
+ bitstream->bytes = raw_data;
+ bitstream->size = file_length;
+
+ return TRUE;
+
+ } catch(const char *text) {
+ if(raw_data) {
+ free(raw_data);
+ }
+ memset(bitstream, 0, sizeof(WebPData));
+ if(NULL != text) {
+ FreeImage_OutputMessageProc(s_format_id, text);
+ }
+ return FALSE;
+ }
+}
+
+// ----------------------------------------------------------
+// Helpers for the save function
+// ----------------------------------------------------------
+
+/**
+Output function. Should return 1 if writing was successful.
+data/data_size is the segment of data to write, and 'picture' is for
+reference (and so one can make use of picture->custom_ptr).
+*/
+static int
+WebP_MemoryWriter(const BYTE *data, size_t data_size, const WebPPicture* const picture) {
+ FIMEMORY *hmem = (FIMEMORY*)picture->custom_ptr;
+ return data_size ? (FreeImage_WriteMemory(data, 1, (unsigned)data_size, hmem) == data_size) : 0;
+}
+
+// ==========================================================
+// Plugin Implementation
+// ==========================================================
+
+static const char * DLL_CALLCONV
+Format() {
+ return "WebP";
+}
+
+static const char * DLL_CALLCONV
+Description() {
+ return "Google WebP image format";
+}
+
+static const char * DLL_CALLCONV
+Extension() {
+ return "webp";
+}
+
+static const char * DLL_CALLCONV
+RegExpr() {
+ return NULL;
+}
+
+static const char * DLL_CALLCONV
+MimeType() {
+ return "image/webp";
+}
+
+static BOOL DLL_CALLCONV
+Validate(FreeImageIO *io, fi_handle handle) {
+ BYTE riff_signature[4] = { 0x52, 0x49, 0x46, 0x46 };
+ BYTE webp_signature[4] = { 0x57, 0x45, 0x42, 0x50 };
+ BYTE signature[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ io->read_proc(signature, 1, 12, handle);
+
+ if(memcmp(riff_signature, signature, 4) == 0) {
+ if(memcmp(webp_signature, signature + 8, 4) == 0) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static BOOL DLL_CALLCONV
+SupportsExportDepth(int depth) {
+ return (
+ (depth == 24) ||
+ (depth == 32)
+ );
+}
+
+static BOOL DLL_CALLCONV
+SupportsExportType(FREE_IMAGE_TYPE type) {
+ return (type == FIT_BITMAP) ? TRUE : FALSE;
+}
+
+static BOOL DLL_CALLCONV
+SupportsICCProfiles() {
+ return TRUE;
+}
+
+static BOOL DLL_CALLCONV
+SupportsNoPixels() {
+ return TRUE;
+}
+
+// ----------------------------------------------------------
+
+static void * DLL_CALLCONV
+Open(FreeImageIO *io, fi_handle handle, BOOL read) {
+ WebPMux *mux = NULL;
+ int copy_data = 1; // 1 : copy data into the mux, 0 : keep a link to local data
+
+ if(read) {
+ // create the MUX object from the input stream
+ WebPData bitstream;
+ // read the input file and put it in memory
+ if(!ReadFileToWebPData(io, handle, &bitstream)) {
+ return NULL;
+ }
+ // create the MUX object
+ mux = WebPMuxCreate(&bitstream, copy_data);
+ // no longer needed since copy_data == 1
+ free((void*)bitstream.bytes);
+ if(mux == NULL) {
+ FreeImage_OutputMessageProc(s_format_id, "Failed to create mux object from file");
+ return NULL;
+ }
+ } else {
+ // creates an empty mux object
+ mux = WebPMuxNew();
+ if(mux == NULL) {
+ FreeImage_OutputMessageProc(s_format_id, "Failed to create empty mux object");
+ return NULL;
+ }
+ }
+
+ return mux;
+}
+
+static void DLL_CALLCONV
+Close(FreeImageIO *io, fi_handle handle, void *data) {
+ WebPMux *mux = (WebPMux*)data;
+ if(mux != NULL) {
+ // free the MUX object
+ WebPMuxDelete(mux);
+ }
+}
+
+// ----------------------------------------------------------
+
+/**
+Decode a WebP image and returns a FIBITMAP image
+@param webp_image Raw WebP image
+@param flags FreeImage load flags
+@return Returns a dib if successfull, returns NULL otherwise
+*/
+static FIBITMAP *
+DecodeImage(WebPData *webp_image, int flags) {
+ FIBITMAP *dib = NULL;
+
+ const uint8_t* data = webp_image->bytes; // raw image data
+ const size_t data_size = webp_image->size; // raw image size
+
+ VP8StatusCode webp_status = VP8_STATUS_OK;
+
+ BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
+
+ // Main object storing the configuration for advanced decoding
+ WebPDecoderConfig decoder_config;
+ // Output buffer
+ WebPDecBuffer* const output_buffer = &decoder_config.output;
+ // Features gathered from the bitstream
+ WebPBitstreamFeatures* const bitstream = &decoder_config.input;
+
+ try {
+ // Initialize the configuration as empty
+ // This function must always be called first, unless WebPGetFeatures() is to be called
+ if(!WebPInitDecoderConfig(&decoder_config)) {
+ throw "Library version mismatch";
+ }
+
+ // Retrieve features from the bitstream
+ // The bitstream structure is filled with information gathered from the bitstream
+ webp_status = WebPGetFeatures(data, data_size, bitstream);
+ if(webp_status != VP8_STATUS_OK) {
+ throw FI_MSG_ERROR_PARSING;
+ }
+
+ // Allocate output dib
+
+ unsigned bpp = bitstream->has_alpha ? 32 : 24;
+ unsigned width = (unsigned)bitstream->width;
+ unsigned height = (unsigned)bitstream->height;
+
+ dib = FreeImage_AllocateHeader(header_only, width, height, bpp, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
+ if(!dib) {
+ throw FI_MSG_ERROR_DIB_MEMORY;
+ }
+
+ if(header_only) {
+ WebPFreeDecBuffer(output_buffer);
+ return dib;
+ }
+
+ // --- Set decoding options ---
+
+ // use multi-threaded decoding
+ decoder_config.options.use_threads = 1;
+ // set output color space
+ output_buffer->colorspace = bitstream->has_alpha ? MODE_BGRA : MODE_BGR;
+
+ // ---
+
+ // decode the input stream, taking 'config' into account.
+
+ webp_status = WebPDecode(data, data_size, &decoder_config);
+ if(webp_status != VP8_STATUS_OK) {
+ throw FI_MSG_ERROR_PARSING;
+ }
+
+ // fill the dib with the decoded data
+
+ const BYTE *src_bitmap = output_buffer->u.RGBA.rgba;
+ const unsigned src_pitch = (unsigned)output_buffer->u.RGBA.stride;
+
+ switch(bpp) {
+ case 24:
+ for(unsigned y = 0; y < height; y++) {
+ const BYTE *src_bits = src_bitmap + y * src_pitch;
+ BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, height-1-y);
+ for(unsigned x = 0; x < width; x++) {
+ dst_bits[FI_RGBA_BLUE] = src_bits[0]; // B
+ dst_bits[FI_RGBA_GREEN] = src_bits[1]; // G
+ dst_bits[FI_RGBA_RED] = src_bits[2]; // R
+ src_bits += 3;
+ dst_bits += 3;
+ }
+ }
+ break;
+ case 32:
+ for(unsigned y = 0; y < height; y++) {
+ const BYTE *src_bits = src_bitmap + y * src_pitch;
+ BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, height-1-y);
+ for(unsigned x = 0; x < width; x++) {
+ dst_bits[FI_RGBA_BLUE] = src_bits[0]; // B
+ dst_bits[FI_RGBA_GREEN] = src_bits[1]; // G
+ dst_bits[FI_RGBA_RED] = src_bits[2]; // R
+ dst_bits[FI_RGBA_ALPHA] = src_bits[3]; // A
+ src_bits += 4;
+ dst_bits += 4;
+ }
+ }
+ break;
+ }
+
+ // Free the decoder
+ WebPFreeDecBuffer(output_buffer);
+
+ return dib;
+
+ } catch (const char *text) {
+ if(dib) {
+ FreeImage_Unload(dib);
+ }
+ WebPFreeDecBuffer(output_buffer);
+
+ if(NULL != text) {
+ FreeImage_OutputMessageProc(s_format_id, text);
+ }
+
+ return NULL;
+ }
+}
+
+static FIBITMAP * DLL_CALLCONV
+Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
+ WebPMux *mux = NULL;
+ WebPMuxFrameInfo webp_frame = { 0 }; // raw image
+ WebPData color_profile; // ICC raw data
+ WebPData xmp_metadata; // XMP raw data
+ WebPData exif_metadata; // EXIF raw data
+ FIBITMAP *dib = NULL;
+ WebPMuxError error_status;
+
+ if(!handle) {
+ return NULL;
+ }
+
+ try {
+ // get the MUX object
+ mux = (WebPMux*)data;
+ if(!mux) {
+ throw (1);
+ }
+
+ // gets the feature flags from the mux object
+ uint32_t webp_flags = 0;
+ error_status = WebPMuxGetFeatures(mux, &webp_flags);
+ if(error_status != WEBP_MUX_OK) {
+ throw (1);
+ }
+
+ // get image data
+ error_status = WebPMuxGetFrame(mux, 1, &webp_frame);
+
+ if(error_status == WEBP_MUX_OK) {
+ // decode the data (can be limited to the header if flags uses FIF_LOAD_NOPIXELS)
+ dib = DecodeImage(&webp_frame.bitstream, flags);
+ if(!dib) {
+ throw (1);
+ }
+
+ // get ICC profile
+ if(webp_flags & ICCP_FLAG) {
+ error_status = WebPMuxGetChunk(mux, "ICCP", &color_profile);
+ if(error_status == WEBP_MUX_OK) {
+ FreeImage_CreateICCProfile(dib, (void*)color_profile.bytes, (long)color_profile.size);
+ }
+ }
+
+ // get XMP metadata
+ if(webp_flags & XMP_FLAG) {
+ error_status = WebPMuxGetChunk(mux, "XMP ", &xmp_metadata);
+ if(error_status == WEBP_MUX_OK) {
+ // create a tag
+ FITAG *tag = FreeImage_CreateTag();
+ if(tag) {
+ FreeImage_SetTagKey(tag, g_TagLib_XMPFieldName);
+ FreeImage_SetTagLength(tag, (DWORD)xmp_metadata.size);
+ FreeImage_SetTagCount(tag, (DWORD)xmp_metadata.size);
+ FreeImage_SetTagType(tag, FIDT_ASCII);
+ FreeImage_SetTagValue(tag, xmp_metadata.bytes);
+
+ // store the tag
+ FreeImage_SetMetadata(FIMD_XMP, dib, FreeImage_GetTagKey(tag), tag);
+
+ // destroy the tag
+ FreeImage_DeleteTag(tag);
+ }
+ }
+ }
+
+ // get Exif metadata
+ if(webp_flags & EXIF_FLAG) {
+ error_status = WebPMuxGetChunk(mux, "EXIF", &exif_metadata);
+ if(error_status == WEBP_MUX_OK) {
+ // read the Exif raw data as a blob
+ jpeg_read_exif_profile_raw(dib, exif_metadata.bytes, (unsigned)exif_metadata.size);
+ // read and decode the Exif data
+ jpeg_read_exif_profile(dib, exif_metadata.bytes, (unsigned)exif_metadata.size);
+ }
+ }
+ }
+
+ WebPDataClear(&webp_frame.bitstream);
+
+ return dib;
+
+ } catch(int) {
+ WebPDataClear(&webp_frame.bitstream);
+ return NULL;
+ }
+}
+
+// --------------------------------------------------------------------------
+
+/**
+Encode a FIBITMAP to a WebP image
+@param hmem Memory output stream, containing on return the encoded image
+@param dib The FIBITMAP to encode
+@param flags FreeImage save flags
+@return Returns TRUE if successfull, returns FALSE otherwise
+*/
+static BOOL
+EncodeImage(FIMEMORY *hmem, FIBITMAP *dib, int flags) {
+ WebPPicture picture; // Input buffer
+ WebPConfig config; // Coding parameters
+
+ BOOL bIsFlipped = FALSE;
+
+ try {
+ const unsigned width = FreeImage_GetWidth(dib);
+ const unsigned height = FreeImage_GetHeight(dib);
+ const unsigned bpp = FreeImage_GetBPP(dib);
+ const unsigned pitch = FreeImage_GetPitch(dib);
+
+ // check image type
+ FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
+
+ if( !((image_type == FIT_BITMAP) && ((bpp == 24) || (bpp == 32))) ) {
+ throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
+ }
+
+ // check format limits
+ if(MAX(width, height) > WEBP_MAX_DIMENSION) {
+ FreeImage_OutputMessageProc(s_format_id, "Unsupported image size: width x height = %d x %d", width, height);
+ return FALSE;
+ }
+
+ // Initialize output I/O
+ if(WebPPictureInit(&picture) == 1) {
+ picture.writer = WebP_MemoryWriter;
+ picture.custom_ptr = hmem;
+ picture.width = (int)width;
+ picture.height = (int)height;
+ } else {
+ throw "Couldn't initialize WebPPicture";
+ }
+
+ // --- Set encoding parameters ---
+
+ // Initialize encoding parameters to default values
+ WebPConfigInit(&config);
+
+ // quality/speed trade-off (0=fast, 6=slower-better)
+ config.method = 6;
+
+ if((flags & WEBP_LOSSLESS) == WEBP_LOSSLESS) {
+ // lossless encoding
+ config.lossless = 1;
+ picture.use_argb = 1;
+ } else if((flags & 0x7F) > 0) {
+ // lossy encoding
+ config.lossless = 0;
+ // quality is between 1 (smallest file) and 100 (biggest) - default to 75
+ config.quality = (float)(flags & 0x7F);
+ if(config.quality > 100) {
+ config.quality = 100;
+ }
+ }
+
+ // validate encoding parameters
+ if(WebPValidateConfig(&config) == 0) {
+ throw "Failed to initialize encoder";
+ }
+
+ // --- Perform encoding ---
+
+ // Invert dib scanlines
+ bIsFlipped = FreeImage_FlipVertical(dib);
+
+
+ // convert dib buffer to output stream
+
+ const BYTE *bits = FreeImage_GetBits(dib);
+
+#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
+ switch(bpp) {
+ case 24:
+ WebPPictureImportBGR(&picture, bits, pitch);
+ break;
+ case 32:
+ WebPPictureImportBGRA(&picture, bits, pitch);
+ break;
+ }
+#else
+ switch(bpp) {
+ case 24:
+ WebPPictureImportRGB(&picture, bits, pitch);
+ break;
+ case 32:
+ WebPPictureImportRGBA(&picture, bits, pitch);
+ break;
+ }
+
+#endif // FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
+
+ if(!WebPEncode(&config, &picture)) {
+ throw "Failed to encode image";
+ }
+
+ WebPPictureFree(&picture);
+
+ if(bIsFlipped) {
+ // invert dib scanlines
+ FreeImage_FlipVertical(dib);
+ }
+
+ return TRUE;
+
+ } catch (const char* text) {
+
+ WebPPictureFree(&picture);
+
+ if(bIsFlipped) {
+ // invert dib scanlines
+ FreeImage_FlipVertical(dib);
+ }
+
+ if(NULL != text) {
+ FreeImage_OutputMessageProc(s_format_id, text);
+ }
+ }
+
+ return FALSE;
+}
+
+static BOOL DLL_CALLCONV
+Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
+ WebPMux *mux = NULL;
+ FIMEMORY *hmem = NULL;
+ WebPData webp_image;
+ WebPData output_data = { 0 };
+ WebPMuxError error_status;
+
+ int copy_data = 1; // 1 : copy data into the mux, 0 : keep a link to local data
+
+ if(!dib || !handle || !data) {
+ return FALSE;
+ }
+
+ try {
+
+ // get the MUX object
+ mux = (WebPMux*)data;
+ if(!mux) {
+ return FALSE;
+ }
+
+ // --- prepare image data ---
+
+ // encode image as a WebP blob
+ hmem = FreeImage_OpenMemory();
+ if(!hmem || !EncodeImage(hmem, dib, flags)) {
+ throw (1);
+ }
+ // store the blob into the mux
+ BYTE *data = NULL;
+ DWORD data_size = 0;
+ FreeImage_AcquireMemory(hmem, &data, &data_size);
+ webp_image.bytes = data;
+ webp_image.size = data_size;
+ error_status = WebPMuxSetImage(mux, &webp_image, copy_data);
+ // no longer needed since copy_data == 1
+ FreeImage_CloseMemory(hmem);
+ hmem = NULL;
+ if(error_status != WEBP_MUX_OK) {
+ throw (1);
+ }
+
+ // --- set metadata ---
+
+ // set ICC color profile
+ {
+ FIICCPROFILE *iccProfile = FreeImage_GetICCProfile(dib);
+ if (iccProfile->size && iccProfile->data) {
+ WebPData icc_profile;
+ icc_profile.bytes = (uint8_t*)iccProfile->data;
+ icc_profile.size = (size_t)iccProfile->size;
+ error_status = WebPMuxSetChunk(mux, "ICCP", &icc_profile, copy_data);
+ if(error_status != WEBP_MUX_OK) {
+ throw (1);
+ }
+ }
+ }
+
+ // set XMP metadata
+ {
+ FITAG *tag = NULL;
+ if(FreeImage_GetMetadata(FIMD_XMP, dib, g_TagLib_XMPFieldName, &tag)) {
+ WebPData xmp_profile;
+ xmp_profile.bytes = (uint8_t*)FreeImage_GetTagValue(tag);
+ xmp_profile.size = (size_t)FreeImage_GetTagLength(tag);
+ error_status = WebPMuxSetChunk(mux, "XMP ", &xmp_profile, copy_data);
+ if(error_status != WEBP_MUX_OK) {
+ throw (1);
+ }
+ }
+ }
+
+ // set Exif metadata
+ {
+ FITAG *tag = NULL;
+ if(FreeImage_GetMetadata(FIMD_EXIF_RAW, dib, g_TagLib_ExifRawFieldName, &tag)) {
+ WebPData exif_profile;
+ exif_profile.bytes = (uint8_t*)FreeImage_GetTagValue(tag);
+ exif_profile.size = (size_t)FreeImage_GetTagLength(tag);
+ error_status = WebPMuxSetChunk(mux, "EXIF", &exif_profile, copy_data);
+ if(error_status != WEBP_MUX_OK) {
+ throw (1);
+ }
+ }
+ }
+
+ // get data from mux in WebP RIFF format
+ error_status = WebPMuxAssemble(mux, &output_data);
+ if(error_status != WEBP_MUX_OK) {
+ FreeImage_OutputMessageProc(s_format_id, "Failed to create webp output file");
+ throw (1);
+ }
+
+ // write the file to the output stream
+ if(io->write_proc((void*)output_data.bytes, 1, (unsigned)output_data.size, handle) != output_data.size) {
+ FreeImage_OutputMessageProc(s_format_id, "Failed to write webp output file");
+ throw (1);
+ }
+
+ // free WebP output file
+ WebPDataClear(&output_data);
+
+ return TRUE;
+
+ } catch(int) {
+ if(hmem) {
+ FreeImage_CloseMemory(hmem);
+ }
+
+ WebPDataClear(&output_data);
+
+ return FALSE;
+ }
+}
+
+// ==========================================================
+// Init
+// ==========================================================
+
+void DLL_CALLCONV
+InitWEBP(Plugin *plugin, int format_id) {
+ s_format_id = format_id;
+
+ plugin->format_proc = Format;
+ plugin->description_proc = Description;
+ plugin->extension_proc = Extension;
+ plugin->regexpr_proc = RegExpr;
+ plugin->open_proc = Open;
+ plugin->close_proc = Close;
+ plugin->pagecount_proc = NULL;
+ plugin->pagecapability_proc = NULL;
+ plugin->load_proc = Load;
+ plugin->save_proc = Save;
+ plugin->validate_proc = Validate;
+ plugin->mime_proc = MimeType;
+ plugin->supports_export_bpp_proc = SupportsExportDepth;
+ plugin->supports_export_type_proc = SupportsExportType;
+ plugin->supports_icc_profiles_proc = SupportsICCProfiles;
+ plugin->supports_no_pixels_proc = SupportsNoPixels;
+}
+
diff --git a/plugins/AdvaImg/src/FreeImage/tmoColorConvert.cpp b/plugins/AdvaImg/src/FreeImage/tmoColorConvert.cpp
index 66869b2806..6b103a08c1 100644
--- a/plugins/AdvaImg/src/FreeImage/tmoColorConvert.cpp
+++ b/plugins/AdvaImg/src/FreeImage/tmoColorConvert.cpp
@@ -1,479 +1,479 @@
-// ==========================================================
-// High Dynamic Range bitmap conversion routines
-//
-// Design and implementation by
-// - Hervé Drolon (drolon@infonie.fr)
-// - Mihail Naydenov (mnaydenov@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 "FreeImage.h"
-#include "Utilities.h"
-#include "ToneMapping.h"
-
-// ----------------------------------------------------------
-// Convert RGB to and from Yxy, same as in Reinhard et al. SIGGRAPH 2002
-// References :
-// [1] Radiance Home Page [Online] http://radsite.lbl.gov/radiance/HOME.html
-// [2] E. Reinhard, M. Stark, P. Shirley, and J. Ferwerda,
-// Photographic Tone Reproduction for Digital Images, ACM Transactions on Graphics,
-// 21(3):267-276, 2002 (Proceedings of SIGGRAPH 2002).
-// [3] J. Tumblin and H.E. Rushmeier,
-// Tone Reproduction for Realistic Images. IEEE Computer Graphics and Applications,
-// 13(6):42-48, 1993.
-// ----------------------------------------------------------
-
-/**
-nominal CRT primaries
-*/
-/*
-static const float CIE_x_r = 0.640F;
-static const float CIE_y_r = 0.330F;
-static const float CIE_x_g = 0.290F;
-static const float CIE_y_g = 0.600F;
-static const float CIE_x_b = 0.150F;
-static const float CIE_y_b = 0.060F;
-static const float CIE_x_w = 0.3333F; // use true white
-static const float CIE_y_w = 0.3333F;
-*/
-/**
-sRGB primaries
-*/
-static const float CIE_x_r = 0.640F;
-static const float CIE_y_r = 0.330F;
-static const float CIE_x_g = 0.300F;
-static const float CIE_y_g = 0.600F;
-static const float CIE_x_b = 0.150F;
-static const float CIE_y_b = 0.060F;
-static const float CIE_x_w = 0.3127F; // Illuminant D65
-static const float CIE_y_w = 0.3290F;
-
-static const float CIE_D = ( CIE_x_r*(CIE_y_g - CIE_y_b) + CIE_x_g*(CIE_y_b - CIE_y_r) + CIE_x_b*(CIE_y_r - CIE_y_g) );
-static const float CIE_C_rD = ( (1/CIE_y_w) * ( CIE_x_w*(CIE_y_g - CIE_y_b) - CIE_y_w*(CIE_x_g - CIE_x_b) + CIE_x_g*CIE_y_b - CIE_x_b*CIE_y_g) );
-static const float CIE_C_gD = ( (1/CIE_y_w) * ( CIE_x_w*(CIE_y_b - CIE_y_r) - CIE_y_w*(CIE_x_b - CIE_x_r) - CIE_x_r*CIE_y_b + CIE_x_b*CIE_y_r) );
-static const float CIE_C_bD = ( (1/CIE_y_w) * ( CIE_x_w*(CIE_y_r - CIE_y_g) - CIE_y_w*(CIE_x_r - CIE_x_g) + CIE_x_r*CIE_y_g - CIE_x_g*CIE_y_r) );
-
-/**
-RGB to XYZ (no white balance)
-*/
-static const float RGB2XYZ[3][3] = {
- { CIE_x_r*CIE_C_rD / CIE_D,
- CIE_x_g*CIE_C_gD / CIE_D,
- CIE_x_b*CIE_C_bD / CIE_D
- },
- { CIE_y_r*CIE_C_rD / CIE_D,
- CIE_y_g*CIE_C_gD / CIE_D,
- CIE_y_b*CIE_C_bD / CIE_D
- },
- { (1 - CIE_x_r-CIE_y_r)*CIE_C_rD / CIE_D,
- (1 - CIE_x_g-CIE_y_g)*CIE_C_gD / CIE_D,
- (1 - CIE_x_b-CIE_y_b)*CIE_C_bD / CIE_D
- }
-};
-
-/**
-XYZ to RGB (no white balance)
-*/
-static const float XYZ2RGB[3][3] = {
- {(CIE_y_g - CIE_y_b - CIE_x_b*CIE_y_g + CIE_y_b*CIE_x_g) / CIE_C_rD,
- (CIE_x_b - CIE_x_g - CIE_x_b*CIE_y_g + CIE_x_g*CIE_y_b) / CIE_C_rD,
- (CIE_x_g*CIE_y_b - CIE_x_b*CIE_y_g) / CIE_C_rD
- },
- {(CIE_y_b - CIE_y_r - CIE_y_b*CIE_x_r + CIE_y_r*CIE_x_b) / CIE_C_gD,
- (CIE_x_r - CIE_x_b - CIE_x_r*CIE_y_b + CIE_x_b*CIE_y_r) / CIE_C_gD,
- (CIE_x_b*CIE_y_r - CIE_x_r*CIE_y_b) / CIE_C_gD
- },
- {(CIE_y_r - CIE_y_g - CIE_y_r*CIE_x_g + CIE_y_g*CIE_x_r) / CIE_C_bD,
- (CIE_x_g - CIE_x_r - CIE_x_g*CIE_y_r + CIE_x_r*CIE_y_g) / CIE_C_bD,
- (CIE_x_r*CIE_y_g - CIE_x_g*CIE_y_r) / CIE_C_bD
- }
-};
-
-/**
-This gives approximately the following matrices :
-
-static const float RGB2XYZ[3][3] = {
- { 0.41239083F, 0.35758433F, 0.18048081F },
- { 0.21263903F, 0.71516865F, 0.072192319F },
- { 0.019330820F, 0.11919473F, 0.95053220F }
-};
-static const float XYZ2RGB[3][3] = {
- { 3.2409699F, -1.5373832F, -0.49861079F },
- { -0.96924376F, 1.8759676F, 0.041555084F },
- { 0.055630036F, -0.20397687F, 1.0569715F }
-};
-*/
-
-// ----------------------------------------------------------
-
-static const float EPSILON = 1e-06F;
-static const float INF = 1e+10F;
-
-/**
-Convert in-place floating point RGB data to Yxy.<br>
-On output, pixel->red == Y, pixel->green == x, pixel->blue == y
-@param dib Input RGBF / Output Yxy image
-@return Returns TRUE if successful, returns FALSE otherwise
-*/
-BOOL
-ConvertInPlaceRGBFToYxy(FIBITMAP *dib) {
- float result[3];
-
- if(FreeImage_GetImageType(dib) != FIT_RGBF)
- return FALSE;
-
- const unsigned width = FreeImage_GetWidth(dib);
- const unsigned height = FreeImage_GetHeight(dib);
- const unsigned pitch = FreeImage_GetPitch(dib);
-
- BYTE *bits = (BYTE*)FreeImage_GetBits(dib);
- for(unsigned y = 0; y < height; y++) {
- FIRGBF *pixel = (FIRGBF*)bits;
- for(unsigned x = 0; x < width; x++) {
- result[0] = result[1] = result[2] = 0;
- for (int i = 0; i < 3; i++) {
- result[i] += RGB2XYZ[i][0] * pixel[x].red;
- result[i] += RGB2XYZ[i][1] * pixel[x].green;
- result[i] += RGB2XYZ[i][2] * pixel[x].blue;
- }
- const float W = result[0] + result[1] + result[2];
- const float Y = result[1];
- if(W > 0) {
- pixel[x].red = Y; // Y
- pixel[x].green = result[0] / W; // x
- pixel[x].blue = result[1] / W; // y
- } else {
- pixel[x].red = pixel[x].green = pixel[x].blue = 0;
- }
- }
- // next line
- bits += pitch;
- }
-
- return TRUE;
-}
-
-/**
-Convert in-place Yxy image to floating point RGB data.<br>
-On input, pixel->red == Y, pixel->green == x, pixel->blue == y
-@param dib Input Yxy / Output RGBF image
-@return Returns TRUE if successful, returns FALSE otherwise
-*/
-BOOL
-ConvertInPlaceYxyToRGBF(FIBITMAP *dib) {
- float result[3];
- float X, Y, Z;
-
- if(FreeImage_GetImageType(dib) != FIT_RGBF)
- return FALSE;
-
- const unsigned width = FreeImage_GetWidth(dib);
- const unsigned height = FreeImage_GetHeight(dib);
- const unsigned pitch = FreeImage_GetPitch(dib);
-
- BYTE *bits = (BYTE*)FreeImage_GetBits(dib);
- for(unsigned y = 0; y < height; y++) {
- FIRGBF *pixel = (FIRGBF*)bits;
- for(unsigned x = 0; x < width; x++) {
- Y = pixel[x].red; // Y
- result[1] = pixel[x].green; // x
- result[2] = pixel[x].blue; // y
- if ((Y > EPSILON) && (result[1] > EPSILON) && (result[2] > EPSILON)) {
- X = (result[1] * Y) / result[2];
- Z = (X / result[1]) - X - Y;
- } else {
- X = Z = EPSILON;
- }
- pixel[x].red = X;
- pixel[x].green = Y;
- pixel[x].blue = Z;
- result[0] = result[1] = result[2] = 0;
- for (int i = 0; i < 3; i++) {
- result[i] += XYZ2RGB[i][0] * pixel[x].red;
- result[i] += XYZ2RGB[i][1] * pixel[x].green;
- result[i] += XYZ2RGB[i][2] * pixel[x].blue;
- }
- pixel[x].red = result[0]; // R
- pixel[x].green = result[1]; // G
- pixel[x].blue = result[2]; // B
- }
- // next line
- bits += pitch;
- }
-
- return TRUE;
-}
-
-/**
-Get the maximum, minimum and average luminance.<br>
-On input, pixel->red == Y, pixel->green == x, pixel->blue == y
-@param Yxy Source Yxy image to analyze
-@param maxLum Maximum luminance
-@param minLum Minimum luminance
-@param worldLum Average luminance (world adaptation luminance)
-@return Returns TRUE if successful, returns FALSE otherwise
-*/
-BOOL
-LuminanceFromYxy(FIBITMAP *Yxy, float *maxLum, float *minLum, float *worldLum) {
- if(FreeImage_GetImageType(Yxy) != FIT_RGBF)
- return FALSE;
-
- const unsigned width = FreeImage_GetWidth(Yxy);
- const unsigned height = FreeImage_GetHeight(Yxy);
- const unsigned pitch = FreeImage_GetPitch(Yxy);
-
- float max_lum = 0, min_lum = 0;
- double sum = 0;
-
- BYTE *bits = (BYTE*)FreeImage_GetBits(Yxy);
- for(unsigned y = 0; y < height; y++) {
- const FIRGBF *pixel = (FIRGBF*)bits;
- for(unsigned x = 0; x < width; x++) {
- const float Y = pixel[x].red;
- max_lum = (max_lum < Y) ? Y : max_lum; // max Luminance in the scene
- min_lum = (min_lum < Y) ? min_lum : Y; // min Luminance in the scene
- sum += log(2.3e-5F + Y); // contrast constant in Tumblin paper
- }
- // next line
- bits += pitch;
- }
- // maximum luminance
- *maxLum = max_lum;
- // minimum luminance
- *minLum = min_lum;
- // average log luminance
- double avgLogLum = (sum / (width * height));
- // world adaptation luminance
- *worldLum = (float)exp(avgLogLum);
-
- return TRUE;
-}
-
-/**
-Clamp RGBF image highest values to display white,
-then convert to 24-bit RGB
-*/
-FIBITMAP*
-ClampConvertRGBFTo24(FIBITMAP *src) {
- if(FreeImage_GetImageType(src) != FIT_RGBF)
- return FALSE;
-
- const unsigned width = FreeImage_GetWidth(src);
- const unsigned height = FreeImage_GetHeight(src);
-
- FIBITMAP *dst = FreeImage_Allocate(width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
- if(!dst) return NULL;
-
- const unsigned src_pitch = FreeImage_GetPitch(src);
- const unsigned dst_pitch = FreeImage_GetPitch(dst);
-
- BYTE *src_bits = (BYTE*)FreeImage_GetBits(src);
- BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst);
-
- for(unsigned y = 0; y < height; y++) {
- const FIRGBF *src_pixel = (FIRGBF*)src_bits;
- BYTE *dst_pixel = (BYTE*)dst_bits;
- for(unsigned x = 0; x < width; x++) {
- const float red = (src_pixel[x].red > 1) ? 1 : src_pixel[x].red;
- const float green = (src_pixel[x].green > 1) ? 1 : src_pixel[x].green;
- const float blue = (src_pixel[x].blue > 1) ? 1 : src_pixel[x].blue;
-
- dst_pixel[FI_RGBA_RED] = (BYTE)(255.0F * red + 0.5F);
- dst_pixel[FI_RGBA_GREEN] = (BYTE)(255.0F * green + 0.5F);
- dst_pixel[FI_RGBA_BLUE] = (BYTE)(255.0F * blue + 0.5F);
- dst_pixel += 3;
- }
- src_bits += src_pitch;
- dst_bits += dst_pitch;
- }
-
- return dst;
-}
-
-/**
-Extract the luminance channel L from a RGBF image.
-Luminance is calculated from the sRGB model (RGB2XYZ matrix)
-using a D65 white point :
-L = ( 0.2126 * r ) + ( 0.7152 * g ) + ( 0.0722 * b )
-Reference :
-A Standard Default Color Space for the Internet - sRGB.
-[online] http://www.w3.org/Graphics/Color/sRGB
-*/
-FIBITMAP*
-ConvertRGBFToY(FIBITMAP *src) {
- if(FreeImage_GetImageType(src) != FIT_RGBF)
- return FALSE;
-
- const unsigned width = FreeImage_GetWidth(src);
- const unsigned height = FreeImage_GetHeight(src);
-
- FIBITMAP *dst = FreeImage_AllocateT(FIT_FLOAT, width, height);
- if(!dst) return NULL;
-
- const unsigned src_pitch = FreeImage_GetPitch(src);
- const unsigned dst_pitch = FreeImage_GetPitch(dst);
-
-
- BYTE *src_bits = (BYTE*)FreeImage_GetBits(src);
- BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst);
-
- for(unsigned y = 0; y < height; y++) {
- const FIRGBF *src_pixel = (FIRGBF*)src_bits;
- float *dst_pixel = (float*)dst_bits;
- for(unsigned x = 0; x < width; x++) {
- const float L = LUMA_REC709(src_pixel[x].red, src_pixel[x].green, src_pixel[x].blue);
- dst_pixel[x] = (L > 0) ? L : 0;
- }
- // next line
- src_bits += src_pitch;
- dst_bits += dst_pitch;
- }
-
- return dst;
-}
-
-/**
-Get the maximum, minimum, average luminance and log average luminance from a Y image
-@param dib Source Y image to analyze
-@param maxLum Maximum luminance
-@param minLum Minimum luminance
-@param Lav Average luminance
-@param Llav Log average luminance (also known as 'world adaptation luminance')
-@return Returns TRUE if successful, returns FALSE otherwise
-@see ConvertRGBFToY, FreeImage_TmoReinhard05Ex
-*/
-BOOL
-LuminanceFromY(FIBITMAP *dib, float *maxLum, float *minLum, float *Lav, float *Llav) {
- if(FreeImage_GetImageType(dib) != FIT_FLOAT)
- return FALSE;
-
- unsigned width = FreeImage_GetWidth(dib);
- unsigned height = FreeImage_GetHeight(dib);
- unsigned pitch = FreeImage_GetPitch(dib);
-
- float max_lum = -1e20F, min_lum = 1e20F;
- double sumLum = 0, sumLogLum = 0;
-
- BYTE *bits = (BYTE*)FreeImage_GetBits(dib);
- for(unsigned y = 0; y < height; y++) {
- const float *pixel = (float*)bits;
- for(unsigned x = 0; x < width; x++) {
- const float Y = pixel[x];
- max_lum = (max_lum < Y) ? Y : max_lum; // max Luminance in the scene
- min_lum = ((Y > 0) && (min_lum < Y)) ? min_lum : Y; // min Luminance in the scene
- sumLum += Y; // average luminance
- sumLogLum += log(2.3e-5F + Y); // contrast constant in Tumblin paper
- }
- // next line
- bits += pitch;
- }
-
- // maximum luminance
- *maxLum = max_lum;
- // minimum luminance
- *minLum = min_lum;
- // average luminance
- *Lav = (float)(sumLum / (width * height));
- // average log luminance, a.k.a. world adaptation luminance
- *Llav = (float)exp(sumLogLum / (width * height));
-
- return TRUE;
-}
-// --------------------------------------------------------------------------
-
-static void findMaxMinPercentile(FIBITMAP *Y, float minPrct, float *minLum, float maxPrct, float *maxLum) {
- int x, y;
- int width = FreeImage_GetWidth(Y);
- int height = FreeImage_GetHeight(Y);
- int pitch = FreeImage_GetPitch(Y);
-
- std::vector<float> vY(width * height);
-
- BYTE *bits = (BYTE*)FreeImage_GetBits(Y);
- for(y = 0; y < height; y++) {
- float *pixel = (float*)bits;
- for(x = 0; x < width; x++) {
- if(pixel[x] != 0) {
- vY.push_back(pixel[x]);
- }
- }
- bits += pitch;
- }
-
- std::sort(vY.begin(), vY.end());
-
- *minLum = vY.at( int(minPrct * vY.size()) );
- *maxLum = vY.at( int(maxPrct * vY.size()) );
-}
-
-/**
-Clipping function<br>
-Remove any extremely bright and/or extremely dark pixels
-and normalize between 0 and 1.
-@param Y Input/Output image
-@param minPrct Minimum percentile
-@param maxPrct Maximum percentile
-*/
-void
-NormalizeY(FIBITMAP *Y, float minPrct, float maxPrct) {
- int x, y;
- float maxLum, minLum;
-
- if(minPrct > maxPrct) {
- // swap values
- float t = minPrct; minPrct = maxPrct; maxPrct = t;
- }
- if(minPrct < 0) minPrct = 0;
- if(maxPrct > 1) maxPrct = 1;
-
- int width = FreeImage_GetWidth(Y);
- int height = FreeImage_GetHeight(Y);
- int pitch = FreeImage_GetPitch(Y);
-
- // find max & min luminance values
- if((minPrct > 0) || (maxPrct < 1)) {
- maxLum = 0, minLum = 0;
- findMaxMinPercentile(Y, minPrct, &minLum, maxPrct, &maxLum);
- } else {
- maxLum = -1e20F, minLum = 1e20F;
- BYTE *bits = (BYTE*)FreeImage_GetBits(Y);
- for(y = 0; y < height; y++) {
- const float *pixel = (float*)bits;
- for(x = 0; x < width; x++) {
- const float value = pixel[x];
- maxLum = (maxLum < value) ? value : maxLum; // max Luminance in the scene
- minLum = (minLum < value) ? minLum : value; // min Luminance in the scene
- }
- // next line
- bits += pitch;
- }
- }
- if(maxLum == minLum) return;
-
- // normalize to range 0..1
- const float divider = maxLum - minLum;
- BYTE *bits = (BYTE*)FreeImage_GetBits(Y);
- for(y = 0; y < height; y++) {
- float *pixel = (float*)bits;
- for(x = 0; x < width; x++) {
- pixel[x] = (pixel[x] - minLum) / divider;
- if(pixel[x] <= 0) pixel[x] = EPSILON;
- if(pixel[x] > 1) pixel[x] = 1;
- }
- // next line
- bits += pitch;
- }
-}
+// ==========================================================
+// High Dynamic Range bitmap conversion routines
+//
+// Design and implementation by
+// - Hervé Drolon (drolon@infonie.fr)
+// - Mihail Naydenov (mnaydenov@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 "FreeImage.h"
+#include "Utilities.h"
+#include "ToneMapping.h"
+
+// ----------------------------------------------------------
+// Convert RGB to and from Yxy, same as in Reinhard et al. SIGGRAPH 2002
+// References :
+// [1] Radiance Home Page [Online] http://radsite.lbl.gov/radiance/HOME.html
+// [2] E. Reinhard, M. Stark, P. Shirley, and J. Ferwerda,
+// Photographic Tone Reproduction for Digital Images, ACM Transactions on Graphics,
+// 21(3):267-276, 2002 (Proceedings of SIGGRAPH 2002).
+// [3] J. Tumblin and H.E. Rushmeier,
+// Tone Reproduction for Realistic Images. IEEE Computer Graphics and Applications,
+// 13(6):42-48, 1993.
+// ----------------------------------------------------------
+
+/**
+nominal CRT primaries
+*/
+/*
+static const float CIE_x_r = 0.640F;
+static const float CIE_y_r = 0.330F;
+static const float CIE_x_g = 0.290F;
+static const float CIE_y_g = 0.600F;
+static const float CIE_x_b = 0.150F;
+static const float CIE_y_b = 0.060F;
+static const float CIE_x_w = 0.3333F; // use true white
+static const float CIE_y_w = 0.3333F;
+*/
+/**
+sRGB primaries
+*/
+static const float CIE_x_r = 0.640F;
+static const float CIE_y_r = 0.330F;
+static const float CIE_x_g = 0.300F;
+static const float CIE_y_g = 0.600F;
+static const float CIE_x_b = 0.150F;
+static const float CIE_y_b = 0.060F;
+static const float CIE_x_w = 0.3127F; // Illuminant D65
+static const float CIE_y_w = 0.3290F;
+
+static const float CIE_D = ( CIE_x_r*(CIE_y_g - CIE_y_b) + CIE_x_g*(CIE_y_b - CIE_y_r) + CIE_x_b*(CIE_y_r - CIE_y_g) );
+static const float CIE_C_rD = ( (1/CIE_y_w) * ( CIE_x_w*(CIE_y_g - CIE_y_b) - CIE_y_w*(CIE_x_g - CIE_x_b) + CIE_x_g*CIE_y_b - CIE_x_b*CIE_y_g) );
+static const float CIE_C_gD = ( (1/CIE_y_w) * ( CIE_x_w*(CIE_y_b - CIE_y_r) - CIE_y_w*(CIE_x_b - CIE_x_r) - CIE_x_r*CIE_y_b + CIE_x_b*CIE_y_r) );
+static const float CIE_C_bD = ( (1/CIE_y_w) * ( CIE_x_w*(CIE_y_r - CIE_y_g) - CIE_y_w*(CIE_x_r - CIE_x_g) + CIE_x_r*CIE_y_g - CIE_x_g*CIE_y_r) );
+
+/**
+RGB to XYZ (no white balance)
+*/
+static const float RGB2XYZ[3][3] = {
+ { CIE_x_r*CIE_C_rD / CIE_D,
+ CIE_x_g*CIE_C_gD / CIE_D,
+ CIE_x_b*CIE_C_bD / CIE_D
+ },
+ { CIE_y_r*CIE_C_rD / CIE_D,
+ CIE_y_g*CIE_C_gD / CIE_D,
+ CIE_y_b*CIE_C_bD / CIE_D
+ },
+ { (1 - CIE_x_r-CIE_y_r)*CIE_C_rD / CIE_D,
+ (1 - CIE_x_g-CIE_y_g)*CIE_C_gD / CIE_D,
+ (1 - CIE_x_b-CIE_y_b)*CIE_C_bD / CIE_D
+ }
+};
+
+/**
+XYZ to RGB (no white balance)
+*/
+static const float XYZ2RGB[3][3] = {
+ {(CIE_y_g - CIE_y_b - CIE_x_b*CIE_y_g + CIE_y_b*CIE_x_g) / CIE_C_rD,
+ (CIE_x_b - CIE_x_g - CIE_x_b*CIE_y_g + CIE_x_g*CIE_y_b) / CIE_C_rD,
+ (CIE_x_g*CIE_y_b - CIE_x_b*CIE_y_g) / CIE_C_rD
+ },
+ {(CIE_y_b - CIE_y_r - CIE_y_b*CIE_x_r + CIE_y_r*CIE_x_b) / CIE_C_gD,
+ (CIE_x_r - CIE_x_b - CIE_x_r*CIE_y_b + CIE_x_b*CIE_y_r) / CIE_C_gD,
+ (CIE_x_b*CIE_y_r - CIE_x_r*CIE_y_b) / CIE_C_gD
+ },
+ {(CIE_y_r - CIE_y_g - CIE_y_r*CIE_x_g + CIE_y_g*CIE_x_r) / CIE_C_bD,
+ (CIE_x_g - CIE_x_r - CIE_x_g*CIE_y_r + CIE_x_r*CIE_y_g) / CIE_C_bD,
+ (CIE_x_r*CIE_y_g - CIE_x_g*CIE_y_r) / CIE_C_bD
+ }
+};
+
+/**
+This gives approximately the following matrices :
+
+static const float RGB2XYZ[3][3] = {
+ { 0.41239083F, 0.35758433F, 0.18048081F },
+ { 0.21263903F, 0.71516865F, 0.072192319F },
+ { 0.019330820F, 0.11919473F, 0.95053220F }
+};
+static const float XYZ2RGB[3][3] = {
+ { 3.2409699F, -1.5373832F, -0.49861079F },
+ { -0.96924376F, 1.8759676F, 0.041555084F },
+ { 0.055630036F, -0.20397687F, 1.0569715F }
+};
+*/
+
+// ----------------------------------------------------------
+
+static const float EPSILON = 1e-06F;
+static const float INF = 1e+10F;
+
+/**
+Convert in-place floating point RGB data to Yxy.<br>
+On output, pixel->red == Y, pixel->green == x, pixel->blue == y
+@param dib Input RGBF / Output Yxy image
+@return Returns TRUE if successful, returns FALSE otherwise
+*/
+BOOL
+ConvertInPlaceRGBFToYxy(FIBITMAP *dib) {
+ float result[3];
+
+ if(FreeImage_GetImageType(dib) != FIT_RGBF)
+ return FALSE;
+
+ const unsigned width = FreeImage_GetWidth(dib);
+ const unsigned height = FreeImage_GetHeight(dib);
+ const unsigned pitch = FreeImage_GetPitch(dib);
+
+ BYTE *bits = (BYTE*)FreeImage_GetBits(dib);
+ for(unsigned y = 0; y < height; y++) {
+ FIRGBF *pixel = (FIRGBF*)bits;
+ for(unsigned x = 0; x < width; x++) {
+ result[0] = result[1] = result[2] = 0;
+ for (int i = 0; i < 3; i++) {
+ result[i] += RGB2XYZ[i][0] * pixel[x].red;
+ result[i] += RGB2XYZ[i][1] * pixel[x].green;
+ result[i] += RGB2XYZ[i][2] * pixel[x].blue;
+ }
+ const float W = result[0] + result[1] + result[2];
+ const float Y = result[1];
+ if(W > 0) {
+ pixel[x].red = Y; // Y
+ pixel[x].green = result[0] / W; // x
+ pixel[x].blue = result[1] / W; // y
+ } else {
+ pixel[x].red = pixel[x].green = pixel[x].blue = 0;
+ }
+ }
+ // next line
+ bits += pitch;
+ }
+
+ return TRUE;
+}
+
+/**
+Convert in-place Yxy image to floating point RGB data.<br>
+On input, pixel->red == Y, pixel->green == x, pixel->blue == y
+@param dib Input Yxy / Output RGBF image
+@return Returns TRUE if successful, returns FALSE otherwise
+*/
+BOOL
+ConvertInPlaceYxyToRGBF(FIBITMAP *dib) {
+ float result[3];
+ float X, Y, Z;
+
+ if(FreeImage_GetImageType(dib) != FIT_RGBF)
+ return FALSE;
+
+ const unsigned width = FreeImage_GetWidth(dib);
+ const unsigned height = FreeImage_GetHeight(dib);
+ const unsigned pitch = FreeImage_GetPitch(dib);
+
+ BYTE *bits = (BYTE*)FreeImage_GetBits(dib);
+ for(unsigned y = 0; y < height; y++) {
+ FIRGBF *pixel = (FIRGBF*)bits;
+ for(unsigned x = 0; x < width; x++) {
+ Y = pixel[x].red; // Y
+ result[1] = pixel[x].green; // x
+ result[2] = pixel[x].blue; // y
+ if ((Y > EPSILON) && (result[1] > EPSILON) && (result[2] > EPSILON)) {
+ X = (result[1] * Y) / result[2];
+ Z = (X / result[1]) - X - Y;
+ } else {
+ X = Z = EPSILON;
+ }
+ pixel[x].red = X;
+ pixel[x].green = Y;
+ pixel[x].blue = Z;
+ result[0] = result[1] = result[2] = 0;
+ for (int i = 0; i < 3; i++) {
+ result[i] += XYZ2RGB[i][0] * pixel[x].red;
+ result[i] += XYZ2RGB[i][1] * pixel[x].green;
+ result[i] += XYZ2RGB[i][2] * pixel[x].blue;
+ }
+ pixel[x].red = result[0]; // R
+ pixel[x].green = result[1]; // G
+ pixel[x].blue = result[2]; // B
+ }
+ // next line
+ bits += pitch;
+ }
+
+ return TRUE;
+}
+
+/**
+Get the maximum, minimum and average luminance.<br>
+On input, pixel->red == Y, pixel->green == x, pixel->blue == y
+@param Yxy Source Yxy image to analyze
+@param maxLum Maximum luminance
+@param minLum Minimum luminance
+@param worldLum Average luminance (world adaptation luminance)
+@return Returns TRUE if successful, returns FALSE otherwise
+*/
+BOOL
+LuminanceFromYxy(FIBITMAP *Yxy, float *maxLum, float *minLum, float *worldLum) {
+ if(FreeImage_GetImageType(Yxy) != FIT_RGBF)
+ return FALSE;
+
+ const unsigned width = FreeImage_GetWidth(Yxy);
+ const unsigned height = FreeImage_GetHeight(Yxy);
+ const unsigned pitch = FreeImage_GetPitch(Yxy);
+
+ float max_lum = 0, min_lum = 0;
+ double sum = 0;
+
+ BYTE *bits = (BYTE*)FreeImage_GetBits(Yxy);
+ for(unsigned y = 0; y < height; y++) {
+ const FIRGBF *pixel = (FIRGBF*)bits;
+ for(unsigned x = 0; x < width; x++) {
+ const float Y = MAX(0.0F, pixel[x].red);// avoid negative values
+ max_lum = (max_lum < Y) ? Y : max_lum; // max Luminance in the scene
+ min_lum = (min_lum < Y) ? min_lum : Y; // min Luminance in the scene
+ sum += log(2.3e-5F + Y); // contrast constant in Tumblin paper
+ }
+ // next line
+ bits += pitch;
+ }
+ // maximum luminance
+ *maxLum = max_lum;
+ // minimum luminance
+ *minLum = min_lum;
+ // average log luminance
+ double avgLogLum = (sum / (width * height));
+ // world adaptation luminance
+ *worldLum = (float)exp(avgLogLum);
+
+ return TRUE;
+}
+
+/**
+Clamp RGBF image highest values to display white,
+then convert to 24-bit RGB
+*/
+FIBITMAP*
+ClampConvertRGBFTo24(FIBITMAP *src) {
+ if(FreeImage_GetImageType(src) != FIT_RGBF)
+ return FALSE;
+
+ const unsigned width = FreeImage_GetWidth(src);
+ const unsigned height = FreeImage_GetHeight(src);
+
+ FIBITMAP *dst = FreeImage_Allocate(width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
+ if(!dst) return NULL;
+
+ const unsigned src_pitch = FreeImage_GetPitch(src);
+ const unsigned dst_pitch = FreeImage_GetPitch(dst);
+
+ BYTE *src_bits = (BYTE*)FreeImage_GetBits(src);
+ BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst);
+
+ for(unsigned y = 0; y < height; y++) {
+ const FIRGBF *src_pixel = (FIRGBF*)src_bits;
+ BYTE *dst_pixel = (BYTE*)dst_bits;
+ for(unsigned x = 0; x < width; x++) {
+ const float red = (src_pixel[x].red > 1) ? 1 : src_pixel[x].red;
+ const float green = (src_pixel[x].green > 1) ? 1 : src_pixel[x].green;
+ const float blue = (src_pixel[x].blue > 1) ? 1 : src_pixel[x].blue;
+
+ dst_pixel[FI_RGBA_RED] = (BYTE)(255.0F * red + 0.5F);
+ dst_pixel[FI_RGBA_GREEN] = (BYTE)(255.0F * green + 0.5F);
+ dst_pixel[FI_RGBA_BLUE] = (BYTE)(255.0F * blue + 0.5F);
+ dst_pixel += 3;
+ }
+ src_bits += src_pitch;
+ dst_bits += dst_pitch;
+ }
+
+ return dst;
+}
+
+/**
+Extract the luminance channel L from a RGBF image.
+Luminance is calculated from the sRGB model (RGB2XYZ matrix)
+using a D65 white point :
+L = ( 0.2126 * r ) + ( 0.7152 * g ) + ( 0.0722 * b )
+Reference :
+A Standard Default Color Space for the Internet - sRGB.
+[online] http://www.w3.org/Graphics/Color/sRGB
+*/
+FIBITMAP*
+ConvertRGBFToY(FIBITMAP *src) {
+ if(FreeImage_GetImageType(src) != FIT_RGBF)
+ return FALSE;
+
+ const unsigned width = FreeImage_GetWidth(src);
+ const unsigned height = FreeImage_GetHeight(src);
+
+ FIBITMAP *dst = FreeImage_AllocateT(FIT_FLOAT, width, height);
+ if(!dst) return NULL;
+
+ const unsigned src_pitch = FreeImage_GetPitch(src);
+ const unsigned dst_pitch = FreeImage_GetPitch(dst);
+
+
+ BYTE *src_bits = (BYTE*)FreeImage_GetBits(src);
+ BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst);
+
+ for(unsigned y = 0; y < height; y++) {
+ const FIRGBF *src_pixel = (FIRGBF*)src_bits;
+ float *dst_pixel = (float*)dst_bits;
+ for(unsigned x = 0; x < width; x++) {
+ const float L = LUMA_REC709(src_pixel[x].red, src_pixel[x].green, src_pixel[x].blue);
+ dst_pixel[x] = (L > 0) ? L : 0;
+ }
+ // next line
+ src_bits += src_pitch;
+ dst_bits += dst_pitch;
+ }
+
+ return dst;
+}
+
+/**
+Get the maximum, minimum, average luminance and log average luminance from a Y image
+@param dib Source Y image to analyze
+@param maxLum Maximum luminance
+@param minLum Minimum luminance
+@param Lav Average luminance
+@param Llav Log average luminance (also known as 'world adaptation luminance')
+@return Returns TRUE if successful, returns FALSE otherwise
+@see ConvertRGBFToY, FreeImage_TmoReinhard05Ex
+*/
+BOOL
+LuminanceFromY(FIBITMAP *dib, float *maxLum, float *minLum, float *Lav, float *Llav) {
+ if(FreeImage_GetImageType(dib) != FIT_FLOAT)
+ return FALSE;
+
+ unsigned width = FreeImage_GetWidth(dib);
+ unsigned height = FreeImage_GetHeight(dib);
+ unsigned pitch = FreeImage_GetPitch(dib);
+
+ float max_lum = -1e20F, min_lum = 1e20F;
+ double sumLum = 0, sumLogLum = 0;
+
+ BYTE *bits = (BYTE*)FreeImage_GetBits(dib);
+ for(unsigned y = 0; y < height; y++) {
+ const float *pixel = (float*)bits;
+ for(unsigned x = 0; x < width; x++) {
+ const float Y = pixel[x];
+ max_lum = (max_lum < Y) ? Y : max_lum; // max Luminance in the scene
+ min_lum = ((Y > 0) && (min_lum < Y)) ? min_lum : Y; // min Luminance in the scene
+ sumLum += Y; // average luminance
+ sumLogLum += log(2.3e-5F + Y); // contrast constant in Tumblin paper
+ }
+ // next line
+ bits += pitch;
+ }
+
+ // maximum luminance
+ *maxLum = max_lum;
+ // minimum luminance
+ *minLum = min_lum;
+ // average luminance
+ *Lav = (float)(sumLum / (width * height));
+ // average log luminance, a.k.a. world adaptation luminance
+ *Llav = (float)exp(sumLogLum / (width * height));
+
+ return TRUE;
+}
+// --------------------------------------------------------------------------
+
+static void findMaxMinPercentile(FIBITMAP *Y, float minPrct, float *minLum, float maxPrct, float *maxLum) {
+ int x, y;
+ int width = FreeImage_GetWidth(Y);
+ int height = FreeImage_GetHeight(Y);
+ int pitch = FreeImage_GetPitch(Y);
+
+ std::vector<float> vY(width * height);
+
+ BYTE *bits = (BYTE*)FreeImage_GetBits(Y);
+ for(y = 0; y < height; y++) {
+ float *pixel = (float*)bits;
+ for(x = 0; x < width; x++) {
+ if(pixel[x] != 0) {
+ vY.push_back(pixel[x]);
+ }
+ }
+ bits += pitch;
+ }
+
+ std::sort(vY.begin(), vY.end());
+
+ *minLum = vY.at( int(minPrct * vY.size()) );
+ *maxLum = vY.at( int(maxPrct * vY.size()) );
+}
+
+/**
+Clipping function<br>
+Remove any extremely bright and/or extremely dark pixels
+and normalize between 0 and 1.
+@param Y Input/Output image
+@param minPrct Minimum percentile
+@param maxPrct Maximum percentile
+*/
+void
+NormalizeY(FIBITMAP *Y, float minPrct, float maxPrct) {
+ int x, y;
+ float maxLum, minLum;
+
+ if(minPrct > maxPrct) {
+ // swap values
+ float t = minPrct; minPrct = maxPrct; maxPrct = t;
+ }
+ if(minPrct < 0) minPrct = 0;
+ if(maxPrct > 1) maxPrct = 1;
+
+ int width = FreeImage_GetWidth(Y);
+ int height = FreeImage_GetHeight(Y);
+ int pitch = FreeImage_GetPitch(Y);
+
+ // find max & min luminance values
+ if((minPrct > 0) || (maxPrct < 1)) {
+ maxLum = 0, minLum = 0;
+ findMaxMinPercentile(Y, minPrct, &minLum, maxPrct, &maxLum);
+ } else {
+ maxLum = -1e20F, minLum = 1e20F;
+ BYTE *bits = (BYTE*)FreeImage_GetBits(Y);
+ for(y = 0; y < height; y++) {
+ const float *pixel = (float*)bits;
+ for(x = 0; x < width; x++) {
+ const float value = pixel[x];
+ maxLum = (maxLum < value) ? value : maxLum; // max Luminance in the scene
+ minLum = (minLum < value) ? minLum : value; // min Luminance in the scene
+ }
+ // next line
+ bits += pitch;
+ }
+ }
+ if(maxLum == minLum) return;
+
+ // normalize to range 0..1
+ const float divider = maxLum - minLum;
+ BYTE *bits = (BYTE*)FreeImage_GetBits(Y);
+ for(y = 0; y < height; y++) {
+ float *pixel = (float*)bits;
+ for(x = 0; x < width; x++) {
+ pixel[x] = (pixel[x] - minLum) / divider;
+ if(pixel[x] <= 0) pixel[x] = EPSILON;
+ if(pixel[x] > 1) pixel[x] = 1;
+ }
+ // next line
+ bits += pitch;
+ }
+}
diff --git a/plugins/AdvaImg/src/FreeImage/tmoDrago03.cpp b/plugins/AdvaImg/src/FreeImage/tmoDrago03.cpp
index a61534474d..d46a8c8426 100644
--- a/plugins/AdvaImg/src/FreeImage/tmoDrago03.cpp
+++ b/plugins/AdvaImg/src/FreeImage/tmoDrago03.cpp
@@ -1,295 +1,295 @@
-// ==========================================================
-// Tone mapping operator (Drago, 2003)
-//
-// Design and implementation by
-// - Hervé Drolon (drolon@infonie.fr)
-//
-// 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 "FreeImage.h"
-#include "Utilities.h"
-#include "ToneMapping.h"
-
-// ----------------------------------------------------------
-// Logarithmic mapping operator
-// Reference:
-// [1] F. Drago, K. Myszkowski, T. Annen, and N. Chiba,
-// Adaptive Logarithmic Mapping for Displaying High Contrast Scenes,
-// Eurographics 2003.
-// ----------------------------------------------------------
-
-/**
-Bias function
-*/
-static inline double
-biasFunction(const double b, const double x) {
- return pow (x, b); // pow(x, log(bias)/log(0.5)
-}
-
-/**
-Padé approximation of log(x + 1)
-x(6+x)/(6+4x) good if x < 1
-x*(6 + 0.7662x)/(5.9897 + 3.7658x) between 1 and 2
-See http://www.nezumi.demon.co.uk/consult/logx.htm
-*/
-static inline double
-pade_log(const double x) {
- if(x < 1) {
- return (x * (6 + x) / (6 + 4 * x));
- } else if(x < 2) {
- return (x * (6 + 0.7662 * x) / (5.9897 + 3.7658 * x));
- }
- return log(x + 1);
-}
-
-/**
-Log mapping operator
-@param dib Input / Output Yxy image
-@param maxLum Maximum luminance
-@param avgLum Average luminance (world adaptation luminance)
-@param biasParam Bias parameter (a zero value default to 0.85)
-@param exposure Exposure parameter (default to 0)
-@return Returns TRUE if successful, returns FALSE otherwise
-*/
-static BOOL
-ToneMappingDrago03(FIBITMAP *dib, const float maxLum, const float avgLum, float biasParam, const float exposure) {
- const float LOG05 = -0.693147F; // log(0.5)
-
- double Lmax, divider, interpol, biasP;
- unsigned x, y;
- double L;
-
- if(FreeImage_GetImageType(dib) != FIT_RGBF)
- return FALSE;
-
- const unsigned width = FreeImage_GetWidth(dib);
- const unsigned height = FreeImage_GetHeight(dib);
- const unsigned pitch = FreeImage_GetPitch(dib);
-
-
- // arbitrary Bias Parameter
- if(biasParam == 0)
- biasParam = 0.85F;
-
- // normalize maximum luminance by average luminance
- Lmax = maxLum / avgLum;
-
- divider = log10(Lmax+1);
- biasP = log(biasParam)/LOG05;
-
-#if !defined(DRAGO03_FAST)
-
- /**
- Normal tone mapping of every pixel
- further acceleration is obtained by a Padé approximation of log(x + 1)
- */
- BYTE *bits = (BYTE*)FreeImage_GetBits(dib);
- for(y = 0; y < height; y++) {
- FIRGBF *pixel = (FIRGBF*)bits;
- for(x = 0; x < width; x++) {
- double Yw = pixel[x].red / avgLum;
- Yw *= exposure;
- interpol = log(2 + biasFunction(biasP, Yw / Lmax) * 8);
- L = pade_log(Yw);// log(Yw + 1)
- pixel[x].red = (float)((L / interpol) / divider);
- }
- // next line
- bits += pitch;
- }
-
-#else
- unsigned index;
- int i, j;
-
- unsigned max_width = width - (width % 3);
- unsigned max_height = height - (height % 3);
- unsigned fpitch = pitch / sizeof(FIRGBF);
-
- /**
- fast tone mapping
- split the image into 3x3 pixel tiles and perform the computation for each group of 9 pixels
- further acceleration is obtained by a Padé approximation of log(x + 1)
- => produce artifacts and not so faster, so the code has been disabled
- */
-#define PIXEL(x, y) image[y*fpitch + x].red
-
- FIRGBF *image = (FIRGBF*)FreeImage_GetBits(dib);
- for(y = 0; y < max_height; y += 3) {
- for(x = 0; x < max_width; x += 3) {
- double average = 0;
- for(i = 0; i < 3; i++) {
- for(j = 0; j < 3; j++) {
- index = (y + i)*fpitch + (x + j);
- image[index].red /= (float)avgLum;
- image[index].red *= exposure;
- average += image[index].red;
- }
- }
- average = average / 9 - PIXEL(x, y);
- if(average > -1 && average < 1) {
- interpol = log(2 + pow(PIXEL(x + 1, y + 1) / Lmax, biasP) * 8);
- for(i = 0; i < 3; i++) {
- for(j = 0; j < 3; j++) {
- index = (y + i)*fpitch + (x + j);
- L = pade_log(image[index].red);// log(image[index].red + 1)
- image[index].red = (float)((L / interpol) / divider);
- }
- }
- }
- else {
- for(i = 0; i < 3; i++) {
- for(j = 0; j < 3; j++) {
- index = (y + i)*fpitch + (x + j);
- interpol = log(2 + pow(image[index].red / Lmax, biasP) * 8);
- L = pade_log(image[index].red);// log(image[index].red + 1)
- image[index].red = (float)((L / interpol) / divider);
- }
- }
- }
- } //x
- } // y
-
- /**
- Normal tone mapping of every pixel for the remaining right and bottom bands
- */
- BYTE *bits;
-
- // right band
- bits = (BYTE*)FreeImage_GetBits(dib);
- for(y = 0; y < height; y++) {
- FIRGBF *pixel = (FIRGBF*)bits;
- for(x = max_width; x < width; x++) {
- double Yw = pixel[x].red / avgLum;
- Yw *= exposure;
- interpol = log(2 + biasFunction(biasP, Yw / Lmax) * 8);
- L = pade_log(Yw);// log(Yw + 1)
- pixel[x].red = (float)((L / interpol) / divider);
- }
- // next line
- bits += pitch;
- }
- // bottom band
- bits = (BYTE*)FreeImage_GetBits(dib);
- for(y = max_height; y < height; y++) {
- FIRGBF *pixel = (FIRGBF*)bits;
- for(x = 0; x < max_width; x++) {
- double Yw = pixel[x].red / avgLum;
- Yw *= exposure;
- interpol = log(2 + biasFunction(biasP, Yw / Lmax) * 8);
- L = pade_log(Yw);// log(Yw + 1)
- pixel[x].red = (float)((L / interpol) / divider);
- }
- // next line
- bits += pitch;
- }
-
-#endif // DRAGO03_FAST
-
- return TRUE;
-}
-
-/**
-Custom gamma correction based on the ITU-R BT.709 standard
-@param dib RGBF image to be corrected
-@param gammaval Gamma value (2.2 is a good default value)
-@return Returns TRUE if successful, returns FALSE otherwise
-*/
-static BOOL
-REC709GammaCorrection(FIBITMAP *dib, const float gammaval) {
- if(FreeImage_GetImageType(dib) != FIT_RGBF)
- return FALSE;
-
- float slope = 4.5F;
- float start = 0.018F;
-
- const float fgamma = (float)((0.45 / gammaval) * 2);
- if(gammaval >= 2.1F) {
- start = (float)(0.018 / ((gammaval - 2) * 7.5));
- slope = (float)(4.5 * ((gammaval - 2) * 7.5));
- } else if (gammaval <= 1.9F) {
- start = (float)(0.018 * ((2 - gammaval) * 7.5));
- slope = (float)(4.5 / ((2 - gammaval) * 7.5));
- }
-
- const unsigned width = FreeImage_GetWidth(dib);
- const unsigned height = FreeImage_GetHeight(dib);
- const unsigned pitch = FreeImage_GetPitch(dib);
-
- BYTE *bits = (BYTE*)FreeImage_GetBits(dib);
- for(unsigned y = 0; y < height; y++) {
- float *pixel = (float*)bits;
- for(unsigned x = 0; x < width; x++) {
- for(int i = 0; i < 3; i++) {
- *pixel = (*pixel <= start) ? *pixel * slope : (1.099F * pow(*pixel, fgamma) - 0.099F);
- pixel++;
- }
- }
- bits += pitch;
- }
-
- return TRUE;
-}
-
-// ----------------------------------------------------------
-// Main algorithm
-// ----------------------------------------------------------
-
-/**
-Apply the Adaptive Logarithmic Mapping operator to a HDR image and convert to 24-bit RGB
-@param src Input RGB16 or RGB[A]F image
-@param gamma Gamma correction (gamma > 0). 1 means no correction, 2.2 in the original paper.
-@param exposure Exposure parameter (0 means no correction, 0 in the original paper)
-@return Returns a 24-bit RGB image if successful, returns NULL otherwise
-*/
-FIBITMAP* DLL_CALLCONV
-FreeImage_TmoDrago03(FIBITMAP *src, double gamma, double exposure) {
- float maxLum, minLum, avgLum;
-
- if(!FreeImage_HasPixels(src)) return NULL;
-
- // working RGBF variable
- FIBITMAP *dib = NULL;
-
- dib = FreeImage_ConvertToRGBF(src);
- if(!dib) return NULL;
-
- // default algorithm parameters
- const float biasParam = 0.85F;
- const float expoParam = (float)pow(2.0, exposure); //default exposure is 1, 2^0
-
- // convert to Yxy
- ConvertInPlaceRGBFToYxy(dib);
- // get the luminance
- LuminanceFromYxy(dib, &maxLum, &minLum, &avgLum);
- // perform the tone mapping
- ToneMappingDrago03(dib, maxLum, avgLum, biasParam, expoParam);
- // convert back to RGBF
- ConvertInPlaceYxyToRGBF(dib);
- if(gamma != 1) {
- // perform gamma correction
- REC709GammaCorrection(dib, (float)gamma);
- }
- // clamp image highest values to display white, then convert to 24-bit RGB
- FIBITMAP *dst = ClampConvertRGBFTo24(dib);
-
- // clean-up and return
- FreeImage_Unload(dib);
-
- // copy metadata from src to dst
- FreeImage_CloneMetadata(dst, src);
-
- return dst;
-}
+// ==========================================================
+// Tone mapping operator (Drago, 2003)
+//
+// Design and implementation by
+// - Hervé Drolon (drolon@infonie.fr)
+//
+// 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 "FreeImage.h"
+#include "Utilities.h"
+#include "ToneMapping.h"
+
+// ----------------------------------------------------------
+// Logarithmic mapping operator
+// Reference:
+// [1] F. Drago, K. Myszkowski, T. Annen, and N. Chiba,
+// Adaptive Logarithmic Mapping for Displaying High Contrast Scenes,
+// Eurographics 2003.
+// ----------------------------------------------------------
+
+/**
+Bias function
+*/
+static inline double
+biasFunction(const double b, const double x) {
+ return pow (x, b); // pow(x, log(bias)/log(0.5)
+}
+
+/**
+Padé approximation of log(x + 1)
+x(6+x)/(6+4x) good if x < 1
+x*(6 + 0.7662x)/(5.9897 + 3.7658x) between 1 and 2
+See http://www.nezumi.demon.co.uk/consult/logx.htm
+*/
+static inline double
+pade_log(const double x) {
+ if(x < 1) {
+ return (x * (6 + x) / (6 + 4 * x));
+ } else if(x < 2) {
+ return (x * (6 + 0.7662 * x) / (5.9897 + 3.7658 * x));
+ }
+ return log(x + 1);
+}
+
+/**
+Log mapping operator
+@param dib Input / Output Yxy image
+@param maxLum Maximum luminance
+@param avgLum Average luminance (world adaptation luminance)
+@param biasParam Bias parameter (a zero value default to 0.85)
+@param exposure Exposure parameter (default to 0)
+@return Returns TRUE if successful, returns FALSE otherwise
+*/
+static BOOL
+ToneMappingDrago03(FIBITMAP *dib, const float maxLum, const float avgLum, float biasParam, const float exposure) {
+ const float LOG05 = -0.693147F; // log(0.5)
+
+ double Lmax, divider, interpol, biasP;
+ unsigned x, y;
+ double L;
+
+ if(FreeImage_GetImageType(dib) != FIT_RGBF)
+ return FALSE;
+
+ const unsigned width = FreeImage_GetWidth(dib);
+ const unsigned height = FreeImage_GetHeight(dib);
+ const unsigned pitch = FreeImage_GetPitch(dib);
+
+
+ // arbitrary Bias Parameter
+ if(biasParam == 0)
+ biasParam = 0.85F;
+
+ // normalize maximum luminance by average luminance
+ Lmax = maxLum / avgLum;
+
+ divider = log10(Lmax+1);
+ biasP = log(biasParam)/LOG05;
+
+#if !defined(DRAGO03_FAST)
+
+ /**
+ Normal tone mapping of every pixel
+ further acceleration is obtained by a Padé approximation of log(x + 1)
+ */
+ BYTE *bits = (BYTE*)FreeImage_GetBits(dib);
+ for(y = 0; y < height; y++) {
+ FIRGBF *pixel = (FIRGBF*)bits;
+ for(x = 0; x < width; x++) {
+ double Yw = pixel[x].red / avgLum;
+ Yw *= exposure;
+ interpol = log(2 + biasFunction(biasP, Yw / Lmax) * 8);
+ L = pade_log(Yw);// log(Yw + 1)
+ pixel[x].red = (float)((L / interpol) / divider);
+ }
+ // next line
+ bits += pitch;
+ }
+
+#else
+ unsigned index;
+ int i, j;
+
+ unsigned max_width = width - (width % 3);
+ unsigned max_height = height - (height % 3);
+ unsigned fpitch = pitch / sizeof(FIRGBF);
+
+ /**
+ fast tone mapping
+ split the image into 3x3 pixel tiles and perform the computation for each group of 9 pixels
+ further acceleration is obtained by a Padé approximation of log(x + 1)
+ => produce artifacts and not so faster, so the code has been disabled
+ */
+#define PIXEL(x, y) image[y*fpitch + x].red
+
+ FIRGBF *image = (FIRGBF*)FreeImage_GetBits(dib);
+ for(y = 0; y < max_height; y += 3) {
+ for(x = 0; x < max_width; x += 3) {
+ double average = 0;
+ for(i = 0; i < 3; i++) {
+ for(j = 0; j < 3; j++) {
+ index = (y + i)*fpitch + (x + j);
+ image[index].red /= (float)avgLum;
+ image[index].red *= exposure;
+ average += image[index].red;
+ }
+ }
+ average = average / 9 - PIXEL(x, y);
+ if(average > -1 && average < 1) {
+ interpol = log(2 + pow(PIXEL(x + 1, y + 1) / Lmax, biasP) * 8);
+ for(i = 0; i < 3; i++) {
+ for(j = 0; j < 3; j++) {
+ index = (y + i)*fpitch + (x + j);
+ L = pade_log(image[index].red);// log(image[index].red + 1)
+ image[index].red = (float)((L / interpol) / divider);
+ }
+ }
+ }
+ else {
+ for(i = 0; i < 3; i++) {
+ for(j = 0; j < 3; j++) {
+ index = (y + i)*fpitch + (x + j);
+ interpol = log(2 + pow(image[index].red / Lmax, biasP) * 8);
+ L = pade_log(image[index].red);// log(image[index].red + 1)
+ image[index].red = (float)((L / interpol) / divider);
+ }
+ }
+ }
+ } //x
+ } // y
+
+ /**
+ Normal tone mapping of every pixel for the remaining right and bottom bands
+ */
+ BYTE *bits;
+
+ // right band
+ bits = (BYTE*)FreeImage_GetBits(dib);
+ for(y = 0; y < height; y++) {
+ FIRGBF *pixel = (FIRGBF*)bits;
+ for(x = max_width; x < width; x++) {
+ double Yw = pixel[x].red / avgLum;
+ Yw *= exposure;
+ interpol = log(2 + biasFunction(biasP, Yw / Lmax) * 8);
+ L = pade_log(Yw);// log(Yw + 1)
+ pixel[x].red = (float)((L / interpol) / divider);
+ }
+ // next line
+ bits += pitch;
+ }
+ // bottom band
+ bits = (BYTE*)FreeImage_GetBits(dib);
+ for(y = max_height; y < height; y++) {
+ FIRGBF *pixel = (FIRGBF*)bits;
+ for(x = 0; x < max_width; x++) {
+ double Yw = pixel[x].red / avgLum;
+ Yw *= exposure;
+ interpol = log(2 + biasFunction(biasP, Yw / Lmax) * 8);
+ L = pade_log(Yw);// log(Yw + 1)
+ pixel[x].red = (float)((L / interpol) / divider);
+ }
+ // next line
+ bits += pitch;
+ }
+
+#endif // DRAGO03_FAST
+
+ return TRUE;
+}
+
+/**
+Custom gamma correction based on the ITU-R BT.709 standard
+@param dib RGBF image to be corrected
+@param gammaval Gamma value (2.2 is a good default value)
+@return Returns TRUE if successful, returns FALSE otherwise
+*/
+static BOOL
+REC709GammaCorrection(FIBITMAP *dib, const float gammaval) {
+ if(FreeImage_GetImageType(dib) != FIT_RGBF)
+ return FALSE;
+
+ float slope = 4.5F;
+ float start = 0.018F;
+
+ const float fgamma = (float)((0.45 / gammaval) * 2);
+ if(gammaval >= 2.1F) {
+ start = (float)(0.018 / ((gammaval - 2) * 7.5));
+ slope = (float)(4.5 * ((gammaval - 2) * 7.5));
+ } else if (gammaval <= 1.9F) {
+ start = (float)(0.018 * ((2 - gammaval) * 7.5));
+ slope = (float)(4.5 / ((2 - gammaval) * 7.5));
+ }
+
+ const unsigned width = FreeImage_GetWidth(dib);
+ const unsigned height = FreeImage_GetHeight(dib);
+ const unsigned pitch = FreeImage_GetPitch(dib);
+
+ BYTE *bits = (BYTE*)FreeImage_GetBits(dib);
+ for(unsigned y = 0; y < height; y++) {
+ float *pixel = (float*)bits;
+ for(unsigned x = 0; x < width; x++) {
+ for(int i = 0; i < 3; i++) {
+ *pixel = (*pixel <= start) ? *pixel * slope : (1.099F * pow(*pixel, fgamma) - 0.099F);
+ pixel++;
+ }
+ }
+ bits += pitch;
+ }
+
+ return TRUE;
+}
+
+// ----------------------------------------------------------
+// Main algorithm
+// ----------------------------------------------------------
+
+/**
+Apply the Adaptive Logarithmic Mapping operator to a HDR image and convert to 24-bit RGB
+@param src Input RGB16 or RGB[A]F image
+@param gamma Gamma correction (gamma > 0). 1 means no correction, 2.2 in the original paper.
+@param exposure Exposure parameter (0 means no correction, 0 in the original paper)
+@return Returns a 24-bit RGB image if successful, returns NULL otherwise
+*/
+FIBITMAP* DLL_CALLCONV
+FreeImage_TmoDrago03(FIBITMAP *src, double gamma, double exposure) {
+ float maxLum, minLum, avgLum;
+
+ if(!FreeImage_HasPixels(src)) return NULL;
+
+ // working RGBF variable
+ FIBITMAP *dib = NULL;
+
+ dib = FreeImage_ConvertToRGBF(src);
+ if(!dib) return NULL;
+
+ // default algorithm parameters
+ const float biasParam = 0.85F;
+ const float expoParam = (float)pow(2.0, exposure); //default exposure is 1, 2^0
+
+ // convert to Yxy
+ ConvertInPlaceRGBFToYxy(dib);
+ // get the luminance
+ LuminanceFromYxy(dib, &maxLum, &minLum, &avgLum);
+ // perform the tone mapping
+ ToneMappingDrago03(dib, maxLum, avgLum, biasParam, expoParam);
+ // convert back to RGBF
+ ConvertInPlaceYxyToRGBF(dib);
+ if(gamma != 1) {
+ // perform gamma correction
+ REC709GammaCorrection(dib, (float)gamma);
+ }
+ // clamp image highest values to display white, then convert to 24-bit RGB
+ FIBITMAP *dst = ClampConvertRGBFTo24(dib);
+
+ // clean-up and return
+ FreeImage_Unload(dib);
+
+ // copy metadata from src to dst
+ FreeImage_CloneMetadata(dst, src);
+
+ return dst;
+}
diff --git a/plugins/AdvaImg/src/FreeImage/tmoFattal02.cpp b/plugins/AdvaImg/src/FreeImage/tmoFattal02.cpp
index 88f054412a..c63f91f762 100644
--- a/plugins/AdvaImg/src/FreeImage/tmoFattal02.cpp
+++ b/plugins/AdvaImg/src/FreeImage/tmoFattal02.cpp
@@ -1,689 +1,689 @@
-// ==========================================================
-// Tone mapping operator (Fattal, 2002)
-//
-// Design and implementation by
-// - Hervé Drolon (drolon@infonie.fr)
-//
-// 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 "FreeImage.h"
-#include "Utilities.h"
-#include "ToneMapping.h"
-
-// ----------------------------------------------------------
-// Gradient domain HDR compression
-// Reference:
-// [1] R. Fattal, D. Lischinski, and M.Werman,
-// Gradient domain high dynamic range compression,
-// ACM Transactions on Graphics, special issue on Proc. of ACM SIGGRAPH 2002,
-// San Antonio, Texas, vol. 21(3), pp. 257-266, 2002.
-// ----------------------------------------------------------
-
-static const float EPSILON = 1e-4F;
-
-/**
-Performs a 5 by 5 gaussian filtering using two 1D convolutions,
-followed by a subsampling by 2.
-@param dib Input image
-@return Returns a blurred image of size SIZE(dib)/2
-@see GaussianPyramid
-*/
-static FIBITMAP* GaussianLevel5x5(FIBITMAP *dib) {
- FIBITMAP *h_dib = NULL, *v_dib = NULL, *dst = NULL;
- float *src_pixel, *dst_pixel;
-
- try {
- const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
- if(image_type != FIT_FLOAT) throw(1);
-
- const unsigned width = FreeImage_GetWidth(dib);
- const unsigned height = FreeImage_GetHeight(dib);
-
- h_dib = FreeImage_AllocateT(image_type, width, height);
- v_dib = FreeImage_AllocateT(image_type, width, height);
- if(!h_dib || !v_dib) throw(1);
-
- const unsigned pitch = FreeImage_GetPitch(dib) / sizeof(float);
-
- // horizontal convolution dib -> h_dib
-
- src_pixel = (float*)FreeImage_GetBits(dib);
- dst_pixel = (float*)FreeImage_GetBits(h_dib);
-
- for(unsigned y = 0; y < height; y++) {
- // work on line y
- for(unsigned x = 2; x < width - 2; x++) {
- dst_pixel[x] = src_pixel[x-2] + src_pixel[x+2] + 4 * (src_pixel[x-1] + src_pixel[x+1]) + 6 * src_pixel[x];
- dst_pixel[x] /= 16;
- }
- // boundary mirroring
- dst_pixel[0] = (2 * src_pixel[2] + 8 * src_pixel[1] + 6 * src_pixel[0]) / 16;
- dst_pixel[1] = (src_pixel[3] + 4 * (src_pixel[0] + src_pixel[2]) + 7 * src_pixel[1]) / 16;
- dst_pixel[width-2] = (src_pixel[width-4] + 5 * src_pixel[width-1] + 4 * src_pixel[width-3] + 6 * src_pixel[width-2]) / 16;
- dst_pixel[width-1] = (src_pixel[width-3] + 5 * src_pixel[width-2] + 10 * src_pixel[width-1]) / 16;
-
- // next line
- src_pixel += pitch;
- dst_pixel += pitch;
- }
-
- // vertical convolution h_dib -> v_dib
-
- src_pixel = (float*)FreeImage_GetBits(h_dib);
- dst_pixel = (float*)FreeImage_GetBits(v_dib);
-
- for(unsigned x = 0; x < width; x++) {
- // work on column x
- for(unsigned y = 2; y < height - 2; y++) {
- const unsigned index = y*pitch + x;
- dst_pixel[index] = src_pixel[index-2*pitch] + src_pixel[index+2*pitch] + 4 * (src_pixel[index-pitch] + src_pixel[index+pitch]) + 6 * src_pixel[index];
- dst_pixel[index] /= 16;
- }
- // boundary mirroring
- dst_pixel[x] = (2 * src_pixel[x+2*pitch] + 8 * src_pixel[x+pitch] + 6 * src_pixel[x]) / 16;
- dst_pixel[x+pitch] = (src_pixel[x+3*pitch] + 4 * (src_pixel[x] + src_pixel[x+2*pitch]) + 7 * src_pixel[x+pitch]) / 16;
- dst_pixel[(height-2)*pitch+x] = (src_pixel[(height-4)*pitch+x] + 5 * src_pixel[(height-1)*pitch+x] + 4 * src_pixel[(height-3)*pitch+x] + 6 * src_pixel[(height-2)*pitch+x]) / 16;
- dst_pixel[(height-1)*pitch+x] = (src_pixel[(height-3)*pitch+x] + 5 * src_pixel[(height-2)*pitch+x] + 10 * src_pixel[(height-1)*pitch+x]) / 16;
- }
-
- FreeImage_Unload(h_dib); h_dib = NULL;
-
- // perform downsampling
-
- dst = FreeImage_Rescale(v_dib, width/2, height/2, FILTER_BILINEAR);
-
- FreeImage_Unload(v_dib);
-
- return dst;
-
- } catch(int) {
- if(h_dib) FreeImage_Unload(h_dib);
- if(v_dib) FreeImage_Unload(v_dib);
- if(dst) FreeImage_Unload(dst);
- return NULL;
- }
-}
-
-/**
-Compute a Gaussian pyramid using the specified number of levels.
-@param H Original bitmap
-@param pyramid Resulting pyramid array
-@param nlevels Number of resolution levels
-@return Returns TRUE if successful, returns FALSE otherwise
-*/
-static BOOL GaussianPyramid(FIBITMAP *H, FIBITMAP **pyramid, int nlevels) {
- try {
- // first level is the original image
- pyramid[0] = FreeImage_Clone(H);
- if(pyramid[0] == NULL) throw(1);
- // compute next levels
- for(int k = 1; k < nlevels; k++) {
- pyramid[k] = GaussianLevel5x5(pyramid[k-1]);
- if(pyramid[k] == NULL) throw(1);
- }
- return TRUE;
- } catch(int) {
- for(int k = 0; k < nlevels; k++) {
- if(pyramid[k] != NULL) {
- FreeImage_Unload(pyramid[k]);
- pyramid[k] = NULL;
- }
- }
- return FALSE;
- }
-}
-
-/**
-Compute the gradient magnitude of an input image H using central differences,
-and returns the average gradient.
-@param H Input image
-@param avgGrad [out] Average gradient
-@param k Level number
-@return Returns the gradient magnitude if successful, returns NULL otherwise
-@see GradientPyramid
-*/
-static FIBITMAP* GradientLevel(FIBITMAP *H, float *avgGrad, int k) {
- FIBITMAP *G = NULL;
-
- try {
- const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(H);
- if(image_type != FIT_FLOAT) throw(1);
-
- const unsigned width = FreeImage_GetWidth(H);
- const unsigned height = FreeImage_GetHeight(H);
-
- G = FreeImage_AllocateT(image_type, width, height);
- if(!G) throw(1);
-
- const unsigned pitch = FreeImage_GetPitch(H) / sizeof(float);
-
- const float divider = (float)(1 << (k + 1));
- float average = 0;
-
- float *src_pixel = (float*)FreeImage_GetBits(H);
- float *dst_pixel = (float*)FreeImage_GetBits(G);
-
- for(unsigned y = 0; y < height; y++) {
- const unsigned n = (y == 0 ? 0 : y-1);
- const unsigned s = (y+1 == height ? y : y+1);
- for(unsigned x = 0; x < width; x++) {
- const unsigned w = (x == 0 ? 0 : x-1);
- const unsigned e = (x+1 == width ? x : x+1);
- // central difference
- const float gx = (src_pixel[y*pitch+e] - src_pixel[y*pitch+w]) / divider; // [Hk(x+1, y) - Hk(x-1, y)] / 2**(k+1)
- const float gy = (src_pixel[s*pitch+x] - src_pixel[n*pitch+x]) / divider; // [Hk(x, y+1) - Hk(x, y-1)] / 2**(k+1)
- // gradient
- dst_pixel[x] = sqrt(gx*gx + gy*gy);
- // average gradient
- average += dst_pixel[x];
- }
- // next line
- dst_pixel += pitch;
- }
-
- *avgGrad = average / (width * height);
-
- return G;
-
- } catch(int) {
- if(G) FreeImage_Unload(G);
- return NULL;
- }
-}
-
-/**
-Calculate gradient magnitude and its average value on each pyramid level
-@param pyramid Gaussian pyramid (nlevels levels)
-@param nlevels Number of levels
-@param gradients [out] Gradient pyramid (nlevels levels)
-@param avgGrad [out] Average gradient on each level (array of size nlevels)
-@return Returns TRUE if successful, returns FALSE otherwise
-*/
-static BOOL GradientPyramid(FIBITMAP **pyramid, int nlevels, FIBITMAP **gradients, float *avgGrad) {
- try {
- for(int k = 0; k < nlevels; k++) {
- FIBITMAP *Hk = pyramid[k];
- gradients[k] = GradientLevel(Hk, &avgGrad[k], k);
- if(gradients[k] == NULL) throw(1);
- }
- return TRUE;
- } catch(int) {
- for(int k = 0; k < nlevels; k++) {
- if(gradients[k] != NULL) {
- FreeImage_Unload(gradients[k]);
- gradients[k] = NULL;
- }
- }
- return FALSE;
- }
-}
-
-/**
-Compute the gradient attenuation function PHI(x, y)
-@param gradients Gradient pyramid (nlevels levels)
-@param avgGrad Average gradient on each level (array of size nlevels)
-@param nlevels Number of levels
-@param alpha Parameter alpha in the paper
-@param beta Parameter beta in the paper
-@return Returns the attenuation matrix Phi if successful, returns NULL otherwise
-*/
-static FIBITMAP* PhiMatrix(FIBITMAP **gradients, float *avgGrad, int nlevels, float alpha, float beta) {
- float *src_pixel, *dst_pixel;
- FIBITMAP **phi = NULL;
-
- try {
- phi = (FIBITMAP**)malloc(nlevels * sizeof(FIBITMAP*));
- if(!phi) throw(1);
- memset(phi, 0, nlevels * sizeof(FIBITMAP*));
-
- for(int k = nlevels-1; k >= 0; k--) {
- // compute phi(k)
-
- FIBITMAP *Gk = gradients[k];
-
- const unsigned width = FreeImage_GetWidth(Gk);
- const unsigned height = FreeImage_GetHeight(Gk);
- const unsigned pitch = FreeImage_GetPitch(Gk) / sizeof(float);
-
- // parameter alpha is 0.1 times the average gradient magnitude
- // also, note the factor of 2**k in the denominator;
- // that is there to correct for the fact that an average gradient avgGrad(H) over 2**k pixels
- // in the original image will appear as a gradient grad(Hk) = 2**k*avgGrad(H) over a single pixel in Hk.
- float ALPHA = alpha * avgGrad[k] * (float)((int)1 << k);
- if(ALPHA == 0) ALPHA = EPSILON;
-
- phi[k] = FreeImage_AllocateT(FIT_FLOAT, width, height);
- if(!phi[k]) throw(1);
-
- src_pixel = (float*)FreeImage_GetBits(Gk);
- dst_pixel = (float*)FreeImage_GetBits(phi[k]);
- for(unsigned y = 0; y < height; y++) {
- for(unsigned x = 0; x < width; x++) {
- // compute (alpha / grad) * (grad / alpha) ** beta
- const float v = src_pixel[x] / ALPHA;
- const float value = (float)pow((float)v, (float)(beta-1));
- dst_pixel[x] = (value > 1) ? 1 : value;
- }
- // next line
- src_pixel += pitch;
- dst_pixel += pitch;
- }
-
- if(k < nlevels-1) {
- // compute PHI(k) = L( PHI(k+1) ) * phi(k)
- FIBITMAP *L = FreeImage_Rescale(phi[k+1], width, height, FILTER_BILINEAR);
- if(!L) throw(1);
-
- src_pixel = (float*)FreeImage_GetBits(L);
- dst_pixel = (float*)FreeImage_GetBits(phi[k]);
- for(unsigned y = 0; y < height; y++) {
- for(unsigned x = 0; x < width; x++) {
- dst_pixel[x] *= src_pixel[x];
- }
- // next line
- src_pixel += pitch;
- dst_pixel += pitch;
- }
-
- FreeImage_Unload(L);
-
- // PHI(k+1) is no longer needed
- FreeImage_Unload(phi[k+1]);
- phi[k+1] = NULL;
- }
-
- // next level
- }
-
- // get the final result and return
- FIBITMAP *dst = phi[0];
-
- free(phi);
-
- return dst;
-
- } catch(int) {
- if(phi) {
- for(int k = nlevels-1; k >= 0; k--) {
- if(phi[k]) FreeImage_Unload(phi[k]);
- }
- free(phi);
- }
- return NULL;
- }
-}
-
-/**
-Compute gradients in x and y directions, attenuate them with the attenuation matrix,
-then compute the divergence div G from the attenuated gradient.
-@param H Normalized luminance
-@param PHI Attenuation matrix
-@return Returns the divergence matrix if successful, returns NULL otherwise
-*/
-static FIBITMAP* Divergence(FIBITMAP *H, FIBITMAP *PHI) {
- FIBITMAP *Gx = NULL, *Gy = NULL, *divG = NULL;
- float *phi, *h, *gx, *gy, *divg;
-
- try {
- const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(H);
- if(image_type != FIT_FLOAT) throw(1);
-
- const unsigned width = FreeImage_GetWidth(H);
- const unsigned height = FreeImage_GetHeight(H);
-
- Gx = FreeImage_AllocateT(image_type, width, height);
- if(!Gx) throw(1);
- Gy = FreeImage_AllocateT(image_type, width, height);
- if(!Gy) throw(1);
-
- const unsigned pitch = FreeImage_GetPitch(H) / sizeof(float);
-
- // perform gradient attenuation
-
- phi = (float*)FreeImage_GetBits(PHI);
- h = (float*)FreeImage_GetBits(H);
- gx = (float*)FreeImage_GetBits(Gx);
- gy = (float*)FreeImage_GetBits(Gy);
-
- for(unsigned y = 0; y < height; y++) {
- const unsigned s = (y+1 == height ? y : y+1);
- for(unsigned x = 0; x < width; x++) {
- const unsigned e = (x+1 == width ? x : x+1);
- // forward difference
- const unsigned index = y*pitch + x;
- const float phi_xy = phi[index];
- const float h_xy = h[index];
- gx[x] = (h[y*pitch+e] - h_xy) * phi_xy; // [H(x+1, y) - H(x, y)] * PHI(x, y)
- gy[x] = (h[s*pitch+x] - h_xy) * phi_xy; // [H(x, y+1) - H(x, y)] * PHI(x, y)
- }
- // next line
- gx += pitch;
- gy += pitch;
- }
-
- // calculate the divergence
-
- divG = FreeImage_AllocateT(image_type, width, height);
- if(!divG) throw(1);
-
- gx = (float*)FreeImage_GetBits(Gx);
- gy = (float*)FreeImage_GetBits(Gy);
- divg = (float*)FreeImage_GetBits(divG);
-
- for(unsigned y = 0; y < height; y++) {
- for(unsigned x = 0; x < width; x++) {
- // backward difference approximation
- // divG = Gx(x, y) - Gx(x-1, y) + Gy(x, y) - Gy(x, y-1)
- const unsigned index = y*pitch + x;
- divg[index] = gx[index] + gy[index];
- if(x > 0) divg[index] -= gx[index-1];
- if(y > 0) divg[index] -= gy[index-pitch];
- }
- }
-
- // no longer needed ...
- FreeImage_Unload(Gx);
- FreeImage_Unload(Gy);
-
- // return the divergence
- return divG;
-
- } catch(int) {
- if(Gx) FreeImage_Unload(Gx);
- if(Gy) FreeImage_Unload(Gy);
- if(divG) FreeImage_Unload(divG);
- return NULL;
- }
-}
-
-/**
-Given the luminance channel, find max & min luminance values,
-normalize to range 0..100 and take the logarithm.
-@param Y Image luminance
-@return Returns the normalized luminance H if successful, returns NULL otherwise
-*/
-static FIBITMAP* LogLuminance(FIBITMAP *Y) {
- FIBITMAP *H = NULL;
-
- try {
- // get the luminance channel
- FIBITMAP *H = FreeImage_Clone(Y);
- if(!H) throw(1);
-
- const unsigned width = FreeImage_GetWidth(H);
- const unsigned height = FreeImage_GetHeight(H);
- const unsigned pitch = FreeImage_GetPitch(H);
-
- // find max & min luminance values
- float maxLum = -1e20F, minLum = 1e20F;
-
- BYTE *bits = (BYTE*)FreeImage_GetBits(H);
- for(unsigned y = 0; y < height; y++) {
- const float *pixel = (float*)bits;
- for(unsigned x = 0; x < width; x++) {
- const float value = pixel[x];
- maxLum = (maxLum < value) ? value : maxLum; // max Luminance in the scene
- minLum = (minLum < value) ? minLum : value; // min Luminance in the scene
- }
- // next line
- bits += pitch;
- }
- if(maxLum == minLum) throw(1);
-
- // normalize to range 0..100 and take the logarithm
- const float scale = 100.F / (maxLum - minLum);
- bits = (BYTE*)FreeImage_GetBits(H);
- for(unsigned y = 0; y < height; y++) {
- float *pixel = (float*)bits;
- for(unsigned x = 0; x < width; x++) {
- const float value = (pixel[x] - minLum) * scale;
- pixel[x] = log(value + EPSILON);
- }
- // next line
- bits += pitch;
- }
-
- return H;
-
- } catch(int) {
- if(H) FreeImage_Unload(H);
- return NULL;
- }
-}
-
-/**
-Given a normalized luminance, perform exponentiation and recover the log compressed image
-@param Y Input/Output luminance image
-*/
-static void ExpLuminance(FIBITMAP *Y) {
- const unsigned width = FreeImage_GetWidth(Y);
- const unsigned height = FreeImage_GetHeight(Y);
- const unsigned pitch = FreeImage_GetPitch(Y);
-
- BYTE *bits = (BYTE*)FreeImage_GetBits(Y);
- for(unsigned y = 0; y < height; y++) {
- float *pixel = (float*)bits;
- for(unsigned x = 0; x < width; x++) {
- pixel[x] = exp(pixel[x]) - EPSILON;
- }
- bits += pitch;
- }
-}
-
-// --------------------------------------------------------------------------
-
-/**
-Gradient Domain HDR tone mapping operator
-@param Y Image luminance values
-@param alpha Parameter alpha of the paper (suggested value is 0.1)
-@param beta Parameter beta of the paper (suggested value is between 0.8 and 0.9)
-@return returns the tone mapped luminance
-*/
-static FIBITMAP* tmoFattal02(FIBITMAP *Y, float alpha, float beta) {
- const unsigned MIN_PYRAMID_SIZE = 32; // minimun size (width or height) of the coarsest level of the pyramid
-
- FIBITMAP *H = NULL;
- FIBITMAP **pyramid = NULL;
- FIBITMAP **gradients = NULL;
- FIBITMAP *phy = NULL;
- FIBITMAP *divG = NULL;
- FIBITMAP *U = NULL;
- float *avgGrad = NULL;
-
- int k;
- int nlevels = 0;
-
- try {
- // get the normalized luminance
- FIBITMAP *H = LogLuminance(Y);
- if(!H) throw(1);
-
- // get the number of levels for the pyramid
- const unsigned width = FreeImage_GetWidth(H);
- const unsigned height = FreeImage_GetHeight(H);
- unsigned minsize = MIN(width, height);
- while(minsize >= MIN_PYRAMID_SIZE) {
- nlevels++;
- minsize /= 2;
- }
-
- // create the Gaussian pyramid
- pyramid = (FIBITMAP**)malloc(nlevels * sizeof(FIBITMAP*));
- if(!pyramid) throw(1);
- memset(pyramid, 0, nlevels * sizeof(FIBITMAP*));
-
- if(!GaussianPyramid(H, pyramid, nlevels)) throw(1);
-
- // calculate gradient magnitude and its average value on each pyramid level
- gradients = (FIBITMAP**)malloc(nlevels * sizeof(FIBITMAP*));
- if(!gradients) throw(1);
- memset(gradients, 0, nlevels * sizeof(FIBITMAP*));
- avgGrad = (float*)malloc(nlevels * sizeof(float));
- if(!avgGrad) throw(1);
-
- if(!GradientPyramid(pyramid, nlevels, gradients, avgGrad)) throw(1);
-
- // free the Gaussian pyramid
- for(k = 0; k < nlevels; k++) {
- if(pyramid[k]) FreeImage_Unload(pyramid[k]);
- }
- free(pyramid); pyramid = NULL;
-
- // compute the gradient attenuation function PHI(x, y)
- phy = PhiMatrix(gradients, avgGrad, nlevels, alpha, beta);
- if(!phy) throw(1);
-
- // free the gradient pyramid
- for(k = 0; k < nlevels; k++) {
- if(gradients[k]) FreeImage_Unload(gradients[k]);
- }
- free(gradients); gradients = NULL;
- free(avgGrad); avgGrad = NULL;
-
- // compute gradients in x and y directions, attenuate them with the attenuation matrix,
- // then compute the divergence div G from the attenuated gradient.
- divG = Divergence(H, phy);
- if(!divG) throw(1);
-
- // H & phy no longer needed
- FreeImage_Unload(H); H = NULL;
- FreeImage_Unload(phy); phy = NULL;
-
- // solve the PDE (Poisson equation) using a multigrid solver and 3 cycles
- FIBITMAP *U = FreeImage_MultigridPoissonSolver(divG, 3);
- if(!U) throw(1);
-
- FreeImage_Unload(divG);
-
- // perform exponentiation and recover the log compressed image
- ExpLuminance(U);
-
- return U;
-
- } catch(int) {
- if(H) FreeImage_Unload(H);
- if(pyramid) {
- for(int i = 0; i < nlevels; i++) {
- if(pyramid[i]) FreeImage_Unload(pyramid[i]);
- }
- free(pyramid);
- }
- if(gradients) {
- for(int i = 0; i < nlevels; i++) {
- if(gradients[i]) FreeImage_Unload(gradients[i]);
- }
- free(gradients);
- }
- if(avgGrad) free(avgGrad);
- if(phy) FreeImage_Unload(phy);
- if(divG) FreeImage_Unload(divG);
- if(U) FreeImage_Unload(U);
-
- return NULL;
- }
-}
-
-// ----------------------------------------------------------
-// Main algorithm
-// ----------------------------------------------------------
-
-/**
-Apply the Gradient Domain High Dynamic Range Compression to a RGBF image and convert to 24-bit RGB
-@param dib Input RGBF / RGB16 image
-@param color_saturation Color saturation (s parameter in the paper) in [0.4..0.6]
-@param attenuation Atenuation factor (beta parameter in the paper) in [0.8..0.9]
-@return Returns a 24-bit RGB image if successful, returns NULL otherwise
-*/
-FIBITMAP* DLL_CALLCONV
-FreeImage_TmoFattal02(FIBITMAP *dib, double color_saturation, double attenuation) {
- const float alpha = 0.1F; // parameter alpha = 0.1
- const float beta = (float)MAX(0.8, MIN(0.9, attenuation)); // parameter beta = [0.8..0.9]
- const float s = (float)MAX(0.4, MIN(0.6, color_saturation));// exponent s controls color saturation = [0.4..0.6]
-
- FIBITMAP *src = NULL;
- FIBITMAP *Yin = NULL;
- FIBITMAP *Yout = NULL;
- FIBITMAP *dst = NULL;
-
- if(!FreeImage_HasPixels(dib)) return NULL;
-
- try {
-
- // convert to RGBF
- src = FreeImage_ConvertToRGBF(dib);
- if(!src) throw(1);
-
- // get the luminance channel
- Yin = ConvertRGBFToY(src);
- if(!Yin) throw(1);
-
- // perform the tone mapping
- Yout = tmoFattal02(Yin, alpha, beta);
- if(!Yout) throw(1);
-
- // clip low and high values and normalize to [0..1]
- //NormalizeY(Yout, 0.001F, 0.995F);
- NormalizeY(Yout, 0, 1);
-
- // compress the dynamic range
-
- const unsigned width = FreeImage_GetWidth(src);
- const unsigned height = FreeImage_GetHeight(src);
-
- const unsigned rgb_pitch = FreeImage_GetPitch(src);
- const unsigned y_pitch = FreeImage_GetPitch(Yin);
-
- BYTE *bits = (BYTE*)FreeImage_GetBits(src);
- BYTE *bits_yin = (BYTE*)FreeImage_GetBits(Yin);
- BYTE *bits_yout = (BYTE*)FreeImage_GetBits(Yout);
-
- for(unsigned y = 0; y < height; y++) {
- float *Lin = (float*)bits_yin;
- float *Lout = (float*)bits_yout;
- float *color = (float*)bits;
- for(unsigned x = 0; x < width; x++) {
- for(unsigned c = 0; c < 3; c++) {
- *color = (Lin[x] > 0) ? pow(*color/Lin[x], s) * Lout[x] : 0;
- color++;
- }
- }
- bits += rgb_pitch;
- bits_yin += y_pitch;
- bits_yout += y_pitch;
- }
-
- // not needed anymore
- FreeImage_Unload(Yin); Yin = NULL;
- FreeImage_Unload(Yout); Yout = NULL;
-
- // clamp image highest values to display white, then convert to 24-bit RGB
- dst = ClampConvertRGBFTo24(src);
-
- // clean-up and return
- FreeImage_Unload(src); src = NULL;
-
- // copy metadata from src to dst
- FreeImage_CloneMetadata(dst, dib);
-
- return dst;
-
- } catch(int) {
- if(src) FreeImage_Unload(src);
- if(Yin) FreeImage_Unload(Yin);
- if(Yout) FreeImage_Unload(Yout);
- return NULL;
- }
-}
+// ==========================================================
+// Tone mapping operator (Fattal, 2002)
+//
+// Design and implementation by
+// - Hervé Drolon (drolon@infonie.fr)
+//
+// 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 "FreeImage.h"
+#include "Utilities.h"
+#include "ToneMapping.h"
+
+// ----------------------------------------------------------
+// Gradient domain HDR compression
+// Reference:
+// [1] R. Fattal, D. Lischinski, and M.Werman,
+// Gradient domain high dynamic range compression,
+// ACM Transactions on Graphics, special issue on Proc. of ACM SIGGRAPH 2002,
+// San Antonio, Texas, vol. 21(3), pp. 257-266, 2002.
+// ----------------------------------------------------------
+
+static const float EPSILON = 1e-4F;
+
+/**
+Performs a 5 by 5 gaussian filtering using two 1D convolutions,
+followed by a subsampling by 2.
+@param dib Input image
+@return Returns a blurred image of size SIZE(dib)/2
+@see GaussianPyramid
+*/
+static FIBITMAP* GaussianLevel5x5(FIBITMAP *dib) {
+ FIBITMAP *h_dib = NULL, *v_dib = NULL, *dst = NULL;
+ float *src_pixel, *dst_pixel;
+
+ try {
+ const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
+ if(image_type != FIT_FLOAT) throw(1);
+
+ const unsigned width = FreeImage_GetWidth(dib);
+ const unsigned height = FreeImage_GetHeight(dib);
+
+ h_dib = FreeImage_AllocateT(image_type, width, height);
+ v_dib = FreeImage_AllocateT(image_type, width, height);
+ if(!h_dib || !v_dib) throw(1);
+
+ const unsigned pitch = FreeImage_GetPitch(dib) / sizeof(float);
+
+ // horizontal convolution dib -> h_dib
+
+ src_pixel = (float*)FreeImage_GetBits(dib);
+ dst_pixel = (float*)FreeImage_GetBits(h_dib);
+
+ for(unsigned y = 0; y < height; y++) {
+ // work on line y
+ for(unsigned x = 2; x < width - 2; x++) {
+ dst_pixel[x] = src_pixel[x-2] + src_pixel[x+2] + 4 * (src_pixel[x-1] + src_pixel[x+1]) + 6 * src_pixel[x];
+ dst_pixel[x] /= 16;
+ }
+ // boundary mirroring
+ dst_pixel[0] = (2 * src_pixel[2] + 8 * src_pixel[1] + 6 * src_pixel[0]) / 16;
+ dst_pixel[1] = (src_pixel[3] + 4 * (src_pixel[0] + src_pixel[2]) + 7 * src_pixel[1]) / 16;
+ dst_pixel[width-2] = (src_pixel[width-4] + 5 * src_pixel[width-1] + 4 * src_pixel[width-3] + 6 * src_pixel[width-2]) / 16;
+ dst_pixel[width-1] = (src_pixel[width-3] + 5 * src_pixel[width-2] + 10 * src_pixel[width-1]) / 16;
+
+ // next line
+ src_pixel += pitch;
+ dst_pixel += pitch;
+ }
+
+ // vertical convolution h_dib -> v_dib
+
+ src_pixel = (float*)FreeImage_GetBits(h_dib);
+ dst_pixel = (float*)FreeImage_GetBits(v_dib);
+
+ for(unsigned x = 0; x < width; x++) {
+ // work on column x
+ for(unsigned y = 2; y < height - 2; y++) {
+ const unsigned index = y*pitch + x;
+ dst_pixel[index] = src_pixel[index-2*pitch] + src_pixel[index+2*pitch] + 4 * (src_pixel[index-pitch] + src_pixel[index+pitch]) + 6 * src_pixel[index];
+ dst_pixel[index] /= 16;
+ }
+ // boundary mirroring
+ dst_pixel[x] = (2 * src_pixel[x+2*pitch] + 8 * src_pixel[x+pitch] + 6 * src_pixel[x]) / 16;
+ dst_pixel[x+pitch] = (src_pixel[x+3*pitch] + 4 * (src_pixel[x] + src_pixel[x+2*pitch]) + 7 * src_pixel[x+pitch]) / 16;
+ dst_pixel[(height-2)*pitch+x] = (src_pixel[(height-4)*pitch+x] + 5 * src_pixel[(height-1)*pitch+x] + 4 * src_pixel[(height-3)*pitch+x] + 6 * src_pixel[(height-2)*pitch+x]) / 16;
+ dst_pixel[(height-1)*pitch+x] = (src_pixel[(height-3)*pitch+x] + 5 * src_pixel[(height-2)*pitch+x] + 10 * src_pixel[(height-1)*pitch+x]) / 16;
+ }
+
+ FreeImage_Unload(h_dib); h_dib = NULL;
+
+ // perform downsampling
+
+ dst = FreeImage_Rescale(v_dib, width/2, height/2, FILTER_BILINEAR);
+
+ FreeImage_Unload(v_dib);
+
+ return dst;
+
+ } catch(int) {
+ if(h_dib) FreeImage_Unload(h_dib);
+ if(v_dib) FreeImage_Unload(v_dib);
+ if(dst) FreeImage_Unload(dst);
+ return NULL;
+ }
+}
+
+/**
+Compute a Gaussian pyramid using the specified number of levels.
+@param H Original bitmap
+@param pyramid Resulting pyramid array
+@param nlevels Number of resolution levels
+@return Returns TRUE if successful, returns FALSE otherwise
+*/
+static BOOL GaussianPyramid(FIBITMAP *H, FIBITMAP **pyramid, int nlevels) {
+ try {
+ // first level is the original image
+ pyramid[0] = FreeImage_Clone(H);
+ if(pyramid[0] == NULL) throw(1);
+ // compute next levels
+ for(int k = 1; k < nlevels; k++) {
+ pyramid[k] = GaussianLevel5x5(pyramid[k-1]);
+ if(pyramid[k] == NULL) throw(1);
+ }
+ return TRUE;
+ } catch(int) {
+ for(int k = 0; k < nlevels; k++) {
+ if(pyramid[k] != NULL) {
+ FreeImage_Unload(pyramid[k]);
+ pyramid[k] = NULL;
+ }
+ }
+ return FALSE;
+ }
+}
+
+/**
+Compute the gradient magnitude of an input image H using central differences,
+and returns the average gradient.
+@param H Input image
+@param avgGrad [out] Average gradient
+@param k Level number
+@return Returns the gradient magnitude if successful, returns NULL otherwise
+@see GradientPyramid
+*/
+static FIBITMAP* GradientLevel(FIBITMAP *H, float *avgGrad, int k) {
+ FIBITMAP *G = NULL;
+
+ try {
+ const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(H);
+ if(image_type != FIT_FLOAT) throw(1);
+
+ const unsigned width = FreeImage_GetWidth(H);
+ const unsigned height = FreeImage_GetHeight(H);
+
+ G = FreeImage_AllocateT(image_type, width, height);
+ if(!G) throw(1);
+
+ const unsigned pitch = FreeImage_GetPitch(H) / sizeof(float);
+
+ const float divider = (float)(1 << (k + 1));
+ float average = 0;
+
+ float *src_pixel = (float*)FreeImage_GetBits(H);
+ float *dst_pixel = (float*)FreeImage_GetBits(G);
+
+ for(unsigned y = 0; y < height; y++) {
+ const unsigned n = (y == 0 ? 0 : y-1);
+ const unsigned s = (y+1 == height ? y : y+1);
+ for(unsigned x = 0; x < width; x++) {
+ const unsigned w = (x == 0 ? 0 : x-1);
+ const unsigned e = (x+1 == width ? x : x+1);
+ // central difference
+ const float gx = (src_pixel[y*pitch+e] - src_pixel[y*pitch+w]) / divider; // [Hk(x+1, y) - Hk(x-1, y)] / 2**(k+1)
+ const float gy = (src_pixel[s*pitch+x] - src_pixel[n*pitch+x]) / divider; // [Hk(x, y+1) - Hk(x, y-1)] / 2**(k+1)
+ // gradient
+ dst_pixel[x] = sqrt(gx*gx + gy*gy);
+ // average gradient
+ average += dst_pixel[x];
+ }
+ // next line
+ dst_pixel += pitch;
+ }
+
+ *avgGrad = average / (width * height);
+
+ return G;
+
+ } catch(int) {
+ if(G) FreeImage_Unload(G);
+ return NULL;
+ }
+}
+
+/**
+Calculate gradient magnitude and its average value on each pyramid level
+@param pyramid Gaussian pyramid (nlevels levels)
+@param nlevels Number of levels
+@param gradients [out] Gradient pyramid (nlevels levels)
+@param avgGrad [out] Average gradient on each level (array of size nlevels)
+@return Returns TRUE if successful, returns FALSE otherwise
+*/
+static BOOL GradientPyramid(FIBITMAP **pyramid, int nlevels, FIBITMAP **gradients, float *avgGrad) {
+ try {
+ for(int k = 0; k < nlevels; k++) {
+ FIBITMAP *Hk = pyramid[k];
+ gradients[k] = GradientLevel(Hk, &avgGrad[k], k);
+ if(gradients[k] == NULL) throw(1);
+ }
+ return TRUE;
+ } catch(int) {
+ for(int k = 0; k < nlevels; k++) {
+ if(gradients[k] != NULL) {
+ FreeImage_Unload(gradients[k]);
+ gradients[k] = NULL;
+ }
+ }
+ return FALSE;
+ }
+}
+
+/**
+Compute the gradient attenuation function PHI(x, y)
+@param gradients Gradient pyramid (nlevels levels)
+@param avgGrad Average gradient on each level (array of size nlevels)
+@param nlevels Number of levels
+@param alpha Parameter alpha in the paper
+@param beta Parameter beta in the paper
+@return Returns the attenuation matrix Phi if successful, returns NULL otherwise
+*/
+static FIBITMAP* PhiMatrix(FIBITMAP **gradients, float *avgGrad, int nlevels, float alpha, float beta) {
+ float *src_pixel, *dst_pixel;
+ FIBITMAP **phi = NULL;
+
+ try {
+ phi = (FIBITMAP**)malloc(nlevels * sizeof(FIBITMAP*));
+ if(!phi) throw(1);
+ memset(phi, 0, nlevels * sizeof(FIBITMAP*));
+
+ for(int k = nlevels-1; k >= 0; k--) {
+ // compute phi(k)
+
+ FIBITMAP *Gk = gradients[k];
+
+ const unsigned width = FreeImage_GetWidth(Gk);
+ const unsigned height = FreeImage_GetHeight(Gk);
+ const unsigned pitch = FreeImage_GetPitch(Gk) / sizeof(float);
+
+ // parameter alpha is 0.1 times the average gradient magnitude
+ // also, note the factor of 2**k in the denominator;
+ // that is there to correct for the fact that an average gradient avgGrad(H) over 2**k pixels
+ // in the original image will appear as a gradient grad(Hk) = 2**k*avgGrad(H) over a single pixel in Hk.
+ float ALPHA = alpha * avgGrad[k] * (float)((int)1 << k);
+ if(ALPHA == 0) ALPHA = EPSILON;
+
+ phi[k] = FreeImage_AllocateT(FIT_FLOAT, width, height);
+ if(!phi[k]) throw(1);
+
+ src_pixel = (float*)FreeImage_GetBits(Gk);
+ dst_pixel = (float*)FreeImage_GetBits(phi[k]);
+ for(unsigned y = 0; y < height; y++) {
+ for(unsigned x = 0; x < width; x++) {
+ // compute (alpha / grad) * (grad / alpha) ** beta
+ const float v = src_pixel[x] / ALPHA;
+ const float value = (float)pow((float)v, (float)(beta-1));
+ dst_pixel[x] = (value > 1) ? 1 : value;
+ }
+ // next line
+ src_pixel += pitch;
+ dst_pixel += pitch;
+ }
+
+ if(k < nlevels-1) {
+ // compute PHI(k) = L( PHI(k+1) ) * phi(k)
+ FIBITMAP *L = FreeImage_Rescale(phi[k+1], width, height, FILTER_BILINEAR);
+ if(!L) throw(1);
+
+ src_pixel = (float*)FreeImage_GetBits(L);
+ dst_pixel = (float*)FreeImage_GetBits(phi[k]);
+ for(unsigned y = 0; y < height; y++) {
+ for(unsigned x = 0; x < width; x++) {
+ dst_pixel[x] *= src_pixel[x];
+ }
+ // next line
+ src_pixel += pitch;
+ dst_pixel += pitch;
+ }
+
+ FreeImage_Unload(L);
+
+ // PHI(k+1) is no longer needed
+ FreeImage_Unload(phi[k+1]);
+ phi[k+1] = NULL;
+ }
+
+ // next level
+ }
+
+ // get the final result and return
+ FIBITMAP *dst = phi[0];
+
+ free(phi);
+
+ return dst;
+
+ } catch(int) {
+ if(phi) {
+ for(int k = nlevels-1; k >= 0; k--) {
+ if(phi[k]) FreeImage_Unload(phi[k]);
+ }
+ free(phi);
+ }
+ return NULL;
+ }
+}
+
+/**
+Compute gradients in x and y directions, attenuate them with the attenuation matrix,
+then compute the divergence div G from the attenuated gradient.
+@param H Normalized luminance
+@param PHI Attenuation matrix
+@return Returns the divergence matrix if successful, returns NULL otherwise
+*/
+static FIBITMAP* Divergence(FIBITMAP *H, FIBITMAP *PHI) {
+ FIBITMAP *Gx = NULL, *Gy = NULL, *divG = NULL;
+ float *phi, *h, *gx, *gy, *divg;
+
+ try {
+ const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(H);
+ if(image_type != FIT_FLOAT) throw(1);
+
+ const unsigned width = FreeImage_GetWidth(H);
+ const unsigned height = FreeImage_GetHeight(H);
+
+ Gx = FreeImage_AllocateT(image_type, width, height);
+ if(!Gx) throw(1);
+ Gy = FreeImage_AllocateT(image_type, width, height);
+ if(!Gy) throw(1);
+
+ const unsigned pitch = FreeImage_GetPitch(H) / sizeof(float);
+
+ // perform gradient attenuation
+
+ phi = (float*)FreeImage_GetBits(PHI);
+ h = (float*)FreeImage_GetBits(H);
+ gx = (float*)FreeImage_GetBits(Gx);
+ gy = (float*)FreeImage_GetBits(Gy);
+
+ for(unsigned y = 0; y < height; y++) {
+ const unsigned s = (y+1 == height ? y : y+1);
+ for(unsigned x = 0; x < width; x++) {
+ const unsigned e = (x+1 == width ? x : x+1);
+ // forward difference
+ const unsigned index = y*pitch + x;
+ const float phi_xy = phi[index];
+ const float h_xy = h[index];
+ gx[x] = (h[y*pitch+e] - h_xy) * phi_xy; // [H(x+1, y) - H(x, y)] * PHI(x, y)
+ gy[x] = (h[s*pitch+x] - h_xy) * phi_xy; // [H(x, y+1) - H(x, y)] * PHI(x, y)
+ }
+ // next line
+ gx += pitch;
+ gy += pitch;
+ }
+
+ // calculate the divergence
+
+ divG = FreeImage_AllocateT(image_type, width, height);
+ if(!divG) throw(1);
+
+ gx = (float*)FreeImage_GetBits(Gx);
+ gy = (float*)FreeImage_GetBits(Gy);
+ divg = (float*)FreeImage_GetBits(divG);
+
+ for(unsigned y = 0; y < height; y++) {
+ for(unsigned x = 0; x < width; x++) {
+ // backward difference approximation
+ // divG = Gx(x, y) - Gx(x-1, y) + Gy(x, y) - Gy(x, y-1)
+ const unsigned index = y*pitch + x;
+ divg[index] = gx[index] + gy[index];
+ if(x > 0) divg[index] -= gx[index-1];
+ if(y > 0) divg[index] -= gy[index-pitch];
+ }
+ }
+
+ // no longer needed ...
+ FreeImage_Unload(Gx);
+ FreeImage_Unload(Gy);
+
+ // return the divergence
+ return divG;
+
+ } catch(int) {
+ if(Gx) FreeImage_Unload(Gx);
+ if(Gy) FreeImage_Unload(Gy);
+ if(divG) FreeImage_Unload(divG);
+ return NULL;
+ }
+}
+
+/**
+Given the luminance channel, find max & min luminance values,
+normalize to range 0..100 and take the logarithm.
+@param Y Image luminance
+@return Returns the normalized luminance H if successful, returns NULL otherwise
+*/
+static FIBITMAP* LogLuminance(FIBITMAP *Y) {
+ FIBITMAP *H = NULL;
+
+ try {
+ // get the luminance channel
+ FIBITMAP *H = FreeImage_Clone(Y);
+ if(!H) throw(1);
+
+ const unsigned width = FreeImage_GetWidth(H);
+ const unsigned height = FreeImage_GetHeight(H);
+ const unsigned pitch = FreeImage_GetPitch(H);
+
+ // find max & min luminance values
+ float maxLum = -1e20F, minLum = 1e20F;
+
+ BYTE *bits = (BYTE*)FreeImage_GetBits(H);
+ for(unsigned y = 0; y < height; y++) {
+ const float *pixel = (float*)bits;
+ for(unsigned x = 0; x < width; x++) {
+ const float value = pixel[x];
+ maxLum = (maxLum < value) ? value : maxLum; // max Luminance in the scene
+ minLum = (minLum < value) ? minLum : value; // min Luminance in the scene
+ }
+ // next line
+ bits += pitch;
+ }
+ if(maxLum == minLum) throw(1);
+
+ // normalize to range 0..100 and take the logarithm
+ const float scale = 100.F / (maxLum - minLum);
+ bits = (BYTE*)FreeImage_GetBits(H);
+ for(unsigned y = 0; y < height; y++) {
+ float *pixel = (float*)bits;
+ for(unsigned x = 0; x < width; x++) {
+ const float value = (pixel[x] - minLum) * scale;
+ pixel[x] = log(value + EPSILON);
+ }
+ // next line
+ bits += pitch;
+ }
+
+ return H;
+
+ } catch(int) {
+ if(H) FreeImage_Unload(H);
+ return NULL;
+ }
+}
+
+/**
+Given a normalized luminance, perform exponentiation and recover the log compressed image
+@param Y Input/Output luminance image
+*/
+static void ExpLuminance(FIBITMAP *Y) {
+ const unsigned width = FreeImage_GetWidth(Y);
+ const unsigned height = FreeImage_GetHeight(Y);
+ const unsigned pitch = FreeImage_GetPitch(Y);
+
+ BYTE *bits = (BYTE*)FreeImage_GetBits(Y);
+ for(unsigned y = 0; y < height; y++) {
+ float *pixel = (float*)bits;
+ for(unsigned x = 0; x < width; x++) {
+ pixel[x] = exp(pixel[x]) - EPSILON;
+ }
+ bits += pitch;
+ }
+}
+
+// --------------------------------------------------------------------------
+
+/**
+Gradient Domain HDR tone mapping operator
+@param Y Image luminance values
+@param alpha Parameter alpha of the paper (suggested value is 0.1)
+@param beta Parameter beta of the paper (suggested value is between 0.8 and 0.9)
+@return returns the tone mapped luminance
+*/
+static FIBITMAP* tmoFattal02(FIBITMAP *Y, float alpha, float beta) {
+ const unsigned MIN_PYRAMID_SIZE = 32; // minimun size (width or height) of the coarsest level of the pyramid
+
+ FIBITMAP *H = NULL;
+ FIBITMAP **pyramid = NULL;
+ FIBITMAP **gradients = NULL;
+ FIBITMAP *phy = NULL;
+ FIBITMAP *divG = NULL;
+ FIBITMAP *U = NULL;
+ float *avgGrad = NULL;
+
+ int k;
+ int nlevels = 0;
+
+ try {
+ // get the normalized luminance
+ FIBITMAP *H = LogLuminance(Y);
+ if(!H) throw(1);
+
+ // get the number of levels for the pyramid
+ const unsigned width = FreeImage_GetWidth(H);
+ const unsigned height = FreeImage_GetHeight(H);
+ unsigned minsize = MIN(width, height);
+ while(minsize >= MIN_PYRAMID_SIZE) {
+ nlevels++;
+ minsize /= 2;
+ }
+
+ // create the Gaussian pyramid
+ pyramid = (FIBITMAP**)malloc(nlevels * sizeof(FIBITMAP*));
+ if(!pyramid) throw(1);
+ memset(pyramid, 0, nlevels * sizeof(FIBITMAP*));
+
+ if(!GaussianPyramid(H, pyramid, nlevels)) throw(1);
+
+ // calculate gradient magnitude and its average value on each pyramid level
+ gradients = (FIBITMAP**)malloc(nlevels * sizeof(FIBITMAP*));
+ if(!gradients) throw(1);
+ memset(gradients, 0, nlevels * sizeof(FIBITMAP*));
+ avgGrad = (float*)malloc(nlevels * sizeof(float));
+ if(!avgGrad) throw(1);
+
+ if(!GradientPyramid(pyramid, nlevels, gradients, avgGrad)) throw(1);
+
+ // free the Gaussian pyramid
+ for(k = 0; k < nlevels; k++) {
+ if(pyramid[k]) FreeImage_Unload(pyramid[k]);
+ }
+ free(pyramid); pyramid = NULL;
+
+ // compute the gradient attenuation function PHI(x, y)
+ phy = PhiMatrix(gradients, avgGrad, nlevels, alpha, beta);
+ if(!phy) throw(1);
+
+ // free the gradient pyramid
+ for(k = 0; k < nlevels; k++) {
+ if(gradients[k]) FreeImage_Unload(gradients[k]);
+ }
+ free(gradients); gradients = NULL;
+ free(avgGrad); avgGrad = NULL;
+
+ // compute gradients in x and y directions, attenuate them with the attenuation matrix,
+ // then compute the divergence div G from the attenuated gradient.
+ divG = Divergence(H, phy);
+ if(!divG) throw(1);
+
+ // H & phy no longer needed
+ FreeImage_Unload(H); H = NULL;
+ FreeImage_Unload(phy); phy = NULL;
+
+ // solve the PDE (Poisson equation) using a multigrid solver and 3 cycles
+ FIBITMAP *U = FreeImage_MultigridPoissonSolver(divG, 3);
+ if(!U) throw(1);
+
+ FreeImage_Unload(divG);
+
+ // perform exponentiation and recover the log compressed image
+ ExpLuminance(U);
+
+ return U;
+
+ } catch(int) {
+ if(H) FreeImage_Unload(H);
+ if(pyramid) {
+ for(int i = 0; i < nlevels; i++) {
+ if(pyramid[i]) FreeImage_Unload(pyramid[i]);
+ }
+ free(pyramid);
+ }
+ if(gradients) {
+ for(int i = 0; i < nlevels; i++) {
+ if(gradients[i]) FreeImage_Unload(gradients[i]);
+ }
+ free(gradients);
+ }
+ if(avgGrad) free(avgGrad);
+ if(phy) FreeImage_Unload(phy);
+ if(divG) FreeImage_Unload(divG);
+ if(U) FreeImage_Unload(U);
+
+ return NULL;
+ }
+}
+
+// ----------------------------------------------------------
+// Main algorithm
+// ----------------------------------------------------------
+
+/**
+Apply the Gradient Domain High Dynamic Range Compression to a RGBF image and convert to 24-bit RGB
+@param dib Input RGBF / RGB16 image
+@param color_saturation Color saturation (s parameter in the paper) in [0.4..0.6]
+@param attenuation Atenuation factor (beta parameter in the paper) in [0.8..0.9]
+@return Returns a 24-bit RGB image if successful, returns NULL otherwise
+*/
+FIBITMAP* DLL_CALLCONV
+FreeImage_TmoFattal02(FIBITMAP *dib, double color_saturation, double attenuation) {
+ const float alpha = 0.1F; // parameter alpha = 0.1
+ const float beta = (float)MAX(0.8, MIN(0.9, attenuation)); // parameter beta = [0.8..0.9]
+ const float s = (float)MAX(0.4, MIN(0.6, color_saturation));// exponent s controls color saturation = [0.4..0.6]
+
+ FIBITMAP *src = NULL;
+ FIBITMAP *Yin = NULL;
+ FIBITMAP *Yout = NULL;
+ FIBITMAP *dst = NULL;
+
+ if(!FreeImage_HasPixels(dib)) return NULL;
+
+ try {
+
+ // convert to RGBF
+ src = FreeImage_ConvertToRGBF(dib);
+ if(!src) throw(1);
+
+ // get the luminance channel
+ Yin = ConvertRGBFToY(src);
+ if(!Yin) throw(1);
+
+ // perform the tone mapping
+ Yout = tmoFattal02(Yin, alpha, beta);
+ if(!Yout) throw(1);
+
+ // clip low and high values and normalize to [0..1]
+ //NormalizeY(Yout, 0.001F, 0.995F);
+ NormalizeY(Yout, 0, 1);
+
+ // compress the dynamic range
+
+ const unsigned width = FreeImage_GetWidth(src);
+ const unsigned height = FreeImage_GetHeight(src);
+
+ const unsigned rgb_pitch = FreeImage_GetPitch(src);
+ const unsigned y_pitch = FreeImage_GetPitch(Yin);
+
+ BYTE *bits = (BYTE*)FreeImage_GetBits(src);
+ BYTE *bits_yin = (BYTE*)FreeImage_GetBits(Yin);
+ BYTE *bits_yout = (BYTE*)FreeImage_GetBits(Yout);
+
+ for(unsigned y = 0; y < height; y++) {
+ float *Lin = (float*)bits_yin;
+ float *Lout = (float*)bits_yout;
+ float *color = (float*)bits;
+ for(unsigned x = 0; x < width; x++) {
+ for(unsigned c = 0; c < 3; c++) {
+ *color = (Lin[x] > 0) ? pow(*color/Lin[x], s) * Lout[x] : 0;
+ color++;
+ }
+ }
+ bits += rgb_pitch;
+ bits_yin += y_pitch;
+ bits_yout += y_pitch;
+ }
+
+ // not needed anymore
+ FreeImage_Unload(Yin); Yin = NULL;
+ FreeImage_Unload(Yout); Yout = NULL;
+
+ // clamp image highest values to display white, then convert to 24-bit RGB
+ dst = ClampConvertRGBFTo24(src);
+
+ // clean-up and return
+ FreeImage_Unload(src); src = NULL;
+
+ // copy metadata from src to dst
+ FreeImage_CloneMetadata(dst, dib);
+
+ return dst;
+
+ } catch(int) {
+ if(src) FreeImage_Unload(src);
+ if(Yin) FreeImage_Unload(Yin);
+ if(Yout) FreeImage_Unload(Yout);
+ return NULL;
+ }
+}