summaryrefslogtreecommitdiff
path: root/plugins/AdvaImg
diff options
context:
space:
mode:
authorKirill Volinsky <mataes2007@gmail.com>2015-05-18 07:31:16 +0000
committerKirill Volinsky <mataes2007@gmail.com>2015-05-18 07:31:16 +0000
commit76b86227951fdb5096572c36a256f07aee76def3 (patch)
tree713dcf30179d88b685605bdc8a03a5068832e4ff /plugins/AdvaImg
parent4b289716d4cdd6b3ea29aec8d50e0b69afdc8384 (diff)
git-svn-id: http://svn.miranda-ng.org/main/trunk@13671 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/AdvaImg')
-rw-r--r--plugins/AdvaImg/AdvaImg_10.vcxproj3
-rw-r--r--plugins/AdvaImg/AdvaImg_10.vcxproj.filters9
-rw-r--r--plugins/AdvaImg/AdvaImg_12.vcxproj3
-rw-r--r--plugins/AdvaImg/AdvaImg_12.vcxproj.filters51
-rw-r--r--plugins/AdvaImg/Docs/Whatsnew.txt49
-rw-r--r--plugins/AdvaImg/src/FreeImage.h265
-rw-r--r--plugins/AdvaImg/src/FreeImage/BitmapAccess.cpp427
-rw-r--r--plugins/AdvaImg/src/FreeImage/ColorLookup.cpp337
-rw-r--r--plugins/AdvaImg/src/FreeImage/Conversion.cpp66
-rw-r--r--plugins/AdvaImg/src/FreeImage/ConversionType.cpp10
-rw-r--r--plugins/AdvaImg/src/FreeImage/FreeImageIO.cpp49
-rw-r--r--plugins/AdvaImg/src/FreeImage/LFPQuantizer.cpp208
-rw-r--r--plugins/AdvaImg/src/FreeImage/MNGHelper.cpp27
-rw-r--r--plugins/AdvaImg/src/FreeImage/MemoryIO.cpp4
-rw-r--r--plugins/AdvaImg/src/FreeImage/MultiPage.cpp22
-rw-r--r--plugins/AdvaImg/src/FreeImage/PixelAccess.cpp13
-rw-r--r--plugins/AdvaImg/src/FreeImage/Plugin.cpp22
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginEXR.cpp111
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginG3.cpp2
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginGIF.cpp13
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginHDR.cpp3
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginICO.cpp24
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginJ2K.cpp27
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginJP2.cpp29
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginJPEG.cpp27
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginJXR.cpp184
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginPFM.cpp31
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginPICT.cpp19
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginPNG.cpp442
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginPNM.cpp31
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginRAW.cpp250
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginTARGA.cpp46
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginTIFF.cpp62
-rw-r--r--plugins/AdvaImg/src/FreeImage/WuQuantizer.cpp53
-rw-r--r--plugins/AdvaImg/src/FreeImageIO.h31
-rw-r--r--plugins/AdvaImg/src/FreeImageToolkit/Background.cpp12
-rw-r--r--plugins/AdvaImg/src/FreeImageToolkit/CopyPaste.cpp116
-rw-r--r--plugins/AdvaImg/src/FreeImageToolkit/JPEGTransform.cpp1230
-rw-r--r--plugins/AdvaImg/src/FreeImageToolkit/Rescale.cpp41
-rw-r--r--plugins/AdvaImg/src/FreeImageToolkit/Resize.cpp4114
-rw-r--r--plugins/AdvaImg/src/FreeImageToolkit/Resize.h392
-rw-r--r--plugins/AdvaImg/src/MapIntrospector.h212
-rw-r--r--plugins/AdvaImg/src/Metadata/Exif.cpp478
-rw-r--r--plugins/AdvaImg/src/Metadata/FreeImageTag.cpp33
-rw-r--r--plugins/AdvaImg/src/Metadata/FreeImageTag.h25
-rw-r--r--plugins/AdvaImg/src/Metadata/XTIFF.cpp313
-rw-r--r--plugins/AdvaImg/src/Quantizers.h129
-rw-r--r--plugins/AdvaImg/src/Utilities.h47
48 files changed, 6139 insertions, 3953 deletions
diff --git a/plugins/AdvaImg/AdvaImg_10.vcxproj b/plugins/AdvaImg/AdvaImg_10.vcxproj
index ad8f30c192..37cf1843a9 100644
--- a/plugins/AdvaImg/AdvaImg_10.vcxproj
+++ b/plugins/AdvaImg/AdvaImg_10.vcxproj
@@ -190,10 +190,13 @@
<ClCompile Include="src\FreeImage\ColorLookup.cpp" />
<ClCompile Include="src\FreeImage\ConversionFloat.cpp" />
<ClCompile Include="src\FreeImage\ConversionRGB16.cpp" />
+ <ClCompile Include="src\FreeImage\ConversionRGBA16.cpp" />
+ <ClCompile Include="src\FreeImage\ConversionRGBAF.cpp" />
<ClCompile Include="src\FreeImage\ConversionUINT16.cpp" />
<ClCompile Include="src\FreeImage\FreeImage.cpp" />
<ClCompile Include="src\FreeImage\FreeImageIO.cpp" />
<ClCompile Include="src\FreeImage\GetType.cpp" />
+ <ClCompile Include="src\FreeImage\LFPQuantizer.cpp" />
<ClCompile Include="src\FreeImage\MemoryIO.cpp" />
<ClCompile Include="src\FreeImage\PixelAccess.cpp" />
<ClCompile Include="src\FreeImage\Plugin.cpp" />
diff --git a/plugins/AdvaImg/AdvaImg_10.vcxproj.filters b/plugins/AdvaImg/AdvaImg_10.vcxproj.filters
index c90205fc3b..d99cac1b16 100644
--- a/plugins/AdvaImg/AdvaImg_10.vcxproj.filters
+++ b/plugins/AdvaImg/AdvaImg_10.vcxproj.filters
@@ -119,6 +119,12 @@
<ClCompile Include="src\FreeImage\ConversionRGBF.cpp">
<Filter>Source Files\Conversion</Filter>
</ClCompile>
+ <ClCompile Include="src\FreeImage\ConversionRGBA16.cpp">
+ <Filter>Source Files\Conversion</Filter>
+ </ClCompile>
+ <ClCompile Include="src\FreeImage\ConversionRGBAF.cpp">
+ <Filter>Source Files\Conversion</Filter>
+ </ClCompile>
<ClCompile Include="src\FreeImage\ConversionType.cpp">
<Filter>Source Files\Conversion</Filter>
</ClCompile>
@@ -143,6 +149,9 @@
<ClCompile Include="src\FreeImage\ToneMapping.cpp">
<Filter>Source Files\Conversion</Filter>
</ClCompile>
+ <ClCompile Include="src\FreeImage\LFPQuantizer.cpp">
+ <Filter>Source Files\Quantizers</Filter>
+ </ClCompile>
<ClCompile Include="src\FreeImage\NNQuantizer.cpp">
<Filter>Source Files\Quantizers</Filter>
</ClCompile>
diff --git a/plugins/AdvaImg/AdvaImg_12.vcxproj b/plugins/AdvaImg/AdvaImg_12.vcxproj
index b887d1831f..3f34191495 100644
--- a/plugins/AdvaImg/AdvaImg_12.vcxproj
+++ b/plugins/AdvaImg/AdvaImg_12.vcxproj
@@ -187,10 +187,13 @@
<ClCompile Include="src\FreeImage\ColorLookup.cpp" />
<ClCompile Include="src\FreeImage\ConversionFloat.cpp" />
<ClCompile Include="src\FreeImage\ConversionRGB16.cpp" />
+ <ClCompile Include="src\FreeImage\ConversionRGBA16.cpp" />
+ <ClCompile Include="src\FreeImage\ConversionRGBAF.cpp" />
<ClCompile Include="src\FreeImage\ConversionUINT16.cpp" />
<ClCompile Include="src\FreeImage\FreeImage.cpp" />
<ClCompile Include="src\FreeImage\FreeImageIO.cpp" />
<ClCompile Include="src\FreeImage\GetType.cpp" />
+ <ClCompile Include="src\FreeImage\LFPQuantizer.cpp" />
<ClCompile Include="src\FreeImage\MemoryIO.cpp" />
<ClCompile Include="src\FreeImage\PixelAccess.cpp" />
<ClCompile Include="src\FreeImage\Plugin.cpp" />
diff --git a/plugins/AdvaImg/AdvaImg_12.vcxproj.filters b/plugins/AdvaImg/AdvaImg_12.vcxproj.filters
index c90205fc3b..e92ec756ea 100644
--- a/plugins/AdvaImg/AdvaImg_12.vcxproj.filters
+++ b/plugins/AdvaImg/AdvaImg_12.vcxproj.filters
@@ -119,6 +119,21 @@
<ClCompile Include="src\FreeImage\ConversionRGBF.cpp">
<Filter>Source Files\Conversion</Filter>
</ClCompile>
+ <ClCompile Include="src\FreeImage\ConversionRGBA16.cpp">
+ <Filter>Source Files\Conversion</Filter>
+ </ClCompile>
+ <ClCompile Include="src\FreeImage\ConversionFloat.cpp">
+ <Filter>Source Files\Conversion</Filter>
+ </ClCompile>
+ <ClCompile Include="src\FreeImage\ConversionRGB16.cpp">
+ <Filter>Source Files\Conversion</Filter>
+ </ClCompile>
+ <ClCompile Include="src\FreeImage\ConversionUINT16.cpp">
+ <Filter>Source Files\Conversion</Filter>
+ </ClCompile>
+ <ClCompile Include="src\FreeImage\ConversionRGBAF.cpp">
+ <Filter>Source Files\Conversion</Filter>
+ </ClCompile>
<ClCompile Include="src\FreeImage\ConversionType.cpp">
<Filter>Source Files\Conversion</Filter>
</ClCompile>
@@ -143,6 +158,9 @@
<ClCompile Include="src\FreeImage\ToneMapping.cpp">
<Filter>Source Files\Conversion</Filter>
</ClCompile>
+ <ClCompile Include="src\FreeImage\LFPQuantizer.cpp">
+ <Filter>Source Files\Quantizers</Filter>
+ </ClCompile>
<ClCompile Include="src\FreeImage\NNQuantizer.cpp">
<Filter>Source Files\Quantizers</Filter>
</ClCompile>
@@ -344,6 +362,18 @@
<ClCompile Include="src\LibJPEG\wrtarga.c">
<Filter>Source Files\LibJPEG\Source Files</Filter>
</ClCompile>
+ <ClCompile Include="src\LibJPEG\jaricom.c">
+ <Filter>Source Files\LibJPEG\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\LibJPEG\jcarith.c">
+ <Filter>Source Files\LibJPEG\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\LibJPEG\jdarith.c">
+ <Filter>Source Files\LibJPEG\Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\LibJPEG\jdhuff.c">
+ <Filter>Source Files\LibJPEG\Source Files</Filter>
+ </ClCompile>
<ClCompile Include="src\LibPNG\png.c">
<Filter>Source Files\LibPNG\Source Files</Filter>
</ClCompile>
@@ -419,27 +449,6 @@
<ClCompile Include="src\FreeImageToolkit\Resize.cpp">
<Filter>Toolkit Files</Filter>
</ClCompile>
- <ClCompile Include="src\LibJPEG\jaricom.c">
- <Filter>Source Files\LibJPEG\Source Files</Filter>
- </ClCompile>
- <ClCompile Include="src\LibJPEG\jcarith.c">
- <Filter>Source Files\LibJPEG\Source Files</Filter>
- </ClCompile>
- <ClCompile Include="src\LibJPEG\jdarith.c">
- <Filter>Source Files\LibJPEG\Source Files</Filter>
- </ClCompile>
- <ClCompile Include="src\LibJPEG\jdhuff.c">
- <Filter>Source Files\LibJPEG\Source Files</Filter>
- </ClCompile>
- <ClCompile Include="src\FreeImage\ConversionFloat.cpp">
- <Filter>Source Files\Conversion</Filter>
- </ClCompile>
- <ClCompile Include="src\FreeImage\ConversionRGB16.cpp">
- <Filter>Source Files\Conversion</Filter>
- </ClCompile>
- <ClCompile Include="src\FreeImage\ConversionUINT16.cpp">
- <Filter>Source Files\Conversion</Filter>
- </ClCompile>
<ClCompile Include="src\FreeImageToolkit\Background.cpp">
<Filter>Toolkit Files</Filter>
</ClCompile>
diff --git a/plugins/AdvaImg/Docs/Whatsnew.txt b/plugins/AdvaImg/Docs/Whatsnew.txt
index d761069a64..83515452ac 100644
--- a/plugins/AdvaImg/Docs/Whatsnew.txt
+++ b/plugins/AdvaImg/Docs/Whatsnew.txt
@@ -5,6 +5,55 @@ What's New for FreeImage
! : changed
+ : added
+March 15th, 2015 - 3.17.0
+! FreeImage now uses LibPNG 1.6.16
+! FreeImage now uses LibWebP 0.4.2 (GIT patch 2015-03-03)
+! FreeImage now uses LibRaw 0.17-Alpha1
+! FreeImage now uses LibTIFF 4.0.4 (CVS patch 2015-01-26)
+! FreeImage now uses OpenEXR 2.2.0
+- [Herve Drolon] removed VS 2003 project files : this IDE is no longer supported because of its outdated C++ compiler
++ [Mihail Naydenov] added FreeImage_ConvertFromRawBitsEx
++ [Herve Drolon] added RAW_UNPROCESSED load flag to the RAW plugin
++ [Herve Drolon] added FreeImage_SetMetadataKeyValue
++ [Herve Drolon] added support for metadata writing to the JPEG-JXR plugin
++ [Herve Drolon] added VS 2013 project files
++ [Herve Drolon] added support for PNG tIME metadata (read/write, handle as Exif-TIFF DateTime)
++ [Carsten Klein] added explicit definition of endianness and color order in compiler options
++ [Carsten Klein] added FIQ_LFPQUANT quantizer algorithm
++ [Carsten Klein] added support for input 32-bit dib in Wu quantizer
++ [Tanner Helland] added FreeImage_ConvertToRGBAF and updated conversions in FreeImage_ConvertToType
++ [Herve Drolon] added FreeImage_ConvertToRGBA16 and updated conversions in FreeImage_ConvertToType
++ [Carsten Klein] added FreeImage_CreateView
++ [Carsten Klein] added FreeImage_RescaleRect
++ [Carsten Klein] added FreeImage_GetMemorySize
+* [Tanner Helland] ICO plugin: improved support for Vista icons
+* [fpgaminer] fixed a rounding error in RGB to greyscale conversion formula
+* [Sven-Hendrik Haase] fixed Makefile.fip so that it installs symlinks
+* [Joachim Reichel] fixed a potential memory access violation in PluginHDR Save function
+* [Christian Schluchter] fixed a bug in FreeImage_LookupSVGColor ("green" color was not found)
+* [Marco Altomonte] fixed TARGA signature validation for TARGA versions < 2.0
+* [Jeremy Reyniers] fixed FreeImage_GetScanLine not working with very large images on x64 platforms
+* [Herve Drolon] improved PluginTIFF compatibility with LibTIFF 4
+* [Aaron Shumate] fixed a segfault occuring on a corrupted animated GIF
+* [Herve Drolon] improved memory allocation in PluginRAW
+* [Herve Drolon] fixed loading/saving of TIFF containing a GPS IFD inside the Exif-TIFF metadata segment (the solution is to ignore the tag)
+* [Mihail Naydenov] fixed a bug in FreeImage_JPEGCrop*/_JPEGTransform* functions occuring when using the same source / destination filename
+* [Herve Drolon] fixed a bug with output image quality in PluginJP2::Save & PluginJ2K::Save functions (regression from FI 3.15.4)
+* [Herve Drolon] improved RAW file format detection
+* [Aaron Shumate] fixed FreeImage_GetFileType behavior with ANI file formats
+* [Herve Drolon] improved Exif reader so as to handle Exif IFD with a suspicious offset (can occur with maker notes)
+* [Herve Drolon] fixed a memory leak in PluginPNG:Save occuring when dealing with invalid PNG files
+* [Tanner Helland] fixed PNG plugin handling of 16-bit grayscale + 16-bit alpha images
+* [Tanner Helland] fixed PNG plugin handling of 16-bit grayscale + tRNS chunk images
+* [Tanner Helland] fixed PNG plugin handling of 24-bit RGB + tRNS chunk images
+* [Tanner Helland] fixed PNG plugin handling of 1-,4-bit greyscale/palettized + tRNS chunk images
+* [ekpyron] fixed invalid directory delimiter in include statement (mingw-w64) in Source/LibJXR/image/sys/strcodec.h
+* [ekpyron] fixed Invalid condition for defining _byteswap_ulong (mingw-w64) in Source/LibJXR/image/sys/strcodec.c
+* [tostercx] fixed FreeImage_Get*Mask not returning 0 for greyscale images
+* [robpats] fixed loading of external plugins when using UNICODE directory names to store plugins
+* [Herve Drolon] fixed loading of JXR files when using memory streams
+* [Carsten Klein] added Dist/ directory creation in Makefiles (in case it is not already present)
+
March 23rd, 2014 - 3.16.0
! FreeImage now uses LibJPEG 9a
! FreeImage now uses LibPNG 1.6.10
diff --git a/plugins/AdvaImg/src/FreeImage.h b/plugins/AdvaImg/src/FreeImage.h
index 80a5d07514..fa70ea9f39 100644
--- a/plugins/AdvaImg/src/FreeImage.h
+++ b/plugins/AdvaImg/src/FreeImage.h
@@ -29,7 +29,7 @@
// Version information ------------------------------------------------------
#define FREEIMAGE_MAJOR_VERSION 3
-#define FREEIMAGE_MINOR_VERSION 16
+#define FREEIMAGE_MINOR_VERSION 17
#define FREEIMAGE_RELEASE_SERIAL 0
// Compiler options ---------------------------------------------------------
@@ -69,22 +69,36 @@
#endif // WIN32 / !WIN32
#endif // FREEIMAGE_LIB
-// Some versions of gcc may have BYTE_ORDER or __BYTE_ORDER defined
+// Endianness:
+// Some versions of gcc may have BYTE_ORDER or __BYTE_ORDER defined.
// If your big endian system isn't being detected, add an OS specific check
-#if (defined(BYTE_ORDER) && BYTE_ORDER==BIG_ENDIAN) || \
- (defined(__BYTE_ORDER) && __BYTE_ORDER==__BIG_ENDIAN) || \
- defined(__BIG_ENDIAN__)
-#define FREEIMAGE_BIGENDIAN
-#endif // BYTE_ORDER
-
-// This really only affects 24 and 32 bit formats, the rest are always RGB order.
-#define FREEIMAGE_COLORORDER_BGR 0
-#define FREEIMAGE_COLORORDER_RGB 1
-#if defined(FREEIMAGE_BIGENDIAN)
-#define FREEIMAGE_COLORORDER FREEIMAGE_COLORORDER_RGB
-#else
-#define FREEIMAGE_COLORORDER FREEIMAGE_COLORORDER_BGR
-#endif
+// or define any of FREEIMAGE_BIGENDIAN and FREEIMAGE_LITTLEENDIAN directly
+// to specify the desired endianness.
+#if (!defined(FREEIMAGE_BIGENDIAN) && !defined(FREEIMAGE_LITTLEENDIAN))
+ #if (defined(BYTE_ORDER) && BYTE_ORDER==BIG_ENDIAN) || (defined(__BYTE_ORDER) && __BYTE_ORDER==__BIG_ENDIAN) || defined(__BIG_ENDIAN__)
+ #define FREEIMAGE_BIGENDIAN
+ #endif // BYTE_ORDER
+#endif // !FREEIMAGE_[BIG|LITTLE]ENDIAN
+
+// Color-Order:
+// The specified order of color components red, green and blue affects 24-
+// and 32-bit images of type FIT_BITMAP as well as the colors that are part
+// of a color palette. All other images always use RGB order. By default,
+// color order is coupled to endianness:
+// little-endian -> BGR
+// big-endian -> RGB
+// However, you can always define FREEIMAGE_COLORORDER to any of the known
+// orders FREEIMAGE_COLORORDER_BGR (0) and FREEIMAGE_COLORORDER_RGB (1) to
+// specify your preferred color order.
+#define FREEIMAGE_COLORORDER_BGR 0
+#define FREEIMAGE_COLORORDER_RGB 1
+#if (!defined(FREEIMAGE_COLORORDER)) || ((FREEIMAGE_COLORORDER != FREEIMAGE_COLORORDER_BGR) && (FREEIMAGE_COLORORDER != FREEIMAGE_COLORORDER_RGB))
+ #if defined(FREEIMAGE_BIGENDIAN)
+ #define FREEIMAGE_COLORORDER FREEIMAGE_COLORORDER_RGB
+ #else
+ #define FREEIMAGE_COLORORDER FREEIMAGE_COLORORDER_BGR
+ #endif // FREEIMAGE_BIGENDIAN
+#endif // FREEIMAGE_COLORORDER
// Ensure 4-byte enums if we're using Borland C++ compilers
#if defined(__BORLANDC__)
@@ -357,9 +371,9 @@ typedef struct tagFICOMPLEX {
#define FIICC_COLOR_IS_CMYK 0x01
FI_STRUCT (FIICCPROFILE) {
- WORD flags; // info flag
- DWORD size; // profile's size measured in bytes
- void *data; // points to a block of contiguous memory containing the profile
+ WORD flags; //! info flag
+ DWORD size; //! profile's size measured in bytes
+ void *data; //! points to a block of contiguous memory containing the profile
};
// Important enums ----------------------------------------------------------
@@ -411,102 +425,103 @@ FI_ENUM(FREE_IMAGE_FORMAT) {
/** Image type used in FreeImage.
*/
FI_ENUM(FREE_IMAGE_TYPE) {
- FIT_UNKNOWN = 0, // unknown type
- FIT_BITMAP = 1, // standard image : 1-, 4-, 8-, 16-, 24-, 32-bit
- FIT_UINT16 = 2, // array of unsigned short : unsigned 16-bit
- FIT_INT16 = 3, // array of short : signed 16-bit
- FIT_UINT32 = 4, // array of unsigned long : unsigned 32-bit
- FIT_INT32 = 5, // array of long : signed 32-bit
- FIT_FLOAT = 6, // array of float : 32-bit IEEE floating point
- FIT_DOUBLE = 7, // array of double : 64-bit IEEE floating point
- FIT_COMPLEX = 8, // array of FICOMPLEX : 2 x 64-bit IEEE floating point
- FIT_RGB16 = 9, // 48-bit RGB image : 3 x 16-bit
- FIT_RGBA16 = 10, // 64-bit RGBA image : 4 x 16-bit
- FIT_RGBF = 11, // 96-bit RGB float image : 3 x 32-bit IEEE floating point
- FIT_RGBAF = 12 // 128-bit RGBA float image : 4 x 32-bit IEEE floating point
+ FIT_UNKNOWN = 0, //! unknown type
+ FIT_BITMAP = 1, //! standard image : 1-, 4-, 8-, 16-, 24-, 32-bit
+ FIT_UINT16 = 2, //! array of unsigned short : unsigned 16-bit
+ FIT_INT16 = 3, //! array of short : signed 16-bit
+ FIT_UINT32 = 4, //! array of unsigned long : unsigned 32-bit
+ FIT_INT32 = 5, //! array of long : signed 32-bit
+ FIT_FLOAT = 6, //! array of float : 32-bit IEEE floating point
+ FIT_DOUBLE = 7, //! array of double : 64-bit IEEE floating point
+ FIT_COMPLEX = 8, //! array of FICOMPLEX : 2 x 64-bit IEEE floating point
+ FIT_RGB16 = 9, //! 48-bit RGB image : 3 x 16-bit
+ FIT_RGBA16 = 10, //! 64-bit RGBA image : 4 x 16-bit
+ FIT_RGBF = 11, //! 96-bit RGB float image : 3 x 32-bit IEEE floating point
+ FIT_RGBAF = 12 //! 128-bit RGBA float image : 4 x 32-bit IEEE floating point
};
/** Image color type used in FreeImage.
*/
FI_ENUM(FREE_IMAGE_COLOR_TYPE) {
- FIC_MINISWHITE = 0, // min value is white
- FIC_MINISBLACK = 1, // min value is black
- FIC_RGB = 2, // RGB color model
- FIC_PALETTE = 3, // color map indexed
- FIC_RGBALPHA = 4, // RGB color model with alpha channel
- FIC_CMYK = 5 // CMYK color model
+ FIC_MINISWHITE = 0, //! min value is white
+ FIC_MINISBLACK = 1, //! min value is black
+ FIC_RGB = 2, //! RGB color model
+ FIC_PALETTE = 3, //! color map indexed
+ FIC_RGBALPHA = 4, //! RGB color model with alpha channel
+ FIC_CMYK = 5 //! CMYK color model
};
/** Color quantization algorithms.
Constants used in FreeImage_ColorQuantize.
*/
FI_ENUM(FREE_IMAGE_QUANTIZE) {
- FIQ_WUQUANT = 0, // Xiaolin Wu color quantization algorithm
- FIQ_NNQUANT = 1 // NeuQuant neural-net quantization algorithm by Anthony Dekker
+ FIQ_WUQUANT = 0, //! Xiaolin Wu color quantization algorithm
+ FIQ_NNQUANT = 1, //! NeuQuant neural-net quantization algorithm by Anthony Dekker
+ FIQ_LFPQUANT = 2 //! Lossless Fast Pseudo-Quantization Algorithm by Carsten Klein
};
/** Dithering algorithms.
Constants used in FreeImage_Dither.
*/
FI_ENUM(FREE_IMAGE_DITHER) {
- FID_FS = 0, // Floyd & Steinberg error diffusion
- FID_BAYER4x4 = 1, // Bayer ordered dispersed dot dithering (order 2 dithering matrix)
- FID_BAYER8x8 = 2, // Bayer ordered dispersed dot dithering (order 3 dithering matrix)
- FID_CLUSTER6x6 = 3, // Ordered clustered dot dithering (order 3 - 6x6 matrix)
- FID_CLUSTER8x8 = 4, // Ordered clustered dot dithering (order 4 - 8x8 matrix)
- FID_CLUSTER16x16= 5, // Ordered clustered dot dithering (order 8 - 16x16 matrix)
- FID_BAYER16x16 = 6 // Bayer ordered dispersed dot dithering (order 4 dithering matrix)
+ FID_FS = 0, //! Floyd & Steinberg error diffusion
+ FID_BAYER4x4 = 1, //! Bayer ordered dispersed dot dithering (order 2 dithering matrix)
+ FID_BAYER8x8 = 2, //! Bayer ordered dispersed dot dithering (order 3 dithering matrix)
+ FID_CLUSTER6x6 = 3, //! Ordered clustered dot dithering (order 3 - 6x6 matrix)
+ FID_CLUSTER8x8 = 4, //! Ordered clustered dot dithering (order 4 - 8x8 matrix)
+ FID_CLUSTER16x16= 5, //! Ordered clustered dot dithering (order 8 - 16x16 matrix)
+ FID_BAYER16x16 = 6 //! Bayer ordered dispersed dot dithering (order 4 dithering matrix)
};
/** Lossless JPEG transformations
Constants used in FreeImage_JPEGTransform
*/
FI_ENUM(FREE_IMAGE_JPEG_OPERATION) {
- FIJPEG_OP_NONE = 0, // no transformation
- FIJPEG_OP_FLIP_H = 1, // horizontal flip
- FIJPEG_OP_FLIP_V = 2, // vertical flip
- FIJPEG_OP_TRANSPOSE = 3, // transpose across UL-to-LR axis
- FIJPEG_OP_TRANSVERSE = 4, // transpose across UR-to-LL axis
- FIJPEG_OP_ROTATE_90 = 5, // 90-degree clockwise rotation
- FIJPEG_OP_ROTATE_180 = 6, // 180-degree rotation
- FIJPEG_OP_ROTATE_270 = 7 // 270-degree clockwise (or 90 ccw)
+ FIJPEG_OP_NONE = 0, //! no transformation
+ FIJPEG_OP_FLIP_H = 1, //! horizontal flip
+ FIJPEG_OP_FLIP_V = 2, //! vertical flip
+ FIJPEG_OP_TRANSPOSE = 3, //! transpose across UL-to-LR axis
+ FIJPEG_OP_TRANSVERSE = 4, //! transpose across UR-to-LL axis
+ FIJPEG_OP_ROTATE_90 = 5, //! 90-degree clockwise rotation
+ FIJPEG_OP_ROTATE_180 = 6, //! 180-degree rotation
+ FIJPEG_OP_ROTATE_270 = 7 //! 270-degree clockwise (or 90 ccw)
};
/** Tone mapping operators.
Constants used in FreeImage_ToneMapping.
*/
FI_ENUM(FREE_IMAGE_TMO) {
- FITMO_DRAGO03 = 0, // Adaptive logarithmic mapping (F. Drago, 2003)
- FITMO_REINHARD05 = 1, // Dynamic range reduction inspired by photoreceptor physiology (E. Reinhard, 2005)
- FITMO_FATTAL02 = 2 // Gradient domain high dynamic range compression (R. Fattal, 2002)
+ FITMO_DRAGO03 = 0, //! Adaptive logarithmic mapping (F. Drago, 2003)
+ FITMO_REINHARD05 = 1, //! Dynamic range reduction inspired by photoreceptor physiology (E. Reinhard, 2005)
+ FITMO_FATTAL02 = 2 //! Gradient domain high dynamic range compression (R. Fattal, 2002)
};
/** Upsampling / downsampling filters.
Constants used in FreeImage_Rescale.
*/
FI_ENUM(FREE_IMAGE_FILTER) {
- FILTER_BOX = 0, // Box, pulse, Fourier window, 1st order (constant) b-spline
- FILTER_BICUBIC = 1, // Mitchell & Netravali's two-param cubic filter
- FILTER_BILINEAR = 2, // Bilinear filter
- FILTER_BSPLINE = 3, // 4th order (cubic) b-spline
- FILTER_CATMULLROM = 4, // Catmull-Rom spline, Overhauser spline
- FILTER_LANCZOS3 = 5 // Lanczos3 filter
+ FILTER_BOX = 0, //! Box, pulse, Fourier window, 1st order (constant) b-spline
+ FILTER_BICUBIC = 1, //! Mitchell & Netravali's two-param cubic filter
+ FILTER_BILINEAR = 2, //! Bilinear filter
+ FILTER_BSPLINE = 3, //! 4th order (cubic) b-spline
+ FILTER_CATMULLROM = 4, //! Catmull-Rom spline, Overhauser spline
+ FILTER_LANCZOS3 = 5 //! Lanczos3 filter
};
/** Color channels.
Constants used in color manipulation routines.
*/
FI_ENUM(FREE_IMAGE_COLOR_CHANNEL) {
- FICC_RGB = 0, // Use red, green and blue channels
- FICC_RED = 1, // Use red channel
- FICC_GREEN = 2, // Use green channel
- FICC_BLUE = 3, // Use blue channel
- FICC_ALPHA = 4, // Use alpha channel
- FICC_BLACK = 5, // Use black channel
- FICC_REAL = 6, // Complex images: use real part
- FICC_IMAG = 7, // Complex images: use imaginary part
- FICC_MAG = 8, // Complex images: use magnitude
- FICC_PHASE = 9 // Complex images: use phase
+ FICC_RGB = 0, //! Use red, green and blue channels
+ FICC_RED = 1, //! Use red channel
+ FICC_GREEN = 2, //! Use green channel
+ FICC_BLUE = 3, //! Use blue channel
+ FICC_ALPHA = 4, //! Use alpha channel
+ FICC_BLACK = 5, //! Use black channel
+ FICC_REAL = 6, //! Complex images: use real part
+ FICC_IMAG = 7, //! Complex images: use imaginary part
+ FICC_MAG = 8, //! Complex images: use magnitude
+ FICC_PHASE = 9 //! Complex images: use phase
};
// Metadata support ---------------------------------------------------------
@@ -517,24 +532,24 @@ FI_ENUM(FREE_IMAGE_COLOR_CHANNEL) {
Note: RATIONALs are the ratio of two 32-bit integer values.
*/
FI_ENUM(FREE_IMAGE_MDTYPE) {
- FIDT_NOTYPE = 0, // placeholder
- FIDT_BYTE = 1, // 8-bit unsigned integer
- FIDT_ASCII = 2, // 8-bit bytes w/ last byte null
- FIDT_SHORT = 3, // 16-bit unsigned integer
- FIDT_LONG = 4, // 32-bit unsigned integer
- FIDT_RATIONAL = 5, // 64-bit unsigned fraction
- FIDT_SBYTE = 6, // 8-bit signed integer
- FIDT_UNDEFINED = 7, // 8-bit untyped data
- FIDT_SSHORT = 8, // 16-bit signed integer
- FIDT_SLONG = 9, // 32-bit signed integer
- FIDT_SRATIONAL = 10, // 64-bit signed fraction
- FIDT_FLOAT = 11, // 32-bit IEEE floating point
- FIDT_DOUBLE = 12, // 64-bit IEEE floating point
- FIDT_IFD = 13, // 32-bit unsigned integer (offset)
- FIDT_PALETTE = 14, // 32-bit RGBQUAD
- FIDT_LONG8 = 16, // 64-bit unsigned integer
- FIDT_SLONG8 = 17, // 64-bit signed integer
- FIDT_IFD8 = 18 // 64-bit unsigned integer (offset)
+ FIDT_NOTYPE = 0, //! placeholder
+ FIDT_BYTE = 1, //! 8-bit unsigned integer
+ FIDT_ASCII = 2, //! 8-bit bytes w/ last byte null
+ FIDT_SHORT = 3, //! 16-bit unsigned integer
+ FIDT_LONG = 4, //! 32-bit unsigned integer
+ FIDT_RATIONAL = 5, //! 64-bit unsigned fraction
+ FIDT_SBYTE = 6, //! 8-bit signed integer
+ FIDT_UNDEFINED = 7, //! 8-bit untyped data
+ FIDT_SSHORT = 8, //! 16-bit signed integer
+ FIDT_SLONG = 9, //! 32-bit signed integer
+ FIDT_SRATIONAL = 10, //! 64-bit signed fraction
+ FIDT_FLOAT = 11, //! 32-bit IEEE floating point
+ FIDT_DOUBLE = 12, //! 64-bit IEEE floating point
+ FIDT_IFD = 13, //! 32-bit unsigned integer (offset)
+ FIDT_PALETTE = 14, //! 32-bit RGBQUAD
+ FIDT_LONG8 = 16, //! 64-bit unsigned integer
+ FIDT_SLONG8 = 17, //! 64-bit signed integer
+ FIDT_IFD8 = 18 //! 64-bit unsigned integer (offset)
};
/**
@@ -542,18 +557,18 @@ FI_ENUM(FREE_IMAGE_MDTYPE) {
*/
FI_ENUM(FREE_IMAGE_MDMODEL) {
FIMD_NODATA = -1,
- FIMD_COMMENTS = 0, // single comment or keywords
- FIMD_EXIF_MAIN = 1, // Exif-TIFF metadata
- FIMD_EXIF_EXIF = 2, // Exif-specific metadata
- FIMD_EXIF_GPS = 3, // Exif GPS metadata
- FIMD_EXIF_MAKERNOTE = 4, // Exif maker note metadata
- FIMD_EXIF_INTEROP = 5, // Exif interoperability metadata
- FIMD_IPTC = 6, // IPTC/NAA metadata
- FIMD_XMP = 7, // Abobe XMP metadata
- FIMD_GEOTIFF = 8, // GeoTIFF metadata
- FIMD_ANIMATION = 9, // Animation metadata
- FIMD_CUSTOM = 10, // Used to attach other metadata types to a dib
- FIMD_EXIF_RAW = 11 // Exif metadata as a raw buffer
+ FIMD_COMMENTS = 0, //! single comment or keywords
+ FIMD_EXIF_MAIN = 1, //! Exif-TIFF metadata
+ FIMD_EXIF_EXIF = 2, //! Exif-specific metadata
+ FIMD_EXIF_GPS = 3, //! Exif GPS metadata
+ FIMD_EXIF_MAKERNOTE = 4, //! Exif maker note metadata
+ FIMD_EXIF_INTEROP = 5, //! Exif interoperability metadata
+ FIMD_IPTC = 6, //! IPTC/NAA metadata
+ FIMD_XMP = 7, //! Abobe XMP metadata
+ FIMD_GEOTIFF = 8, //! GeoTIFF metadata
+ FIMD_ANIMATION = 9, //! Animation metadata
+ FIMD_CUSTOM = 10, //! Used to attach other metadata types to a dib
+ FIMD_EXIF_RAW = 11 //! Exif metadata as a raw buffer
};
/**
@@ -584,10 +599,10 @@ typedef long (DLL_CALLCONV *FI_TellProc) (fi_handle handle);
#endif // WIN32
FI_STRUCT(FreeImageIO) {
- FI_ReadProc read_proc; // pointer to the function used to read data
- FI_WriteProc write_proc; // pointer to the function used to write data
- FI_SeekProc seek_proc; // pointer to the function used to seek
- FI_TellProc tell_proc; // pointer to the function used to aquire the current position
+ FI_ReadProc read_proc; //! pointer to the function used to read data
+ FI_WriteProc write_proc; //! pointer to the function used to write data
+ FI_SeekProc seek_proc; //! pointer to the function used to seek
+ FI_TellProc tell_proc; //! pointer to the function used to aquire the current position
};
#if (defined(_WIN32) || defined(__WIN32__))
@@ -721,6 +736,7 @@ typedef void (DLL_CALLCONV *FI_InitProc)(Plugin *plugin, int format_id);
#define RAW_PREVIEW 1 //! try to load the embedded JPEG preview with included Exif Data or default to RGB 24-bit
#define RAW_DISPLAY 2 //! load the file as RGB 24-bit
#define RAW_HALFSIZE 4 //! output a half-size color image
+#define RAW_UNPROCESSED 8 //! output a FIT_UINT16 raw Bayer image
#define SGI_DEFAULT 0
#define TARGA_DEFAULT 0
#define TARGA_LOAD_RGB888 1 //! if set the loader converts RGB555 and ARGB8888 -> RGB888.
@@ -748,12 +764,19 @@ typedef void (DLL_CALLCONV *FI_InitProc)(Plugin *plugin, int format_id);
// Background filling options ---------------------------------------------------------
// Constants used in FreeImage_FillBackground and FreeImage_EnlargeCanvas
-#define FI_COLOR_IS_RGB_COLOR 0x00 // RGBQUAD color is a RGB color (contains no valid alpha channel)
-#define FI_COLOR_IS_RGBA_COLOR 0x01 // RGBQUAD color is a RGBA color (contains a valid alpha channel)
-#define FI_COLOR_FIND_EQUAL_COLOR 0x02 // For palettized images: lookup equal RGB color from palette
-#define FI_COLOR_ALPHA_IS_INDEX 0x04 // The color's rgbReserved member (alpha) contains the palette index to be used
+#define FI_COLOR_IS_RGB_COLOR 0x00 //! RGBQUAD color is a RGB color (contains no valid alpha channel)
+#define FI_COLOR_IS_RGBA_COLOR 0x01 //! RGBQUAD color is a RGBA color (contains a valid alpha channel)
+#define FI_COLOR_FIND_EQUAL_COLOR 0x02 //! For palettized images: lookup equal RGB color from palette
+#define FI_COLOR_ALPHA_IS_INDEX 0x04 //! The color's rgbReserved member (alpha) contains the palette index to be used
#define FI_COLOR_PALETTE_SEARCH_MASK (FI_COLOR_FIND_EQUAL_COLOR | FI_COLOR_ALPHA_IS_INDEX) // No color lookup is performed
+// RescaleEx options ---------------------------------------------------------
+// Constants used in FreeImage_RescaleEx
+
+#define FI_RESCALE_DEFAULT 0x00 //! default options; none of the following other options apply
+#define FI_RESCALE_TRUE_COLOR 0x01 //! for non-transparent greyscale images, convert to 24-bit if src bitdepth <= 8 (default is a 8-bit greyscale image).
+#define FI_RESCALE_OMIT_METADATA 0x02 //! do not copy metadata to the rescaled image
+
#ifdef __cplusplus
extern "C" {
@@ -887,6 +910,7 @@ DLL_API unsigned DLL_CALLCONV FreeImage_GetHeight(FIBITMAP *dib);
DLL_API unsigned DLL_CALLCONV FreeImage_GetLine(FIBITMAP *dib);
DLL_API unsigned DLL_CALLCONV FreeImage_GetPitch(FIBITMAP *dib);
DLL_API unsigned DLL_CALLCONV FreeImage_GetDIBSize(FIBITMAP *dib);
+DLL_API unsigned DLL_CALLCONV FreeImage_GetMemorySize(FIBITMAP *dib);
DLL_API RGBQUAD *DLL_CALLCONV FreeImage_GetPalette(FIBITMAP *dib);
DLL_API unsigned DLL_CALLCONV FreeImage_GetDotsPerMeterX(FIBITMAP *dib);
@@ -977,12 +1001,15 @@ DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Threshold(FIBITMAP *dib, BYTE T);
DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Dither(FIBITMAP *dib, FREE_IMAGE_DITHER algorithm);
DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertFromRawBits(BYTE *bits, int width, int height, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown FI_DEFAULT(FALSE));
+DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertFromRawBitsEx(BOOL copySource, BYTE *bits, FREE_IMAGE_TYPE type, int width, int height, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown FI_DEFAULT(FALSE));
DLL_API void DLL_CALLCONV FreeImage_ConvertToRawBits(BYTE *bits, FIBITMAP *dib, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown FI_DEFAULT(FALSE));
DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToFloat(FIBITMAP *dib);
DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToRGBF(FIBITMAP *dib);
+DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToRGBAF(FIBITMAP *dib);
DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToUINT16(FIBITMAP *dib);
DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToRGB16(FIBITMAP *dib);
+DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToRGBA16(FIBITMAP *dib);
DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToStandardType(FIBITMAP *src, BOOL scale_linear FI_DEFAULT(TRUE));
DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToType(FIBITMAP *src, FREE_IMAGE_TYPE dst_type, BOOL scale_linear FI_DEFAULT(TRUE));
@@ -1038,6 +1065,7 @@ DLL_API void DLL_CALLCONV FreeImage_FindCloseMetadata(FIMETADATA *mdhandle);
// metadata setter and getter
DLL_API BOOL DLL_CALLCONV FreeImage_SetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, FITAG *tag);
DLL_API BOOL DLL_CALLCONV FreeImage_GetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, FITAG **tag);
+DLL_API BOOL DLL_CALLCONV FreeImage_SetMetadataKeyValue(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, const char *value);
// helpers
DLL_API unsigned DLL_CALLCONV FreeImage_GetMetadataCount(FREE_IMAGE_MDMODEL model, FIBITMAP *dib);
@@ -1054,11 +1082,11 @@ DLL_API BOOL DLL_CALLCONV FreeImage_JPEGTransform(const char *src_file, const ch
DLL_API BOOL DLL_CALLCONV FreeImage_JPEGTransformU(const wchar_t *src_file, const wchar_t *dst_file, FREE_IMAGE_JPEG_OPERATION operation, BOOL perfect FI_DEFAULT(TRUE));
DLL_API BOOL DLL_CALLCONV FreeImage_JPEGCrop(const char *src_file, const char *dst_file, int left, int top, int right, int bottom);
DLL_API BOOL DLL_CALLCONV FreeImage_JPEGCropU(const wchar_t *src_file, const wchar_t *dst_file, int left, int top, int right, int bottom);
-DLL_API BOOL DLL_CALLCONV FreeImage_JPEGTransformFromHandle(FreeImageIO* src_io, fi_handle src_handle, FreeImageIO* dst_io, fi_handle dst_handle, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect FI_DEFAULT(TRUE));
-DLL_API BOOL DLL_CALLCONV FreeImage_JPEGTransformCombined(const char *src_file, const char *dst_file, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect FI_DEFAULT(TRUE));
-DLL_API BOOL DLL_CALLCONV FreeImage_JPEGTransformCombinedU(const wchar_t *src_file, const wchar_t *dst_file, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect FI_DEFAULT(TRUE));
-DLL_API BOOL DLL_CALLCONV FreeImage_JPEGTransformCombinedFromMemory(FIMEMORY* src_stream, FIMEMORY* dst_stream, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect FI_DEFAULT(TRUE));
-
+DLL_API BOOL DLL_CALLCONV FreeImage_JPEGTransformFromHandle(FreeImageIO* src_io, fi_handle src_handle, FreeImageIO* dst_io, fi_handle dst_handle, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect FI_DEFAULT(TRUE));
+DLL_API BOOL DLL_CALLCONV FreeImage_JPEGTransformCombined(const char *src_file, const char *dst_file, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect FI_DEFAULT(TRUE));
+DLL_API BOOL DLL_CALLCONV FreeImage_JPEGTransformCombinedU(const wchar_t *src_file, const wchar_t *dst_file, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect FI_DEFAULT(TRUE));
+DLL_API BOOL DLL_CALLCONV FreeImage_JPEGTransformCombinedFromMemory(FIMEMORY* src_stream, FIMEMORY* dst_stream, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect FI_DEFAULT(TRUE));
+
// --------------------------------------------------------------------------
// Image manipulation toolkit
@@ -1075,6 +1103,7 @@ DLL_API BOOL DLL_CALLCONV FreeImage_FlipVertical(FIBITMAP *dib);
// upsampling / downsampling
DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Rescale(FIBITMAP *dib, int dst_width, int dst_height, FREE_IMAGE_FILTER filter FI_DEFAULT(FILTER_CATMULLROM));
DLL_API FIBITMAP *DLL_CALLCONV FreeImage_MakeThumbnail(FIBITMAP *dib, int max_pixel_size, BOOL convert FI_DEFAULT(TRUE));
+DLL_API FIBITMAP *DLL_CALLCONV FreeImage_RescaleRect(FIBITMAP *dib, int dst_width, int dst_height, int left, int top, int right, int bottom, FREE_IMAGE_FILTER filter FI_DEFAULT(FILTER_CATMULLROM), unsigned flags FI_DEFAULT(0));
// color manipulation routines (point operations)
DLL_API BOOL DLL_CALLCONV FreeImage_AdjustCurve(FIBITMAP *dib, BYTE *LUT, FREE_IMAGE_COLOR_CHANNEL channel);
@@ -1099,6 +1128,8 @@ DLL_API BOOL DLL_CALLCONV FreeImage_SetComplexChannel(FIBITMAP *dst, FIBITMAP *s
// copy / paste / composite routines
DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Copy(FIBITMAP *dib, int left, int top, int right, int bottom);
DLL_API BOOL DLL_CALLCONV FreeImage_Paste(FIBITMAP *dst, FIBITMAP *src, int left, int top, int alpha);
+DLL_API FIBITMAP *DLL_CALLCONV FreeImage_CreateView(FIBITMAP *dib, unsigned left, unsigned top, unsigned right, unsigned bottom);
+
DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Composite(FIBITMAP *fg, BOOL useFileBkg FI_DEFAULT(FALSE), RGBQUAD *appBkColor FI_DEFAULT(NULL), FIBITMAP *bg FI_DEFAULT(NULL));
DLL_API BOOL DLL_CALLCONV FreeImage_PreMultiplyWithAlpha(FIBITMAP *dib);
diff --git a/plugins/AdvaImg/src/FreeImage/BitmapAccess.cpp b/plugins/AdvaImg/src/FreeImage/BitmapAccess.cpp
index 2ba5539d4c..347ad1f3e5 100644
--- a/plugins/AdvaImg/src/FreeImage/BitmapAccess.cpp
+++ b/plugins/AdvaImg/src/FreeImage/BitmapAccess.cpp
@@ -36,10 +36,18 @@
#include "FreeImage.h"
#include "FreeImageIO.h"
#include "Utilities.h"
+#include "MapIntrospector.h"
#include "../Metadata/FreeImageTag.h"
-/** Constants for the BITMAPINFOHEADER::biCompression field */
+/**
+Constants for the BITMAPINFOHEADER::biCompression field
+BI_RGB:
+The bitmap is in uncompressed red green blue (RGB) format that is not compressed and does not use color masks.
+BI_BITFIELDS:
+The bitmap is not compressed and the color table consists of three DWORD color masks that specify the red, green, and blue components,
+respectively, of each pixel. This is valid when used with 16 and 32-bits per pixel bitmaps.
+*/
#ifndef _WINGDI_
#define BI_RGB 0L
#define BI_BITFIELDS 3L
@@ -49,38 +57,66 @@
// Metadata definitions
// ----------------------------------------------------------
-// helper for map<key, value> where value is a pointer to a FreeImage tag
+/** helper for map<key, value> where value is a pointer to a FreeImage tag */
typedef std::map<std::string, FITAG*> TAGMAP;
-// helper for map<FREE_IMAGE_MDMODEL, TAGMAP*>
+/** helper for map<FREE_IMAGE_MDMODEL, TAGMAP*> */
typedef std::map<int, TAGMAP*> METADATAMAP;
-// helper for metadata iterator
+/** helper for metadata iterator */
FI_STRUCT (METADATAHEADER) {
- long pos; // current position when iterating the map
- TAGMAP *tagmap; // pointer to the tag map
+ long pos; //! current position when iterating the map
+ TAGMAP *tagmap; //! pointer to the tag map
};
// ----------------------------------------------------------
// FIBITMAP definition
// ----------------------------------------------------------
+/**
+FreeImage header structure
+*/
FI_STRUCT (FREEIMAGEHEADER) {
- FREE_IMAGE_TYPE type; // data type - bitmap, array of long, double, complex, etc
+ /** data type - bitmap, array of long, double, complex, etc */
+ FREE_IMAGE_TYPE type;
+
+ /** background color used for RGB transparency */
+ RGBQUAD bkgnd_color;
+
+ /**@name transparency management */
+ //@{
+ /**
+ why another table ? for easy transparency table retrieval !
+ transparency could be stored in the palette, which is better
+ overall, but it requires quite some changes and it will render
+ FreeImage_GetTransparencyTable obsolete in its current form;
+ */
+ BYTE transparent_table[256];
+ /** number of transparent colors */
+ int transparency_count;
+ /** TRUE if the image is transparent */
+ BOOL transparent;
+ //@}
- RGBQUAD bkgnd_color; // background color used for RGB transparency
+ /** space to hold ICC profile */
+ FIICCPROFILE iccProfile;
- BOOL transparent; // why another table? for easy transparency table retrieval!
- int transparency_count; // transparency could be stored in the palette, which is better
- BYTE transparent_table[256];// overall, but it requires quite some changes and it will render
- // FreeImage_GetTransparencyTable obsolete in its current form;
- FIICCPROFILE iccProfile; // space to hold ICC profile
+ /** contains a list of metadata models attached to the bitmap */
+ METADATAMAP *metadata;
- METADATAMAP *metadata; // contains a list of metadata models attached to the bitmap
+ /** FALSE if the FIBITMAP only contains the header and no pixel data */
+ BOOL has_pixels;
- BOOL has_pixels; // FALSE if the FIBITMAP only contains the header and no pixel data
+ /** optionally contains a thumbnail attached to the bitmap */
+ FIBITMAP *thumbnail;
- FIBITMAP *thumbnail; // optionally contains a thumbnail attached to the bitmap
+ /**@name external pixel buffer management */
+ //@{
+ /** pointer to user provided pixels, NULL otherwise */
+ BYTE *external_bits;
+ /** user provided pitch, 0 otherwise */
+ unsigned external_pitch;
+ //@}
//BYTE filler[1]; // fill to 32-bit alignment
};
@@ -89,10 +125,13 @@ FI_STRUCT (FREEIMAGEHEADER) {
// FREEIMAGERGBMASKS definition
// ----------------------------------------------------------
+/**
+RGB mask structure - mainly used for 16-bit RGB555 / RGB 565 FIBITMAP
+*/
FI_STRUCT (FREEIMAGERGBMASKS) {
- unsigned red_mask; // bit layout of the red components
- unsigned green_mask; // bit layout of the green components
- unsigned blue_mask; // bit layout of the blue components
+ unsigned red_mask; //! bit layout of the red components
+ unsigned green_mask; //! bit layout of the green components
+ unsigned blue_mask; //! bit layout of the blue components
};
// ----------------------------------------------------------
@@ -155,40 +194,50 @@ void FreeImage_Aligned_Free(void* mem) {
#endif // _WIN32 || _WIN64
// ----------------------------------------------------------
-// DIB information functions
+// FIBITMAP memory management
// ----------------------------------------------------------
/**
Calculate the size of a FreeImage image.
Align the palette and the pixels on a FIBITMAP_ALIGNMENT bytes alignment boundary.
+This function includes a protection against malicious images, based on a KISS integer overflow detection mechanism.
@param header_only If TRUE, calculate a 'header only' FIBITMAP size, otherwise calculate a full FIBITMAP size
-@param width
-@param height
-@param bpp
-@param need_masks
-@see FreeImage_AllocateHeaderT
+@param width Image width
+@param height Image height
+@param bpp Number of bits-per-pixel
+@param need_masks We only store the masks (and allocate memory for them) for 16-bit images of type FIT_BITMAP
+@return Returns a size in BYTE units
+@see FreeImage_AllocateBitmap
*/
static size_t
-FreeImage_GetImageSizeHeader(BOOL header_only, unsigned width, unsigned height, unsigned bpp, BOOL need_masks) {
- size_t dib_size = sizeof(FREEIMAGEHEADER);
- dib_size += (dib_size % FIBITMAP_ALIGNMENT ? FIBITMAP_ALIGNMENT - dib_size % FIBITMAP_ALIGNMENT : 0);
- dib_size += FIBITMAP_ALIGNMENT - sizeof(BITMAPINFOHEADER) % FIBITMAP_ALIGNMENT;
- dib_size += sizeof(BITMAPINFOHEADER);
+FreeImage_GetInternalImageSize(BOOL header_only, unsigned width, unsigned height, unsigned bpp, BOOL need_masks) {
+ size_t dib_size = sizeof(FREEIMAGEHEADER);
+ dib_size += (dib_size % FIBITMAP_ALIGNMENT ? FIBITMAP_ALIGNMENT - dib_size % FIBITMAP_ALIGNMENT : 0);
+ dib_size += FIBITMAP_ALIGNMENT - sizeof(BITMAPINFOHEADER) % FIBITMAP_ALIGNMENT;
+ dib_size += sizeof(BITMAPINFOHEADER);
// palette is aligned on a 16 bytes boundary
dib_size += sizeof(RGBQUAD) * CalculateUsedPaletteEntries(bpp);
// we both add palette size and masks size if need_masks is true, since CalculateUsedPaletteEntries
// always returns 0 if need_masks is true (which is only true for 16 bit images).
dib_size += need_masks ? sizeof(DWORD) * 3 : 0;
- dib_size += (dib_size % FIBITMAP_ALIGNMENT ? FIBITMAP_ALIGNMENT - dib_size % FIBITMAP_ALIGNMENT : 0);
+ dib_size += (dib_size % FIBITMAP_ALIGNMENT ? FIBITMAP_ALIGNMENT - dib_size % FIBITMAP_ALIGNMENT : 0);
+
if(!header_only) {
const size_t header_size = dib_size;
// pixels are aligned on a 16 bytes boundary
- dib_size += (size_t)CalculatePitch(CalculateLine(width, bpp)) * (size_t)height;
+ dib_size += (size_t)CalculatePitch(CalculateLine(width, bpp)) * (size_t)height;
// check for possible malloc overflow using a KISS integer overflow detection mechanism
{
+ const double dPitch = floor( ((double)bpp * width + 31.0) / 32.0 ) * 4.0;
+ const double dImageSize = (double)header_size + dPitch * height;
+ if(dImageSize != (double)dib_size) {
+ // here, we are sure to encounter a malloc overflow: try to avoid it ...
+ return 0;
+ }
+
/*
The following constant take into account the additionnal memory used by
aligned malloc functions as well as debug malloc functions.
@@ -196,12 +245,7 @@ FreeImage_GetImageSizeHeader(BOOL header_only, unsigned width, unsigned height,
for the target compiler.
*/
const double FIBITMAP_MAX_MEMORY = (double)((size_t)-1) - 8 * FIBITMAP_ALIGNMENT;
- const double dPitch = floor( ((double)bpp * width + 31.0) / 32.0 ) * 4.0;
- const double dImageSize = (double)header_size + dPitch * height;
- if(dImageSize != (double)dib_size) {
- // here, we are sure to encounter a malloc overflow: try to avoid it ...
- return 0;
- }
+
if(dImageSize > FIBITMAP_MAX_MEMORY) {
// avoid possible overflow inside C allocation functions
return 0;
@@ -224,8 +268,33 @@ FreeImage_GetRGBMasks(FIBITMAP *dib) {
return FreeImage_HasRGBMasks(dib) ? (FREEIMAGERGBMASKS *)(((BYTE *)FreeImage_GetInfoHeader(dib)) + sizeof(BITMAPINFOHEADER)) : NULL;
}
-FIBITMAP * DLL_CALLCONV
-FreeImage_AllocateHeaderT(BOOL header_only, FREE_IMAGE_TYPE type, int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) {
+/**
+Internal FIBITMAP allocation.
+
+This function accepts (ext_bits, ext_pitch) arguments. If these are provided the FIBITMAP
+will be allocated as "header only", but bits and pitch will be stored within the FREEIMAGEHEADER
+and the resulting FIBITMAP will have pixels, i.e. HasPixels() will return TRUE.
+- GetBits() and GetPitch return the correct values - either offsets or the stored values (user-provided bits and pitch).
+- Clone() creates a new FIBITMAP with copy of the user pixel data.
+- Unload's implementation does not need to change - it just release a "header only" dib.
+Note that when using external data, the data does not need to have the same alignment as the default 4-byte alignment.
+This enables the possibility to access buffers with, for instance, stricter alignment,
+like the ones used in low-level APIs like OpenCL or intrinsics.
+
+@param header_only If TRUE, allocate a 'header only' FIBITMAP, otherwise allocate a full FIBITMAP
+@param ext_bits Pointer to external user's pixel buffer if using wrapped buffer, NULL otherwise
+@param ext_pitch Pointer to external user's pixel buffer pitch if using wrapped buffer, 0 otherwise
+@param type Image type
+@param width Image width
+@param height Image height
+@param bpp Number of bits per pixel
+@param red_mask Image red mask
+@param green_mask Image green mask
+@param blue_mask Image blue mask
+@return Returns the allocated FIBITMAP if successful, returns NULL otherwise
+*/
+static FIBITMAP *
+FreeImage_AllocateBitmap(BOOL header_only, BYTE *ext_bits, unsigned ext_pitch, FREE_IMAGE_TYPE type, int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) {
// check input variables
width = abs(width);
@@ -233,6 +302,12 @@ FreeImage_AllocateHeaderT(BOOL header_only, FREE_IMAGE_TYPE type, int width, int
if(!((width > 0) && (height > 0))) {
return NULL;
}
+ if(ext_bits) {
+ if(ext_pitch == 0) {
+ return NULL;
+ }
+ assert(header_only == FALSE);
+ }
// we only store the masks (and allocate memory for them) for 16-bit images of type FIT_BITMAP
BOOL need_masks = FALSE;
@@ -302,7 +377,9 @@ FreeImage_AllocateHeaderT(BOOL header_only, FREE_IMAGE_TYPE type, int width, int
// palette is aligned on a 16 bytes boundary
// pixels are aligned on a 16 bytes boundary
- size_t dib_size = FreeImage_GetImageSizeHeader(header_only, width, height, bpp, need_masks);
+ // when using a user provided pixel buffer, force a 'header only' allocation
+
+ size_t dib_size = FreeImage_GetInternalImageSize(header_only || ext_bits, width, height, bpp, need_masks);
if(dib_size == 0) {
// memory allocation will fail (probably a malloc overflow)
@@ -317,12 +394,13 @@ FreeImage_AllocateHeaderT(BOOL header_only, FREE_IMAGE_TYPE type, int width, int
// write out the FREEIMAGEHEADER
- FREEIMAGEHEADER *fih = (FREEIMAGEHEADER *)bitmap->data;
- fih->type = type;
+ FREEIMAGEHEADER *fih = (FREEIMAGEHEADER *)bitmap->data;
+
+ fih->type = type;
memset(&fih->bkgnd_color, 0, sizeof(RGBQUAD));
- fih->transparent = FALSE;
+ fih->transparent = FALSE;
fih->transparency_count = 0;
memset(fih->transparent_table, 0xff, 256);
@@ -331,9 +409,9 @@ FreeImage_AllocateHeaderT(BOOL header_only, FREE_IMAGE_TYPE type, int width, int
// initialize FIICCPROFILE link
FIICCPROFILE *iccProfile = FreeImage_GetICCProfile(bitmap);
- iccProfile->size = 0;
- iccProfile->data = 0;
- iccProfile->flags = 0;
+ iccProfile->size = 0;
+ iccProfile->data = 0;
+ iccProfile->flags = 0;
// initialize metadata models list
@@ -343,6 +421,11 @@ FreeImage_AllocateHeaderT(BOOL header_only, FREE_IMAGE_TYPE type, int width, int
fih->thumbnail = NULL;
+ // store a pointer to user provided pixel buffer (if any)
+
+ fih->external_bits = ext_bits;
+ fih->external_pitch = ext_pitch;
+
// write out the BITMAPINFOHEADER
BITMAPINFOHEADER *bih = FreeImage_GetInfoHeader(bitmap);
@@ -385,18 +468,28 @@ FreeImage_AllocateHeaderT(BOOL header_only, FREE_IMAGE_TYPE type, int width, int
}
FIBITMAP * DLL_CALLCONV
+FreeImage_AllocateHeaderForBits(BYTE *ext_bits, unsigned ext_pitch, FREE_IMAGE_TYPE type, int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) {
+ return FreeImage_AllocateBitmap(FALSE, ext_bits, ext_pitch, type, width, height, bpp, red_mask, green_mask, blue_mask);
+}
+
+FIBITMAP * DLL_CALLCONV
+FreeImage_AllocateHeaderT(BOOL header_only, FREE_IMAGE_TYPE type, int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) {
+ return FreeImage_AllocateBitmap(header_only, NULL, 0, type, width, height, bpp, red_mask, green_mask, blue_mask);
+}
+
+FIBITMAP * DLL_CALLCONV
FreeImage_AllocateHeader(BOOL header_only, int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) {
- return FreeImage_AllocateHeaderT(header_only, FIT_BITMAP, width, height, bpp, red_mask, green_mask, blue_mask);
+ return FreeImage_AllocateBitmap(header_only, NULL, 0, FIT_BITMAP, width, height, bpp, red_mask, green_mask, blue_mask);
}
FIBITMAP * DLL_CALLCONV
FreeImage_Allocate(int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) {
- return FreeImage_AllocateHeaderT(FALSE, FIT_BITMAP, width, height, bpp, red_mask, green_mask, blue_mask);
+ return FreeImage_AllocateBitmap(FALSE, NULL, 0, FIT_BITMAP, width, height, bpp, red_mask, green_mask, blue_mask);
}
FIBITMAP * DLL_CALLCONV
FreeImage_AllocateT(FREE_IMAGE_TYPE type, int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) {
- return FreeImage_AllocateHeaderT(FALSE, type, width, height, bpp, red_mask, green_mask, blue_mask);
+ return FreeImage_AllocateBitmap(FALSE, NULL, 0, type, width, height, bpp, red_mask, green_mask, blue_mask);
}
void DLL_CALLCONV
@@ -404,8 +497,9 @@ FreeImage_Unload(FIBITMAP *dib) {
if (NULL != dib) {
if (NULL != dib->data) {
// delete possible icc profile ...
- if (FreeImage_GetICCProfile(dib)->data)
+ if (FreeImage_GetICCProfile(dib)->data) {
free(FreeImage_GetICCProfile(dib)->data);
+ }
// delete metadata models
METADATAMAP *metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
@@ -431,6 +525,7 @@ FreeImage_Unload(FIBITMAP *dib) {
// delete bitmap ...
FreeImage_Aligned_Free(dib->data);
}
+
free(dib); // ... and the wrapper
}
}
@@ -439,17 +534,22 @@ FreeImage_Unload(FIBITMAP *dib) {
FIBITMAP * DLL_CALLCONV
FreeImage_Clone(FIBITMAP *dib) {
- if(!dib) return NULL;
+ if(!dib) {
+ return NULL;
+ }
FREE_IMAGE_TYPE type = FreeImage_GetImageType(dib);
- unsigned width = FreeImage_GetWidth(dib);
- unsigned height = FreeImage_GetHeight(dib);
- unsigned bpp = FreeImage_GetBPP(dib);
+ unsigned width = FreeImage_GetWidth(dib);
+ unsigned height = FreeImage_GetHeight(dib);
+ unsigned bpp = FreeImage_GetBPP(dib);
+
+ const BYTE *ext_bits = ((FREEIMAGEHEADER *)dib->data)->external_bits;
// check for pixel availability ...
BOOL header_only = FreeImage_HasPixels(dib) ? FALSE : TRUE;
+
// check whether this image has masks defined ...
- BOOL need_masks = (bpp == 16 && type == FIT_BITMAP) ? TRUE : FALSE;
+ BOOL need_masks = (bpp == 16 && type == FIT_BITMAP) ? TRUE : FALSE;
// allocate a new dib
FIBITMAP *new_dib = FreeImage_AllocateHeaderT(header_only, type, width, height, bpp,
@@ -464,12 +564,14 @@ FreeImage_Clone(FIBITMAP *dib) {
METADATAMAP *src_metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
METADATAMAP *dst_metadata = ((FREEIMAGEHEADER *)new_dib->data)->metadata;
- // calculate the size of a FreeImage image
+ // calculate the size of the src image
// align the palette and the pixels on a FIBITMAP_ALIGNMENT bytes alignment boundary
// palette is aligned on a 16 bytes boundary
// pixels are aligned on a 16 bytes boundary
+
+ // when using a user provided pixel buffer, force a 'header only' calculation
- size_t dib_size = FreeImage_GetImageSizeHeader(header_only, width, height, bpp, need_masks);
+ size_t dib_size = FreeImage_GetInternalImageSize(header_only || ext_bits, width, height, bpp, need_masks);
// copy the bitmap + internal pointers (remember to restore new_dib internal pointers later)
memcpy(new_dib->data, dib->data, dib_size);
@@ -515,6 +617,16 @@ FreeImage_Clone(FIBITMAP *dib) {
// copy the thumbnail
FreeImage_SetThumbnail(new_dib, FreeImage_GetThumbnail(dib));
+ // copy user provided pixel buffer (if any)
+ if(ext_bits) {
+ const unsigned pitch = FreeImage_GetPitch(dib);
+ const unsigned linesize = FreeImage_GetLine(dib);
+ for(unsigned y = 0; y < height; y++) {
+ memcpy(FreeImage_GetScanLine(new_dib, y), ext_bits, linesize);
+ ext_bits += pitch;
+ }
+ }
+
return new_dib;
}
@@ -523,6 +635,28 @@ FreeImage_Clone(FIBITMAP *dib) {
// ----------------------------------------------------------
+BYTE * DLL_CALLCONV
+FreeImage_GetBits(FIBITMAP *dib) {
+ if(!FreeImage_HasPixels(dib)) {
+ return NULL;
+ }
+
+ if(((FREEIMAGEHEADER *)dib->data)->external_bits) {
+ return ((FREEIMAGEHEADER *)dib->data)->external_bits;
+ }
+
+ // returns the pixels aligned on a FIBITMAP_ALIGNMENT bytes alignment boundary
+ size_t lp = (size_t)FreeImage_GetInfoHeader(dib);
+ lp += sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * FreeImage_GetColorsUsed(dib);
+ lp += FreeImage_HasRGBMasks(dib) ? sizeof(DWORD) * 3 : 0;
+ lp += (lp % FIBITMAP_ALIGNMENT ? FIBITMAP_ALIGNMENT - lp % FIBITMAP_ALIGNMENT : 0);
+ return (BYTE *)lp;
+}
+
+// ----------------------------------------------------------
+// DIB information functions
+// ----------------------------------------------------------
+
FIBITMAP* DLL_CALLCONV
FreeImage_GetThumbnail(FIBITMAP *dib) {
return (dib != NULL) ? ((FREEIMAGEHEADER *)dib->data)->thumbnail : NULL;
@@ -589,15 +723,17 @@ FreeImage_GetColorType(FIBITMAP *dib) {
if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0)) {
rgb++;
- if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255))
- return FIC_MINISBLACK;
+ if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255)) {
+ return FIC_MINISBLACK;
+ }
}
if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255)) {
rgb++;
- if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0))
- return FIC_MINISWHITE;
+ if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0)) {
+ return FIC_MINISWHITE;
+ }
}
return FIC_PALETTE;
@@ -611,16 +747,18 @@ FreeImage_GetColorType(FIBITMAP *dib) {
rgb = FreeImage_GetPalette(dib);
for (int i = 0; i < ncolors; i++) {
- if ((rgb->rgbRed != rgb->rgbGreen) || (rgb->rgbRed != rgb->rgbBlue))
+ if ((rgb->rgbRed != rgb->rgbGreen) || (rgb->rgbRed != rgb->rgbBlue)) {
return FIC_PALETTE;
+ }
// The DIB has a color palette if the greyscale isn't a linear ramp
// Take care of reversed grey images
if (rgb->rgbRed != i) {
- if ((ncolors-i-1) != rgb->rgbRed)
+ if ((ncolors-i-1) != rgb->rgbRed) {
return FIC_PALETTE;
- else
+ } else {
minisblack = 0;
+ }
}
rgb++;
@@ -635,17 +773,20 @@ FreeImage_GetColorType(FIBITMAP *dib) {
case 32:
{
- if (FreeImage_GetICCProfile(dib)->flags & FIICC_COLOR_IS_CMYK)
+ if (FreeImage_GetICCProfile(dib)->flags & FIICC_COLOR_IS_CMYK) {
return FIC_CMYK;
+ }
if( FreeImage_HasPixels(dib) ) {
// check for fully opaque alpha layer
for (unsigned y = 0; y < FreeImage_GetHeight(dib); y++) {
rgb = (RGBQUAD *)FreeImage_GetScanLine(dib, y);
- for (unsigned x = 0; x < FreeImage_GetWidth(dib); x++)
- if (rgb[x].rgbReserved != 0xFF)
- return FIC_RGBALPHA;
+ for (unsigned x = 0; x < FreeImage_GetWidth(dib); x++) {
+ if (rgb[x].rgbReserved != 0xFF) {
+ return FIC_RGBALPHA;
+ }
+ }
}
return FIC_RGB;
}
@@ -687,7 +828,10 @@ FreeImage_GetRedMask(FIBITMAP *dib) {
case FIT_BITMAP:
// check for 16-bit RGB (565 or 555)
masks = FreeImage_GetRGBMasks(dib);
- return masks ? masks->red_mask : FI_RGBA_RED_MASK;
+ if (masks) {
+ return masks->red_mask;
+ }
+ return FreeImage_GetBPP(dib) >= 24 ? FI_RGBA_RED_MASK : 0;
default:
return 0;
}
@@ -701,7 +845,10 @@ FreeImage_GetGreenMask(FIBITMAP *dib) {
case FIT_BITMAP:
// check for 16-bit RGB (565 or 555)
masks = FreeImage_GetRGBMasks(dib);
- return masks ? masks->green_mask : FI_RGBA_GREEN_MASK;
+ if (masks) {
+ return masks->green_mask;
+ }
+ return FreeImage_GetBPP(dib) >= 24 ? FI_RGBA_GREEN_MASK : 0;
default:
return 0;
}
@@ -715,7 +862,10 @@ FreeImage_GetBlueMask(FIBITMAP *dib) {
case FIT_BITMAP:
// check for 16-bit RGB (565 or 555)
masks = FreeImage_GetRGBMasks(dib);
- return masks ? masks->blue_mask : FI_RGBA_BLUE_MASK;
+ if (masks) {
+ return masks->blue_mask;
+ }
+ return FreeImage_GetBPP(dib) >= 24 ? FI_RGBA_BLUE_MASK : 0;
default:
return 0;
}
@@ -967,7 +1117,11 @@ FreeImage_GetLine(FIBITMAP *dib) {
unsigned DLL_CALLCONV
FreeImage_GetPitch(FIBITMAP *dib) {
- return dib ? FreeImage_GetLine(dib) + 3 & ~3 : 0;
+ if(dib) {
+ FREEIMAGEHEADER *fih = (FREEIMAGEHEADER *)dib->data;
+ return fih->external_bits ? fih->external_pitch : (FreeImage_GetLine(dib) + 3 & ~3);
+ }
+ return 0;
}
unsigned DLL_CALLCONV
@@ -1011,7 +1165,9 @@ FreeImage_SetDotsPerMeterY(FIBITMAP *dib, unsigned res) {
BITMAPINFOHEADER * DLL_CALLCONV
FreeImage_GetInfoHeader(FIBITMAP *dib) {
- if(!dib) return NULL;
+ if(!dib) {
+ return NULL;
+ }
size_t lp = (size_t)dib->data + sizeof(FREEIMAGEHEADER);
lp += (lp % FIBITMAP_ALIGNMENT ? FIBITMAP_ALIGNMENT - lp % FIBITMAP_ALIGNMENT : 0);
lp += FIBITMAP_ALIGNMENT - sizeof(BITMAPINFOHEADER) % FIBITMAP_ALIGNMENT;
@@ -1029,8 +1185,9 @@ FreeImage_GetInfo(FIBITMAP *dib) {
FIMETADATA * DLL_CALLCONV
FreeImage_FindFirstMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, FITAG **tag) {
- if(!dib)
+ if(!dib) {
return NULL;
+ }
// get the metadata model
METADATAMAP *metadata = ((FREEIMAGEHEADER *)dib->data)->metadata;
@@ -1072,8 +1229,9 @@ FreeImage_FindFirstMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, FITAG **tag
BOOL DLL_CALLCONV
FreeImage_FindNextMetadata(FIMETADATA *mdhandle, FITAG **tag) {
- if(!mdhandle)
+ if(!mdhandle) {
return FALSE;
+ }
METADATAHEADER *mdh = (METADATAHEADER *)mdhandle->data;
TAGMAP *tagmap = mdh->tagmap;
@@ -1115,7 +1273,9 @@ FreeImage_FindCloseMetadata(FIMETADATA *mdhandle) {
BOOL DLL_CALLCONV
FreeImage_CloneMetadata(FIBITMAP *dst, FIBITMAP *src) {
- if(!src || !dst) return FALSE;
+ if(!src || !dst) {
+ return FALSE;
+ }
// get metadata links
METADATAMAP *src_metadata = ((FREEIMAGEHEADER *)src->data)->metadata;
@@ -1165,8 +1325,9 @@ FreeImage_CloneMetadata(FIBITMAP *dst, FIBITMAP *src) {
BOOL DLL_CALLCONV
FreeImage_SetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, FITAG *tag) {
- if(!dib)
+ if(!dib) {
return FALSE;
+ }
TAGMAP *tagmap = NULL;
@@ -1254,8 +1415,9 @@ FreeImage_SetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key,
BOOL DLL_CALLCONV
FreeImage_GetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, FITAG **tag) {
- if(!dib || !key || !tag)
+ if(!dib || !key || !tag) {
return FALSE;
+ }
TAGMAP *tagmap = NULL;
*tag = NULL;
@@ -1278,12 +1440,50 @@ FreeImage_GetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key,
return (*tag != NULL) ? TRUE : FALSE;
}
+/**
+Build and set a FITAG whose type is FIDT_ASCII.
+@param model Metadata model to be filled
+@param dib Image to be filled
+@param key Tag key
+@param value Tag value as a ASCII string
+@return Returns TRUE if successful, returns FALSE otherwise
+*/
+BOOL DLL_CALLCONV
+FreeImage_SetMetadataKeyValue(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, const char *value) {
+ if(!dib || !key || !value) {
+ return FALSE;
+ }
+ // create a tag
+ FITAG *tag = FreeImage_CreateTag();
+ if(tag) {
+ BOOL bSuccess = TRUE;
+ // fill the tag
+ DWORD tag_length = (DWORD)(strlen(value) + 1);
+ bSuccess &= FreeImage_SetTagKey(tag, key);
+ bSuccess &= FreeImage_SetTagLength(tag, tag_length);
+ bSuccess &= FreeImage_SetTagCount(tag, tag_length);
+ bSuccess &= FreeImage_SetTagType(tag, FIDT_ASCII);
+ bSuccess &= FreeImage_SetTagValue(tag, value);
+ if(bSuccess) {
+ // set the tag
+ bSuccess &= FreeImage_SetMetadata(model, dib, FreeImage_GetTagKey(tag), tag);
+ }
+ // delete the tag
+ FreeImage_DeleteTag(tag);
+
+ return bSuccess;
+ }
+
+ return FALSE;
+}
+
// ----------------------------------------------------------
unsigned DLL_CALLCONV
FreeImage_GetMetadataCount(FREE_IMAGE_MDMODEL model, FIBITMAP *dib) {
- if(!dib)
+ if(!dib) {
return FALSE;
+ }
TAGMAP *tagmap = NULL;
@@ -1303,4 +1503,71 @@ FreeImage_GetMetadataCount(FREE_IMAGE_MDMODEL model, FIBITMAP *dib) {
// ----------------------------------------------------------
+unsigned DLL_CALLCONV
+FreeImage_GetMemorySize(FIBITMAP *dib) {
+ if (!dib) {
+ return 0;
+ }
+ FREEIMAGEHEADER *header = (FREEIMAGEHEADER *)dib->data;
+ BITMAPINFOHEADER *bih = FreeImage_GetInfoHeader(dib);
+
+ BOOL header_only = !header->has_pixels || header->external_bits != NULL;
+ BOOL need_masks = bih->biCompression == BI_BITFIELDS;
+ unsigned width = bih->biWidth;
+ unsigned height = bih->biHeight;
+ unsigned bpp = bih->biBitCount;
+
+ // start off with the size of the FIBITMAP structure
+ size_t size = sizeof(FIBITMAP);
+
+ // add sizes of FREEIMAGEHEADER, BITMAPINFOHEADER, palette and DIB data
+ size += FreeImage_GetInternalImageSize(header_only, width, height, bpp, need_masks);
+
+ // add ICC profile size
+ size += header->iccProfile.size;
+
+ // add thumbnail image size
+ if (header->thumbnail) {
+ // we assume a thumbnail not having a thumbnail as well,
+ // so this recursive call should not create an infinite loop
+ size += FreeImage_GetMemorySize(header->thumbnail);
+ }
+
+ // add metadata size
+ METADATAMAP *md = header->metadata;
+ if (!md) {
+ return (unsigned)size;
+ }
+
+ // add size of METADATAMAP
+ size += sizeof(METADATAMAP);
+
+ const size_t models = md->size();
+ if (models == 0) {
+ return (unsigned)size;
+ }
+
+ unsigned tags = 0;
+
+ for (METADATAMAP::iterator i = md->begin(); i != md->end(); i++) {
+ TAGMAP *tm = i->second;
+ if (tm) {
+ for (TAGMAP::iterator j = tm->begin(); j != tm->end(); j++) {
+ ++tags;
+ const std::string & key = j->first;
+ size += key.capacity();
+ size += FreeImage_GetTagMemorySize(j->second);
+ }
+ }
+ }
+
+ // add size of all TAGMAP instances
+ size += models * sizeof(TAGMAP);
+ // add size of tree nodes in METADATAMAP
+ size += MapIntrospector<METADATAMAP>::GetNodesMemorySize(models);
+ // add size of tree nodes in TAGMAP
+ size += MapIntrospector<TAGMAP>::GetNodesMemorySize(tags);
+
+ return (unsigned)size;
+}
diff --git a/plugins/AdvaImg/src/FreeImage/ColorLookup.cpp b/plugins/AdvaImg/src/FreeImage/ColorLookup.cpp
index 5f677eee5c..0f4435a725 100644
--- a/plugins/AdvaImg/src/FreeImage/ColorLookup.cpp
+++ b/plugins/AdvaImg/src/FreeImage/ColorLookup.cpp
@@ -26,10 +26,10 @@
// RGB color names ---------------------------------------------------------
typedef struct tagNamedColor {
- const char *name; // color name
- BYTE r; // red value
- BYTE g; // green value
- BYTE b; // blue value
+ const char *name; //! color name
+ BYTE r; //! red value
+ BYTE g; //! green value
+ BYTE b; //! blue value
} NamedColor;
// --------------------------------------------------------------------------
@@ -43,20 +43,21 @@ Helper function : perform a binary search on a color array
*/
static int
binsearch(const char *name, const NamedColor *color_array, int n) {
- int cond, low, mid, high;
+ int cond, low, mid, high;
low = 0;
high = n - 1;
while (low <= high) {
- mid = (low + high) / 2;
- if ((cond = strcmp(name, color_array[mid].name)) < 0)
- high = mid - 1;
- else if (cond > 0)
- low = mid + 1;
- else
- return mid;
- }
- return -1;
+ mid = (low + high) / 2;
+ if ((cond = strcmp(name, color_array[mid].name)) < 0) {
+ high = mid - 1;
+ } else if (cond > 0) {
+ low = mid + 1;
+ } else {
+ return mid;
+ }
+ }
+ return -1;
}
/**
@@ -68,22 +69,24 @@ Perform a binary search on a color array
*/
static int
FreeImage_LookupNamedColor(const char *szColor, const NamedColor *color_array, int ncolors) {
- int i;
+ int i;
char color[64];
// make lower case name, squezze white space
for (i = 0; szColor[i] && i < sizeof(color) - 1; i++) {
- if (isspace(szColor[i]))
+ if (isspace(szColor[i])) {
continue;
- if (isupper(szColor[i]))
- color[i] = (char)tolower(szColor[i]);
- else
+ }
+ if (isupper(szColor[i])) {
+ color[i] = (char)tolower(szColor[i]);
+ } else {
color[i] = szColor[i];
+ }
}
color[i] = 0;
- return (binsearch(color, color_array, ncolors));
+ return binsearch(color, color_array, ncolors);
}
// ==========================================================
@@ -595,153 +598,153 @@ FreeImage_LookupX11Color(const char *szColor, BYTE *nRed, BYTE *nGreen, BYTE *nB
the final recommendation for changes)
*/
static NamedColor SVGColorMap[] = {
- { "aliceblue", 240, 248, 255 },
- { "antiquewhite", 250, 235, 215 },
- { "aqua", 0, 255, 255 },
- { "aquamarine", 127, 255, 212 },
- { "azure", 240, 255, 255 },
- { "beige", 245, 245, 220 },
- { "bisque", 255, 228, 196 },
- { "black", 0, 0, 0 },
- { "blanchedalmond", 255, 235, 205 },
- { "blue", 0, 0, 255 },
- { "blueviolet", 138, 43, 226 },
- { "brown", 165, 42, 42 },
- { "burlywood", 222, 184, 135 },
- { "cadetblue", 95, 158, 160 },
- { "chartreuse", 127, 255, 0 },
- { "chocolate", 210, 105, 30 },
- { "coral", 255, 127, 80 },
- { "cornflowerblue", 100, 149, 237 },
- { "cornsilk", 255, 248, 220 },
- { "crimson", 220, 20, 60 },
- { "cyan", 0, 255, 255 },
- { "darkblue", 0, 0, 139 },
- { "darkcyan", 0, 139, 139 },
- { "darkgoldenrod", 184, 134, 11 },
- { "darkgray", 169, 169, 169 },
- { "darkgreen", 0, 100, 0 },
- { "darkgrey", 169, 169, 169 },
- { "darkkhaki", 189, 183, 107 },
- { "darkmagenta", 139, 0, 139 },
- { "darkolivegreen", 85, 107, 47 },
- { "darkorange", 255, 140, 0 },
- { "darkorchid", 153, 50, 204 },
- { "darkred", 139, 0, 0 },
- { "darksalmon", 233, 150, 122 },
- { "darkseagreen", 143, 188, 143 },
- { "darkslateblue", 72, 61, 139 },
- { "darkslategray", 47, 79, 79 },
- { "darkslategrey", 47, 79, 79 },
- { "darkturquoise", 0, 206, 209 },
- { "darkviolet", 148, 0, 211 },
- { "deeppink", 255, 20, 147 },
- { "deepskyblue", 0, 191, 255 },
- { "dimgray", 105, 105, 105 },
- { "dimgrey", 105, 105, 105 },
- { "dodgerblue", 30, 144, 255 },
- { "firebrick", 178, 34, 34 },
- { "floralwhite", 255, 250, 240 },
- { "forestgreen", 34, 139, 34 },
- { "fuchsia", 255, 0, 255 },
- { "gainsboro", 220, 220, 220 },
- { "ghostwhite", 248, 248, 255 },
- { "gold", 255, 215, 0 },
- { "goldenrod", 218, 165, 32 },
- { "gray", 128, 128, 128 },
- { "grey", 128, 128, 128 },
- { "green", 0, 128, 0 },
- { "greenyellow", 173, 255, 47 },
- { "honeydew", 240, 255, 240 },
- { "hotpink", 255, 105, 180 },
- { "indianred", 205, 92, 92 },
- { "indigo", 75, 0, 130 },
- { "ivory", 255, 255, 240 },
- { "khaki", 240, 230, 140 },
- { "lavender", 230, 230, 250 },
- { "lavenderblush", 255, 240, 245 },
- { "lawngreen", 124, 252, 0 },
- { "lemonchiffon", 255, 250, 205 },
- { "lightblue", 173, 216, 230 },
- { "lightcoral", 240, 128, 128 },
- { "lightcyan", 224, 255, 255 },
- { "lightgoldenrodyellow", 250, 250, 210 },
- { "lightgray", 211, 211, 211 },
- { "lightgreen", 144, 238, 144 },
- { "lightgrey", 211, 211, 211 },
- { "lightpink", 255, 182, 193 },
- { "lightsalmon", 255, 160, 122 },
- { "lightseagreen", 32, 178, 170 },
- { "lightskyblue", 135, 206, 250 },
- { "lightslategray", 119, 136, 153 },
- { "lightslategrey", 119, 136, 153 },
- { "lightsteelblue", 176, 196, 222 },
- { "lightyellow", 255, 255, 224 },
- { "lime", 0, 255, 0 },
- { "limegreen", 50, 205, 50 },
- { "linen", 250, 240, 230 },
- { "magenta", 255, 0, 255 },
- { "maroon", 128, 0, 0 },
- { "mediumaquamarine", 102, 205, 170 },
- { "mediumblue", 0, 0, 205 },
- { "mediumorchid", 186, 85, 211 },
- { "mediumpurple", 147, 112, 219 },
- { "mediumseagreen", 60, 179, 113 },
- { "mediumslateblue", 123, 104, 238 },
- { "mediumspringgreen", 0, 250, 154 },
- { "mediumturquoise", 72, 209, 204 },
- { "mediumvioletred", 199, 21, 133 },
- { "midnightblue", 25, 25, 112 },
- { "mintcream", 245, 255, 250 },
- { "mistyrose", 255, 228, 225 },
- { "moccasin", 255, 228, 181 },
- { "navajowhite", 255, 222, 173 },
- { "navy", 0, 0, 128 },
- { "oldlace", 253, 245, 230 },
- { "olive", 128, 128, 0 },
- { "olivedrab", 107, 142, 35 },
- { "orange", 255, 165, 0 },
- { "orangered", 255, 69, 0 },
- { "orchid", 218, 112, 214 },
- { "palegoldenrod", 238, 232, 170 },
- { "palegreen", 152, 251, 152 },
- { "paleturquoise", 175, 238, 238 },
- { "palevioletred", 219, 112, 147 },
- { "papayawhip", 255, 239, 213 },
- { "peachpuff", 255, 218, 185 },
- { "peru", 205, 133, 63 },
- { "pink", 255, 192, 203 },
- { "plum", 221, 160, 221 },
- { "powderblue", 176, 224, 230 },
- { "purple", 128, 0, 128 },
- { "red", 255, 0, 0 },
- { "rosybrown", 188, 143, 143 },
- { "royalblue", 65, 105, 225 },
- { "saddlebrown", 139, 69, 19 },
- { "salmon", 250, 128, 114 },
- { "sandybrown", 244, 164, 96 },
- { "seagreen", 46, 139, 87 },
- { "seashell", 255, 245, 238 },
- { "sienna", 160, 82, 45 },
- { "silver", 192, 192, 192 },
- { "skyblue", 135, 206, 235 },
- { "slateblue", 106, 90, 205 },
- { "slategray", 112, 128, 144 },
- { "slategrey", 112, 128, 144 },
- { "snow", 255, 250, 250 },
- { "springgreen", 0, 255, 127 },
- { "steelblue", 70, 130, 180 },
- { "tan", 210, 180, 140 },
- { "teal", 0, 128, 128 },
- { "thistle", 216, 191, 216 },
- { "tomato", 255, 99, 71 },
- { "turquoise", 64, 224, 208 },
- { "violet", 238, 130, 238 },
- { "wheat", 245, 222, 179 },
- { "white", 255, 255, 255 },
- { "whitesmoke", 245, 245, 245 },
- { "yellow", 255, 255, 0 },
- { "yellowgreen", 154, 205, 50 }
+ { "aliceblue", 240, 248, 255 },
+ { "antiquewhite", 250, 235, 215 },
+ { "aqua", 0, 255, 255 },
+ { "aquamarine", 127, 255, 212 },
+ { "azure", 240, 255, 255 },
+ { "beige", 245, 245, 220 },
+ { "bisque", 255, 228, 196 },
+ { "black", 0, 0, 0 },
+ { "blanchedalmond", 255, 235, 205 },
+ { "blue", 0, 0, 255 },
+ { "blueviolet", 138, 43, 226 },
+ { "brown", 165, 42, 42 },
+ { "burlywood", 222, 184, 135 },
+ { "cadetblue", 95, 158, 160 },
+ { "chartreuse", 127, 255, 0 },
+ { "chocolate", 210, 105, 30 },
+ { "coral", 255, 127, 80 },
+ { "cornflowerblue", 100, 149, 237 },
+ { "cornsilk", 255, 248, 220 },
+ { "crimson", 220, 20, 60 },
+ { "cyan", 0, 255, 255 },
+ { "darkblue", 0, 0, 139 },
+ { "darkcyan", 0, 139, 139 },
+ { "darkgoldenrod", 184, 134, 11 },
+ { "darkgray", 169, 169, 169 },
+ { "darkgreen", 0, 100, 0 },
+ { "darkgrey", 169, 169, 169 },
+ { "darkkhaki", 189, 183, 107 },
+ { "darkmagenta", 139, 0, 139 },
+ { "darkolivegreen", 85, 107, 47 },
+ { "darkorange", 255, 140, 0 },
+ { "darkorchid", 153, 50, 204 },
+ { "darkred", 139, 0, 0 },
+ { "darksalmon", 233, 150, 122 },
+ { "darkseagreen", 143, 188, 143 },
+ { "darkslateblue", 72, 61, 139 },
+ { "darkslategray", 47, 79, 79 },
+ { "darkslategrey", 47, 79, 79 },
+ { "darkturquoise", 0, 206, 209 },
+ { "darkviolet", 148, 0, 211 },
+ { "deeppink", 255, 20, 147 },
+ { "deepskyblue", 0, 191, 255 },
+ { "dimgray", 105, 105, 105 },
+ { "dimgrey", 105, 105, 105 },
+ { "dodgerblue", 30, 144, 255 },
+ { "firebrick", 178, 34, 34 },
+ { "floralwhite", 255, 250, 240 },
+ { "forestgreen", 34, 139, 34 },
+ { "fuchsia", 255, 0, 255 },
+ { "gainsboro", 220, 220, 220 },
+ { "ghostwhite", 248, 248, 255 },
+ { "gold", 255, 215, 0 },
+ { "goldenrod", 218, 165, 32 },
+ { "gray", 128, 128, 128 },
+ { "green", 0, 128, 0 },
+ { "greenyellow", 173, 255, 47 },
+ { "grey", 128, 128, 128 },
+ { "honeydew", 240, 255, 240 },
+ { "hotpink", 255, 105, 180 },
+ { "indianred", 205, 92, 92 },
+ { "indigo", 75, 0, 130 },
+ { "ivory", 255, 255, 240 },
+ { "khaki", 240, 230, 140 },
+ { "lavender", 230, 230, 250 },
+ { "lavenderblush", 255, 240, 245 },
+ { "lawngreen", 124, 252, 0 },
+ { "lemonchiffon", 255, 250, 205 },
+ { "lightblue", 173, 216, 230 },
+ { "lightcoral", 240, 128, 128 },
+ { "lightcyan", 224, 255, 255 },
+ { "lightgoldenrodyellow", 250, 250, 210 },
+ { "lightgray", 211, 211, 211 },
+ { "lightgreen", 144, 238, 144 },
+ { "lightgrey", 211, 211, 211 },
+ { "lightpink", 255, 182, 193 },
+ { "lightsalmon", 255, 160, 122 },
+ { "lightseagreen", 32, 178, 170 },
+ { "lightskyblue", 135, 206, 250 },
+ { "lightslategray", 119, 136, 153 },
+ { "lightslategrey", 119, 136, 153 },
+ { "lightsteelblue", 176, 196, 222 },
+ { "lightyellow", 255, 255, 224 },
+ { "lime", 0, 255, 0 },
+ { "limegreen", 50, 205, 50 },
+ { "linen", 250, 240, 230 },
+ { "magenta", 255, 0, 255 },
+ { "maroon", 128, 0, 0 },
+ { "mediumaquamarine", 102, 205, 170 },
+ { "mediumblue", 0, 0, 205 },
+ { "mediumorchid", 186, 85, 211 },
+ { "mediumpurple", 147, 112, 219 },
+ { "mediumseagreen", 60, 179, 113 },
+ { "mediumslateblue", 123, 104, 238 },
+ { "mediumspringgreen", 0, 250, 154 },
+ { "mediumturquoise", 72, 209, 204 },
+ { "mediumvioletred", 199, 21, 133 },
+ { "midnightblue", 25, 25, 112 },
+ { "mintcream", 245, 255, 250 },
+ { "mistyrose", 255, 228, 225 },
+ { "moccasin", 255, 228, 181 },
+ { "navajowhite", 255, 222, 173 },
+ { "navy", 0, 0, 128 },
+ { "oldlace", 253, 245, 230 },
+ { "olive", 128, 128, 0 },
+ { "olivedrab", 107, 142, 35 },
+ { "orange", 255, 165, 0 },
+ { "orangered", 255, 69, 0 },
+ { "orchid", 218, 112, 214 },
+ { "palegoldenrod", 238, 232, 170 },
+ { "palegreen", 152, 251, 152 },
+ { "paleturquoise", 175, 238, 238 },
+ { "palevioletred", 219, 112, 147 },
+ { "papayawhip", 255, 239, 213 },
+ { "peachpuff", 255, 218, 185 },
+ { "peru", 205, 133, 63 },
+ { "pink", 255, 192, 203 },
+ { "plum", 221, 160, 221 },
+ { "powderblue", 176, 224, 230 },
+ { "purple", 128, 0, 128 },
+ { "red", 255, 0, 0 },
+ { "rosybrown", 188, 143, 143 },
+ { "royalblue", 65, 105, 225 },
+ { "saddlebrown", 139, 69, 19 },
+ { "salmon", 250, 128, 114 },
+ { "sandybrown", 244, 164, 96 },
+ { "seagreen", 46, 139, 87 },
+ { "seashell", 255, 245, 238 },
+ { "sienna", 160, 82, 45 },
+ { "silver", 192, 192, 192 },
+ { "skyblue", 135, 206, 235 },
+ { "slateblue", 106, 90, 205 },
+ { "slategray", 112, 128, 144 },
+ { "slategrey", 112, 128, 144 },
+ { "snow", 255, 250, 250 },
+ { "springgreen", 0, 255, 127 },
+ { "steelblue", 70, 130, 180 },
+ { "tan", 210, 180, 140 },
+ { "teal", 0, 128, 128 },
+ { "thistle", 216, 191, 216 },
+ { "tomato", 255, 99, 71 },
+ { "turquoise", 64, 224, 208 },
+ { "violet", 238, 130, 238 },
+ { "wheat", 245, 222, 179 },
+ { "white", 255, 255, 255 },
+ { "whitesmoke", 245, 245, 245 },
+ { "yellow", 255, 255, 0 },
+ { "yellowgreen", 154, 205, 50 }
};
diff --git a/plugins/AdvaImg/src/FreeImage/Conversion.cpp b/plugins/AdvaImg/src/FreeImage/Conversion.cpp
index 04cec65ab5..815057ad08 100644
--- a/plugins/AdvaImg/src/FreeImage/Conversion.cpp
+++ b/plugins/AdvaImg/src/FreeImage/Conversion.cpp
@@ -6,6 +6,7 @@
// - Hervé Drolon (drolon@infonie.fr)
// - Jani Kajala (janik@remedy.fi)
// - Mihail Naydenov (mnaydenov@users.sourceforge.net)
+// - Carsten Klein (cklein05@users.sourceforge.net)
//
// This file is part of FreeImage 3
//
@@ -372,7 +373,8 @@ FreeImage_ColorQuantizeEx(FIBITMAP *dib, FREE_IMAGE_QUANTIZE quantize, int Palet
if( ReserveSize < 0 ) ReserveSize = 0;
if( ReserveSize > PaletteSize ) ReserveSize = PaletteSize;
if (FreeImage_HasPixels(dib)) {
- if (FreeImage_GetBPP(dib) == 24) {
+ const unsigned bpp = FreeImage_GetBPP(dib);
+ if((FreeImage_GetImageType(dib) == FIT_BITMAP) && (bpp == 24 || bpp == 32)) {
switch(quantize) {
case FIQ_WUQUANT :
{
@@ -387,9 +389,14 @@ FreeImage_ColorQuantizeEx(FIBITMAP *dib, FREE_IMAGE_QUANTIZE quantize, int Palet
} catch (const char *) {
return NULL;
}
+ break;
}
case FIQ_NNQUANT :
{
+ if (bpp == 32) {
+ // 32-bit images not supported by NNQUANT
+ return NULL;
+ }
// sampling factor in range 1..30.
// 1 => slower (but better), 30 => faster. Default value is 1
const int sampling = 1;
@@ -402,6 +409,16 @@ FreeImage_ColorQuantizeEx(FIBITMAP *dib, FREE_IMAGE_QUANTIZE quantize, int Palet
}
return dst;
}
+ case FIQ_LFPQUANT :
+ {
+ LFPQuantizer Q(PaletteSize);
+ FIBITMAP *dst = Q.Quantize(dib, ReserveSize, ReservePalette);
+ if(dst) {
+ // copy metadata from src to dst
+ FreeImage_CloneMetadata(dst, dib);
+ }
+ return dst;
+ }
}
}
}
@@ -412,26 +429,47 @@ FreeImage_ColorQuantizeEx(FIBITMAP *dib, FREE_IMAGE_QUANTIZE quantize, int Palet
// ==========================================================
FIBITMAP * DLL_CALLCONV
-FreeImage_ConvertFromRawBits(BYTE *bits, int width, int height, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown) {
- FIBITMAP *dib = FreeImage_Allocate(width, height, bpp, red_mask, green_mask, blue_mask);
+FreeImage_ConvertFromRawBitsEx(BOOL copySource, BYTE *bits, FREE_IMAGE_TYPE type, int width, int height, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown) {
+ FIBITMAP *dib = NULL;
- if (dib != NULL) {
- if (topdown) {
- for (int i = height - 1; i >= 0; --i) {
- memcpy(FreeImage_GetScanLine(dib, i), bits, FreeImage_GetLine(dib));
- bits += pitch;
- }
- } else {
- for (int i = 0; i < height; ++i) {
- memcpy(FreeImage_GetScanLine(dib, i), bits, FreeImage_GetLine(dib));
- bits += pitch;
- }
+ if(copySource) {
+ // allocate a FIBITMAP with internally managed pixel buffer
+ dib = FreeImage_AllocateT(type, width, height, bpp, red_mask, green_mask, blue_mask);
+ if(!dib) {
+ return NULL;
+ }
+ // copy user provided pixel buffer into the dib
+ const unsigned linesize = FreeImage_GetLine(dib);
+ for(int y = 0; y < height; y++) {
+ memcpy(FreeImage_GetScanLine(dib, y), bits, linesize);
+ // next line in user's buffer
+ bits += pitch;
+ }
+ // flip pixels vertically if needed
+ if(topdown) {
+ FreeImage_FlipVertical(dib);
+ }
+ }
+ else {
+ // allocate a FIBITMAP using a wrapper to user provided pixel buffer
+ dib = FreeImage_AllocateHeaderForBits(bits, pitch, type, width, height, bpp, red_mask, green_mask, blue_mask);
+ if(!dib) {
+ return NULL;
+ }
+ // flip pixels vertically if needed
+ if(topdown) {
+ FreeImage_FlipVertical(dib);
}
}
return dib;
}
+FIBITMAP * DLL_CALLCONV
+FreeImage_ConvertFromRawBits(BYTE *bits, int width, int height, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown) {
+ return FreeImage_ConvertFromRawBitsEx(TRUE /* copySource */, bits, FIT_BITMAP, width, height, pitch, bpp, red_mask, green_mask, blue_mask, topdown);
+}
+
void DLL_CALLCONV
FreeImage_ConvertToRawBits(BYTE *bits, FIBITMAP *dib, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown) {
if (FreeImage_HasPixels(dib) && (bits != NULL)) {
diff --git a/plugins/AdvaImg/src/FreeImage/ConversionType.cpp b/plugins/AdvaImg/src/FreeImage/ConversionType.cpp
index b537f72814..a2ca90ff9d 100644
--- a/plugins/AdvaImg/src/FreeImage/ConversionType.cpp
+++ b/plugins/AdvaImg/src/FreeImage/ConversionType.cpp
@@ -3,6 +3,7 @@
//
// Design and implementation by
// - Hervé Drolon (drolon@infonie.fr)
+// - Tanner Helland (tannerhelland@users.sf.net)
//
// This file is part of FreeImage 3
//
@@ -346,11 +347,13 @@ FreeImage_ConvertToType(FIBITMAP *src, FREE_IMAGE_TYPE dst_type, BOOL scale_line
dst = FreeImage_ConvertToRGB16(src);
break;
case FIT_RGBA16:
+ dst = FreeImage_ConvertToRGBA16(src);
break;
case FIT_RGBF:
dst = FreeImage_ConvertToRGBF(src);
break;
case FIT_RGBAF:
+ dst = FreeImage_ConvertToRGBAF(src);
break;
}
break;
@@ -378,11 +381,13 @@ FreeImage_ConvertToType(FIBITMAP *src, FREE_IMAGE_TYPE dst_type, BOOL scale_line
dst = FreeImage_ConvertToRGB16(src);
break;
case FIT_RGBA16:
+ dst = FreeImage_ConvertToRGBA16(src);
break;
case FIT_RGBF:
dst = FreeImage_ConvertToRGBF(src);
break;
case FIT_RGBAF:
+ dst = FreeImage_ConvertToRGBAF(src);
break;
}
break;
@@ -503,6 +508,7 @@ FreeImage_ConvertToType(FIBITMAP *src, FREE_IMAGE_TYPE dst_type, BOOL scale_line
dst = FreeImage_ConvertToRGBF(src);
break;
case FIT_RGBAF:
+ dst = FreeImage_ConvertToRGBAF(src);
break;
}
break;
@@ -582,11 +588,13 @@ FreeImage_ConvertToType(FIBITMAP *src, FREE_IMAGE_TYPE dst_type, BOOL scale_line
case FIT_COMPLEX:
break;
case FIT_RGBA16:
+ dst = FreeImage_ConvertToRGBA16(src);
break;
case FIT_RGBF:
dst = FreeImage_ConvertToRGBF(src);
break;
case FIT_RGBAF:
+ dst = FreeImage_ConvertToRGBAF(src);
break;
}
break;
@@ -618,6 +626,7 @@ FreeImage_ConvertToType(FIBITMAP *src, FREE_IMAGE_TYPE dst_type, BOOL scale_line
dst = FreeImage_ConvertToRGBF(src);
break;
case FIT_RGBAF:
+ dst = FreeImage_ConvertToRGBAF(src);
break;
}
break;
@@ -645,6 +654,7 @@ FreeImage_ConvertToType(FIBITMAP *src, FREE_IMAGE_TYPE dst_type, BOOL scale_line
case FIT_RGBA16:
break;
case FIT_RGBAF:
+ dst = FreeImage_ConvertToRGBAF(src);
break;
}
break;
diff --git a/plugins/AdvaImg/src/FreeImage/FreeImageIO.cpp b/plugins/AdvaImg/src/FreeImage/FreeImageIO.cpp
index f8cf7604eb..83394f049c 100644
--- a/plugins/AdvaImg/src/FreeImage/FreeImageIO.cpp
+++ b/plugins/AdvaImg/src/FreeImage/FreeImageIO.cpp
@@ -68,14 +68,18 @@ _MemoryReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle) {
FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(((FIMEMORY*)handle)->data);
for(x = 0; x < count; x++) {
- //if there isnt size bytes left to read, set pos to eof and return a short count
- if( (mem_header->filelen - mem_header->curpos) < (long)size ) {
- mem_header->curpos = mem_header->filelen;
+ long remaining_bytes = mem_header->file_length - mem_header->current_position;
+ //if there isn't size bytes left to read, set pos to eof and return a short count
+ if( remaining_bytes < (long)size ) {
+ if(remaining_bytes > 0) {
+ memcpy( buffer, (char *)mem_header->data + mem_header->current_position, remaining_bytes );
+ }
+ mem_header->current_position = mem_header->file_length;
break;
}
//copy size bytes count times
- memcpy( buffer, (char *)mem_header->data + mem_header->curpos, size );
- mem_header->curpos += size;
+ memcpy( buffer, (char *)mem_header->data + mem_header->current_position, size );
+ mem_header->current_position += size;
buffer = (char *)buffer + size;
}
return x;
@@ -89,32 +93,32 @@ _MemoryWriteProc(void *buffer, unsigned size, unsigned count, fi_handle handle)
FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(((FIMEMORY*)handle)->data);
//double the data block size if we need to
- while( (mem_header->curpos + (long)(size*count)) >= mem_header->datalen ) {
+ while( (mem_header->current_position + (long)(size * count)) >= mem_header->data_length ) {
//if we are at or above 1G, we cant double without going negative
- if( mem_header->datalen & 0x40000000 ) {
+ if( mem_header->data_length & 0x40000000 ) {
//max 2G
- if( mem_header->datalen == 0x7FFFFFFF ) {
+ if( mem_header->data_length == 0x7FFFFFFF ) {
return 0;
}
newdatalen = 0x7FFFFFFF;
- } else if( mem_header->datalen == 0 ) {
+ } else if( mem_header->data_length == 0 ) {
//default to 4K if nothing yet
newdatalen = 4096;
} else {
//double size
- newdatalen = mem_header->datalen << 1;
+ newdatalen = mem_header->data_length << 1;
}
newdata = realloc( mem_header->data, newdatalen );
if( !newdata ) {
return 0;
}
mem_header->data = newdata;
- mem_header->datalen = newdatalen;
+ mem_header->data_length = newdatalen;
}
- memcpy( (char *)mem_header->data + mem_header->curpos, buffer, size*count );
- mem_header->curpos += size*count;
- if( mem_header->curpos > mem_header->filelen ) {
- mem_header->filelen = mem_header->curpos;
+ memcpy( (char *)mem_header->data + mem_header->current_position, buffer, size * count );
+ mem_header->current_position += size * count;
+ if( mem_header->current_position > mem_header->file_length ) {
+ mem_header->file_length = mem_header->current_position;
}
return count;
}
@@ -123,25 +127,28 @@ int DLL_CALLCONV
_MemorySeekProc(fi_handle handle, long offset, int origin) {
FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(((FIMEMORY*)handle)->data);
+ // you can use _MemorySeekProc to reposition the pointer anywhere in a file
+ // the pointer can also be positioned beyond the end of the file
+
switch(origin) { //0 to filelen-1 are 'inside' the file
default:
case SEEK_SET: //can fseek() to 0-7FFFFFFF always
if( offset >= 0 ) {
- mem_header->curpos = offset;
+ mem_header->current_position = offset;
return 0;
}
break;
case SEEK_CUR:
- if( mem_header->curpos + offset >= 0 ) {
- mem_header->curpos += offset;
+ if( mem_header->current_position + offset >= 0 ) {
+ mem_header->current_position += offset;
return 0;
}
break;
case SEEK_END:
- if( mem_header->filelen + offset >= 0 ) {
- mem_header->curpos = mem_header->filelen + offset;
+ if( mem_header->file_length + offset >= 0 ) {
+ mem_header->current_position = mem_header->file_length + offset;
return 0;
}
break;
@@ -154,7 +161,7 @@ long DLL_CALLCONV
_MemoryTellProc(fi_handle handle) {
FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(((FIMEMORY*)handle)->data);
- return mem_header->curpos;
+ return mem_header->current_position;
}
// ----------------------------------------------------------
diff --git a/plugins/AdvaImg/src/FreeImage/LFPQuantizer.cpp b/plugins/AdvaImg/src/FreeImage/LFPQuantizer.cpp
new file mode 100644
index 0000000000..8b592c30f1
--- /dev/null
+++ b/plugins/AdvaImg/src/FreeImage/LFPQuantizer.cpp
@@ -0,0 +1,208 @@
+// ==========================================================
+// LFPQuantizer class implementation
+//
+// Design and implementation by
+// - Carsten Klein (cklein05@users.sourceforge.net)
+//
+// This file is part of FreeImage 3
+//
+// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
+// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
+// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
+// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
+// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
+// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
+// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
+// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
+// THIS DISCLAIMER.
+//
+// Use at your own risk!
+// ==========================================================
+
+#include "Quantizers.h"
+#include "FreeImage.h"
+#include "Utilities.h"
+
+LFPQuantizer::LFPQuantizer(unsigned PaletteSize) :
+ m_size(0), m_limit(PaletteSize), m_index(0) {
+ m_map = new MapEntry[MAP_SIZE];
+ memset(m_map, 0xFF, MAP_SIZE * sizeof(MapEntry));
+}
+
+LFPQuantizer::~LFPQuantizer() {
+ delete[] m_map;
+}
+
+FIBITMAP* LFPQuantizer::Quantize(FIBITMAP *dib, int ReserveSize, RGBQUAD *ReservePalette) {
+
+ if (ReserveSize > 0 && ReservePalette != NULL) {
+ AddReservePalette(ReservePalette, ReserveSize);
+ }
+
+ const unsigned width = FreeImage_GetWidth(dib);
+ const unsigned height = FreeImage_GetHeight(dib);
+
+ FIBITMAP *dib8 = FreeImage_Allocate(width, height, 8);
+ if (dib8 == NULL) {
+ return NULL;
+ }
+
+ const unsigned src_pitch = FreeImage_GetPitch(dib);
+ const unsigned dst_pitch = FreeImage_GetPitch(dib8);
+
+ const BYTE * const src_bits = FreeImage_GetBits(dib);
+ BYTE * const dst_bits = FreeImage_GetBits(dib8);
+
+ unsigned last_color = -1;
+ int last_index = 0;
+
+ if (FreeImage_GetBPP(dib) == 24) {
+
+ // Getting the source pixel as an unsigned int is much faster than
+ // working with FI_RGBA_xxx and shifting. However, this may fail
+ // for the very last pixel, since its rgbReserved member (alpha)
+ // may actually point to an address beyond the bitmap's memory. So,
+ // we do not process the last scanline in the first loop.
+
+ // Process all but the last scanline.
+ for (unsigned y = 0; y < height - 1; ++y) {
+ BYTE *dst_line = dst_bits + y * dst_pitch;
+ const BYTE *src_line = src_bits + y * src_pitch;
+ for (unsigned x = 0; x < width; ++x) {
+ const unsigned color = *((unsigned *) src_line) & 0x00FFFFFF;
+ if (color != last_color) {
+ last_color = color;
+ last_index = GetIndexForColor(color);
+ if (last_index == -1) {
+ FreeImage_Unload(dib8);
+ return NULL;
+ }
+ }
+ dst_line[x] = last_index;
+ src_line += 3;
+ }
+ }
+
+ // Process all but the last pixel of the last scanline.
+ BYTE *dst_line = dst_bits + (height - 1) * dst_pitch;
+ const BYTE *src_line = src_bits + (height - 1) * src_pitch;
+ for (unsigned x = 0; x < width - 1; ++x) {
+ const unsigned color = *((unsigned *) src_line) & 0x00FFFFFF;
+ if (color != last_color) {
+ last_color = color;
+ last_index = GetIndexForColor(color);
+ if (last_index == -1) {
+ FreeImage_Unload(dib8);
+ return NULL;
+ }
+ }
+ dst_line[x] = last_index;
+ src_line += 3;
+ }
+
+ // Process the last pixel (src_line should already point to it).
+ const unsigned color = 0 | src_line[FI_RGBA_BLUE] << FI_RGBA_BLUE_SHIFT
+ | src_line[FI_RGBA_GREEN] << FI_RGBA_GREEN_SHIFT
+ | src_line[FI_RGBA_RED] << FI_RGBA_RED_SHIFT;
+ if (color != last_color) {
+ last_color = color;
+ last_index = GetIndexForColor(color);
+ if (last_index == -1) {
+ FreeImage_Unload(dib8);
+ return NULL;
+ }
+ }
+ dst_line[width - 1] = last_index;
+
+ } else {
+ for (unsigned y = 0; y < height; ++y) {
+ BYTE *dst_line = dst_bits + y * dst_pitch;
+ const BYTE *src_line = src_bits + y * src_pitch;
+ for (unsigned x = 0; x < width; ++x) {
+ const unsigned color = *((unsigned *) src_line) & 0x00FFFFFF;
+ if (color != last_color) {
+ last_color = color;
+ last_index = GetIndexForColor(color);
+ if (last_index == -1) {
+ FreeImage_Unload(dib8);
+ return NULL;
+ }
+ }
+ dst_line[x] = last_index;
+ src_line += 4;
+ }
+ }
+ }
+
+ WritePalette(FreeImage_GetPalette(dib8));
+ return dib8;
+}
+
+/**
+ * Returns the palette index of the specified color. Tries to put the
+ * color into the map, if it's not already present in the map. In that
+ * case, a new index is used for the color. Returns -1, if adding the
+ * color would exceed the desired maximum number of colors in the
+ * palette.
+ * @param color the color to get the index from
+ * @return the palette index of the specified color or -1, if there
+ * is no space left in the palette
+ */
+inline int LFPQuantizer::GetIndexForColor(unsigned color) {
+ unsigned bucket = hash(color) & (MAP_SIZE - 1);
+ while (m_map[bucket].color != color) {
+ if (m_map[bucket].color == EMPTY_BUCKET) {
+ if (m_size == m_limit) {
+ return -1;
+ }
+ m_map[bucket].color = color;
+ m_map[bucket].index = m_index++;
+ ++m_size;
+ break;
+ }
+ bucket = (bucket + 1) % MAP_SIZE;
+ }
+ return m_map[bucket].index;
+}
+
+/**
+ * Adds the specified number of entries of the specified reserve
+ * palette to the newly created palette.
+ * @param *palette a pointer to the reserve palette to copy from
+ * @param size the number of entries to copy
+ */
+void LFPQuantizer::AddReservePalette(const void *palette, unsigned size) {
+ if (size > MAX_SIZE) {
+ size = MAX_SIZE;
+ }
+ unsigned *ppal = (unsigned *) palette;
+ const unsigned offset = m_limit - size;
+ for (unsigned i = 0; i < size; ++i) {
+ const unsigned color = *ppal++;
+ const unsigned index = i + offset;
+ unsigned bucket = hash(color) & (MAP_SIZE - 1);
+ while((m_map[bucket].color != EMPTY_BUCKET) && (m_map[bucket].color != color)) {
+ bucket = (bucket + 1) % MAP_SIZE;
+ }
+ if(m_map[bucket].color != color) {
+ m_map[bucket].color = color;
+ m_map[bucket].index = index;
+ }
+ }
+ m_size += size;
+}
+
+/**
+ * Copies the newly created palette into the specified destination
+ * palette. Although unused palette entries are not overwritten in
+ * the destination palette, it is assumed to have space for at
+ * least 256 entries.
+ * @param palette a pointer to the destination palette
+ */
+void LFPQuantizer::WritePalette(void *palette) {
+ for (unsigned i = 0; i < MAP_SIZE; ++i) {
+ if (m_map[i].color != EMPTY_BUCKET) {
+ ((unsigned *) palette)[m_map[i].index] = m_map[i].color;
+ }
+ }
+}
diff --git a/plugins/AdvaImg/src/FreeImage/MNGHelper.cpp b/plugins/AdvaImg/src/FreeImage/MNGHelper.cpp
index a4c67a2abe..ed3664cf77 100644
--- a/plugins/AdvaImg/src/FreeImage/MNGHelper.cpp
+++ b/plugins/AdvaImg/src/FreeImage/MNGHelper.cpp
@@ -357,7 +357,6 @@ Retrieve the position of a chunk in a PNG stream
*/
static BOOL
mng_FindChunk(FIMEMORY *hPngMemory, BYTE *chunk_name, long offset, DWORD *start_pos, DWORD *next_pos) {
- BOOL mEnd = FALSE;
DWORD mLength = 0;
BYTE *data = NULL;
@@ -513,10 +512,14 @@ mng_RemoveChunk(FIMEMORY *hPngMemory, BYTE *chunk_name) {
DWORD next_pos = 0;
bResult = mng_FindChunk(hPngMemory, chunk_name, 8, &start_pos, &next_pos);
- if(!bResult) return FALSE;
+ if(!bResult) {
+ return FALSE;
+ }
bResult = mng_CopyRemoveChunks(hPngMemory, start_pos, next_pos);
- if(!bResult) return FALSE;
+ if(!bResult) {
+ return FALSE;
+ }
return TRUE;
}
@@ -529,10 +532,14 @@ mng_InsertChunk(FIMEMORY *hPngMemory, BYTE *inNextChunkName, BYTE *inInsertChunk
DWORD next_pos = 0;
bResult = mng_FindChunk(hPngMemory, inNextChunkName, 8, &start_pos, &next_pos);
- if(!bResult) return FALSE;
+ if(!bResult) {
+ return FALSE;
+ }
bResult = mng_CopyInsertChunks(hPngMemory, inNextChunkName, inInsertChunk, chunk_length, start_pos, next_pos);
- if(!bResult) return FALSE;
+ if(!bResult) {
+ return FALSE;
+ }
return TRUE;
}
@@ -962,7 +969,7 @@ mng_ReadChunks(int format_id, FreeImageIO *io, fi_handle handle, long Offset, in
jng_color_type = mChunk[8];
jng_image_sample_depth = mChunk[9];
jng_image_compression_method = mChunk[10];
- BYTE jng_image_interlace_method = mChunk[11];
+ //BYTE jng_image_interlace_method = mChunk[11]; // for debug only
jng_alpha_sample_depth = mChunk[12];
jng_alpha_compression_method = mChunk[13];
@@ -1000,7 +1007,9 @@ mng_ReadChunks(int format_id, FreeImageIO *io, fi_handle handle, long Offset, in
break;
}
// load the JPEG
- if(dib) FreeImage_Unload(dib);
+ if(dib) {
+ FreeImage_Unload(dib);
+ }
dib = mng_LoadFromMemoryHandle(hJpegMemory, flags);
// load the PNG alpha layer
@@ -1017,7 +1026,9 @@ mng_ReadChunks(int format_id, FreeImageIO *io, fi_handle handle, long Offset, in
}
mng_WritePNGStream(jng_width, jng_height, jng_alpha_sample_depth, data, size_in_bytes, hPngMemory);
// load the PNG
- if(dib_alpha) FreeImage_Unload(dib_alpha);
+ if(dib_alpha) {
+ FreeImage_Unload(dib_alpha);
+ }
dib_alpha = mng_LoadFromMemoryHandle(hPngMemory, flags);
}
}
diff --git a/plugins/AdvaImg/src/FreeImage/MemoryIO.cpp b/plugins/AdvaImg/src/FreeImage/MemoryIO.cpp
index 6ae3fb2e11..e0997856a9 100644
--- a/plugins/AdvaImg/src/FreeImage/MemoryIO.cpp
+++ b/plugins/AdvaImg/src/FreeImage/MemoryIO.cpp
@@ -48,7 +48,7 @@ FreeImage_OpenMemory(BYTE *data, DWORD size_in_bytes) {
// wrap a user buffer
mem_header->delete_me = FALSE;
mem_header->data = (BYTE*)data;
- mem_header->datalen = mem_header->filelen = size_in_bytes;
+ mem_header->data_length = mem_header->file_length = size_in_bytes;
} else {
mem_header->delete_me = TRUE;
}
@@ -120,7 +120,7 @@ FreeImage_AcquireMemory(FIMEMORY *stream, BYTE **data, DWORD *size_in_bytes) {
FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(stream->data);
*data = (BYTE*)mem_header->data;
- *size_in_bytes = mem_header->filelen;
+ *size_in_bytes = mem_header->file_length;
return TRUE;
}
diff --git a/plugins/AdvaImg/src/FreeImage/MultiPage.cpp b/plugins/AdvaImg/src/FreeImage/MultiPage.cpp
index d48e11be94..4fe76adb16 100644
--- a/plugins/AdvaImg/src/FreeImage/MultiPage.cpp
+++ b/plugins/AdvaImg/src/FreeImage/MultiPage.cpp
@@ -269,8 +269,8 @@ FreeImage_OpenMultiBitmap(FREE_IMAGE_FORMAT fif, const char *filename, BOOL crea
header->node = node;
header->fif = fif;
header->io = io.get ();
- header->handle = handle;
- header->changed = FALSE;
+ header->handle = handle;
+ header->changed = FALSE;
header->read_only = read_only;
header->m_cachefile = NULL;
header->cache_fif = fif;
@@ -344,13 +344,13 @@ FreeImage_OpenMultiBitmapFromHandle(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_h
BOOL read_only = FALSE; // modifications (if any) will be stored into the memory cache
if (io && handle) {
-
+
// retrieve the plugin list to find the node belonging to this plugin
PluginList *list = FreeImage_GetPluginList();
-
+
if (list) {
PluginNode *node = list->FindNodeFromFIF(fif);
-
+
if (node) {
std::auto_ptr<FIMULTIBITMAP> bitmap (new FIMULTIBITMAP);
std::auto_ptr<MULTIBITMAPHEADER> header (new MULTIBITMAPHEADER);
@@ -359,13 +359,13 @@ FreeImage_OpenMultiBitmapFromHandle(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_h
header->m_filename = NULL;
header->node = node;
header->fif = fif;
- header->handle = handle;
- header->changed = FALSE;
- header->read_only = read_only;
+ header->handle = handle;
+ header->changed = FALSE;
+ header->read_only = read_only;
header->m_cachefile = NULL;
header->cache_fif = fif;
header->load_flags = flags;
-
+
// store the MULTIBITMAPHEADER in the surrounding FIMULTIBITMAP structure
bitmap->data = header.get();
@@ -381,7 +381,7 @@ FreeImage_OpenMultiBitmapFromHandle(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_h
if (!read_only) {
// set up the cache
std::auto_ptr<CacheFile> cache_file (new CacheFile("", TRUE));
-
+
if (cache_file->open()) {
header->m_cachefile = cache_file.release();
}
@@ -408,7 +408,7 @@ FreeImage_SaveMultiBitmapToHandle(FREE_IMAGE_FORMAT fif, FIMULTIBITMAP *bitmap,
// retrieve the plugin list to find the node belonging to this plugin
PluginList *list = FreeImage_GetPluginList();
-
+
if (list) {
PluginNode *node = list->FindNodeFromFIF(fif);
diff --git a/plugins/AdvaImg/src/FreeImage/PixelAccess.cpp b/plugins/AdvaImg/src/FreeImage/PixelAccess.cpp
index c69463c316..b5714b2929 100644
--- a/plugins/AdvaImg/src/FreeImage/PixelAccess.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PixelAccess.cpp
@@ -28,19 +28,6 @@
// ----------------------------------------------------------
BYTE * DLL_CALLCONV
-FreeImage_GetBits(FIBITMAP *dib) {
- if(!FreeImage_HasPixels(dib)) {
- return NULL;
- }
- // returns the pixels aligned on a FIBITMAP_ALIGNMENT bytes alignment boundary
- size_t lp = (size_t)FreeImage_GetInfoHeader(dib);
- lp += sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * FreeImage_GetColorsUsed(dib);
- lp += FreeImage_HasRGBMasks(dib) ? sizeof(DWORD) * 3 : 0;
- lp += (lp % FIBITMAP_ALIGNMENT ? FIBITMAP_ALIGNMENT - lp % FIBITMAP_ALIGNMENT : 0);
- return (BYTE *)lp;
-}
-
-BYTE * DLL_CALLCONV
FreeImage_GetScanLine(FIBITMAP *dib, int scanline) {
if(!FreeImage_HasPixels(dib)) {
return NULL;
diff --git a/plugins/AdvaImg/src/FreeImage/Plugin.cpp b/plugins/AdvaImg/src/FreeImage/Plugin.cpp
index 6f88e47e68..13da67434e 100644
--- a/plugins/AdvaImg/src/FreeImage/Plugin.cpp
+++ b/plugins/AdvaImg/src/FreeImage/Plugin.cpp
@@ -218,7 +218,7 @@ FreeImage_GetPluginList() {
void DLL_CALLCONV
FreeImage_Initialise(BOOL load_local_plugins_only) {
if (s_plugin_reference_count++ == 0) {
-
+
/*
Note: initialize all singletons here
in order to avoid race conditions with multi-threading
@@ -261,8 +261,8 @@ FreeImage_Initialise(BOOL load_local_plugins_only) {
//s_plugins->AddNode(InitXBM);
//s_plugins->AddNode(InitXPM);
//s_plugins->AddNode(InitDDS);
- s_plugins->AddNode(InitGIF);
- //s_plugins->AddNode(InitHDR);
+ s_plugins->AddNode(InitGIF);
+ //s_plugins->AddNode(InitHDR);
//s_plugins->AddNode(InitG3);
//s_plugins->AddNode(InitSGI);
//s_plugins->AddNode(InitEXR);
@@ -275,26 +275,26 @@ FreeImage_Initialise(BOOL load_local_plugins_only) {
//#if !(defined(_MSC_VER) && (_MSC_VER <= 1310))
//s_plugins->AddNode(InitJXR);
//#endif // unsupported by MS Visual Studio 2003 !!!
-
+
// external plugin initialization
#ifdef _WIN32
if (!load_local_plugins_only) {
int count = 0;
char buffer[MAX_PATH + 200];
- char current_dir[2 * _MAX_PATH], module[2 * _MAX_PATH];
+ wchar_t current_dir[2 * _MAX_PATH], module[2 * _MAX_PATH];
BOOL bOk = FALSE;
// store the current directory. then set the directory to the application location
- if (GetCurrentDirectoryA(2 * _MAX_PATH, current_dir) != 0) {
- if (GetModuleFileNameA(NULL, module, 2 * _MAX_PATH) != 0) {
- char *last_point = strrchr(module, '\\');
+ if (GetCurrentDirectoryW(2 * _MAX_PATH, current_dir) != 0) {
+ if (GetModuleFileNameW(NULL, module, 2 * _MAX_PATH) != 0) {
+ wchar_t *last_point = wcsrchr(module, L'\\');
if (last_point) {
- *last_point = '\0';
+ *last_point = L'\0';
- bOk = SetCurrentDirectoryA(module);
+ bOk = SetCurrentDirectoryW(module);
}
}
}
@@ -335,7 +335,7 @@ FreeImage_Initialise(BOOL load_local_plugins_only) {
// restore the current directory
if (bOk) {
- SetCurrentDirectoryA(current_dir);
+ SetCurrentDirectoryW(current_dir);
}
}
#endif // _WIN32
diff --git a/plugins/AdvaImg/src/FreeImage/PluginEXR.cpp b/plugins/AdvaImg/src/FreeImage/PluginEXR.cpp
index 4a19b8b56f..b286430380 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginEXR.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginEXR.cpp
@@ -22,6 +22,12 @@
#include "FreeImage.h"
#include "Utilities.h"
+
+#ifdef _MSC_VER
+// OpenEXR has many problems with MSVC warnings (why not just correct them ?), just ignore one of them
+#pragma warning (disable : 4800) // ImfVersion.h - 'const int' : forcing value to bool 'true' or 'false' (performance warning)
+#endif
+
#include "../OpenEXR/IlmImf/ImfIO.h"
#include "../OpenEXR/Iex/Iex.h"
#include "../OpenEXR/IlmImf/ImfOutputFile.h"
@@ -44,72 +50,64 @@ static int s_format_id;
/**
FreeImage input stream wrapper
+@see Imf_2_2::IStream
*/
-class C_IStream: public Imf::IStream {
-public:
- C_IStream (FreeImageIO *io, fi_handle handle):
- IStream(""), _io (io), _handle(handle) {}
-
- virtual bool read (char c[/*n*/], int n);
- virtual Imf::Int64 tellg ();
- virtual void seekg (Imf::Int64 pos);
- virtual void clear () {};
-
+class C_IStream : public Imf::IStream {
private:
FreeImageIO *_io;
fi_handle _handle;
+
+public:
+ C_IStream (FreeImageIO *io, fi_handle handle) :
+ Imf::IStream(""), _io (io), _handle(handle) {
+ }
+
+ virtual bool read (char c[/*n*/], int n) {
+ return ((unsigned)n != _io->read_proc(c, 1, n, _handle));
+ }
+
+ virtual Imath::Int64 tellg() {
+ return _io->tell_proc(_handle);
+ }
+
+ virtual void seekg(Imath::Int64 pos) {
+ _io->seek_proc(_handle, (unsigned)pos, SEEK_SET);
+ }
+
+ virtual void clear() {
+ }
};
+// ----------------------------------------------------------
/**
FreeImage output stream wrapper
+@see Imf_2_2::OStream
*/
-class C_OStream: public Imf::OStream {
-public:
- C_OStream (FreeImageIO *io, fi_handle handle):
- OStream(""), _io (io), _handle(handle) {}
-
- virtual void write (const char c[/*n*/], int n);
- virtual Imf::Int64 tellp ();
- virtual void seekp (Imf::Int64 pos);
-
+class C_OStream : public Imf::OStream {
private:
FreeImageIO *_io;
fi_handle _handle;
-};
-
-
-bool
-C_IStream::read (char c[/*n*/], int n) {
- return ((unsigned)n != _io->read_proc(c, 1, n, _handle));
-}
-
-Imf::Int64
-C_IStream::tellg () {
- return _io->tell_proc(_handle);
-}
-void
-C_IStream::seekg (Imf::Int64 pos) {
- _io->seek_proc(_handle, (unsigned)pos, SEEK_SET);
-}
+public:
+ C_OStream (FreeImageIO *io, fi_handle handle) :
+ Imf::OStream(""), _io (io), _handle(handle) {
+ }
-void
-C_OStream::write (const char c[/*n*/], int n) {
- if((unsigned)n != _io->write_proc((void*)&c[0], 1, n, _handle)) {
- Iex::throwErrnoExc();
+ virtual void write(const char c[/*n*/], int n) {
+ if((unsigned)n != _io->write_proc((void*)&c[0], 1, n, _handle)) {
+ Iex::throwErrnoExc();
+ }
}
-}
-Imf::Int64
-C_OStream::tellp () {
- return _io->tell_proc(_handle);
-}
+ virtual Imath::Int64 tellp() {
+ return _io->tell_proc(_handle);
+ }
-void
-C_OStream::seekp (Imf::Int64 pos) {
- _io->seek_proc(_handle, (unsigned)pos, SEEK_SET);
-}
+ virtual void seekp(Imath::Int64 pos) {
+ _io->seek_proc(_handle, (unsigned)pos, SEEK_SET);
+ }
+};
// ----------------------------------------------------------
@@ -667,7 +665,9 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void
if(pixelType == Imf::HALF) {
// convert from float to half
halfData = new(std::nothrow) half[width * height * components];
- if(!halfData) THROW (Iex::NullExc, FI_MSG_ERROR_MEMORY);
+ if(!halfData) {
+ THROW (Iex::NullExc, FI_MSG_ERROR_MEMORY);
+ }
for(int y = 0; y < height; y++) {
float *src_bits = (float*)FreeImage_GetScanLine(dib, height - 1 - y);
@@ -716,7 +716,9 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void
file.setFrameBuffer (frameBuffer);
file.writePixels (height);
- if(halfData != NULL) delete[] halfData;
+ if(halfData != NULL) {
+ delete[] halfData;
+ }
if(bIsFlipped) {
// invert dib scanlines
FreeImage_FlipVertical(dib);
@@ -725,7 +727,9 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void
return TRUE;
} catch(Iex::BaseExc & e) {
- if(halfData != NULL) delete[] halfData;
+ if(halfData != NULL) {
+ delete[] halfData;
+ }
if(bIsFlipped) {
// invert dib scanlines
FreeImage_FlipVertical(dib);
@@ -745,6 +749,11 @@ void DLL_CALLCONV
InitEXR(Plugin *plugin, int format_id) {
s_format_id = format_id;
+ // initialize the OpenEXR library
+ // note that this OpenEXR function produce so called "false memory leaks"
+ // see http://lists.nongnu.org/archive/html/openexr-devel/2013-11/msg00000.html
+ Imf::staticInitialize();
+
plugin->format_proc = Format;
plugin->description_proc = Description;
plugin->extension_proc = Extension;
diff --git a/plugins/AdvaImg/src/FreeImage/PluginG3.cpp b/plugins/AdvaImg/src/FreeImage/PluginG3.cpp
index d5c08b36e6..0a083b459b 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginG3.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginG3.cpp
@@ -92,7 +92,7 @@ G3GetFileSize(FreeImageIO *io, fi_handle handle) {
static BOOL
G3ReadFile(FreeImageIO *io, fi_handle handle, uint8 *tif_rawdata, tmsize_t tif_rawdatasize) {
- return ((tmsize_t)(io->read_proc(tif_rawdata, tif_rawdatasize, 1, handle) * tif_rawdatasize) == tif_rawdatasize);
+ return ((tmsize_t)(io->read_proc(tif_rawdata, (unsigned)tif_rawdatasize, 1, handle) * tif_rawdatasize) == tif_rawdatasize);
}
// ==========================================================
diff --git a/plugins/AdvaImg/src/FreeImage/PluginGIF.cpp b/plugins/AdvaImg/src/FreeImage/PluginGIF.cpp
index 87c0185865..0153959ab8 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginGIF.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginGIF.cpp
@@ -4,6 +4,7 @@
// Design and implementation by
// - Ryan Rubley <ryan@lostreality.org>
// - Raphaël Gaquer <raphael.gaquer@alcer.com>
+// - Aaron Shumate <aaron@shumate.us>
//
// This file is part of FreeImage 3
//
@@ -773,7 +774,11 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
}
if( info.disposal_method == GIF_DISPOSAL_BACKGROUND ) {
for( y = 0; y < info.height; y++ ) {
- scanline = (RGBQUAD *)FreeImage_GetScanLine(dib, logicalheight - (y + info.top) - 1) + info.left;
+ const int scanidx = logicalheight - (y + info.top) - 1;
+ if ( scanidx < 0 ) {
+ break; // If data is corrupt, don't calculate in invalid scanline
+ }
+ scanline = (RGBQUAD *)FreeImage_GetScanLine(dib, scanidx) + info.left;
for( x = 0; x < info.width; x++ ) {
*scanline++ = background;
}
@@ -800,7 +805,11 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
}
//copy page data into logical buffer, with full alpha opaqueness
for( y = 0; y < info.height; y++ ) {
- scanline = (RGBQUAD *)FreeImage_GetScanLine(dib, logicalheight - (y + info.top) - 1) + info.left;
+ const int scanidx = logicalheight - (y + info.top) - 1;
+ if ( scanidx < 0 ) {
+ break; // If data is corrupt, don't calculate in invalid scanline
+ }
+ scanline = (RGBQUAD *)FreeImage_GetScanLine(dib, scanidx) + info.left;
BYTE *pageline = FreeImage_GetScanLine(pagedib, info.height - y - 1);
for( x = 0; x < info.width; x++ ) {
if( !have_transparent || *pageline != transparent_color ) {
diff --git a/plugins/AdvaImg/src/FreeImage/PluginHDR.cpp b/plugins/AdvaImg/src/FreeImage/PluginHDR.cpp
index 0cde6139db..28ce1a5768 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginHDR.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginHDR.cpp
@@ -459,8 +459,9 @@ rgbe_WriteBytes_RLE(FreeImageIO *io, fi_handle handle, BYTE *data, int numbytes)
beg_run += run_count;
old_run_count = run_count;
run_count = 1;
- while((data[beg_run] == data[beg_run + run_count]) && (beg_run + run_count < numbytes) && (run_count < 127))
+ while((beg_run + run_count < numbytes) && (run_count < 127) && (data[beg_run] == data[beg_run + run_count])) {
run_count++;
+ }
}
// if data before next big run is a short run then write it as such
if ((old_run_count > 1)&&(old_run_count == beg_run - cur)) {
diff --git a/plugins/AdvaImg/src/FreeImage/PluginICO.cpp b/plugins/AdvaImg/src/FreeImage/PluginICO.cpp
index df5ecee91d..c818379f78 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginICO.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginICO.cpp
@@ -110,6 +110,23 @@ CalculateImageOffset(std::vector<FIBITMAP*>& vPages, int nIndex ) {
return dwSize;
}
+/**
+Vista icon support
+@return Returns TRUE if the bitmap data is stored in PNG format
+*/
+static BOOL
+IsPNG(FreeImageIO *io, fi_handle handle) {
+ BYTE png_signature[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
+ BYTE signature[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ long tell = io->tell_proc(handle);
+ io->read_proc(&signature, 1, 8, handle);
+ BOOL bIsPNG = (memcmp(png_signature, signature, 8) == 0);
+ io->seek_proc(handle, tell, SEEK_SET);
+
+ return bIsPNG;
+}
+
#ifdef FREEIMAGE_BIGENDIAN
static void
SwapInfoHeader(BITMAPINFOHEADER *header) {
@@ -407,16 +424,17 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
// load the requested icon
if (page < icon_header->idCount) {
// seek to the start of the bitmap data for the icon
- io->seek_proc(handle, 0, SEEK_SET);
- io->seek_proc(handle, icon_list[page].dwImageOffset, SEEK_CUR);
+ io->seek_proc(handle, icon_list[page].dwImageOffset, SEEK_SET);
- if((icon_list[page].bWidth == 0) && (icon_list[page].bHeight == 0)) {
+ if( IsPNG(io, handle) ) {
// Vista icon support
+ // see http://blogs.msdn.com/b/oldnewthing/archive/2010/10/22/10079192.aspx
dib = FreeImage_LoadFromHandle(FIF_PNG, io, handle, header_only ? FIF_LOAD_NOPIXELS : PNG_DEFAULT);
}
else {
// standard icon support
// see http://msdn.microsoft.com/en-us/library/ms997538.aspx
+ // see http://blogs.msdn.com/b/oldnewthing/archive/2010/10/18/10077133.aspx
dib = LoadStandardIcon(io, handle, flags, header_only);
}
diff --git a/plugins/AdvaImg/src/FreeImage/PluginJ2K.cpp b/plugins/AdvaImg/src/FreeImage/PluginJ2K.cpp
index 5c23a7c6e1..b8bcfc8b58 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginJ2K.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginJ2K.cpp
@@ -175,7 +175,9 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
if (header_only) {
// create output image
dib = J2KImageToFIBITMAP(s_format_id, image, header_only);
- if(!dib) throw "Failed to import JPEG2000 image";
+ if(!dib) {
+ throw "Failed to import JPEG2000 image";
+ }
// clean-up and return header data
opj_destroy_codec(d_codec);
opj_image_destroy(image);
@@ -193,7 +195,9 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
// create output image
dib = J2KImageToFIBITMAP(s_format_id, image, header_only);
- if(!dib) throw "Failed to import JPEG2000 image";
+ if(!dib) {
+ throw "Failed to import JPEG2000 image";
+ }
// free image data structure
opj_image_destroy(image);
@@ -201,7 +205,9 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
return dib;
} catch (const char *text) {
- if(dib) FreeImage_Unload(dib);
+ if(dib) {
+ FreeImage_Unload(dib);
+ }
// free remaining structures
opj_destroy_codec(d_codec);
opj_image_destroy(image);
@@ -231,27 +237,22 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void
opj_set_default_encoder_parameters(&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;
+ parameters.tcp_numlayers = 0;
// if no rate entered, apply a 16:1 rate by default
if(flags == J2K_DEFAULT) {
parameters.tcp_rates[0] = (float)16;
} else {
// for now, the flags parameter is only used to specify the rate
- parameters.tcp_rates[0] = (float)flags;
+ parameters.tcp_rates[0] = (float)(flags & 0x3FF);
}
parameters.tcp_numlayers++;
parameters.cp_disto_alloc = 1;
// convert the dib to a OpenJPEG image
image = FIBITMAPToJ2KImage(s_format_id, dib, &parameters);
- if(!image) return FALSE;
+ if(!image) {
+ return FALSE;
+ }
// decide if MCT should be used
parameters.tcp_mct = (image->numcomps == 3) ? 1 : 0;
diff --git a/plugins/AdvaImg/src/FreeImage/PluginJP2.cpp b/plugins/AdvaImg/src/FreeImage/PluginJP2.cpp
index edf5b396c3..742fe2c038 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginJP2.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginJP2.cpp
@@ -175,7 +175,9 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
if (header_only) {
// create output image
dib = J2KImageToFIBITMAP(s_format_id, image, header_only);
- if(!dib) throw "Failed to import JPEG2000 image";
+ if(!dib) {
+ throw "Failed to import JPEG2000 image";
+ }
// clean-up and return header data
opj_destroy_codec(d_codec);
opj_image_destroy(image);
@@ -193,7 +195,9 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
// create output image
dib = J2KImageToFIBITMAP(s_format_id, image, header_only);
- if(!dib) throw "Failed to import JPEG2000 image";
+ if(!dib) {
+ throw "Failed to import JPEG2000 image";
+ }
// free image data structure
opj_image_destroy(image);
@@ -201,7 +205,9 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
return dib;
} catch (const char *text) {
- if(dib) FreeImage_Unload(dib);
+ if(dib) {
+ FreeImage_Unload(dib);
+ }
// free remaining structures
opj_destroy_codec(d_codec);
opj_image_destroy(image);
@@ -231,27 +237,22 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void
opj_set_default_encoder_parameters(&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;
+ parameters.tcp_numlayers = 0;
// if no rate entered, apply a 16:1 rate by default
- if(flags == J2K_DEFAULT) {
+ if(flags == JP2_DEFAULT) {
parameters.tcp_rates[0] = (float)16;
} else {
// for now, the flags parameter is only used to specify the rate
- parameters.tcp_rates[0] = (float)flags;
+ parameters.tcp_rates[0] = (float)(flags & 0x3FF);
}
parameters.tcp_numlayers++;
parameters.cp_disto_alloc = 1;
// convert the dib to a OpenJPEG image
image = FIBITMAPToJ2KImage(s_format_id, dib, &parameters);
- if(!image) return FALSE;
+ if(!image) {
+ return FALSE;
+ }
// decide if MCT should be used
parameters.tcp_mct = (image->numcomps == 3) ? 1 : 0;
diff --git a/plugins/AdvaImg/src/FreeImage/PluginJPEG.cpp b/plugins/AdvaImg/src/FreeImage/PluginJPEG.cpp
index c1b45e6347..573989c5df 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginJPEG.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginJPEG.cpp
@@ -919,9 +919,6 @@ jpeg_write_exif_profile_raw(j_compress_ptr cinfo, FIBITMAP *dib) {
if(tag_exif) {
const BYTE *tag_value = (BYTE*)FreeImage_GetTagValue(tag_exif);
-
- if (NULL == tag_value)
- return FALSE;
// verify the identifying string
if(memcmp(exif_signature, tag_value, sizeof(exif_signature)) != 0) {
@@ -929,21 +926,23 @@ jpeg_write_exif_profile_raw(j_compress_ptr cinfo, FIBITMAP *dib) {
return FALSE;
}
- DWORD tag_length = FreeImage_GetTagLength(tag_exif);
-
- BYTE *profile = (BYTE*)malloc(tag_length * sizeof(BYTE));
- if(profile == NULL) return FALSE;
+ if(NULL != tag_value) {
+ DWORD tag_length = FreeImage_GetTagLength(tag_exif);
- for(DWORD i = 0; i < tag_length; i += 65504L) {
- unsigned length = MIN((long)(tag_length - i), 65504L);
+ BYTE *profile = (BYTE*)malloc(tag_length * sizeof(BYTE));
+ if(profile == NULL) return FALSE;
- memcpy(profile, tag_value + i, length);
- jpeg_write_marker(cinfo, EXIF_MARKER, profile, length);
- }
+ for(DWORD i = 0; i < tag_length; i += 65504L) {
+ unsigned length = MIN((long)(tag_length - i), 65504L);
+
+ memcpy(profile, tag_value + i, length);
+ jpeg_write_marker(cinfo, EXIF_MARKER, profile, length);
+ }
- free(profile);
+ free(profile);
- return TRUE;
+ return TRUE;
+ }
}
return FALSE;
diff --git a/plugins/AdvaImg/src/FreeImage/PluginJXR.cpp b/plugins/AdvaImg/src/FreeImage/PluginJXR.cpp
index f5e4878c1d..0e14e09ac9 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginJXR.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginJXR.cpp
@@ -163,8 +163,6 @@ JXR_ErrorMessage(const int error) {
default:
return "Invalid instruction - please contact the FreeImage team";
}
-
- return NULL;
}
// ==========================================================
@@ -410,11 +408,12 @@ GetOutputPixelFormat(FIBITMAP *dib, PKPixelFormatGUID *guid_format, BOOL *bHasAl
}
// ==========================================================
-// Metadata loading & saving
+// Metadata loading
// ==========================================================
/**
Read a JPEG-XR IFD as a buffer
+@see ReadMetadata
*/
static ERR
ReadProfile(WMPStream* pStream, unsigned cbByteCount, unsigned uOffset, BYTE **ppbProfile) {
@@ -436,6 +435,7 @@ ReadProfile(WMPStream* pStream, unsigned cbByteCount, unsigned uOffset, BYTE **p
/**
Convert a DPKPROPVARIANT to a FITAG, then store the tag as FIMD_EXIF_MAIN
+@see ReadDescriptiveMetadata
*/
static BOOL
ReadPropVariant(WORD tag_id, const DPKPROPVARIANT & varSrc, FIBITMAP *dib) {
@@ -470,7 +470,7 @@ ReadPropVariant(WORD tag_id, const DPKPROPVARIANT & varSrc, FIBITMAP *dib) {
case DPKVT_LPWSTR:
FreeImage_SetTagType(tag, FIDT_UNDEFINED);
dwSize = (DWORD)(sizeof(U16) * (wcslen((wchar_t *) varSrc.VT.pwszVal) + 1)); // +1 for NULL term
- FreeImage_SetTagCount(tag, dwSize / 2);
+ FreeImage_SetTagCount(tag, dwSize);
FreeImage_SetTagLength(tag, dwSize);
FreeImage_SetTagValue(tag, varSrc.VT.pwszVal);
break;
@@ -533,6 +533,7 @@ ReadDescriptiveMetadata(PKImageDecode *pID, FIBITMAP *dib) {
/**
Read ICC, XMP, Exif, Exif-GPS, IPTC, descriptive (i.e. Exif-TIFF) metadata
+@see ReadProfile, ReadDescriptiveMetadata
*/
static ERR
ReadMetadata(PKImageDecode *pID, FIBITMAP *dib) {
@@ -593,7 +594,7 @@ ReadMetadata(PKImageDecode *pID, FIBITMAP *dib) {
error_code = ReadProfile(pStream, cbByteCount, uOffset, &pbProfile);
JXR_CHECK(error_code);
// decode the Exif profile
- jpegxr_read_exif_profile(dib, pbProfile, cbByteCount);
+ jpegxr_read_exif_profile(dib, pbProfile, cbByteCount, uOffset);
}
// Exif-GPS metadata
@@ -603,7 +604,7 @@ ReadMetadata(PKImageDecode *pID, FIBITMAP *dib) {
error_code = ReadProfile(pStream, cbByteCount, uOffset, &pbProfile);
JXR_CHECK(error_code);
// decode the Exif-GPS profile
- jpegxr_read_exif_gps_profile(dib, pbProfile, cbByteCount);
+ jpegxr_read_exif_gps_profile(dib, pbProfile, cbByteCount, uOffset);
}
// free profile buffer
@@ -630,6 +631,168 @@ ReadMetadata(PKImageDecode *pID, FIBITMAP *dib) {
}
// ==========================================================
+// Metadata saving
+// ==========================================================
+
+/**
+Convert a FITAG (coming from FIMD_EXIF_MAIN) to a DPKPROPVARIANT.
+No allocation is needed here, the function just copy pointers when needed.
+@see WriteDescriptiveMetadata
+*/
+static BOOL
+WritePropVariant(FIBITMAP *dib, WORD tag_id, DPKPROPVARIANT & varDst) {
+ FITAG *tag = NULL;
+
+ TagLib& s = TagLib::instance();
+
+ // clear output DPKPROPVARIANT
+ varDst.vt = DPKVT_EMPTY;
+
+ // given the tag id, get the tag key
+ const char *key = s.getTagFieldName(TagLib::EXIF_MAIN, tag_id, NULL);
+ // then, get the tag info
+ if(!FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, key, &tag)) {
+ return FALSE;
+ }
+
+ // set the tag value
+ switch(FreeImage_GetTagType(tag)) {
+ case FIDT_ASCII:
+ varDst.vt = DPKVT_LPSTR;
+ varDst.VT.pszVal = (char*)FreeImage_GetTagValue(tag);
+ break;
+ case FIDT_BYTE:
+ case FIDT_UNDEFINED:
+ varDst.vt = DPKVT_LPWSTR;
+ varDst.VT.pwszVal = (U16*)FreeImage_GetTagValue(tag);
+ break;
+ case FIDT_SHORT:
+ varDst.vt = DPKVT_UI2;
+ varDst.VT.uiVal = *((U16*)FreeImage_GetTagValue(tag));
+ break;
+ case FIDT_LONG:
+ varDst.vt = DPKVT_UI4;
+ varDst.VT.ulVal = *((U32*)FreeImage_GetTagValue(tag));
+ break;
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
+/**
+Write EXIF_MAIN metadata to JPEG-XR descriptive metadata
+@see WritePropVariant
+*/
+static ERR
+WriteDescriptiveMetadata(PKImageEncode *pIE, FIBITMAP *dib) {
+ ERR error_code = 0; // error code as returned by the interface
+ DESCRIPTIVEMETADATA DescMetadata;
+
+ // fill the DESCRIPTIVEMETADATA structure (use pointers to arrays when needed)
+ WritePropVariant(dib, WMP_tagImageDescription, DescMetadata.pvarImageDescription);
+ WritePropVariant(dib, WMP_tagCameraMake, DescMetadata.pvarCameraMake);
+ WritePropVariant(dib, WMP_tagCameraModel, DescMetadata.pvarCameraModel);
+ WritePropVariant(dib, WMP_tagSoftware, DescMetadata.pvarSoftware);
+ WritePropVariant(dib, WMP_tagDateTime, DescMetadata.pvarDateTime);
+ WritePropVariant(dib, WMP_tagArtist, DescMetadata.pvarArtist);
+ WritePropVariant(dib, WMP_tagCopyright, DescMetadata.pvarCopyright);
+ WritePropVariant(dib, WMP_tagRatingStars, DescMetadata.pvarRatingStars);
+ WritePropVariant(dib, WMP_tagRatingValue, DescMetadata.pvarRatingValue);
+ WritePropVariant(dib, WMP_tagCaption, DescMetadata.pvarCaption);
+ WritePropVariant(dib, WMP_tagDocumentName, DescMetadata.pvarDocumentName);
+ WritePropVariant(dib, WMP_tagPageName, DescMetadata.pvarPageName);
+ WritePropVariant(dib, WMP_tagPageNumber, DescMetadata.pvarPageNumber);
+ WritePropVariant(dib, WMP_tagHostComputer, DescMetadata.pvarHostComputer);
+
+ // copy the structure to the encoder
+ error_code = pIE->SetDescriptiveMetadata(pIE, &DescMetadata);
+
+ // no need to free anything here
+ return error_code;
+}
+
+/**
+Write ICC, XMP, Exif, Exif-GPS, IPTC, descriptive (i.e. Exif-TIFF) metadata
+*/
+static ERR
+WriteMetadata(PKImageEncode *pIE, FIBITMAP *dib) {
+ ERR error_code = 0; // error code as returned by the interface
+ BYTE *profile = NULL;
+ unsigned profile_size = 0;
+
+ try {
+ // write ICC profile
+ {
+ FIICCPROFILE *iccProfile = FreeImage_GetICCProfile(dib);
+ if(iccProfile->data) {
+ error_code = pIE->SetColorContext(pIE, (U8*)iccProfile->data, iccProfile->size);
+ JXR_CHECK(error_code);
+ }
+ }
+
+ // write descriptive metadata
+ if(FreeImage_GetMetadataCount(FIMD_EXIF_MAIN, dib)) {
+ error_code = WriteDescriptiveMetadata(pIE, dib);
+ JXR_CHECK(error_code);
+ }
+
+ // write IPTC metadata
+ if(FreeImage_GetMetadataCount(FIMD_IPTC, dib)) {
+ // create a binary profile
+ if(write_iptc_profile(dib, &profile, &profile_size)) {
+ // write the profile
+ error_code = PKImageEncode_SetIPTCNAAMetadata_WMP(pIE, profile, profile_size);
+ JXR_CHECK(error_code);
+ // release profile
+ free(profile);
+ profile = NULL;
+ }
+ }
+
+ // write XMP metadata
+ {
+ FITAG *tag_xmp = NULL;
+ if(FreeImage_GetMetadata(FIMD_XMP, dib, g_TagLib_XMPFieldName, &tag_xmp)) {
+ error_code = PKImageEncode_SetXMPMetadata_WMP(pIE, (BYTE*)FreeImage_GetTagValue(tag_xmp), FreeImage_GetTagLength(tag_xmp));
+ JXR_CHECK(error_code);
+ }
+ }
+
+ // write Exif metadata
+ {
+ if(tiff_get_ifd_profile(dib, FIMD_EXIF_EXIF, &profile, &profile_size)) {
+ error_code = PKImageEncode_SetEXIFMetadata_WMP(pIE, profile, profile_size);
+ JXR_CHECK(error_code);
+ // release profile
+ free(profile);
+ profile = NULL;
+ }
+ }
+
+ // write Exif GPS metadata
+ {
+ if(tiff_get_ifd_profile(dib, FIMD_EXIF_GPS, &profile, &profile_size)) {
+ error_code = PKImageEncode_SetGPSInfoMetadata_WMP(pIE, profile, profile_size);
+ JXR_CHECK(error_code);
+ // release profile
+ free(profile);
+ profile = NULL;
+ }
+ }
+
+ return WMP_errSuccess;
+
+ } catch(...) {
+ free(profile);
+ return error_code;
+ }
+}
+
+
+
+// ==========================================================
// Quantization tables (Y, U, V, YHP, UHP, VHP),
// optimized for PSNR
// ==========================================================
@@ -1238,8 +1401,11 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void
float resY = (float)(unsigned)(0.5F + 0.0254F * FreeImage_GetDotsPerMeterY(dib));
pEncoder->SetResolution(pEncoder, resX, resY);
- // write pixels
- // --------------
+ // set metadata
+ WriteMetadata(pEncoder, dib);
+
+ // write metadata & pixels
+ // -----------------------
// dib coordinates are upside-down relative to usual conventions
bIsFlipped = FreeImage_FlipVertical(dib);
@@ -1250,7 +1416,7 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void
// get dst pitch (count of BYTE for stride)
const unsigned cbStride = FreeImage_GetPitch(dib);
- // write pixels on output
+ // write metadata + pixels on output
error_code = pEncoder->WritePixels(pEncoder, height, dib_bits, cbStride);
JXR_CHECK(error_code);
diff --git a/plugins/AdvaImg/src/FreeImage/PluginPFM.cpp b/plugins/AdvaImg/src/FreeImage/PluginPFM.cpp
index 231e8baa22..ea3c46b14e 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginPFM.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginPFM.cpp
@@ -63,11 +63,13 @@ Get an integer value from the actual position pointed by handle
static int
pfm_get_int(FreeImageIO *io, fi_handle handle) {
char c = 0;
- BOOL firstchar;
+ BOOL bFirstChar;
// skip forward to start of next number
- if(!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING;
+ if(!io->read_proc(&c, 1, 1, handle)) {
+ throw FI_MSG_ERROR_PARSING;
+ }
while (1) {
// eat comments
@@ -75,15 +77,16 @@ pfm_get_int(FreeImageIO *io, fi_handle handle) {
if (c == '#') {
// if we're at a comment, read to end of line
- firstchar = TRUE;
+ bFirstChar = TRUE;
while (1) {
- if(!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING;
+ if(!io->read_proc(&c, 1, 1, handle)) {
+ throw FI_MSG_ERROR_PARSING;
+ }
- if (firstchar && c == ' ') {
+ if (bFirstChar && c == ' ') {
// loop off 1 sp after #
-
- firstchar = FALSE;
+ bFirstChar = FALSE;
} else if (c == '\n') {
break;
}
@@ -92,11 +95,12 @@ pfm_get_int(FreeImageIO *io, fi_handle handle) {
if (c >= '0' && c <='9') {
// we've found what we were looking for
-
break;
}
- if(!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING;
+ if(!io->read_proc(&c, 1, 1, handle)) {
+ throw FI_MSG_ERROR_PARSING;
+ }
}
// we're at the start of a number, continue until we hit a non-number
@@ -106,10 +110,13 @@ pfm_get_int(FreeImageIO *io, fi_handle handle) {
while (1) {
i = (i * 10) + (c - '0');
- if(!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING;
+ if(!io->read_proc(&c, 1, 1, handle)) {
+ throw FI_MSG_ERROR_PARSING;
+ }
- if (c < '0' || c > '9')
- break;
+ if (c < '0' || c > '9') {
+ break;
+ }
}
return i;
diff --git a/plugins/AdvaImg/src/FreeImage/PluginPICT.cpp b/plugins/AdvaImg/src/FreeImage/PluginPICT.cpp
index 99958a489c..371056d20b 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginPICT.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginPICT.cpp
@@ -82,21 +82,21 @@ static const int outputMessageSize = 256;
// Internal functions
// ==========================================================
-static unsigned
+static BYTE
Read8(FreeImageIO *io, fi_handle handle) {
- unsigned char i = 0;
+ BYTE i = 0;
io->read_proc(&i, 1, 1, handle);
return i;
}
-static unsigned
+static WORD
Read16(FreeImageIO *io, fi_handle handle) {
// reads a two-byte big-endian integer from the given file and returns its value.
// assumes unsigned.
unsigned hi = Read8(io, handle);
unsigned lo = Read8(io, handle);
- return lo + (hi << 8);
+ return (WORD)(lo + (hi << 8));
}
static unsigned
@@ -388,7 +388,7 @@ ReadColorTable( FreeImageIO *io, fi_handle handle, WORD* pNumColors, RGBQUAD* pP
// The indicies in a device colour table are bogus and
// usually == 0, so I assume we allocate up the list of
// colours in order.
- val = i;
+ val = (WORD)i;
}
if (val >= numColors) {
throw "pixel value greater than color table size.";
@@ -416,7 +416,7 @@ SkipBits( FreeImageIO *io, fi_handle handle, MacRect* bounds, WORD rowBytes, int
if (pixelSize <= 8) {
rowBytes &= 0x7fff;
}
- pixwidth = width;
+ pixwidth = (WORD)width;
if (pixelSize == 16) {
pixwidth *= 2;
@@ -541,6 +541,7 @@ expandBuf8( FreeImageIO *io, fi_handle handle, int width, int bpp, BYTE* dst )
static BYTE*
UnpackPictRow( FreeImageIO *io, fi_handle handle, BYTE* pLineBuf, int width, int rowBytes, int srcBytes ) {
+
if (rowBytes < 8) { // Ah-ha! The bits aren't actually packed. This will be easy.
io->read_proc( pLineBuf, rowBytes, 1, handle );
}
@@ -589,7 +590,7 @@ Unpack32Bits( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacRect* bounds,
int width = bounds->right - bounds->left;
if (rowBytes == 0) {
- rowBytes = width*4;
+ rowBytes = (WORD)( width * 4 );
}
BYTE* pLineBuf = (BYTE*)malloc( rowBytes ); // Let's allocate enough for 4 bit planes
@@ -656,7 +657,7 @@ Unpack8Bits( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacRect* bounds,
rowBytes &= 0x7fff;
if (rowBytes == 0) {
- rowBytes = width;
+ rowBytes = (WORD)width;
}
for ( int i = 0; i < height; i++ ) {
@@ -694,7 +695,7 @@ UnpackBits( FreeImageIO *io, fi_handle handle, FIBITMAP* dib, MacRect* bounds, W
rowBytes &= 0x7fff;
}
- pixwidth = width;
+ pixwidth = (WORD)width;
pkpixsize = 1; // RLE unit: one byte for everything...
if (pixelSize == 16) { // ...except 16 bpp.
pkpixsize = 2;
diff --git a/plugins/AdvaImg/src/FreeImage/PluginPNG.cpp b/plugins/AdvaImg/src/FreeImage/PluginPNG.cpp
index f6b59e299b..fe80a2b533 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginPNG.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginPNG.cpp
@@ -6,6 +6,7 @@
// - Herve Drolon (drolon@infonie.fr)
// - Detlev Vendt (detlev.vendt@brillit.de)
// - Aaron Shumate (trek@startreker.com)
+// - Tanner Helland (tannerhelland@users.sf.net)
//
// This file is part of FreeImage 3
//
@@ -49,9 +50,9 @@ typedef struct {
fi_handle s_handle;
} fi_ioStructure, *pfi_ioStructure;
-/////////////////////////////////////////////////////////////////////////////
-// libpng interface
-//
+// ==========================================================
+// libpng interface
+// ==========================================================
static void
_ReadProc(png_structp png_ptr, unsigned char *data, png_size_t size) {
@@ -99,6 +100,7 @@ ReadMetadata(png_structp png_ptr, png_infop info_ptr, FIBITMAP *dib) {
FITAG *tag = NULL;
png_textp text_ptr = NULL;
+ png_timep mod_time = NULL;
int num_text = 0;
// iTXt/tEXt/zTXt chuncks
@@ -130,6 +132,31 @@ ReadMetadata(png_structp png_ptr, png_infop info_ptr, FIBITMAP *dib) {
}
}
+ // timestamp chunk
+ if(png_get_tIME(png_ptr, info_ptr, &mod_time)) {
+ char timestamp[32];
+ // create a tag
+ tag = FreeImage_CreateTag();
+ if(!tag) return FALSE;
+
+ // convert as 'yyyy:MM:dd hh:mm:ss'
+ sprintf(timestamp, "%4d:%02d:%02d %2d:%02d:%02d", mod_time->year, mod_time->month, mod_time->day, mod_time->hour, mod_time->minute, mod_time->second);
+
+ DWORD tag_length = (DWORD)strlen(timestamp) + 1;
+ FreeImage_SetTagLength(tag, tag_length);
+ FreeImage_SetTagCount(tag, tag_length);
+ FreeImage_SetTagType(tag, FIDT_ASCII);
+ FreeImage_SetTagID(tag, TAG_DATETIME);
+ FreeImage_SetTagValue(tag, timestamp);
+
+ // store the tag as Exif-TIFF
+ FreeImage_SetTagKey(tag, "DateTime");
+ FreeImage_SetMetadata(FIMD_EXIF_MAIN, dib, FreeImage_GetTagKey(tag), tag);
+
+ // destroy the tag
+ FreeImage_DeleteTag(tag);
+ }
+
return TRUE;
}
@@ -143,6 +170,7 @@ WriteMetadata(png_structp png_ptr, png_infop info_ptr, FIBITMAP *dib) {
BOOL bResult = TRUE;
png_text text_metadata;
+ png_time mod_time;
// set the 'Comments' metadata as iTXt chuncks
@@ -174,7 +202,7 @@ WriteMetadata(png_structp png_ptr, png_infop info_ptr, FIBITMAP *dib) {
if(tag && FreeImage_GetTagLength(tag)) {
memset(&text_metadata, 0, sizeof(png_text));
text_metadata.compression = 1; // iTXt, none
- text_metadata.key = (char*)g_png_xmp_keyword; // keyword, 1-79 character description of "text"
+ text_metadata.key = (char*)g_png_xmp_keyword; // keyword, 1-79 character description of "text"
text_metadata.text = (char*)FreeImage_GetTagValue(tag); // comment, may be an empty string (ie "")
text_metadata.text_length = FreeImage_GetTagLength(tag);// length of the text string
text_metadata.itxt_length = FreeImage_GetTagLength(tag);// length of the itxt string
@@ -186,6 +214,23 @@ WriteMetadata(png_structp png_ptr, png_infop info_ptr, FIBITMAP *dib) {
bResult &= TRUE;
}
+ // set the Exif-TIFF 'DateTime' metadata as a tIME chunk
+ tag = NULL;
+ FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, "DateTime", &tag);
+ if(tag && FreeImage_GetTagLength(tag)) {
+ int year, month, day, hour, minute, second;
+ const char *value = (char*)FreeImage_GetTagValue(tag);
+ if(sscanf(value, "%4d:%02d:%02d %2d:%02d:%02d", &year, &month, &day, &hour, &minute, &second) == 6) {
+ mod_time.year = (png_uint_16)year;
+ mod_time.month = (png_byte)month;
+ mod_time.day = (png_byte)day;
+ mod_time.hour = (png_byte)hour;
+ mod_time.minute = (png_byte)minute;
+ mod_time.second = (png_byte)second;
+ png_set_tIME (png_ptr, info_ptr, &mod_time);
+ }
+ }
+
return bResult;
}
@@ -265,21 +310,207 @@ SupportsNoPixels() {
return TRUE;
}
-// ----------------------------------------------------------
+// --------------------------------------------------------------------------
+
+/**
+Configure the decoder so that decoded pixels are compatible with a FREE_IMAGE_TYPE format.
+Set conversion instructions as needed.
+@param png_ptr PNG handle
+@param info_ptr PNG info handle
+@param flags Decoder flags
+@param output_image_type Returned FreeImage converted image type
+@return Returns TRUE if successful, returns FALSE otherwise
+@see png_read_update_info
+*/
+static BOOL
+ConfigureDecoder(png_structp png_ptr, png_infop info_ptr, int flags, FREE_IMAGE_TYPE *output_image_type) {
+ // get original image info
+ const int color_type = png_get_color_type(png_ptr, info_ptr);
+ const int bit_depth = png_get_bit_depth(png_ptr, info_ptr);
+ const int pixel_depth = bit_depth * png_get_channels(png_ptr, info_ptr);
+
+ FREE_IMAGE_TYPE image_type = FIT_BITMAP; // assume standard image type
+
+ // check for transparency table or single transparent color
+ BOOL bIsTransparent = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) == PNG_INFO_tRNS ? TRUE : FALSE;
+
+ // check allowed combinations of colour type and bit depth
+ // then get converted FreeImage type
+
+ switch(color_type) {
+ case PNG_COLOR_TYPE_GRAY: // color type '0', bitdepth = 1, 2, 4, 8, 16
+ switch(bit_depth) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ // expand grayscale images to the full 8-bit from 2-bit/pixel
+ if (pixel_depth == 2) {
+ png_set_expand_gray_1_2_4_to_8(png_ptr);
+ }
+
+ // if a tRNS chunk is provided, we must also expand the grayscale data to 8-bits,
+ // this allows us to make use of the transparency table with existing FreeImage methods
+ if (bIsTransparent && (pixel_depth < 8)) {
+ png_set_expand_gray_1_2_4_to_8(png_ptr);
+ }
+ break;
+
+ case 16:
+ image_type = (pixel_depth == 16) ? FIT_UINT16 : FIT_UNKNOWN;
+
+ // 16-bit grayscale images can contain a transparent value (shade)
+ // if found, expand the transparent value to a full alpha channel
+ if (bIsTransparent && (image_type != FIT_UNKNOWN)) {
+ // expand tRNS to a full alpha channel
+ png_set_tRNS_to_alpha(png_ptr);
+
+ // expand new 16-bit gray + 16-bit alpha to full 64-bit RGBA
+ png_set_gray_to_rgb(png_ptr);
+
+ image_type = FIT_RGBA16;
+ }
+ break;
+
+ default:
+ image_type = FIT_UNKNOWN;
+ break;
+ }
+ break;
+
+ case PNG_COLOR_TYPE_RGB: // color type '2', bitdepth = 8, 16
+ switch(bit_depth) {
+ case 8:
+ image_type = (pixel_depth == 24) ? FIT_BITMAP : FIT_UNKNOWN;
+ break;
+ case 16:
+ image_type = (pixel_depth == 48) ? FIT_RGB16 : FIT_UNKNOWN;
+ break;
+ default:
+ image_type = FIT_UNKNOWN;
+ break;
+ }
+ // sometimes, 24- or 48-bit images may contain transparency information
+ // check for this use case and convert to an alpha-compatible format
+ if (bIsTransparent && (image_type != FIT_UNKNOWN)) {
+ // if the image is 24-bit RGB, mark it as 32-bit; if it is 48-bit, mark it as 64-bit
+ image_type = (pixel_depth == 24) ? FIT_BITMAP : (pixel_depth == 48) ? FIT_RGBA16 : FIT_UNKNOWN;
+ // expand tRNS chunk to alpha channel
+ png_set_tRNS_to_alpha(png_ptr);
+ }
+ break;
+
+ case PNG_COLOR_TYPE_PALETTE: // color type '3', bitdepth = 1, 2, 4, 8
+ switch(bit_depth) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ // expand palette images to the full 8 bits from 2 bits/pixel
+ if (pixel_depth == 2) {
+ png_set_packing(png_ptr);
+ }
+
+ // if a tRNS chunk is provided, we must also expand the palletized data to 8-bits,
+ // this allows us to make use of the transparency table with existing FreeImage methods
+ if (bIsTransparent && (pixel_depth < 8)) {
+ png_set_packing(png_ptr);
+ }
+ break;
+
+ default:
+ image_type = FIT_UNKNOWN;
+ break;
+ }
+ break;
+
+ case PNG_COLOR_TYPE_GRAY_ALPHA: // color type '4', bitdepth = 8, 16
+ switch(bit_depth) {
+ case 8:
+ // 8-bit grayscale + 8-bit alpha => convert to 32-bit RGBA
+ image_type = (pixel_depth == 16) ? FIT_BITMAP : FIT_UNKNOWN;
+ break;
+ case 16:
+ // 16-bit grayscale + 16-bit alpha => convert to 64-bit RGBA
+ image_type = (pixel_depth == 32) ? FIT_RGBA16 : FIT_UNKNOWN;
+ break;
+ default:
+ image_type = FIT_UNKNOWN;
+ break;
+ }
+ // expand 8-bit greyscale + 8-bit alpha to 32-bit
+ // expand 16-bit greyscale + 16-bit alpha to 64-bit
+ png_set_gray_to_rgb(png_ptr);
+ break;
+
+ case PNG_COLOR_TYPE_RGB_ALPHA: // color type '6', bitdepth = 8, 16
+ switch(bit_depth) {
+ case 8:
+ break;
+ case 16:
+ image_type = (pixel_depth == 64) ? FIT_RGBA16 : FIT_UNKNOWN;
+ break;
+ default:
+ image_type = FIT_UNKNOWN;
+ break;
+ }
+ break;
+ }
+
+ // check for unknown or invalid formats
+ if(image_type == FIT_UNKNOWN) {
+ *output_image_type = image_type;
+ return FALSE;
+ }
+
+#ifndef FREEIMAGE_BIGENDIAN
+ if((image_type == FIT_UINT16) || (image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) {
+ // turn on 16-bit byte swapping
+ png_set_swap(png_ptr);
+ }
+#endif
+
+#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
+ if((image_type == FIT_BITMAP) && ((color_type == PNG_COLOR_TYPE_RGB) || (color_type == PNG_COLOR_TYPE_RGB_ALPHA))) {
+ // flip the RGB pixels to BGR (or RGBA to BGRA)
+ png_set_bgr(png_ptr);
+ }
+#endif
+
+ // gamma correction
+ // unlike the example in the libpng documentation, we have *no* idea where
+ // this file may have come from--so if it doesn't have a file gamma, don't
+ // do any correction ("do no harm")
+
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) {
+ double gamma = 0;
+ double screen_gamma = 2.2;
+
+ if (png_get_gAMA(png_ptr, info_ptr, &gamma) && ( flags & PNG_IGNOREGAMMA ) != PNG_IGNOREGAMMA) {
+ png_set_gamma(png_ptr, screen_gamma, gamma);
+ }
+ }
+
+ // all transformations have been registered; now update info_ptr data
+ png_read_update_info(png_ptr, info_ptr);
+
+ // return the output image type
+ *output_image_type = image_type;
+
+ return TRUE;
+}
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
png_structp png_ptr = NULL;
- png_infop info_ptr;
+ png_infop info_ptr = NULL;
png_uint_32 width, height;
- png_colorp png_palette = NULL;
- int color_type, palette_entries = 0;
- int bit_depth, pixel_depth; // pixel_depth = bit_depth * channels
+ int color_type;
+ int bit_depth;
+ int pixel_depth = 0; // pixel_depth = bit_depth * channels
FIBITMAP *dib = NULL;
- RGBQUAD *palette = NULL; // pointer to dib palette
- png_bytepp row_pointers = NULL;
- int i;
+ png_bytepp row_pointers = NULL;
fi_ioStructure fio;
fio.s_handle = handle;
@@ -334,154 +565,58 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
png_read_info(png_ptr, info_ptr);
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL);
- pixel_depth = png_get_bit_depth(png_ptr, info_ptr) * png_get_channels(png_ptr, info_ptr);
-
- // get image data type (assume standard image type)
+ // configure the decoder
FREE_IMAGE_TYPE image_type = FIT_BITMAP;
- if (bit_depth == 16) {
- if ((pixel_depth == 16) && (color_type == PNG_COLOR_TYPE_GRAY)) {
- image_type = FIT_UINT16;
- }
- else if ((pixel_depth == 48) && (color_type == PNG_COLOR_TYPE_RGB)) {
- image_type = FIT_RGB16;
- }
- else if ((pixel_depth == 64) && (color_type == PNG_COLOR_TYPE_RGB_ALPHA)) {
- image_type = FIT_RGBA16;
- } else {
- // tell libpng to strip 16 bit/color files down to 8 bits/color
- png_set_strip_16(png_ptr);
- bit_depth = 8;
- }
- }
-
-#ifndef FREEIMAGE_BIGENDIAN
- if((image_type == FIT_UINT16) || (image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) {
- // turn on 16 bit byte swapping
- png_set_swap(png_ptr);
- }
-#endif
-
- // set some additional flags
-
- switch(color_type) {
- case PNG_COLOR_TYPE_RGB:
- case PNG_COLOR_TYPE_RGB_ALPHA:
-#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
- // flip the RGB pixels to BGR (or RGBA to BGRA)
-
- if(image_type == FIT_BITMAP) {
- png_set_bgr(png_ptr);
- }
-#endif
- break;
-
- case PNG_COLOR_TYPE_PALETTE:
- // expand palette images to the full 8 bits from 2 bits/pixel
-
- if (pixel_depth == 2) {
- png_set_packing(png_ptr);
- pixel_depth = 8;
- }
-
- break;
-
- case PNG_COLOR_TYPE_GRAY:
- // expand grayscale images to the full 8 bits from 2 bits/pixel
- // but *do not* expand fully transparent palette entries to a full alpha channel
-
- if (pixel_depth == 2) {
- png_set_expand_gray_1_2_4_to_8(png_ptr);
- pixel_depth = 8;
- }
-
- break;
-
- case PNG_COLOR_TYPE_GRAY_ALPHA:
- // expand 8-bit greyscale + 8-bit alpha to 32-bit
- png_set_gray_to_rgb(png_ptr);
-#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
- // flip the RGBA pixels to BGRA
-
- png_set_bgr(png_ptr);
-#endif
- pixel_depth = 32;
-
- break;
-
- default:
- throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
+ if(!ConfigureDecoder(png_ptr, info_ptr, flags, &image_type)) {
+ throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
}
- // unlike the example in the libpng documentation, we have *no* idea where
- // this file may have come from--so if it doesn't have a file gamma, don't
- // do any correction ("do no harm")
-
- if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) {
- double gamma = 0;
- double screen_gamma = 2.2;
-
- if (png_get_gAMA(png_ptr, info_ptr, &gamma) && ( flags & PNG_IGNOREGAMMA ) != PNG_IGNOREGAMMA) {
- png_set_gamma(png_ptr, screen_gamma, gamma);
- }
- }
-
- // all transformations have been registered; now update info_ptr data
-
- png_read_update_info(png_ptr, info_ptr);
+ // update image info
- // color type may have changed, due to our transformations
+ color_type = png_get_color_type(png_ptr, info_ptr);
+ bit_depth = png_get_bit_depth(png_ptr, info_ptr);
+ pixel_depth = bit_depth * png_get_channels(png_ptr, info_ptr);
- color_type = png_get_color_type(png_ptr,info_ptr);
-
- // create a DIB and write the bitmap header
- // set up the DIB palette, if needed
+ // create a dib and write the bitmap header
+ // set up the dib palette, if needed
switch (color_type) {
case PNG_COLOR_TYPE_RGB:
- png_set_invert_alpha(png_ptr);
-
- if(image_type == FIT_BITMAP) {
- dib = FreeImage_AllocateHeader(header_only, width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
- } else {
- dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth);
- }
- break;
-
case PNG_COLOR_TYPE_RGB_ALPHA:
- if(image_type == FIT_BITMAP) {
- dib = FreeImage_AllocateHeader(header_only, width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
- } else {
- dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth);
- }
+ dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
break;
case PNG_COLOR_TYPE_PALETTE:
- dib = FreeImage_AllocateHeader(header_only, width, height, pixel_depth);
+ dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
+ if(dib) {
+ png_colorp png_palette = NULL;
+ int palette_entries = 0;
- png_get_PLTE(png_ptr,info_ptr, &png_palette, &palette_entries);
+ png_get_PLTE(png_ptr,info_ptr, &png_palette, &palette_entries);
- palette_entries = MIN((unsigned)palette_entries, FreeImage_GetColorsUsed(dib));
- palette = FreeImage_GetPalette(dib);
+ palette_entries = MIN((unsigned)palette_entries, FreeImage_GetColorsUsed(dib));
- // store the palette
+ // store the palette
- for (i = 0; i < palette_entries; i++) {
- palette[i].rgbRed = png_palette[i].red;
- palette[i].rgbGreen = png_palette[i].green;
- palette[i].rgbBlue = png_palette[i].blue;
+ RGBQUAD *palette = FreeImage_GetPalette(dib);
+ for(int i = 0; i < palette_entries; i++) {
+ palette[i].rgbRed = png_palette[i].red;
+ palette[i].rgbGreen = png_palette[i].green;
+ palette[i].rgbBlue = png_palette[i].blue;
+ }
}
break;
case PNG_COLOR_TYPE_GRAY:
- dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth);
+ dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
- if(pixel_depth <= 8) {
- palette = FreeImage_GetPalette(dib);
- palette_entries = 1 << pixel_depth;
+ if(dib && (pixel_depth <= 8)) {
+ RGBQUAD *palette = FreeImage_GetPalette(dib);
+ const int palette_entries = 1 << pixel_depth;
- for (i = 0; i < palette_entries; i++) {
+ for(int i = 0; i < palette_entries; i++) {
palette[i].rgbRed =
palette[i].rgbGreen =
palette[i].rgbBlue = (BYTE)((i * 255) / (palette_entries - 1));
@@ -493,6 +628,10 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
}
+ if(!dib) {
+ throw FI_MSG_ERROR_DIB_MEMORY;
+ }
+
// store the transparency table
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
@@ -507,21 +646,26 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
if((color_type == PNG_COLOR_TYPE_GRAY) && trans_color) {
// single transparent color
- if (trans_color->gray < palette_entries) {
+ if (trans_color->gray < 256) {
BYTE table[256];
- memset(table, 0xFF, palette_entries);
+ memset(table, 0xFF, 256);
table[trans_color->gray] = 0;
- FreeImage_SetTransparencyTable(dib, table, palette_entries);
+ FreeImage_SetTransparencyTable(dib, table, 256);
+ }
+ // check for a full transparency table, too
+ else if ((trans_alpha) && (pixel_depth <= 8)) {
+ FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans);
}
+
} else if((color_type == PNG_COLOR_TYPE_PALETTE) && trans_alpha) {
// transparency table
FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans);
}
}
- // store the background color
+ // store the background color (only supported for FIT_BITMAP types)
- if (png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) {
+ if ((image_type == FIT_BITMAP) && png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) {
// Get the background color to draw transparent and alpha images over.
// Note that even if the PNG file supplies a background, you are not required to
// use it - you should use the (solid) application background if it has one.
@@ -598,7 +742,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
// allow loading of PNG with minor errors (such as images with several IDAT chunks)
for (png_uint_32 k = 0; k < height; k++) {
- row_pointers[height - 1 - k] = FreeImage_GetScanLine(dib, k);
+ row_pointers[height - 1 - k] = FreeImage_GetScanLine(dib, k);
}
png_set_benign_errors(png_ptr, 1);
@@ -644,7 +788,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
free(row_pointers);
}
if (dib) {
- FreeImage_Unload(dib);
+ FreeImage_Unload(dib);
}
FreeImage_OutputMessageProc(s_format_id, text);
@@ -655,6 +799,8 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
return NULL;
}
+// --------------------------------------------------------------------------
+
static BOOL DLL_CALLCONV
Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
png_structp png_ptr;
@@ -903,7 +1049,7 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void
// the number of passes is either 1 for non-interlaced images, or 7 for interlaced images
for (int pass = 0; pass < number_passes; pass++) {
for (png_uint_32 k = 0; k < height; k++) {
- FreeImage_ConvertLine32To24(buffer, FreeImage_GetScanLine(dib, height - k - 1), width);
+ FreeImage_ConvertLine32To24(buffer, FreeImage_GetScanLine(dib, height - k - 1), width);
png_write_row(png_ptr, buffer);
}
}
@@ -911,8 +1057,8 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void
} else {
// the number of passes is either 1 for non-interlaced images, or 7 for interlaced images
for (int pass = 0; pass < number_passes; pass++) {
- for (png_uint_32 k = 0; k < height; k++) {
- png_write_row(png_ptr, FreeImage_GetScanLine(dib, height - k - 1));
+ for (png_uint_32 k = 0; k < height; k++) {
+ png_write_row(png_ptr, FreeImage_GetScanLine(dib, height - k - 1));
}
}
}
@@ -930,7 +1076,11 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void
png_destroy_write_struct(&png_ptr, &info_ptr);
return TRUE;
+
} catch (const char *text) {
+ if(png_ptr) {
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ }
FreeImage_OutputMessageProc(s_format_id, text);
}
}
diff --git a/plugins/AdvaImg/src/FreeImage/PluginPNM.cpp b/plugins/AdvaImg/src/FreeImage/PluginPNM.cpp
index 3155315559..3b4d0de554 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginPNM.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginPNM.cpp
@@ -33,11 +33,13 @@ Get an integer value from the actual position pointed by handle
static int
GetInt(FreeImageIO *io, fi_handle handle) {
char c = 0;
- BOOL firstchar;
+ BOOL bFirstChar;
// skip forward to start of next number
- if(!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING;
+ if(!io->read_proc(&c, 1, 1, handle)) {
+ throw FI_MSG_ERROR_PARSING;
+ }
while (1) {
// eat comments
@@ -45,15 +47,16 @@ GetInt(FreeImageIO *io, fi_handle handle) {
if (c == '#') {
// if we're at a comment, read to end of line
- firstchar = TRUE;
+ bFirstChar = TRUE;
while (1) {
- if(!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING;
+ if(!io->read_proc(&c, 1, 1, handle)) {
+ throw FI_MSG_ERROR_PARSING;
+ }
- if (firstchar && c == ' ') {
+ if (bFirstChar && c == ' ') {
// loop off 1 sp after #
-
- firstchar = FALSE;
+ bFirstChar = FALSE;
} else if (c == '\n') {
break;
}
@@ -62,11 +65,12 @@ GetInt(FreeImageIO *io, fi_handle handle) {
if (c >= '0' && c <='9') {
// we've found what we were looking for
-
break;
}
- if(!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING;
+ if(!io->read_proc(&c, 1, 1, handle)) {
+ throw FI_MSG_ERROR_PARSING;
+ }
}
// we're at the start of a number, continue until we hit a non-number
@@ -76,10 +80,13 @@ GetInt(FreeImageIO *io, fi_handle handle) {
while (1) {
i = (i * 10) + (c - '0');
- if(!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING;
+ if(!io->read_proc(&c, 1, 1, handle)) {
+ throw FI_MSG_ERROR_PARSING;
+ }
- if (c < '0' || c > '9')
- break;
+ if (c < '0' || c > '9') {
+ break;
+ }
}
return i;
diff --git a/plugins/AdvaImg/src/FreeImage/PluginRAW.cpp b/plugins/AdvaImg/src/FreeImage/PluginRAW.cpp
index bf5d82169c..e9bd5bfa77 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginRAW.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginRAW.cpp
@@ -140,12 +140,72 @@ public:
/**
Convert a processed raw data array to a FIBITMAP
+@param RawProcessor LibRaw handle containing the processed raw image
+@return Returns the converted dib if successfull, returns NULL otherwise
+*/
+static FIBITMAP *
+libraw_ConvertProcessedRawToDib(LibRaw *RawProcessor) {
+ FIBITMAP *dib = NULL;
+ int width, height, colors, bpp;
+
+ try {
+ int bgr = 0; // pixel copy order: RGB if (bgr == 0) and BGR otherwise
+
+ // get image info
+ RawProcessor->get_mem_image_format(&width, &height, &colors, &bpp);
+
+ // only 3-color images supported...
+ if(colors != 3) {
+ throw "LibRaw : only 3-color images supported";
+ }
+
+ if(bpp == 16) {
+ // allocate output dib
+ dib = FreeImage_AllocateT(FIT_RGB16, width, height);
+ if(!dib) {
+ throw FI_MSG_ERROR_DIB_MEMORY;
+ }
+
+ } else if(bpp == 8) {
+#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
+ bgr = 1; // only useful for FIT_BITMAP types
+#endif
+
+ // allocate output dib
+ dib = FreeImage_AllocateT(FIT_BITMAP, width, height, 24);
+ if(!dib) {
+ throw FI_MSG_ERROR_DIB_MEMORY;
+ }
+ }
+
+ // copy post-processed bitmap data into FIBITMAP buffer
+ if(RawProcessor->copy_mem_image(FreeImage_GetBits(dib), FreeImage_GetPitch(dib), bgr) != LIBRAW_SUCCESS) {
+ throw "LibRaw : failed to copy data into dib";
+ }
+
+ // flip vertically
+ FreeImage_FlipVertical(dib);
+
+ return dib;
+
+ } catch(const char *text) {
+ FreeImage_Unload(dib);
+ FreeImage_OutputMessageProc(s_format_id, text);
+ return NULL;
+ }
+}
+
+
+/**
+Convert a processed raw image to a FIBITMAP
@param image Processed raw image
@return Returns the converted dib if successfull, returns NULL otherwise
+@see libraw_LoadEmbeddedPreview
*/
static FIBITMAP *
-libraw_ConvertToDib(libraw_processed_image_t *image) {
+libraw_ConvertProcessedImageToDib(libraw_processed_image_t *image) {
FIBITMAP *dib = NULL;
+
try {
unsigned width = image->width;
unsigned height = image->height;
@@ -185,12 +245,14 @@ libraw_ConvertToDib(libraw_processed_image_t *image) {
}
}
}
+
+ return dib;
} catch(const char *text) {
+ FreeImage_Unload(dib);
FreeImage_OutputMessageProc(s_format_id, text);
+ return NULL;
}
-
- return dib;
}
/**
@@ -228,9 +290,9 @@ libraw_LoadEmbeddedPreview(LibRaw *RawProcessor, int flags) {
dib = FreeImage_LoadFromMemory(fif, hmem, flags);
// close the stream
FreeImage_CloseMemory(hmem);
- } else {
+ } else if((flags & FIF_LOAD_NOPIXELS) != FIF_LOAD_NOPIXELS) {
// convert processed data to output dib
- dib = libraw_ConvertToDib(thumb_image);
+ dib = libraw_ConvertProcessedImageToDib(thumb_image);
}
} else {
throw "LibRaw : failed to run dcraw_make_mem_thumb";
@@ -262,7 +324,6 @@ Load raw data and convert to FIBITMAP
static FIBITMAP *
libraw_LoadRawData(LibRaw *RawProcessor, int bitspersample) {
FIBITMAP *dib = NULL;
- libraw_processed_image_t *processed_image = NULL;
try {
// set decoding parameters
@@ -300,38 +361,119 @@ libraw_LoadRawData(LibRaw *RawProcessor, int bitspersample) {
}
// retrieve processed image
- int error_code = 0;
- processed_image = RawProcessor->dcraw_make_mem_image(&error_code);
- if(processed_image) {
- // type SHOULD be LIBRAW_IMAGE_BITMAP, but we'll check
- if(processed_image->type != LIBRAW_IMAGE_BITMAP) {
- throw "invalid image type";
+ dib = libraw_ConvertProcessedRawToDib(RawProcessor);
+
+ return dib;
+
+ } catch(const char *text) {
+ FreeImage_OutputMessageProc(s_format_id, text);
+ return NULL;
+ }
+}
+
+/**
+Load the Bayer matrix (unprocessed raw data) as a FIT_UINT16 image.
+Note that some formats don't have a Bayer matrix (e.g. Foveon, Canon sRAW, demosaiced DNG files).
+@param RawProcessor Libraw handle
+@return Returns the loaded dib if successfull, returns NULL otherwise
+*/
+static FIBITMAP *
+libraw_LoadUnprocessedData(LibRaw *RawProcessor) {
+ FIBITMAP *dib = NULL;
+
+ try {
+ // unpack data
+ if(RawProcessor->unpack() != LIBRAW_SUCCESS) {
+ throw "LibRaw : failed to unpack data";
+ }
+
+ // check for a supported Bayer format
+ if(!(RawProcessor->imgdata.idata.filters || RawProcessor->imgdata.idata.colors == 1)) {
+ throw "LibRaw : only Bayer-pattern RAW files are supported";
+ }
+
+ // allocate output dib
+ const unsigned width = RawProcessor->imgdata.sizes.raw_width;
+ const unsigned height = RawProcessor->imgdata.sizes.raw_height;
+ const size_t line_size = width * sizeof(WORD);
+ const WORD *src_bits = (WORD*)RawProcessor->imgdata.rawdata.raw_image;
+
+ if(src_bits) {
+ dib = FreeImage_AllocateT(FIT_UINT16, width, height);
+ }
+ if(!dib) {
+ throw FI_MSG_ERROR_DIB_MEMORY;
+ }
+
+ // retrieve the raw image
+ for(unsigned y = 0; y < height; y++) {
+ WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dib, height - 1 - y);
+ memcpy(dst_bits, src_bits, line_size);
+ src_bits += width;
+ }
+
+ // store metadata needed for post-processing
+ {
+ char value[512];
+
+ const libraw_image_sizes_t *sizes = &RawProcessor->imgdata.sizes;
+
+ // image output width & height
+ {
+ sprintf(value, "%d", sizes->iwidth);
+ FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.Output.Width", value);
+
+ sprintf(value, "%d", sizes->iheight);
+ FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.Output.Height", value);
}
- // only 3-color images supported...
- if(processed_image->colors != 3) {
- throw "only 3-color images supported";
+
+ // image output frame
+ {
+ const unsigned f_left = sizes->left_margin;
+ const unsigned f_top = sizes->top_margin;
+ const unsigned f_width = sizes->width;
+ const unsigned f_height = sizes->height;
+
+ sprintf(value, "%d", f_left);
+ FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.Frame.Left", value);
+
+ sprintf(value, "%d", f_top);
+ FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.Frame.Top", value);
+
+ sprintf(value, "%d", f_width);
+ FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.Frame.Width", value);
+
+ sprintf(value, "%d", f_height);
+ FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.Frame.Height", value);
}
- } else {
- throw "LibRaw : failed to run dcraw_make_mem_image";
- }
- // convert processed data to output dib
- dib = libraw_ConvertToDib(processed_image);
-
- // clean-up and return
- RawProcessor->dcraw_clear_mem(processed_image);
+ // Bayer pattern
+ // Mask describing the order of color pixels in the matrix.
+ // This field describe 16 pixels (8 rows with two pixels in each, from left to right and from top to bottom).
+
+ if(RawProcessor->imgdata.idata.filters) {
+ // description of colors numbered from 0 to 3 (RGBG,RGBE,GMCY, or GBTG)
+ char *cdesc = RawProcessor->imgdata.idata.cdesc;
+ if(!cdesc[3]) {
+ cdesc[3] = 'G';
+ }
+ char *pattern = &value[0];
+ for(int i = 0; i < 16; i++) {
+ pattern[i] = cdesc[ RawProcessor->fcol(i >> 1, i & 1) ];
+ }
+ pattern[16] = 0;
+ FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.BayerPattern", value);
+ }
+ }
+
return dib;
} catch(const char *text) {
- // clean-up and return
- if(processed_image) {
- RawProcessor->dcraw_clear_mem(processed_image);
- }
+ FreeImage_Unload(dib);
FreeImage_OutputMessageProc(s_format_id, text);
+ return NULL;
}
-
- return NULL;
}
// ==========================================================
@@ -397,8 +539,8 @@ Extension() {
"sr2," // Sony Digital Camera Raw Image Format.
"srf," // Sony Digital Camera Raw Image Format for DSC-F828 8 megapixel digital camera or Sony DSC-R1.
"srw," // Samsung Raw Image Format.
- "sti"; // Sinar Capture Shop Raw Image File.
-// "x3f" // Sigma Digital Camera Raw Image Format for devices based on Foveon X3 direct image sensor.
+ "sti," // Sinar Capture Shop Raw Image File.
+ "x3f"; // Sigma Digital Camera Raw Image Format for devices based on Foveon X3 direct image sensor.
return raw_extensions;
}
@@ -416,33 +558,37 @@ static BOOL
HasMagicHeader(FreeImageIO *io, fi_handle handle) {
const unsigned signature_size = 32;
BYTE signature[signature_size] = { 0 };
-
- // Canon (CR2), Intel byte order
+ /*
+ note: classic TIFF signature is
+ { 0x49, 0x49, 0x2A, 0x00 } Classic TIFF, little-endian
+ { 0x4D, 0x4D, 0x00, 0x2A } Classic TIFF, big-endian
+ */
+ // Canon (CR2), little-endian byte order
const BYTE CR2_II[] = { 0x49, 0x49, 0x2A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x43, 0x52, 0x02, 0x00 };
- // Canon (CR2), Motorola byte order
- const BYTE CR2_MM[] = { 0x4D, 0x4D, 0x2A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x43, 0x52, 0x02, 0x00 };
- // Canon (CRW), Intel byte order
- const BYTE CRW_II[] = { 0x49, 0x49, 0x1A, 0x00, 0x00, 0x00, 0x48, 0x45, 0x41, 0x50, 0x43, 0x43, 0x44, 0x52, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ // Canon (CRW), little-endian byte order
+ const BYTE CRW_II[] = { 0x49, 0x49, 0x1A, 0x00, 0x00, 0x00, 0x48, 0x45, 0x41, 0x50, 0x43, 0x43, 0x44, 0x52, 0x02, 0x00 };
// Minolta (MRW)
const BYTE MRW[] = { 0x00, 0x4D, 0x52, 0x4D, 0x00 };
- // Olympus (ORF), Intel byte order
+ // Olympus (ORF), little-endian byte order
const BYTE ORF_IIRS[] = { 0x49, 0x49, 0x52, 0x53, 0x08, 0x00, 0x00, 0x00 };
const BYTE ORF_IIRO[] = { 0x49, 0x49, 0x52, 0x4F, 0x08, 0x00, 0x00, 0x00 };
- // Olympus (ORF), Motorola byte order
+ // Olympus (ORF), big-endian byte order
const BYTE ORF_MMOR[] = { 0x4D, 0x4D, 0x4F, 0x52, 0x00, 0x00, 0x00, 0x08 };
// Fujifilm (RAF)
- const BYTE RAF[] = { 0x46, 0x55, 0x4A, 0x49, 0x46, 0x49, 0x4C, 0x4D, 0x43, 0x43, 0x44, 0x2D, 0x52, 0x41, 0x57, 0x20, 0x30, 0x32, 0x30, 0x31 };
- // Panasonic (RW2) or Leica (RWL)
- const BYTE RW2_II[] = { 0x49, 0x49, 0x55, 0x00, 0x18, 0x00, 0x00, 0x00, 0x88, 0xE7, 0x74, 0xD8, 0xF8, 0x25, 0x1D, 0x4D, 0x94, 0x7A, 0x6E, 0x77, 0x82, 0x2B, 0x5D, 0x6A };
+ const BYTE RAF[] = { 0x46, 0x55, 0x4A, 0x49, 0x46, 0x49, 0x4C, 0x4D, 0x43, 0x43, 0x44, 0x2D, 0x52, 0x41, 0x57, 0x20 };
+ // Panasonic (RW2) or Leica (RWL), little-endian byte order
+ const BYTE RWx_II[] = { 0x49, 0x49, 0x55, 0x00, 0x18, 0x00, 0x00, 0x00, 0x88, 0xE7, 0x74, 0xD8, 0xF8, 0x25, 0x1D, 0x4D, 0x94, 0x7A, 0x6E, 0x77, 0x82, 0x2B, 0x5D, 0x6A };
+ // Panasonic (RAW) or Leica (RAW), little-endian byte order
+ const BYTE RAW_II[] = { 0x49, 0x49, 0x55, 0x00, 0x08, 0x00, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00 };
+ // Foveon (X3F)
+ const BYTE X3F[] = { 0x46, 0x4F, 0x56, 0x62 };
if(io->read_proc(signature, 1, signature_size, handle) != signature_size) {
return FALSE;
}
if(memcmp(CR2_II, signature, 12) == 0)
return TRUE;
- if(memcmp(CR2_MM, signature, 12) == 0)
- return TRUE;
- if(memcmp(CRW_II, signature, 26) == 0)
+ if(memcmp(CRW_II, signature, 16) == 0)
return TRUE;
if(memcmp(MRW, signature, 5) == 0)
return TRUE;
@@ -452,9 +598,13 @@ HasMagicHeader(FreeImageIO *io, fi_handle handle) {
return TRUE;
if(memcmp(ORF_MMOR, signature, 8) == 0)
return TRUE;
- if(memcmp(RAF, signature, 20) == 0)
+ if(memcmp(RAF, signature, 16) == 0)
return TRUE;
- if(memcmp(RW2_II, signature, 24) == 0)
+ if(memcmp(RWx_II, signature, 24) == 0)
+ return TRUE;
+ if(memcmp(RAW_II, signature, 18) == 0)
+ return TRUE;
+ if(memcmp(X3F, signature, 4) == 0)
return TRUE;
return FALSE;
@@ -547,6 +697,8 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
RawProcessor->imgdata.params.shot_select = 0;
// (-w) Use camera white balance, if possible (otherwise, fallback to auto_wb)
RawProcessor->imgdata.params.use_camera_wb = 1;
+ // (-M) Use any color matrix from the camera metadata. This option only affects Olympus, Leaf, and Phase One cameras.
+ RawProcessor->imgdata.params.use_camera_matrix = 1;
// (-h) outputs the image in 50% size
RawProcessor->imgdata.params.half_size = ((flags & RAW_HALFSIZE) == RAW_HALFSIZE) ? 1 : 0;
@@ -559,6 +711,10 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
// header only mode
dib = FreeImage_AllocateHeaderT(header_only, FIT_RGB16, RawProcessor->imgdata.sizes.width, RawProcessor->imgdata.sizes.height);
}
+ else if((flags & RAW_UNPROCESSED) == RAW_UNPROCESSED) {
+ // load raw data without post-processing (i.e. as a Bayer matrix)
+ dib = libraw_LoadUnprocessedData(RawProcessor);
+ }
else if((flags & RAW_PREVIEW) == RAW_PREVIEW) {
// try to get the embedded JPEG
dib = libraw_LoadEmbeddedPreview(RawProcessor, 0);
diff --git a/plugins/AdvaImg/src/FreeImage/PluginTARGA.cpp b/plugins/AdvaImg/src/FreeImage/PluginTARGA.cpp
index f12d7286ce..84864308e0 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginTARGA.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginTARGA.cpp
@@ -39,20 +39,20 @@
#endif
typedef struct tagTGAHEADER {
- BYTE id_length; // ID length
- BYTE color_map_type; // color map type
- BYTE image_type; // image type
-
- WORD cm_first_entry; // first entry index
- WORD cm_length; // color map length
- BYTE cm_size; // color map entry size, in bits
-
- WORD is_xorigin; // X-origin of image
- WORD is_yorigin; // Y-origin of image
- WORD is_width; // image width
- WORD is_height; // image height
- BYTE is_pixel_depth; // pixel depth
- BYTE is_image_descriptor; // image descriptor
+ BYTE id_length; //! length of the image ID field
+ BYTE color_map_type; //! whether a color map is included
+ BYTE image_type; //! compression and color types
+
+ WORD cm_first_entry; //! first entry index (offset into the color map table)
+ WORD cm_length; //! color map length (number of entries)
+ BYTE cm_size; //! color map entry size, in bits (number of bits per pixel)
+
+ WORD is_xorigin; //! X-origin of image (absolute coordinate of lower-left corner for displays where origin is at the lower left)
+ WORD is_yorigin; //! Y-origin of image (as for X-origin)
+ WORD is_width; //! image width
+ WORD is_height; //! image height
+ BYTE is_pixel_depth; //! bits per pixel
+ BYTE is_image_descriptor; //! image descriptor, bits 3-0 give the alpha channel depth, bits 5-4 give direction
} TGAHEADER;
typedef struct tagTGAEXTENSIONAREA {
@@ -400,14 +400,14 @@ Validate(FreeImageIO *io, fi_handle handle) {
}
// if the color map type is 1 then we validate the map entry information...
if(header.color_map_type > 0) {
- // It doesn't make any sense if the first entry is larger than the color map table
+ // it doesn't make any sense if the first entry is larger than the color map table
if(header.cm_first_entry >= header.cm_length) {
return FALSE;
}
- }
- // check header.cm_size, don't allow 0 or anything bigger than 32
- if(header.cm_size == 0 || header.cm_size > 32) {
- return FALSE;
+ // check header.cm_size, don't allow 0 or anything bigger than 32
+ if(header.cm_size == 0 || header.cm_size > 32) {
+ return FALSE;
+ }
}
// the width/height shouldn't be 0, right ?
if(header.is_width == 0 || header.is_height == 0) {
@@ -415,9 +415,9 @@ Validate(FreeImageIO *io, fi_handle handle) {
}
// let's now verify all the types that are supported by FreeImage (this is our final verification)
switch(header.image_type) {
- case TGA_CMAP :
+ case TGA_CMAP:
case TGA_RGB:
- case TGA_MONO :
+ case TGA_MONO:
case TGA_RLECMAP:
case TGA_RLERGB:
case TGA_RLEMONO:
@@ -435,8 +435,6 @@ Validate(FreeImageIO *io, fi_handle handle) {
return FALSE;
}
}
-
- return FALSE;
}
static BOOL DLL_CALLCONV
@@ -1339,7 +1337,7 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void
header.is_width = (WORD)FreeImage_GetWidth(dib);
header.is_height = (WORD)FreeImage_GetHeight(dib);
header.is_pixel_depth = (BYTE)bpp;
- header.is_image_descriptor = 0;
+ header.is_image_descriptor = (bpp == 32 ? 8 : 0);
if (palette) {
header.color_map_type = 1;
diff --git a/plugins/AdvaImg/src/FreeImage/PluginTIFF.cpp b/plugins/AdvaImg/src/FreeImage/PluginTIFF.cpp
index 4e502c56e8..1b454531c1 100644
--- a/plugins/AdvaImg/src/FreeImage/PluginTIFF.cpp
+++ b/plugins/AdvaImg/src/FreeImage/PluginTIFF.cpp
@@ -44,29 +44,22 @@
#include "FreeImageIO.h"
#include "PSDParser.h"
-// ----------------------------------------------------------
-// geotiff interface (see XTIFF.cpp)
-// ----------------------------------------------------------
-
-// Extended TIFF Directory GEO Tag Support
+// --------------------------------------------------------------------------
+// GeoTIFF profile (see XTIFF.cpp)
+// --------------------------------------------------------------------------
void XTIFFInitialize();
+BOOL tiff_read_geotiff_profile(TIFF *tif, FIBITMAP *dib);
+BOOL tiff_write_geotiff_profile(TIFF *tif, FIBITMAP *dib);
-// GeoTIFF profile
-void tiff_read_geotiff_profile(TIFF *tif, FIBITMAP *dib);
-void tiff_write_geotiff_profile(TIFF *tif, FIBITMAP *dib);
-
-// ----------------------------------------------------------
-// exif interface (see XTIFF.cpp)
+// --------------------------------------------------------------------------
+// TIFF Exif profile (see XTIFF.cpp)
// ----------------------------------------------------------
-
-// TIFF Exif profile
BOOL tiff_read_exif_tags(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib);
BOOL tiff_write_exif_tags(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib);
-// ----------------------------------------------------------
+// --------------------------------------------------------------------------
// LogLuv conversion functions interface (see TIFFLogLuv.cpp)
-// ----------------------------------------------------------
-
+// --------------------------------------------------------------------------
void tiff_ConvertLineXYZToRGB(BYTE *target, BYTE *source, double stonits, int width_in_pixels);
void tiff_ConvertLineRGBToXYZ(BYTE *target, BYTE *source, int width_in_pixels);
@@ -141,13 +134,13 @@ typedef struct {
static tmsize_t
_tiffReadProc(thandle_t handle, void *buf, tmsize_t size) {
fi_TIFFIO *fio = (fi_TIFFIO*)handle;
- return fio->io->read_proc(buf, size, 1, fio->handle) * size;
+ return fio->io->read_proc(buf, (unsigned)size, 1, fio->handle) * size;
}
static tmsize_t
_tiffWriteProc(thandle_t handle, void *buf, tmsize_t size) {
fi_TIFFIO *fio = (fi_TIFFIO*)handle;
- return fio->io->write_proc(buf, size, 1, fio->handle) * size;
+ return fio->io->write_proc(buf, (unsigned)size, 1, fio->handle) * size;
}
static toff_t
@@ -192,21 +185,12 @@ Open a TIFF file descriptor for reading or writing
TIFF *
TIFFFdOpen(thandle_t handle, const char *name, const char *mode) {
TIFF *tif;
-
// Open the file; the callback will set everything up
tif = TIFFClientOpen(name, mode, handle,
_tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
_tiffSizeProc, _tiffMapProc, _tiffUnmapProc);
- // Warning: tif_fd is declared as 'int' currently (see libTIFF),
- // may result in incorrect file pointers inside libTIFF on
- // 64bit machines (sizeof(int) != sizeof(long)).
- // Needs to be fixed within libTIFF.
- if (tif) {
- tif->tif_fd = (long)handle;
- }
-
return tif;
}
@@ -933,7 +917,6 @@ tiff_write_xmp_profile(TIFF *tiff, FIBITMAP *dib) {
static BOOL
tiff_write_exif_profile(TIFF *tiff, FIBITMAP *dib) {
BOOL bResult = FALSE;
- uint32 exif_offset = 0;
// write EXIF_MAIN tags, EXIF_EXIF not supported yet
bResult = tiff_write_exif_tags(tiff, TagLib::EXIF_MAIN, dib);
@@ -1062,6 +1045,8 @@ Open(FreeImageIO *io, fi_handle handle, BOOL read) {
if (read) {
fio->tif = TIFFFdOpen((thandle_t)fio, "", "r");
} else {
+ // mode = "w" : write Classic TIFF
+ // mode = "w8" : write Big TIFF
fio->tif = TIFFFdOpen((thandle_t)fio, "", "w");
}
if(fio->tif == NULL) {
@@ -1106,11 +1091,10 @@ PageCount(FreeImageIO *io, fi_handle handle, void *data) {
check for uncommon bitspersample values (e.g. 10, 12, ...)
@param photometric TIFFTAG_PHOTOMETRIC tiff tag
@param bitspersample TIFFTAG_BITSPERSAMPLE tiff tag
-@param samplesperpixel TIFFTAG_SAMPLESPERPIXEL tiff tag
@return Returns FALSE if a uncommon bit-depth is encountered, returns TRUE otherwise
*/
static BOOL
-IsValidBitsPerSample(uint16 photometric, uint16 bitspersample, uint16 samplesperpixel) {
+IsValidBitsPerSample(uint16 photometric, uint16 bitspersample) {
switch(bitspersample) {
case 1:
@@ -1131,7 +1115,12 @@ IsValidBitsPerSample(uint16 photometric, uint16 bitspersample, uint16 samplesper
}
break;
case 32:
- return TRUE;
+ if((photometric == PHOTOMETRIC_MINISWHITE) || (photometric == PHOTOMETRIC_MINISBLACK) || (photometric == PHOTOMETRIC_LOGLUV)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ break;
case 64:
case 128:
if(photometric == PHOTOMETRIC_MINISBLACK) {
@@ -1376,7 +1365,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
// check for unsupported formats
// ---------------------------------------------------------------------------------
- if(IsValidBitsPerSample(photometric, bitspersample, samplesperpixel) == FALSE) {
+ if(IsValidBitsPerSample(photometric, bitspersample) == FALSE) {
FreeImage_OutputMessageProc(s_format_id,
"Unable to handle this format: bitspersample = %d, samplesperpixel = %d, photometric = %d",
(int)bitspersample, (int)samplesperpixel, (int)photometric);
@@ -2029,8 +2018,8 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
// calculate src line and dst pitch
int dst_pitch = FreeImage_GetPitch(dib);
- int tileRowSize = TIFFTileRowSize(tif);
- int imageRowSize = TIFFScanlineSize(tif);
+ uint32 tileRowSize = (uint32)TIFFTileRowSize(tif);
+ uint32 imageRowSize = (uint32)TIFFScanlineSize(tif);
// In the tiff file the lines are saved from up to down
@@ -2038,11 +2027,10 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
BYTE *bits = FreeImage_GetScanLine(dib, height - 1);
- uint32 x, y, rowSize;
- for (y = 0; y < height; y += tileHeight) {
+ for (uint32 y = 0; y < height; y += tileHeight) {
int32 nrows = (y + tileHeight > height ? height - y : tileHeight);
- for (x = 0, rowSize = 0; x < width; x += tileWidth, rowSize += tileRowSize) {
+ for (uint32 x = 0, rowSize = 0; x < width; x += tileWidth, rowSize += tileRowSize) {
memset(tileBuffer, 0, tileSize);
// read one tile
diff --git a/plugins/AdvaImg/src/FreeImage/WuQuantizer.cpp b/plugins/AdvaImg/src/FreeImage/WuQuantizer.cpp
index 041eae368b..66d37066bf 100644
--- a/plugins/AdvaImg/src/FreeImage/WuQuantizer.cpp
+++ b/plugins/AdvaImg/src/FreeImage/WuQuantizer.cpp
@@ -108,22 +108,43 @@ WuQuantizer::Hist3D(LONG *vwt, LONG *vmr, LONG *vmg, LONG *vmb, float *m2, int R
for(i = 0; i < 256; i++)
table[i] = i * i;
- for(y = 0; y < height; y++) {
- BYTE *bits = FreeImage_GetScanLine(m_dib, y);
-
- for(x = 0; x < width; x++) {
- inr = (bits[FI_RGBA_RED] >> 3) + 1;
- ing = (bits[FI_RGBA_GREEN] >> 3) + 1;
- inb = (bits[FI_RGBA_BLUE] >> 3) + 1;
- ind = INDEX(inr, ing, inb);
- Qadd[y*width + x] = (WORD)ind;
- // [inr][ing][inb]
- vwt[ind]++;
- vmr[ind] += bits[FI_RGBA_RED];
- vmg[ind] += bits[FI_RGBA_GREEN];
- vmb[ind] += bits[FI_RGBA_BLUE];
- m2[ind] += (float)(table[bits[FI_RGBA_RED]] + table[bits[FI_RGBA_GREEN]] + table[bits[FI_RGBA_BLUE]]);
- bits += 3;
+ if (FreeImage_GetBPP(m_dib) == 24) {
+ for(y = 0; y < height; y++) {
+ BYTE *bits = FreeImage_GetScanLine(m_dib, y);
+
+ for(x = 0; x < width; x++) {
+ inr = (bits[FI_RGBA_RED] >> 3) + 1;
+ ing = (bits[FI_RGBA_GREEN] >> 3) + 1;
+ inb = (bits[FI_RGBA_BLUE] >> 3) + 1;
+ ind = INDEX(inr, ing, inb);
+ Qadd[y*width + x] = (WORD)ind;
+ // [inr][ing][inb]
+ vwt[ind]++;
+ vmr[ind] += bits[FI_RGBA_RED];
+ vmg[ind] += bits[FI_RGBA_GREEN];
+ vmb[ind] += bits[FI_RGBA_BLUE];
+ m2[ind] += (float)(table[bits[FI_RGBA_RED]] + table[bits[FI_RGBA_GREEN]] + table[bits[FI_RGBA_BLUE]]);
+ bits += 3;
+ }
+ }
+ } else {
+ for(y = 0; y < height; y++) {
+ BYTE *bits = FreeImage_GetScanLine(m_dib, y);
+
+ for(x = 0; x < width; x++) {
+ inr = (bits[FI_RGBA_RED] >> 3) + 1;
+ ing = (bits[FI_RGBA_GREEN] >> 3) + 1;
+ inb = (bits[FI_RGBA_BLUE] >> 3) + 1;
+ ind = INDEX(inr, ing, inb);
+ Qadd[y*width + x] = (WORD)ind;
+ // [inr][ing][inb]
+ vwt[ind]++;
+ vmr[ind] += bits[FI_RGBA_RED];
+ vmg[ind] += bits[FI_RGBA_GREEN];
+ vmb[ind] += bits[FI_RGBA_BLUE];
+ m2[ind] += (float)(table[bits[FI_RGBA_RED]] + table[bits[FI_RGBA_GREEN]] + table[bits[FI_RGBA_BLUE]]);
+ bits += 4;
+ }
}
}
diff --git a/plugins/AdvaImg/src/FreeImageIO.h b/plugins/AdvaImg/src/FreeImageIO.h
index b251d474f6..c846b5bf0a 100644
--- a/plugins/AdvaImg/src/FreeImageIO.h
+++ b/plugins/AdvaImg/src/FreeImageIO.h
@@ -29,16 +29,31 @@
// ----------------------------------------------------------
FI_STRUCT (FIMEMORYHEADER) {
- /// remember to delete the buffer
+ /**
+ Flag used to remember to delete the 'data' buffer.
+ When the buffer is a wrapped buffer, it is read-only, no need to delete it.
+ When the buffer is a read/write buffer, it is allocated dynamically and must be deleted when no longer needed.
+ */
BOOL delete_me;
- /// file length
- long filelen;
- /// buffer size
- long datalen;
- /// current position
- long curpos;
- /// start buffer address
+ /**
+ file_length is equal to the input buffer size when the buffer is a wrapped buffer, i.e. file_length == data_length.
+ file_length is the amount of the written bytes when the buffer is a read/write buffer.
+ */
+ long file_length;
+ /**
+ When using read-only input buffers, data_length is equal to the input buffer size, i.e. the file_length.
+ When using read/write buffers, data_length is the size of the allocated buffer,
+ whose size is greater than or equal to file_length.
+ */
+ long data_length;
+ /**
+ start buffer address
+ */
void *data;
+ /**
+ Current position into the memory stream
+ */
+ long current_position;
};
void SetDefaultIO(FreeImageIO *io);
diff --git a/plugins/AdvaImg/src/FreeImageToolkit/Background.cpp b/plugins/AdvaImg/src/FreeImageToolkit/Background.cpp
index 08cdd4473b..06b31aa332 100644
--- a/plugins/AdvaImg/src/FreeImageToolkit/Background.cpp
+++ b/plugins/AdvaImg/src/FreeImageToolkit/Background.cpp
@@ -215,14 +215,13 @@ static BOOL
FillBackgroundBitmap(FIBITMAP *dib, const RGBQUAD *color, int options) {
if ((!dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP)) {
- return FALSE;
+ return FALSE;;
}
if (!color) {
return FALSE;
}
- RGBQUAD blend;
const RGBQUAD *color_intl = color;
unsigned bpp = FreeImage_GetBPP(dib);
unsigned width = FreeImage_GetWidth(dib);
@@ -251,7 +250,7 @@ FillBackgroundBitmap(FIBITMAP *dib, const RGBQUAD *color, int options) {
// release, just assume to have an unicolor background and fill
// all with an 'alpha-blended' color.
if (color->rgbReserved < 255) {
-
+
// If we will draw on an unicolor background, it's
// faster to draw opaque with an alpha blended color.
// So, first get the color from the first pixel in the
@@ -259,24 +258,25 @@ FillBackgroundBitmap(FIBITMAP *dib, const RGBQUAD *color, int options) {
RGBQUAD bgcolor;
if (bpp == 8) {
bgcolor = FreeImage_GetPalette(dib)[*src_bits];
- } else {
+ } else {
bgcolor.rgbBlue = src_bits[FI_RGBA_BLUE];
bgcolor.rgbGreen = src_bits[FI_RGBA_GREEN];
bgcolor.rgbRed = src_bits[FI_RGBA_RED];
bgcolor.rgbReserved = 0xFF;
}
+ RGBQUAD blend;
GetAlphaBlendedColor(&bgcolor, color_intl, &blend);
color_intl = &blend;
}
}
-
+
int index = (bpp <= 8) ? GetPaletteIndex(dib, color_intl, options, &color_type) : 0;
if (index == -1) {
// No palette index found for a palletized
// image. This should never happen...
return FALSE;
}
-
+
// first, build the first scanline (line 0)
switch (bpp) {
case 1: {
diff --git a/plugins/AdvaImg/src/FreeImageToolkit/CopyPaste.cpp b/plugins/AdvaImg/src/FreeImageToolkit/CopyPaste.cpp
index e4b8155739..d05a5dfdc8 100644
--- a/plugins/AdvaImg/src/FreeImageToolkit/CopyPaste.cpp
+++ b/plugins/AdvaImg/src/FreeImageToolkit/CopyPaste.cpp
@@ -6,6 +6,7 @@
// - Hervé Drolon (drolon@infonie.fr)
// - Manfred Tausch (manfred.tausch@t-online.de)
// - Riley McNiff (rmcniff@marexgroup.com)
+// - Carsten Klein (cklein05@users.sourceforge.net)
//
// This file is part of FreeImage 3
//
@@ -92,7 +93,6 @@ Combine1(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned
static BOOL
Combine4(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha) {
-
int swapTable[16];
BOOL bOddStart, bOddEnd;
@@ -744,4 +744,118 @@ FreeImage_Paste(FIBITMAP *dst, FIBITMAP *src, int left, int top, int alpha) {
return bResult;
}
+// ----------------------------------------------------------
+
+/** @brief Creates a dynamic read/write view into a FreeImage bitmap.
+
+ A dynamic view is a FreeImage bitmap with its own width and height, that,
+ however, shares its bits with another FreeImage bitmap. Typically, views
+ are used to define one or more rectangular sub-images of an existing
+ bitmap. All FreeImage operations, like saving, displaying and all the
+ toolkit functions, when applied to the view, only affect the view's
+ rectangular area.
+
+ Although the view's backing image's bits not need to be copied around,
+ which makes the view much faster than similar solutions using
+ FreeImage_Copy, a view uses some private memory that needs to be freed by
+ calling FreeImage_Unload on the view's handle to prevent memory leaks.
+
+ Only the backing image's pixels are shared by the view. For all other image
+ data, notably for the resolution, background color, color palette,
+ transparency table and for the ICC profile, the view gets a private copy
+ of the data. By default, the backing image's metadata is NOT copied to
+ the view.
+
+ As with all FreeImage functions that take a rectangle region, top and left
+ positions are included, whereas right and bottom positions are excluded
+ from the rectangle area.
+
+ Since the memory block shared by the backing image and the view must start
+ at a byte boundary, the value of parameter left must be a multiple of 8
+ for 1-bit images and a multiple of 2 for 4-bit images.
+
+ @param dib The FreeImage bitmap on which to create the view.
+ @param left The left position of the view's area.
+ @param top The top position of the view's area.
+ @param right The right position of the view's area.
+ @param bottom The bottom position of the view's area.
+ @return Returns a handle to the newly created view or NULL if the view
+ was not created.
+ */
+FIBITMAP * DLL_CALLCONV
+FreeImage_CreateView(FIBITMAP *dib, unsigned left, unsigned top, unsigned right, unsigned bottom) {
+ if (!FreeImage_HasPixels(dib)) {
+ return NULL;
+ }
+
+ // normalize the rectangle
+ if (right < left) {
+ INPLACESWAP(left, right);
+ }
+ if (bottom < top) {
+ INPLACESWAP(top, bottom);
+ }
+
+ // check the size of the sub image
+ unsigned width = FreeImage_GetWidth(dib);
+ unsigned height = FreeImage_GetHeight(dib);
+ if (left < 0 || right > width || top < 0 || bottom > height) {
+ return NULL;
+ }
+
+ unsigned bpp = FreeImage_GetBPP(dib);
+ BYTE *bits = FreeImage_GetScanLine(dib, height - bottom);
+ switch (bpp) {
+ case 1:
+ if (left % 8 != 0) {
+ // view can only start at a byte boundary
+ return NULL;
+ }
+ bits += (left / 8);
+ break;
+ case 4:
+ if (left % 2 != 0) {
+ // view can only start at a byte boundary
+ return NULL;
+ }
+ bits += (left / 2);
+ break;
+ default:
+ bits += left * (bpp / 8);
+ break;
+ }
+
+ FIBITMAP *dst = FreeImage_AllocateHeaderForBits(bits, FreeImage_GetPitch(dib), FreeImage_GetImageType(dib),
+ right - left, bottom - top,
+ bpp,
+ FreeImage_GetRedMask(dib), FreeImage_GetGreenMask(dib), FreeImage_GetBlueMask(dib));
+
+ if (dst == NULL) {
+ return NULL;
+ }
+ // copy some basic image properties needed for displaying and saving
+
+ // resolution
+ FreeImage_SetDotsPerMeterX(dst, FreeImage_GetDotsPerMeterX(dib));
+ FreeImage_SetDotsPerMeterY(dst, FreeImage_GetDotsPerMeterY(dib));
+
+ // background color
+ RGBQUAD bkcolor;
+ if (FreeImage_GetBackgroundColor(dib, &bkcolor)) {
+ FreeImage_SetBackgroundColor(dst, &bkcolor);
+ }
+
+ // palette
+ memcpy(FreeImage_GetPalette(dst), FreeImage_GetPalette(dib), FreeImage_GetColorsUsed(dib) * sizeof(RGBQUAD));
+
+ // transparency table
+ FreeImage_SetTransparencyTable(dst, FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib));
+
+ // ICC profile
+ FIICCPROFILE *src_profile = FreeImage_GetICCProfile(dib);
+ FIICCPROFILE *dst_profile = FreeImage_CreateICCProfile(dst, src_profile->data, src_profile->size);
+ dst_profile->flags = src_profile->flags;
+
+ return dst;
+}
diff --git a/plugins/AdvaImg/src/FreeImageToolkit/JPEGTransform.cpp b/plugins/AdvaImg/src/FreeImageToolkit/JPEGTransform.cpp
index 132fef7e85..6f9ba8e1f2 100644
--- a/plugins/AdvaImg/src/FreeImageToolkit/JPEGTransform.cpp
+++ b/plugins/AdvaImg/src/FreeImageToolkit/JPEGTransform.cpp
@@ -1,623 +1,623 @@
-// ==========================================================
-// JPEG lossless transformations
-//
-// Design and implementation by
-// - Petr Pytelka (pyta@lightcomp.com)
-// - Hervé Drolon (drolon@infonie.fr)
+// ==========================================================
+// JPEG lossless transformations
+//
+// Design and implementation by
+// - Petr Pytelka (pyta@lightcomp.com)
+// - 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!
-// ==========================================================
-
-extern "C" {
-#define XMD_H
-#undef FAR
-#include <setjmp.h>
-
-#include "../LibJPEG/jinclude.h"
-#include "../LibJPEG/jpeglib.h"
-#include "../LibJPEG/jerror.h"
-#include "../LibJPEG/transupp.h"
-}
-
-#include "FreeImage.h"
-#include "Utilities.h"
-#include "FreeImageIO.h"
-
+//
+// 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!
+// ==========================================================
+
+extern "C" {
+#define XMD_H
+#undef FAR
+#include <setjmp.h>
+
+#include "../LibJPEG/jinclude.h"
+#include "../LibJPEG/jpeglib.h"
+#include "../LibJPEG/jerror.h"
+#include "../LibJPEG/transupp.h"
+}
+
+#include "FreeImage.h"
+#include "Utilities.h"
+#include "FreeImageIO.h"
+
// ----------------------------------------------------------
// Source manager & Destination manager setup
// (see PluginJPEG.cpp)
// ----------------------------------------------------------
-
+
void jpeg_freeimage_src(j_decompress_ptr cinfo, fi_handle infile, FreeImageIO *io);
void jpeg_freeimage_dst(j_compress_ptr cinfo, fi_handle outfile, FreeImageIO *io);
-
-// ----------------------------------------------------------
-// Error handling
+
+// ----------------------------------------------------------
+// Error handling
// (see also PluginJPEG.cpp)
-// ----------------------------------------------------------
-
-/**
- Receives control for a fatal error. Information sufficient to
- generate the error message has been stored in cinfo->err; call
- output_message to display it. Control must NOT return to the caller;
- generally this routine will exit() or longjmp() somewhere.
-*/
-METHODDEF(void)
-ls_jpeg_error_exit (j_common_ptr cinfo) {
- // always display the message
- (*cinfo->err->output_message)(cinfo);
-
- // allow JPEG with a premature end of file
- if((cinfo)->err->msg_parm.i[0] != 13) {
-
- // let the memory manager delete any temp files before we die
- jpeg_destroy(cinfo);
-
- throw FIF_JPEG;
- }
-}
-
-/**
- Actual output of any JPEG message. Note that this method does not know
- how to generate a message, only where to send it.
-*/
-METHODDEF(void)
-ls_jpeg_output_message (j_common_ptr cinfo) {
- char buffer[JMSG_LENGTH_MAX];
-
- // create the message
- (*cinfo->err->format_message)(cinfo, buffer);
- // send it to user's message proc
- FreeImage_OutputMessageProc(FIF_JPEG, buffer);
-}
-
-// ----------------------------------------------------------
-// Main program
-// ----------------------------------------------------------
-
-/**
-Build a crop string.
-
-@param crop Output crop string
-@param left Specifies the left position of the cropped rectangle
-@param top Specifies the top position of the cropped rectangle
-@param right Specifies the right position of the cropped rectangle
-@param bottom Specifies the bottom position of the cropped rectangle
-@param width Image width
-@param height Image height
-@return Returns TRUE if successful, returns FALSE otherwise
-*/
-static BOOL
-getCropString(char* crop, int* left, int* top, int* right, int* bottom, int width, int height) {
- if(!left || !top || !right || !bottom) {
- return FALSE;
- }
-
- *left = CLAMP(*left, 0, width);
- *top = CLAMP(*top, 0, height);
-
- // negative/zero right and bottom count from the edges inwards
-
- if(*right <= 0) {
- *right = width + *right;
- }
- if(*bottom <= 0) {
- *bottom = height + *bottom;
- }
-
- *right = CLAMP(*right, 0, width);
- *bottom = CLAMP(*bottom, 0, height);
-
- // test for empty rect
-
- if(((*left - *right) == 0) || ((*top - *bottom) == 0)) {
- return FALSE;
- }
-
- // normalize the rectangle
-
- if(*right < *left) {
- INPLACESWAP(*left, *right);
- }
- if(*bottom < *top) {
- INPLACESWAP(*top, *bottom);
- }
-
- // test for "noop" rect
-
- if(*left == 0 && *right == width && *top == 0 && *bottom == height) {
- return FALSE;
- }
-
- // build the crop option
- sprintf(crop, "%dx%d+%d+%d", *right - *left, *bottom - *top, *left, *top);
-
- return TRUE;
-}
-
-static BOOL
-JPEGTransformFromHandle(FreeImageIO* src_io, fi_handle src_handle, FreeImageIO* dst_io, fi_handle dst_handle, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect) {
- const BOOL onlyReturnCropRect = (dst_io == NULL) || (dst_handle == NULL);
- const long stream_start = onlyReturnCropRect ? 0 : dst_io->tell_proc(dst_handle);
- BOOL swappedDim = FALSE;
- BOOL trimH = FALSE;
- BOOL trimV = FALSE;
-
- // Set up the jpeglib structures
- jpeg_decompress_struct srcinfo;
- jpeg_compress_struct dstinfo;
- jpeg_error_mgr jsrcerr, jdsterr;
- jvirt_barray_ptr *src_coef_arrays = NULL;
- jvirt_barray_ptr *dst_coef_arrays = NULL;
- // Support for copying optional markers from source to destination file
- JCOPY_OPTION copyoption;
- // Image transformation options
- jpeg_transform_info transfoptions;
-
- // Initialize structures
- memset(&srcinfo, 0, sizeof(srcinfo));
- memset(&jsrcerr, 0, sizeof(jsrcerr));
- memset(&jdsterr, 0, sizeof(jdsterr));
- memset(&dstinfo, 0, sizeof(dstinfo));
- memset(&transfoptions, 0, sizeof(transfoptions));
-
- // Copy all extra markers from source file
- copyoption = JCOPYOPT_ALL;
-
- // Set up default JPEG parameters
- transfoptions.force_grayscale = FALSE;
- transfoptions.crop = FALSE;
-
- // Select the transform option
- switch(operation) {
- case FIJPEG_OP_FLIP_H: // horizontal flip
- transfoptions.transform = JXFORM_FLIP_H;
- trimH = TRUE;
- break;
- case FIJPEG_OP_FLIP_V: // vertical flip
- transfoptions.transform = JXFORM_FLIP_V;
- trimV = TRUE;
- break;
- case FIJPEG_OP_TRANSPOSE: // transpose across UL-to-LR axis
- transfoptions.transform = JXFORM_TRANSPOSE;
- swappedDim = TRUE;
- break;
- case FIJPEG_OP_TRANSVERSE: // transpose across UR-to-LL axis
- transfoptions.transform = JXFORM_TRANSVERSE;
- trimH = TRUE;
- trimV = TRUE;
- swappedDim = TRUE;
- break;
- case FIJPEG_OP_ROTATE_90: // 90-degree clockwise rotation
- transfoptions.transform = JXFORM_ROT_90;
- trimH = TRUE;
- swappedDim = TRUE;
- break;
- case FIJPEG_OP_ROTATE_180: // 180-degree rotation
- trimH = TRUE;
- trimV = TRUE;
- transfoptions.transform = JXFORM_ROT_180;
- break;
- case FIJPEG_OP_ROTATE_270: // 270-degree clockwise (or 90 ccw)
- transfoptions.transform = JXFORM_ROT_270;
- trimV = TRUE;
- swappedDim = TRUE;
- break;
- default:
- case FIJPEG_OP_NONE: // no transformation
- transfoptions.transform = JXFORM_NONE;
- break;
- }
- // (perfect == TRUE) ==> fail if there is non-transformable edge blocks
- transfoptions.perfect = (perfect == TRUE) ? TRUE : FALSE;
- // Drop non-transformable edge blocks: trim off any partial edge MCUs that the transform can't handle.
- transfoptions.trim = TRUE;
-
- try {
-
- // Initialize the JPEG decompression object with default error handling
- srcinfo.err = jpeg_std_error(&jsrcerr);
- srcinfo.err->error_exit = ls_jpeg_error_exit;
- srcinfo.err->output_message = ls_jpeg_output_message;
- jpeg_create_decompress(&srcinfo);
-
- // Initialize the JPEG compression object with default error handling
- dstinfo.err = jpeg_std_error(&jdsterr);
- dstinfo.err->error_exit = ls_jpeg_error_exit;
- dstinfo.err->output_message = ls_jpeg_output_message;
- jpeg_create_compress(&dstinfo);
-
- // Specify data source for decompression
- jpeg_freeimage_src(&srcinfo, src_handle, src_io);
-
- // Enable saving of extra markers that we want to copy
- jcopy_markers_setup(&srcinfo, copyoption);
-
- // Read the file header
- jpeg_read_header(&srcinfo, TRUE);
-
- // crop option
- char crop[64];
- const BOOL hasCrop = getCropString(crop, left, top, right, bottom, swappedDim ? srcinfo.image_height : srcinfo.image_width, swappedDim ? srcinfo.image_width : srcinfo.image_height);
-
- if(hasCrop) {
- if(!jtransform_parse_crop_spec(&transfoptions, crop)) {
- FreeImage_OutputMessageProc(FIF_JPEG, "Bogus crop argument %s", crop);
- throw(1);
- }
- }
-
- // Any space needed by a transform option must be requested before
- // jpeg_read_coefficients so that memory allocation will be done right
-
- // Prepare transformation workspace
- // Fails right away if perfect flag is TRUE and transformation is not perfect
- if( !jtransform_request_workspace(&srcinfo, &transfoptions) ) {
- FreeImage_OutputMessageProc(FIF_JPEG, "Transformation is not perfect");
- throw(1);
- }
-
- if(left || top) {
- // compute left and top offsets, it's a bit tricky, taking into account both
- // transform, which might have trimed the image,
- // and crop itself, which is adjusted to lie on a iMCU boundary
-
- const int fullWidth = swappedDim ? srcinfo.image_height : srcinfo.image_width;
- const int fullHeight = swappedDim ? srcinfo.image_width : srcinfo.image_height;
-
- int transformedFullWidth = fullWidth;
- int transformedFullHeight = fullHeight;
-
- if(trimH && transformedFullWidth/transfoptions.iMCU_sample_width > 0) {
- transformedFullWidth = (transformedFullWidth/transfoptions.iMCU_sample_width) * transfoptions.iMCU_sample_width;
- }
- if(trimV && transformedFullHeight/transfoptions.iMCU_sample_height > 0) {
- transformedFullHeight = (transformedFullHeight/transfoptions.iMCU_sample_height) * transfoptions.iMCU_sample_height;
- }
-
- const int trimmedWidth = fullWidth - transformedFullWidth;
- const int trimmedHeight = fullHeight - transformedFullHeight;
-
- if(left) {
- *left = trimmedWidth + transfoptions.x_crop_offset * transfoptions.iMCU_sample_width;
- }
- if(top) {
- *top = trimmedHeight + transfoptions.y_crop_offset * transfoptions.iMCU_sample_height;
- }
- }
-
- if(right) {
- *right = (left ? *left : 0) + transfoptions.output_width;
- }
- if(bottom) {
- *bottom = (top ? *top : 0) + transfoptions.output_height;
- }
-
- // if only the crop rect is requested, we are done
-
- if(onlyReturnCropRect) {
- jpeg_destroy_compress(&dstinfo);
- jpeg_destroy_decompress(&srcinfo);
- return TRUE;
- }
-
- // Read source file as DCT coefficients
- src_coef_arrays = jpeg_read_coefficients(&srcinfo);
-
- // Initialize destination compression parameters from source values
- jpeg_copy_critical_parameters(&srcinfo, &dstinfo);
-
- // Adjust destination parameters if required by transform options;
- // also find out which set of coefficient arrays will hold the output
- dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, src_coef_arrays, &transfoptions);
-
- // Note: we assume that jpeg_read_coefficients consumed all input
- // until JPEG_REACHED_EOI, and that jpeg_finish_decompress will
- // only consume more while (! cinfo->inputctl->eoi_reached).
- // We cannot call jpeg_finish_decompress here since we still need the
- // virtual arrays allocated from the source object for processing.
-
- if(src_handle == dst_handle) {
- dst_io->seek_proc(dst_handle, stream_start, SEEK_SET);
- }
-
- // Specify data destination for compression
- jpeg_freeimage_dst(&dstinfo, dst_handle, dst_io);
-
- // Start compressor (note no image data is actually written here)
- jpeg_write_coefficients(&dstinfo, dst_coef_arrays);
-
- // Copy to the output file any extra markers that we want to preserve
- jcopy_markers_execute(&srcinfo, &dstinfo, copyoption);
-
- // Execute image transformation, if any
- jtransform_execute_transformation(&srcinfo, &dstinfo, src_coef_arrays, &transfoptions);
-
- // Finish compression and release memory
- jpeg_finish_compress(&dstinfo);
- jpeg_destroy_compress(&dstinfo);
- jpeg_finish_decompress(&srcinfo);
- jpeg_destroy_decompress(&srcinfo);
-
- }
- catch(...) {
- jpeg_destroy_compress(&dstinfo);
- jpeg_destroy_decompress(&srcinfo);
- return FALSE;
- }
-
- return TRUE;
-}
-
-// ----------------------------------------------------------
-// FreeImage interface
-// ----------------------------------------------------------
-
-BOOL DLL_CALLCONV
-FreeImage_JPEGTransformFromHandle(FreeImageIO* src_io, fi_handle src_handle, FreeImageIO* dst_io, fi_handle dst_handle, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect) {
- return JPEGTransformFromHandle(src_io, src_handle, dst_io, dst_handle, operation, left, top, right, bottom, perfect);
-}
-
-static void
-closeStdIO(fi_handle src_handle, fi_handle dst_handle) {
- if(src_handle) {
- fclose((FILE*)src_handle);
- }
- if(dst_handle) {
- fclose((FILE*)dst_handle);
- }
-}
-
-static BOOL
-openStdIO(const char* src_file, const char* dst_file, FreeImageIO* dst_io, fi_handle* src_handle, fi_handle* dst_handle) {
- *src_handle = NULL;
- *dst_handle = NULL;
-
- FreeImageIO io;
- SetDefaultIO (&io);
-
- const BOOL isSameFile = (dst_file && (strcmp(src_file, dst_file) == 0)) ? TRUE : FALSE;
-
- FILE* srcp = NULL;
- FILE* dstp = NULL;
-
- if(isSameFile) {
- srcp = fopen(src_file, "r+b");
- dstp = srcp;
- }
- else {
- srcp = fopen(src_file, "rb");
- if(dst_file) {
- dstp = fopen(dst_file, "wb");
- }
- }
-
- if(!srcp || (dst_file && !dstp)) {
- if(!srcp) {
- FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open \"%s\" for reading", src_file);
- } else {
- FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open \"%s\" for writing", dst_file);
- }
- closeStdIO(srcp, dstp);
- return FALSE;
- }
-
- if(FreeImage_GetFileTypeFromHandle(&io, srcp) != FIF_JPEG) {
- FreeImage_OutputMessageProc(FIF_JPEG, " Source file \"%s\" is not jpeg", src_file);
- closeStdIO(srcp, dstp);
- return FALSE;
- }
-
- *dst_io = io;
- *src_handle = srcp;
- *dst_handle = dstp;
-
- return TRUE;
-}
-
-static BOOL
-openStdIOU(const wchar_t* src_file, const wchar_t* dst_file, FreeImageIO* dst_io, fi_handle* src_handle, fi_handle* dst_handle) {
-#ifdef _WIN32
-
- *src_handle = NULL;
- *dst_handle = NULL;
-
- FreeImageIO io;
- SetDefaultIO (&io);
-
- const BOOL isSameFile = (dst_file && (wcscmp(src_file, dst_file) == 0)) ? TRUE : FALSE;
-
- FILE* srcp = NULL;
- FILE* dstp = NULL;
-
- if(isSameFile) {
- srcp = _wfopen(src_file, L"r+b");
- dstp = srcp;
- } else {
- srcp = _wfopen(src_file, L"rb");
- if(dst_file) {
- dstp = _wfopen(dst_file, L"wb");
- }
- }
-
- if(!srcp || (dst_file && !dstp)) {
- if(!srcp) {
- FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open source file for reading");
- } else {
- FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open destination file for writing");
- }
- closeStdIO(srcp, dstp);
- return FALSE;
- }
-
- if(FreeImage_GetFileTypeFromHandle(&io, srcp) != FIF_JPEG) {
- FreeImage_OutputMessageProc(FIF_JPEG, " Source file is not jpeg");
- closeStdIO(srcp, dstp);
- return FALSE;
- }
-
- *dst_io = io;
- *src_handle = srcp;
- *dst_handle = dstp;
-
- return TRUE;
-
-#else
- return FALSE;
-#endif // _WIN32
-}
-
-BOOL DLL_CALLCONV
-FreeImage_JPEGTransform(const char *src_file, const char *dst_file, FREE_IMAGE_JPEG_OPERATION operation, BOOL perfect) {
- FreeImageIO io;
- fi_handle src;
- fi_handle dst;
-
- if(!openStdIO(src_file, dst_file, &io, &src, &dst)) {
- return FALSE;
- }
-
- BOOL ret = JPEGTransformFromHandle(&io, src, &io, dst, operation, NULL, NULL, NULL, NULL, perfect);
-
- closeStdIO(src, dst);
-
- return ret;
-}
-
-BOOL DLL_CALLCONV
-FreeImage_JPEGCrop(const char *src_file, const char *dst_file, int left, int top, int right, int bottom) {
- FreeImageIO io;
- fi_handle src;
- fi_handle dst;
-
- if(!openStdIO(src_file, dst_file, &io, &src, &dst)) {
- return FALSE;
- }
-
- BOOL ret = FreeImage_JPEGTransformFromHandle(&io, src, &io, dst, FIJPEG_OP_NONE, &left, &top, &right, &bottom, FALSE);
-
- closeStdIO(src, dst);
-
- return ret;
-}
-
-BOOL DLL_CALLCONV
-FreeImage_JPEGTransformU(const wchar_t *src_file, const wchar_t *dst_file, FREE_IMAGE_JPEG_OPERATION operation, BOOL perfect) {
- FreeImageIO io;
- fi_handle src;
- fi_handle dst;
-
- if(!openStdIOU(src_file, dst_file, &io, &src, &dst)) {
- return FALSE;
- }
-
- BOOL ret = JPEGTransformFromHandle(&io, src, &io, dst, operation, NULL, NULL, NULL, NULL, perfect);
-
- closeStdIO(src, dst);
-
- return ret;
-}
-
-BOOL DLL_CALLCONV
-FreeImage_JPEGCropU(const wchar_t *src_file, const wchar_t *dst_file, int left, int top, int right, int bottom) {
- FreeImageIO io;
- fi_handle src;
- fi_handle dst;
-
- if(!openStdIOU(src_file, dst_file, &io, &src, &dst)) {
- return FALSE;
- }
-
- BOOL ret = FreeImage_JPEGTransformFromHandle(&io, src, &io, dst, FIJPEG_OP_NONE, &left, &top, &right, &bottom, FALSE);
-
- closeStdIO(src, dst);
-
- return ret;
-}
-
-BOOL DLL_CALLCONV
-FreeImage_JPEGTransformCombined(const char *src_file, const char *dst_file, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect) {
- FreeImageIO io;
- fi_handle src;
- fi_handle dst;
-
- if(!openStdIO(src_file, dst_file, &io, &src, &dst)) {
- return FALSE;
- }
-
- BOOL ret = FreeImage_JPEGTransformFromHandle(&io, src, &io, dst, operation, left, top, right, bottom, perfect);
-
- closeStdIO(src, dst);
-
- return ret;
-}
-
-BOOL DLL_CALLCONV
-FreeImage_JPEGTransformCombinedU(const wchar_t *src_file, const wchar_t *dst_file, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect) {
- FreeImageIO io;
- fi_handle src;
- fi_handle dst;
-
- if(!openStdIOU(src_file, dst_file, &io, &src, &dst)) {
- return FALSE;
- }
-
- BOOL ret = FreeImage_JPEGTransformFromHandle(&io, src, &io, dst, operation, left, top, right, bottom, perfect);
-
- closeStdIO(src, dst);
-
- return ret;
-}
-
-// --------------------------------------------------------------------------
-
-static BOOL
-getMemIO(FIMEMORY* src_stream, FIMEMORY* dst_stream, FreeImageIO* dst_io, fi_handle* src_handle, fi_handle* dst_handle) {
- *src_handle = NULL;
- *dst_handle = NULL;
-
- FreeImageIO io;
- SetMemoryIO (&io);
-
- if(dst_stream) {
- FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(dst_stream->data);
- if(mem_header->delete_me != TRUE) {
- // do not save in a user buffer
- FreeImage_OutputMessageProc(FIF_JPEG, "Destination memory buffer is read only");
- return FALSE;
- }
- }
-
- *dst_io = io;
- *src_handle = src_stream;
- *dst_handle = dst_stream;
-
- return TRUE;
-}
-
-BOOL DLL_CALLCONV
-FreeImage_JPEGTransformCombinedFromMemory(FIMEMORY* src_stream, FIMEMORY* dst_stream, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect) {
- FreeImageIO io;
- fi_handle src;
- fi_handle dst;
-
- if(!getMemIO(src_stream, dst_stream, &io, &src, &dst)) {
- return FALSE;
- }
-
- return FreeImage_JPEGTransformFromHandle(&io, src, &io, dst, operation, left, top, right, bottom, perfect);
-}
-
+// ----------------------------------------------------------
+
+/**
+ Receives control for a fatal error. Information sufficient to
+ generate the error message has been stored in cinfo->err; call
+ output_message to display it. Control must NOT return to the caller;
+ generally this routine will exit() or longjmp() somewhere.
+*/
+METHODDEF(void)
+ls_jpeg_error_exit (j_common_ptr cinfo) {
+ // always display the message
+ (*cinfo->err->output_message)(cinfo);
+
+ // allow JPEG with a premature end of file
+ if((cinfo)->err->msg_parm.i[0] != 13) {
+
+ // let the memory manager delete any temp files before we die
+ jpeg_destroy(cinfo);
+
+ throw FIF_JPEG;
+ }
+}
+
+/**
+ Actual output of any JPEG message. Note that this method does not know
+ how to generate a message, only where to send it.
+*/
+METHODDEF(void)
+ls_jpeg_output_message (j_common_ptr cinfo) {
+ char buffer[JMSG_LENGTH_MAX];
+
+ // create the message
+ (*cinfo->err->format_message)(cinfo, buffer);
+ // send it to user's message proc
+ FreeImage_OutputMessageProc(FIF_JPEG, buffer);
+}
+
+// ----------------------------------------------------------
+// Main program
+// ----------------------------------------------------------
+
+/**
+Build a crop string.
+
+@param crop Output crop string
+@param left Specifies the left position of the cropped rectangle
+@param top Specifies the top position of the cropped rectangle
+@param right Specifies the right position of the cropped rectangle
+@param bottom Specifies the bottom position of the cropped rectangle
+@param width Image width
+@param height Image height
+@return Returns TRUE if successful, returns FALSE otherwise
+*/
+static BOOL
+getCropString(char* crop, int* left, int* top, int* right, int* bottom, int width, int height) {
+ if(!left || !top || !right || !bottom) {
+ return FALSE;
+ }
+
+ *left = CLAMP(*left, 0, width);
+ *top = CLAMP(*top, 0, height);
+
+ // negative/zero right and bottom count from the edges inwards
+
+ if(*right <= 0) {
+ *right = width + *right;
+ }
+ if(*bottom <= 0) {
+ *bottom = height + *bottom;
+ }
+
+ *right = CLAMP(*right, 0, width);
+ *bottom = CLAMP(*bottom, 0, height);
+
+ // test for empty rect
+
+ if(((*left - *right) == 0) || ((*top - *bottom) == 0)) {
+ return FALSE;
+ }
+
+ // normalize the rectangle
+
+ if(*right < *left) {
+ INPLACESWAP(*left, *right);
+ }
+ if(*bottom < *top) {
+ INPLACESWAP(*top, *bottom);
+ }
+
+ // test for "noop" rect
+
+ if(*left == 0 && *right == width && *top == 0 && *bottom == height) {
+ return FALSE;
+ }
+
+ // build the crop option
+ sprintf(crop, "%dx%d+%d+%d", *right - *left, *bottom - *top, *left, *top);
+
+ return TRUE;
+}
+
+static BOOL
+JPEGTransformFromHandle(FreeImageIO* src_io, fi_handle src_handle, FreeImageIO* dst_io, fi_handle dst_handle, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect) {
+ const BOOL onlyReturnCropRect = (dst_io == NULL) || (dst_handle == NULL);
+ const long stream_start = onlyReturnCropRect ? 0 : dst_io->tell_proc(dst_handle);
+ BOOL swappedDim = FALSE;
+ BOOL trimH = FALSE;
+ BOOL trimV = FALSE;
+
+ // Set up the jpeglib structures
+ jpeg_decompress_struct srcinfo;
+ jpeg_compress_struct dstinfo;
+ jpeg_error_mgr jsrcerr, jdsterr;
+ jvirt_barray_ptr *src_coef_arrays = NULL;
+ jvirt_barray_ptr *dst_coef_arrays = NULL;
+ // Support for copying optional markers from source to destination file
+ JCOPY_OPTION copyoption;
+ // Image transformation options
+ jpeg_transform_info transfoptions;
+
+ // Initialize structures
+ memset(&srcinfo, 0, sizeof(srcinfo));
+ memset(&jsrcerr, 0, sizeof(jsrcerr));
+ memset(&jdsterr, 0, sizeof(jdsterr));
+ memset(&dstinfo, 0, sizeof(dstinfo));
+ memset(&transfoptions, 0, sizeof(transfoptions));
+
+ // Copy all extra markers from source file
+ copyoption = JCOPYOPT_ALL;
+
+ // Set up default JPEG parameters
+ transfoptions.force_grayscale = FALSE;
+ transfoptions.crop = FALSE;
+
+ // Select the transform option
+ switch(operation) {
+ case FIJPEG_OP_FLIP_H: // horizontal flip
+ transfoptions.transform = JXFORM_FLIP_H;
+ trimH = TRUE;
+ break;
+ case FIJPEG_OP_FLIP_V: // vertical flip
+ transfoptions.transform = JXFORM_FLIP_V;
+ trimV = TRUE;
+ break;
+ case FIJPEG_OP_TRANSPOSE: // transpose across UL-to-LR axis
+ transfoptions.transform = JXFORM_TRANSPOSE;
+ swappedDim = TRUE;
+ break;
+ case FIJPEG_OP_TRANSVERSE: // transpose across UR-to-LL axis
+ transfoptions.transform = JXFORM_TRANSVERSE;
+ trimH = TRUE;
+ trimV = TRUE;
+ swappedDim = TRUE;
+ break;
+ case FIJPEG_OP_ROTATE_90: // 90-degree clockwise rotation
+ transfoptions.transform = JXFORM_ROT_90;
+ trimH = TRUE;
+ swappedDim = TRUE;
+ break;
+ case FIJPEG_OP_ROTATE_180: // 180-degree rotation
+ trimH = TRUE;
+ trimV = TRUE;
+ transfoptions.transform = JXFORM_ROT_180;
+ break;
+ case FIJPEG_OP_ROTATE_270: // 270-degree clockwise (or 90 ccw)
+ transfoptions.transform = JXFORM_ROT_270;
+ trimV = TRUE;
+ swappedDim = TRUE;
+ break;
+ default:
+ case FIJPEG_OP_NONE: // no transformation
+ transfoptions.transform = JXFORM_NONE;
+ break;
+ }
+ // (perfect == TRUE) ==> fail if there is non-transformable edge blocks
+ transfoptions.perfect = (perfect == TRUE) ? TRUE : FALSE;
+ // Drop non-transformable edge blocks: trim off any partial edge MCUs that the transform can't handle.
+ transfoptions.trim = TRUE;
+
+ try {
+
+ // Initialize the JPEG decompression object with default error handling
+ srcinfo.err = jpeg_std_error(&jsrcerr);
+ srcinfo.err->error_exit = ls_jpeg_error_exit;
+ srcinfo.err->output_message = ls_jpeg_output_message;
+ jpeg_create_decompress(&srcinfo);
+
+ // Initialize the JPEG compression object with default error handling
+ dstinfo.err = jpeg_std_error(&jdsterr);
+ dstinfo.err->error_exit = ls_jpeg_error_exit;
+ dstinfo.err->output_message = ls_jpeg_output_message;
+ jpeg_create_compress(&dstinfo);
+
+ // Specify data source for decompression
+ jpeg_freeimage_src(&srcinfo, src_handle, src_io);
+
+ // Enable saving of extra markers that we want to copy
+ jcopy_markers_setup(&srcinfo, copyoption);
+
+ // Read the file header
+ jpeg_read_header(&srcinfo, TRUE);
+
+ // crop option
+ char crop[64];
+ const BOOL hasCrop = getCropString(crop, left, top, right, bottom, swappedDim ? srcinfo.image_height : srcinfo.image_width, swappedDim ? srcinfo.image_width : srcinfo.image_height);
+
+ if(hasCrop) {
+ if(!jtransform_parse_crop_spec(&transfoptions, crop)) {
+ FreeImage_OutputMessageProc(FIF_JPEG, "Bogus crop argument %s", crop);
+ throw(1);
+ }
+ }
+
+ // Any space needed by a transform option must be requested before
+ // jpeg_read_coefficients so that memory allocation will be done right
+
+ // Prepare transformation workspace
+ // Fails right away if perfect flag is TRUE and transformation is not perfect
+ if( !jtransform_request_workspace(&srcinfo, &transfoptions) ) {
+ FreeImage_OutputMessageProc(FIF_JPEG, "Transformation is not perfect");
+ throw(1);
+ }
+
+ if(left || top) {
+ // compute left and top offsets, it's a bit tricky, taking into account both
+ // transform, which might have trimed the image,
+ // and crop itself, which is adjusted to lie on a iMCU boundary
+
+ const int fullWidth = swappedDim ? srcinfo.image_height : srcinfo.image_width;
+ const int fullHeight = swappedDim ? srcinfo.image_width : srcinfo.image_height;
+
+ int transformedFullWidth = fullWidth;
+ int transformedFullHeight = fullHeight;
+
+ if(trimH && transformedFullWidth/transfoptions.iMCU_sample_width > 0) {
+ transformedFullWidth = (transformedFullWidth/transfoptions.iMCU_sample_width) * transfoptions.iMCU_sample_width;
+ }
+ if(trimV && transformedFullHeight/transfoptions.iMCU_sample_height > 0) {
+ transformedFullHeight = (transformedFullHeight/transfoptions.iMCU_sample_height) * transfoptions.iMCU_sample_height;
+ }
+
+ const int trimmedWidth = fullWidth - transformedFullWidth;
+ const int trimmedHeight = fullHeight - transformedFullHeight;
+
+ if(left) {
+ *left = trimmedWidth + transfoptions.x_crop_offset * transfoptions.iMCU_sample_width;
+ }
+ if(top) {
+ *top = trimmedHeight + transfoptions.y_crop_offset * transfoptions.iMCU_sample_height;
+ }
+ }
+
+ if(right) {
+ *right = (left ? *left : 0) + transfoptions.output_width;
+ }
+ if(bottom) {
+ *bottom = (top ? *top : 0) + transfoptions.output_height;
+ }
+
+ // if only the crop rect is requested, we are done
+
+ if(onlyReturnCropRect) {
+ jpeg_destroy_compress(&dstinfo);
+ jpeg_destroy_decompress(&srcinfo);
+ return TRUE;
+ }
+
+ // Read source file as DCT coefficients
+ src_coef_arrays = jpeg_read_coefficients(&srcinfo);
+
+ // Initialize destination compression parameters from source values
+ jpeg_copy_critical_parameters(&srcinfo, &dstinfo);
+
+ // Adjust destination parameters if required by transform options;
+ // also find out which set of coefficient arrays will hold the output
+ dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, src_coef_arrays, &transfoptions);
+
+ // Note: we assume that jpeg_read_coefficients consumed all input
+ // until JPEG_REACHED_EOI, and that jpeg_finish_decompress will
+ // only consume more while (! cinfo->inputctl->eoi_reached).
+ // We cannot call jpeg_finish_decompress here since we still need the
+ // virtual arrays allocated from the source object for processing.
+
+ if(src_handle == dst_handle) {
+ dst_io->seek_proc(dst_handle, stream_start, SEEK_SET);
+ }
+
+ // Specify data destination for compression
+ jpeg_freeimage_dst(&dstinfo, dst_handle, dst_io);
+
+ // Start compressor (note no image data is actually written here)
+ jpeg_write_coefficients(&dstinfo, dst_coef_arrays);
+
+ // Copy to the output file any extra markers that we want to preserve
+ jcopy_markers_execute(&srcinfo, &dstinfo, copyoption);
+
+ // Execute image transformation, if any
+ jtransform_execute_transformation(&srcinfo, &dstinfo, src_coef_arrays, &transfoptions);
+
+ // Finish compression and release memory
+ jpeg_finish_compress(&dstinfo);
+ jpeg_destroy_compress(&dstinfo);
+ jpeg_finish_decompress(&srcinfo);
+ jpeg_destroy_decompress(&srcinfo);
+
+ }
+ catch(...) {
+ jpeg_destroy_compress(&dstinfo);
+ jpeg_destroy_decompress(&srcinfo);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// ----------------------------------------------------------
+// FreeImage interface
+// ----------------------------------------------------------
+
+BOOL DLL_CALLCONV
+FreeImage_JPEGTransformFromHandle(FreeImageIO* src_io, fi_handle src_handle, FreeImageIO* dst_io, fi_handle dst_handle, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect) {
+ return JPEGTransformFromHandle(src_io, src_handle, dst_io, dst_handle, operation, left, top, right, bottom, perfect);
+}
+
+static void
+closeStdIO(fi_handle src_handle, fi_handle dst_handle) {
+ if(src_handle) {
+ fclose((FILE*)src_handle);
+ }
+ if(dst_handle && (dst_handle != src_handle)) {
+ fclose((FILE*)dst_handle);
+ }
+}
+
+static BOOL
+openStdIO(const char* src_file, const char* dst_file, FreeImageIO* dst_io, fi_handle* src_handle, fi_handle* dst_handle) {
+ *src_handle = NULL;
+ *dst_handle = NULL;
+
+ FreeImageIO io;
+ SetDefaultIO (&io);
+
+ const BOOL isSameFile = (dst_file && (strcmp(src_file, dst_file) == 0)) ? TRUE : FALSE;
+
+ FILE* srcp = NULL;
+ FILE* dstp = NULL;
+
+ if(isSameFile) {
+ srcp = fopen(src_file, "r+b");
+ dstp = srcp;
+ }
+ else {
+ srcp = fopen(src_file, "rb");
+ if(dst_file) {
+ dstp = fopen(dst_file, "wb");
+ }
+ }
+
+ if(!srcp || (dst_file && !dstp)) {
+ if(!srcp) {
+ FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open \"%s\" for reading", src_file);
+ } else {
+ FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open \"%s\" for writing", dst_file);
+ }
+ closeStdIO(srcp, dstp);
+ return FALSE;
+ }
+
+ if(FreeImage_GetFileTypeFromHandle(&io, srcp) != FIF_JPEG) {
+ FreeImage_OutputMessageProc(FIF_JPEG, " Source file \"%s\" is not jpeg", src_file);
+ closeStdIO(srcp, dstp);
+ return FALSE;
+ }
+
+ *dst_io = io;
+ *src_handle = srcp;
+ *dst_handle = dstp;
+
+ return TRUE;
+}
+
+static BOOL
+openStdIOU(const wchar_t* src_file, const wchar_t* dst_file, FreeImageIO* dst_io, fi_handle* src_handle, fi_handle* dst_handle) {
+#ifdef _WIN32
+
+ *src_handle = NULL;
+ *dst_handle = NULL;
+
+ FreeImageIO io;
+ SetDefaultIO (&io);
+
+ const BOOL isSameFile = (dst_file && (wcscmp(src_file, dst_file) == 0)) ? TRUE : FALSE;
+
+ FILE* srcp = NULL;
+ FILE* dstp = NULL;
+
+ if(isSameFile) {
+ srcp = _wfopen(src_file, L"r+b");
+ dstp = srcp;
+ } else {
+ srcp = _wfopen(src_file, L"rb");
+ if(dst_file) {
+ dstp = _wfopen(dst_file, L"wb");
+ }
+ }
+
+ if(!srcp || (dst_file && !dstp)) {
+ if(!srcp) {
+ FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open source file for reading");
+ } else {
+ FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open destination file for writing");
+ }
+ closeStdIO(srcp, dstp);
+ return FALSE;
+ }
+
+ if(FreeImage_GetFileTypeFromHandle(&io, srcp) != FIF_JPEG) {
+ FreeImage_OutputMessageProc(FIF_JPEG, " Source file is not jpeg");
+ closeStdIO(srcp, dstp);
+ return FALSE;
+ }
+
+ *dst_io = io;
+ *src_handle = srcp;
+ *dst_handle = dstp;
+
+ return TRUE;
+
+#else
+ return FALSE;
+#endif // _WIN32
+}
+
+BOOL DLL_CALLCONV
+FreeImage_JPEGTransform(const char *src_file, const char *dst_file, FREE_IMAGE_JPEG_OPERATION operation, BOOL perfect) {
+ FreeImageIO io;
+ fi_handle src;
+ fi_handle dst;
+
+ if(!openStdIO(src_file, dst_file, &io, &src, &dst)) {
+ return FALSE;
+ }
+
+ BOOL ret = JPEGTransformFromHandle(&io, src, &io, dst, operation, NULL, NULL, NULL, NULL, perfect);
+
+ closeStdIO(src, dst);
+
+ return ret;
+}
+
+BOOL DLL_CALLCONV
+FreeImage_JPEGCrop(const char *src_file, const char *dst_file, int left, int top, int right, int bottom) {
+ FreeImageIO io;
+ fi_handle src;
+ fi_handle dst;
+
+ if(!openStdIO(src_file, dst_file, &io, &src, &dst)) {
+ return FALSE;
+ }
+
+ BOOL ret = FreeImage_JPEGTransformFromHandle(&io, src, &io, dst, FIJPEG_OP_NONE, &left, &top, &right, &bottom, FALSE);
+
+ closeStdIO(src, dst);
+
+ return ret;
+}
+
+BOOL DLL_CALLCONV
+FreeImage_JPEGTransformU(const wchar_t *src_file, const wchar_t *dst_file, FREE_IMAGE_JPEG_OPERATION operation, BOOL perfect) {
+ FreeImageIO io;
+ fi_handle src;
+ fi_handle dst;
+
+ if(!openStdIOU(src_file, dst_file, &io, &src, &dst)) {
+ return FALSE;
+ }
+
+ BOOL ret = JPEGTransformFromHandle(&io, src, &io, dst, operation, NULL, NULL, NULL, NULL, perfect);
+
+ closeStdIO(src, dst);
+
+ return ret;
+}
+
+BOOL DLL_CALLCONV
+FreeImage_JPEGCropU(const wchar_t *src_file, const wchar_t *dst_file, int left, int top, int right, int bottom) {
+ FreeImageIO io;
+ fi_handle src;
+ fi_handle dst;
+
+ if(!openStdIOU(src_file, dst_file, &io, &src, &dst)) {
+ return FALSE;
+ }
+
+ BOOL ret = FreeImage_JPEGTransformFromHandle(&io, src, &io, dst, FIJPEG_OP_NONE, &left, &top, &right, &bottom, FALSE);
+
+ closeStdIO(src, dst);
+
+ return ret;
+}
+
+BOOL DLL_CALLCONV
+FreeImage_JPEGTransformCombined(const char *src_file, const char *dst_file, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect) {
+ FreeImageIO io;
+ fi_handle src;
+ fi_handle dst;
+
+ if(!openStdIO(src_file, dst_file, &io, &src, &dst)) {
+ return FALSE;
+ }
+
+ BOOL ret = FreeImage_JPEGTransformFromHandle(&io, src, &io, dst, operation, left, top, right, bottom, perfect);
+
+ closeStdIO(src, dst);
+
+ return ret;
+}
+
+BOOL DLL_CALLCONV
+FreeImage_JPEGTransformCombinedU(const wchar_t *src_file, const wchar_t *dst_file, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect) {
+ FreeImageIO io;
+ fi_handle src;
+ fi_handle dst;
+
+ if(!openStdIOU(src_file, dst_file, &io, &src, &dst)) {
+ return FALSE;
+ }
+
+ BOOL ret = FreeImage_JPEGTransformFromHandle(&io, src, &io, dst, operation, left, top, right, bottom, perfect);
+
+ closeStdIO(src, dst);
+
+ return ret;
+}
+
+// --------------------------------------------------------------------------
+
+static BOOL
+getMemIO(FIMEMORY* src_stream, FIMEMORY* dst_stream, FreeImageIO* dst_io, fi_handle* src_handle, fi_handle* dst_handle) {
+ *src_handle = NULL;
+ *dst_handle = NULL;
+
+ FreeImageIO io;
+ SetMemoryIO (&io);
+
+ if(dst_stream) {
+ FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(dst_stream->data);
+ if(mem_header->delete_me != TRUE) {
+ // do not save in a user buffer
+ FreeImage_OutputMessageProc(FIF_JPEG, "Destination memory buffer is read only");
+ return FALSE;
+ }
+ }
+
+ *dst_io = io;
+ *src_handle = src_stream;
+ *dst_handle = dst_stream;
+
+ return TRUE;
+}
+
+BOOL DLL_CALLCONV
+FreeImage_JPEGTransformCombinedFromMemory(FIMEMORY* src_stream, FIMEMORY* dst_stream, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect) {
+ FreeImageIO io;
+ fi_handle src;
+ fi_handle dst;
+
+ if(!getMemIO(src_stream, dst_stream, &io, &src, &dst)) {
+ return FALSE;
+ }
+
+ return FreeImage_JPEGTransformFromHandle(&io, src, &io, dst, operation, left, top, right, bottom, perfect);
+}
+
diff --git a/plugins/AdvaImg/src/FreeImageToolkit/Rescale.cpp b/plugins/AdvaImg/src/FreeImageToolkit/Rescale.cpp
index 0c8bbc2787..4f885c29a5 100644
--- a/plugins/AdvaImg/src/FreeImageToolkit/Rescale.cpp
+++ b/plugins/AdvaImg/src/FreeImageToolkit/Rescale.cpp
@@ -22,11 +22,27 @@
#include "Resize.h"
-FIBITMAP * DLL_CALLCONV
-FreeImage_Rescale(FIBITMAP *src, int dst_width, int dst_height, FREE_IMAGE_FILTER filter) {
+FIBITMAP * DLL_CALLCONV
+FreeImage_RescaleRect(FIBITMAP *src, int dst_width, int dst_height, int src_left, int src_top, int src_right, int src_bottom, FREE_IMAGE_FILTER filter, unsigned flags) {
FIBITMAP *dst = NULL;
- if (!FreeImage_HasPixels(src) || (dst_width <= 0) || (dst_height <= 0) || (FreeImage_GetWidth(src) <= 0) || (FreeImage_GetHeight(src) <= 0)) {
+ const int src_width = FreeImage_GetWidth(src);
+ const int src_height = FreeImage_GetHeight(src);
+
+ if (!FreeImage_HasPixels(src) || (dst_width <= 0) || (dst_height <= 0) || (src_width <= 0) || (src_height <= 0)) {
+ return NULL;
+ }
+
+ // normalize the rectangle
+ if (src_right < src_left) {
+ INPLACESWAP(src_left, src_right);
+ }
+ if (src_bottom < src_top) {
+ INPLACESWAP(src_top, src_bottom);
+ }
+
+ // check the size of the sub image
+ if((src_left < 0) || (src_right > src_width) || (src_top < 0) || (src_bottom > src_height)) {
return NULL;
}
@@ -59,18 +75,25 @@ FreeImage_Rescale(FIBITMAP *src, int dst_width, int dst_height, FREE_IMAGE_FILTE
CResizeEngine Engine(pFilter);
- dst = Engine.scale(src, dst_width, dst_height, 0, 0,
- FreeImage_GetWidth(src), FreeImage_GetHeight(src));
+ dst = Engine.scale(src, dst_width, dst_height, src_left, src_top,
+ src_right - src_left, src_bottom - src_top, flags);
delete pFilter;
- // copy metadata from src to dst
- FreeImage_CloneMetadata(dst, src);
-
+ if ((flags & FI_RESCALE_OMIT_METADATA) != FI_RESCALE_OMIT_METADATA) {
+ // copy metadata from src to dst
+ FreeImage_CloneMetadata(dst, src);
+ }
+
return dst;
}
FIBITMAP * DLL_CALLCONV
+FreeImage_Rescale(FIBITMAP *src, int dst_width, int dst_height, FREE_IMAGE_FILTER filter) {
+ return FreeImage_RescaleRect(src, dst_width, dst_height, 0, 0, FreeImage_GetWidth(src), FreeImage_GetHeight(src), filter, FI_RESCALE_DEFAULT);
+}
+
+FIBITMAP * DLL_CALLCONV
FreeImage_MakeThumbnail(FIBITMAP *dib, int max_pixel_size, BOOL convert) {
FIBITMAP *thumbnail = NULL;
int new_width, new_height;
@@ -164,6 +187,6 @@ FreeImage_MakeThumbnail(FIBITMAP *dib, int max_pixel_size, BOOL convert) {
// copy metadata from src to dst
FreeImage_CloneMetadata(thumbnail, dib);
-
+
return thumbnail;
}
diff --git a/plugins/AdvaImg/src/FreeImageToolkit/Resize.cpp b/plugins/AdvaImg/src/FreeImageToolkit/Resize.cpp
index 283a91e830..dbc738ffd9 100644
--- a/plugins/AdvaImg/src/FreeImageToolkit/Resize.cpp
+++ b/plugins/AdvaImg/src/FreeImageToolkit/Resize.cpp
@@ -1,1998 +1,2116 @@
-// ==========================================================
-// Upsampling / downsampling classes
-//
-// Design and implementation by
-// - Hervé Drolon (drolon@infonie.fr)
-// - Detlev Vendt (detlev.vendt@brillit.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 "Resize.h"
-
-/**
-Returns the color type of a bitmap. In contrast to FreeImage_GetColorType,
-this function optionally supports a boolean OUT parameter, that receives TRUE,
-if the specified bitmap is greyscale, that is, it consists of grey colors only.
-Although it returns the same value as returned by FreeImage_GetColorType for all
-image types, this extended function primarily is intended for palletized images,
-since the boolean pointed to by 'bIsGreyscale' remains unchanged for RGB(A/F)
-images. However, the outgoing boolean is properly maintained for palletized images,
-as well as for any non-RGB image type, like FIT_UINTxx and FIT_DOUBLE, for example.
-@param dib A pointer to a FreeImage bitmap to calculate the extended color type for
-@param bIsGreyscale A pointer to a boolean, that receives TRUE, if the specified bitmap
-is greyscale, that is, it consists of grey colors only. This parameter can be NULL.
-@return the color type of the specified bitmap
-*/
-static FREE_IMAGE_COLOR_TYPE
-GetExtendedColorType(FIBITMAP *dib, BOOL *bIsGreyscale) {
- const unsigned bpp = FreeImage_GetBPP(dib);
- const unsigned size = CalculateUsedPaletteEntries(bpp);
- const RGBQUAD * const pal = FreeImage_GetPalette(dib);
- FREE_IMAGE_COLOR_TYPE color_type = FIC_MINISBLACK;
- BOOL bIsGrey = TRUE;
-
- switch (bpp) {
- case 1:
- {
- for (unsigned i = 0; i < size; i++) {
- if ((pal[i].rgbRed != pal[i].rgbGreen) || (pal[i].rgbRed != pal[i].rgbBlue)) {
- color_type = FIC_PALETTE;
- bIsGrey = FALSE;
- break;
- }
- }
- if (bIsGrey) {
- if (pal[0].rgbBlue == 255 && pal[1].rgbBlue == 0) {
- color_type = FIC_MINISWHITE;
- } else if (pal[0].rgbBlue != 0 || pal[1].rgbBlue != 255) {
- color_type = FIC_PALETTE;
- }
- }
- break;
- }
-
- case 4:
- case 8:
- {
- for (unsigned i = 0; i < size; i++) {
- if ((pal[i].rgbRed != pal[i].rgbGreen) || (pal[i].rgbRed != pal[i].rgbBlue)) {
- color_type = FIC_PALETTE;
- bIsGrey = FALSE;
- break;
- }
- if (color_type != FIC_PALETTE && pal[i].rgbBlue != i) {
- if ((size - i - 1) != pal[i].rgbBlue) {
- color_type = FIC_PALETTE;
- if (!bIsGreyscale) {
- // exit loop if we're not setting
- // bIsGreyscale parameter
- break;
- }
- } else {
- color_type = FIC_MINISWHITE;
- }
- }
- }
- break;
- }
-
- default:
- {
- color_type = FreeImage_GetColorType(dib);
- bIsGrey = (color_type == FIC_MINISBLACK) ? TRUE : FALSE;
- break;
- }
-
- }
- if (bIsGreyscale) {
- *bIsGreyscale = bIsGrey;
- }
-
- return color_type;
-}
-
-/**
-Returns a pointer to an RGBA palette, created from the specified bitmap.
-The RGBA palette is a copy of the specified bitmap's palette, that, additionally
-contains the bitmap's transparency information in the rgbReserved member
-of the palette's RGBQUAD elements.
-@param dib A pointer to a FreeImage bitmap to create the RGBA palette from.
-@param buffer A pointer to the buffer to store the RGBA palette.
-@return A pointer to the newly created RGBA palette or NULL, if the specified
-bitmap is no palletized standard bitmap. If non-NULL, the returned value is
-actually the pointer passed in parameter 'buffer'.
-*/
-static inline RGBQUAD *
-GetRGBAPalette(FIBITMAP *dib, RGBQUAD * const buffer) {
- // clone the palette
- const unsigned ncolors = FreeImage_GetColorsUsed(dib);
- if (ncolors == 0) {
- return NULL;
- }
- memcpy(buffer, FreeImage_GetPalette(dib), ncolors * sizeof(RGBQUAD));
- // merge the transparency table
- const unsigned ntransp = MIN(ncolors, FreeImage_GetTransparencyCount(dib));
- const BYTE * const tt = FreeImage_GetTransparencyTable(dib);
- for (unsigned i = 0; i < ntransp; i++) {
- buffer[i].rgbReserved = tt[i];
- }
- for (unsigned i = ntransp; i < ncolors; i++) {
- buffer[i].rgbReserved = 255;
- }
- return buffer;
-}
-
-// --------------------------------------------------------------------------
-
-CWeightsTable::CWeightsTable(CGenericFilter *pFilter, unsigned uDstSize, unsigned uSrcSize) {
- double dWidth;
- double dFScale;
- const double dFilterWidth = pFilter->GetWidth();
-
- // scale factor
- const double dScale = double(uDstSize) / double(uSrcSize);
-
- if(dScale < 1.0) {
- // minification
- dWidth = dFilterWidth / dScale;
- dFScale = dScale;
- } else {
- // magnification
- dWidth = dFilterWidth;
- dFScale = 1.0;
- }
-
- // allocate a new line contributions structure
- //
- // window size is the number of sampled pixels
- m_WindowSize = 2 * (int)ceil(dWidth) + 1;
- // length of dst line (no. of rows / cols)
- m_LineLength = uDstSize;
-
- // allocate list of contributions
- m_WeightTable = (Contribution*)malloc(m_LineLength * sizeof(Contribution));
- for(unsigned u = 0; u < m_LineLength; u++) {
- // allocate contributions for every pixel
- m_WeightTable[u].Weights = (double*)malloc(m_WindowSize * sizeof(double));
- }
-
- // offset for discrete to continuous coordinate conversion
- const double dOffset = (0.5 / dScale);
-
- for(unsigned u = 0; u < m_LineLength; u++) {
- // scan through line of contributions
-
- // inverse mapping (discrete dst 'u' to continous src 'dCenter')
- const double dCenter = (double)u / dScale + dOffset;
-
- // find the significant edge points that affect the pixel
- const int iLeft = MAX(0, (int)(dCenter - dWidth + 0.5));
- const int iRight = MIN((int)(dCenter + dWidth + 0.5), int(uSrcSize));
-
- m_WeightTable[u].Left = iLeft;
- m_WeightTable[u].Right = iRight;
-
- double dTotalWeight = 0; // sum of weights (initialized to zero)
- for(int iSrc = iLeft; iSrc < iRight; iSrc++) {
- // calculate weights
- const double weight = dFScale * pFilter->Filter(dFScale * ((double)iSrc + 0.5 - dCenter));
- // assert((iSrc-iLeft) < m_WindowSize);
- m_WeightTable[u].Weights[iSrc-iLeft] = weight;
- dTotalWeight += weight;
- }
- if((dTotalWeight > 0) && (dTotalWeight != 1)) {
- // normalize weight of neighbouring points
- for(int iSrc = iLeft; iSrc < iRight; iSrc++) {
- // normalize point
- m_WeightTable[u].Weights[iSrc-iLeft] /= dTotalWeight;
- }
- }
-
- // simplify the filter, discarding null weights at the right
- {
- int iTrailing = iRight - iLeft - 1;
- while(m_WeightTable[u].Weights[iTrailing] == 0) {
- m_WeightTable[u].Right--;
- iTrailing--;
- if(m_WeightTable[u].Right == m_WeightTable[u].Left) {
- break;
- }
- }
-
- }
-
- } // next dst pixel
-}
-
-CWeightsTable::~CWeightsTable() {
- for(unsigned u = 0; u < m_LineLength; u++) {
- // free contributions for every pixel
- free(m_WeightTable[u].Weights);
- }
- // free list of pixels contributions
- free(m_WeightTable);
-}
-
-// --------------------------------------------------------------------------
-
-FIBITMAP* CResizeEngine::scale(FIBITMAP *src, unsigned dst_width, unsigned dst_height, unsigned src_left, unsigned src_top, unsigned src_width, unsigned src_height) {
-
- const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(src);
- const unsigned src_bpp = FreeImage_GetBPP(src);
-
- // determine the image's color type
- BOOL bIsGreyscale = FALSE;
- FREE_IMAGE_COLOR_TYPE color_type;
- if (src_bpp <= 8) {
- color_type = GetExtendedColorType(src, &bIsGreyscale);
- } else {
- color_type = FIC_RGB;
- }
-
- // determine the required bit depth of the destination image
- unsigned dst_bpp;
- if (color_type == FIC_PALETTE && !bIsGreyscale) {
- // non greyscale FIC_PALETTE images require a high-color destination
- // image (24- or 32-bits depending on the image's transparent state)
- dst_bpp = FreeImage_IsTransparent(src) ? 32 : 24;
- } else if (src_bpp <= 8) {
- // greyscale images require an 8-bit destination image
- // (or a 32-bit image if the image is transparent)
- dst_bpp = FreeImage_IsTransparent(src) ? 32 : 8;
- if (dst_bpp == 32) {
- // additionally, for transparent images we always need a
- // palette including transparency information (an RGBA palette)
- // so, set color_type accordingly.
- color_type = FIC_PALETTE;
- }
- } else if (src_bpp == 16 && image_type == FIT_BITMAP) {
- // 16-bit 555 and 565 RGB images require a high-color destination image
- // (fixed to 24 bits, since 16-bit RGBs don't support transparency in FreeImage)
- dst_bpp = 24;
- } else {
- // bit depth remains unchanged for all other images
- dst_bpp = src_bpp;
- }
-
- // early exit if destination size is equal to source size
- if ((src_width == dst_width) && (src_height == dst_height)) {
- FIBITMAP *out = src;
- FIBITMAP *tmp = src;
- if ((src_width != FreeImage_GetWidth(src)) || (src_height != FreeImage_GetHeight(src))) {
- out = FreeImage_Copy(tmp, src_left, src_top, src_left + src_width, src_top + src_height);
- tmp = out;
- }
- if (src_bpp != dst_bpp) {
- switch (dst_bpp) {
- case 8:
- out = FreeImage_ConvertToGreyscale(tmp);
- if (tmp != src) {
- FreeImage_Unload(tmp);
- }
- break;
-
- case 24:
- out = FreeImage_ConvertTo24Bits(tmp);
- if (tmp != src) {
- FreeImage_Unload(tmp);
- }
- break;
-
- case 32:
- out = FreeImage_ConvertTo32Bits(tmp);
- if (tmp != src) {
- FreeImage_Unload(tmp);
- }
- break;
- }
- }
-
- return (out != src) ? out : FreeImage_Clone(src);
- }
-
- RGBQUAD pal_buffer[256];
- RGBQUAD *src_pal = NULL;
-
- // provide the source image's palette to the rescaler for
- // FIC_PALETTE type images (this includes palletized greyscale
- // images with an unordered palette as well as transparent images)
- if (color_type == FIC_PALETTE) {
- if (dst_bpp == 32) {
- // a 32 bit destination image signals transparency, so
- // create an RGBA palette from the source palette
- src_pal = GetRGBAPalette(src, pal_buffer);
- } else {
- src_pal = FreeImage_GetPalette(src);
- }
- }
-
- // allocate the dst image
- FIBITMAP *dst = FreeImage_AllocateT(image_type, dst_width, dst_height, dst_bpp, 0, 0, 0);
- if (!dst) {
- return NULL;
- }
-
- if (dst_bpp == 8) {
- RGBQUAD * const dst_pal = FreeImage_GetPalette(dst);
- if (color_type == FIC_MINISWHITE) {
- // build an inverted greyscale palette
- CREATE_GREYSCALE_PALETTE_REVERSE(dst_pal, 256);
- }
- /*
- else {
- // build a default greyscale palette
- // Currently, FreeImage_AllocateT already creates a default
- // greyscale palette for 8 bpp images, so we can skip this here.
- CREATE_GREYSCALE_PALETTE(dst_pal, 256);
- }
- */
- }
-
- // calculate x and y offsets; since FreeImage uses bottom-up bitmaps, the
- // value of src_offset_y is measured from the bottom of the image
- unsigned src_offset_x = src_left;
- unsigned src_offset_y;
- if (src_top > 0) {
- src_offset_y = FreeImage_GetHeight(src) - src_height - src_top;
- } else {
- src_offset_y = 0;
- }
-
- /*
- Decide which filtering order (xy or yx) is faster for this mapping.
- --- The theory ---
- Try to minimize calculations by counting the number of convolution multiplies
- if(dst_width*src_height <= src_width*dst_height) {
- // xy filtering
- } else {
- // yx filtering
- }
- --- The practice ---
- Try to minimize calculations by counting the number of vertical convolutions (the most time consuming task)
- if(dst_width*dst_height <= src_width*dst_height) {
- // xy filtering
- } else {
- // yx filtering
- }
- */
-
- if (dst_width <= src_width) {
- // xy filtering
- // -------------
-
- FIBITMAP *tmp = NULL;
-
- if (src_width != dst_width) {
- // source and destination widths are different so, we must
- // filter horizontally
- if (src_height != dst_height) {
- // source and destination heights are also different so, we need
- // a temporary image
- tmp = FreeImage_AllocateT(image_type, dst_width, src_height, dst_bpp, 0, 0, 0);
- if (!tmp) {
- FreeImage_Unload(dst);
- return NULL;
- }
- } else {
- // source and destination heights are equal so, we can directly
- // scale into destination image (second filter method will not
- // be invoked)
- tmp = dst;
- }
-
- // scale source image horizontally into temporary (or destination) image
- horizontalFilter(src, src_height, src_width, src_offset_x, src_offset_y, src_pal, tmp, dst_width);
-
- // set x and y offsets to zero for the second filter method
- // invocation (the temporary image only contains the portion of
- // the image to be rescaled with no offsets)
- src_offset_x = 0;
- src_offset_y = 0;
-
- // also ensure, that the second filter method gets no source
- // palette (the temporary image is palletized only, if it is
- // greyscale; in that case, it is an 8-bit image with a linear
- // palette so, the source palette is not needed or will even be
- // mismatching, if the source palette is unordered)
- src_pal = NULL;
- } else {
- // source and destination widths are equal so, just copy the
- // image pointer
- tmp = src;
- }
-
- if (src_height != dst_height) {
- // source and destination heights are different so, scale
- // temporary (or source) image vertically into destination image
- verticalFilter(tmp, dst_width, src_height, src_offset_x, src_offset_y, src_pal, dst, dst_height);
- }
-
- // free temporary image, if not pointing to either src or dst
- if (tmp != src && tmp != dst) {
- FreeImage_Unload(tmp);
- }
-
- } else {
- // yx filtering
- // -------------
-
- // Remark:
- // The yx filtering branch could be more optimized by taking into,
- // account that (src_width != dst_width) is always true, which
- // follows from the above condition, which selects filtering order.
- // Since (dst_width <= src_width) == TRUE selects xy filtering,
- // both widths must be different when performing yx filtering.
- // However, to make the code more robust, not depending on that
- // condition and more symmetric to the xy filtering case, these
- // (src_width != dst_width) conditions are still in place.
-
- FIBITMAP *tmp = NULL;
-
- if (src_height != dst_height) {
- // source and destination heights are different so, we must
- // filter vertically
- if (src_width != dst_width) {
- // source and destination widths are also different so, we need
- // a temporary image
- tmp = FreeImage_AllocateT(image_type, src_width, dst_height, dst_bpp, 0, 0, 0);
- if (!tmp) {
- FreeImage_Unload(dst);
- return NULL;
- }
- } else {
- // source and destination widths are equal so, we can directly
- // scale into destination image (second filter method will not
- // be invoked)
- tmp = dst;
- }
-
- // scale source image vertically into temporary (or destination) image
- verticalFilter(src, src_width, src_height, src_offset_x, src_offset_y, src_pal, tmp, dst_height);
-
- // set x and y offsets to zero for the second filter method
- // invocation (the temporary image only contains the portion of
- // the image to be rescaled with no offsets)
- src_offset_x = 0;
- src_offset_y = 0;
-
- // also ensure, that the second filter method gets no source
- // palette (the temporary image is palletized only, if it is
- // greyscale; in that case, it is an 8-bit image with a linear
- // palette so, the source palette is not needed or will even be
- // mismatching, if the source palette is unordered)
- src_pal = NULL;
-
- } else {
- // source and destination heights are equal so, just copy the
- // image pointer
- tmp = src;
- }
-
- if (src_width != dst_width) {
- // source and destination heights are different so, scale
- // temporary (or source) image horizontally into destination image
- horizontalFilter(tmp, dst_height, src_width, src_offset_x, src_offset_y, src_pal, dst, dst_width);
- }
-
- // free temporary image, if not pointing to either src or dst
- if (tmp != src && tmp != dst) {
- FreeImage_Unload(tmp);
- }
- }
-
- return dst;
-}
-
-void CResizeEngine::horizontalFilter(FIBITMAP *const src, unsigned height, unsigned src_width, unsigned src_offset_x, unsigned src_offset_y, const RGBQUAD *const src_pal, FIBITMAP *const dst, unsigned dst_width) {
-
- // allocate and calculate the contributions
- CWeightsTable weightsTable(m_pFilter, dst_width, src_width);
-
- // step through rows
- switch(FreeImage_GetImageType(src)) {
- case FIT_BITMAP:
- {
- switch(FreeImage_GetBPP(src)) {
- case 1:
- {
- switch(FreeImage_GetBPP(dst)) {
- case 8:
- {
- // transparently convert the 1-bit non-transparent greyscale
- // image to 8 bpp
- src_offset_x >>= 3;
- if (src_pal) {
- // we have got a palette
- for (unsigned y = 0; y < height; y++) {
- // scale each row
- const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
- BYTE * const dst_bits = FreeImage_GetScanLine(dst, y);
-
- for (unsigned x = 0; x < dst_width; x++) {
- // loop through row
- const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
- double value = 0;
-
- for (unsigned i = iLeft; i < iRight; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const unsigned pixel = (src_bits[i >> 3] & (0x80 >> (i & 0x07))) != 0;
- value += (weightsTable.getWeight(x, i - iLeft) * (double)*(BYTE *)&src_pal[pixel]);
- }
-
- // clamp and place result in destination pixel
- dst_bits[x] = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
- }
- }
- } else {
- // we do not have a palette
- for (unsigned y = 0; y < height; y++) {
- // scale each row
- const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
- BYTE * const dst_bits = FreeImage_GetScanLine(dst, y);
-
- for (unsigned x = 0; x < dst_width; x++) {
- // loop through row
- const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
- double value = 0;
-
- for (unsigned i = iLeft; i < iRight; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const unsigned pixel = (src_bits[i >> 3] & (0x80 >> (i & 0x07))) != 0;
- value += (weightsTable.getWeight(x, i - iLeft) * (double)pixel);
- }
- value *= 0xFF;
-
- // clamp and place result in destination pixel
- dst_bits[x] = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
- }
- }
- }
- }
- break;
-
- case 24:
- {
- // transparently convert the non-transparent 1-bit image
- // to 24 bpp; we always have got a palette here
- src_offset_x >>= 3;
-
- for (unsigned y = 0; y < height; y++) {
- // scale each row
- const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
- BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
-
- for (unsigned x = 0; x < dst_width; x++) {
- // loop through row
- const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
- double r = 0, g = 0, b = 0;
-
- for (unsigned i = iLeft; i < iRight; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(x, i - iLeft);
- const unsigned pixel = (src_bits[i >> 3] & (0x80 >> (i & 0x07))) != 0;
- const BYTE * const entry = (BYTE *)&src_pal[pixel];
- r += (weight * (double)entry[FI_RGBA_RED]);
- g += (weight * (double)entry[FI_RGBA_GREEN]);
- b += (weight * (double)entry[FI_RGBA_BLUE]);
- }
-
- // clamp and place result in destination pixel
- dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
- dst_bits += 3;
- }
- }
- }
- break;
-
- case 32:
- {
- // transparently convert the transparent 1-bit image
- // to 32 bpp; we always have got a palette here
- src_offset_x >>= 3;
-
- for (unsigned y = 0; y < height; y++) {
- // scale each row
- const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
- BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
-
- for (unsigned x = 0; x < dst_width; x++) {
- // loop through row
- const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
- double r = 0, g = 0, b = 0, a = 0;
-
- for (unsigned i = iLeft; i < iRight; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(x, i - iLeft);
- const unsigned pixel = (src_bits[i >> 3] & (0x80 >> (i & 0x07))) != 0;
- const BYTE * const entry = (BYTE *)&src_pal[pixel];
- r += (weight * (double)entry[FI_RGBA_RED]);
- g += (weight * (double)entry[FI_RGBA_GREEN]);
- b += (weight * (double)entry[FI_RGBA_BLUE]);
- a += (weight * (double)entry[FI_RGBA_ALPHA]);
- }
-
- // clamp and place result in destination pixel
- dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_ALPHA] = (BYTE)CLAMP<int>((int)(a + 0.5), 0, 0xFF);
- dst_bits += 4;
- }
- }
- }
- break;
- }
- }
- break;
-
- case 4:
- {
- switch(FreeImage_GetBPP(dst)) {
- case 8:
- {
- // transparently convert the non-transparent 4-bit greyscale image
- // to 8 bpp; we always have got a palette for 4-bit images
- src_offset_x >>= 1;
-
- for (unsigned y = 0; y < height; y++) {
- // scale each row
- const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
- BYTE * const dst_bits = FreeImage_GetScanLine(dst, y);
-
- for (unsigned x = 0; x < dst_width; x++) {
- // loop through row
- const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
- double value = 0;
-
- for (unsigned i = iLeft; i < iRight; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const unsigned pixel = i & 0x01 ? src_bits[i >> 1] & 0x0F : src_bits[i >> 1] >> 4;
- value += (weightsTable.getWeight(x, i - iLeft)
- * (double)*(BYTE *)&src_pal[pixel]);
- }
-
- // clamp and place result in destination pixel
- dst_bits[x] = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
- }
- }
- }
- break;
-
- case 24:
- {
- // transparently convert the non-transparent 4-bit image
- // to 24 bpp; we always have got a palette for 4-bit images
- src_offset_x >>= 1;
-
- for (unsigned y = 0; y < height; y++) {
- // scale each row
- const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
- BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
-
- for (unsigned x = 0; x < dst_width; x++) {
- // loop through row
- const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
- double r = 0, g = 0, b = 0;
-
- for (unsigned i = iLeft; i < iRight; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(x, i - iLeft);
- const unsigned pixel = i & 0x01 ? src_bits[i >> 1] & 0x0F : src_bits[i >> 1] >> 4;
- const BYTE * const entry = (BYTE *)&src_pal[pixel];
- r += (weight * (double)entry[FI_RGBA_RED]);
- g += (weight * (double)entry[FI_RGBA_GREEN]);
- b += (weight * (double)entry[FI_RGBA_BLUE]);
- }
-
- // clamp and place result in destination pixel
- dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
- dst_bits += 3;
- }
- }
- }
- break;
-
- case 32:
- {
- // transparently convert the transparent 4-bit image
- // to 32 bpp; we always have got a palette for 4-bit images
- src_offset_x >>= 1;
-
- for (unsigned y = 0; y < height; y++) {
- // scale each row
- const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
- BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
-
- for (unsigned x = 0; x < dst_width; x++) {
- // loop through row
- const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
- double r = 0, g = 0, b = 0, a = 0;
-
- for (unsigned i = iLeft; i < iRight; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(x, i - iLeft);
- const unsigned pixel = i & 0x01 ? src_bits[i >> 1] & 0x0F : src_bits[i >> 1] >> 4;
- const BYTE * const entry = (BYTE *)&src_pal[pixel];
- r += (weight * (double)entry[FI_RGBA_RED]);
- g += (weight * (double)entry[FI_RGBA_GREEN]);
- b += (weight * (double)entry[FI_RGBA_BLUE]);
- a += (weight * (double)entry[FI_RGBA_ALPHA]);
- }
-
- // clamp and place result in destination pixel
- dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_ALPHA] = (BYTE)CLAMP<int>((int)(a + 0.5), 0, 0xFF);
- dst_bits += 4;
- }
- }
- }
- break;
- }
- }
- break;
-
- case 8:
- {
- switch(FreeImage_GetBPP(dst)) {
- case 8:
- {
- // scale the 8-bit non-transparent greyscale image
- // into an 8 bpp destination image
- if (src_pal) {
- // we have got a palette
- for (unsigned y = 0; y < height; y++) {
- // scale each row
- const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
- BYTE * const dst_bits = FreeImage_GetScanLine(dst, y);
-
- for (unsigned x = 0; x < dst_width; x++) {
- // loop through row
- const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
- const BYTE * const pixel = src_bits + iLeft;
- double value = 0;
-
- // for(i = iLeft to iRight)
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- value += (weightsTable.getWeight(x, i)
- * (double)*(BYTE *)&src_pal[pixel[i]]);
- }
-
- // clamp and place result in destination pixel
- dst_bits[x] = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
- }
- }
- } else {
- // we do not have a palette
- for (unsigned y = 0; y < height; y++) {
- // scale each row
- const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
- BYTE * const dst_bits = FreeImage_GetScanLine(dst, y);
-
- for (unsigned x = 0; x < dst_width; x++) {
- // loop through row
- const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
- const BYTE * const pixel = src_bits + iLeft;
- double value = 0;
-
- // for(i = iLeft to iRight)
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- value += (weightsTable.getWeight(x, i) * (double)pixel[i]);
- }
-
- // clamp and place result in destination pixel
- dst_bits[x] = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
- }
- }
- }
- }
- break;
-
- case 24:
- {
- // transparently convert the non-transparent 8-bit image
- // to 24 bpp; we always have got a palette here
- for (unsigned y = 0; y < height; y++) {
- // scale each row
- const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
- BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
-
- for (unsigned x = 0; x < dst_width; x++) {
- // loop through row
- const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
- const BYTE * const pixel = src_bits + iLeft;
- double r = 0, g = 0, b = 0;
-
- // for(i = iLeft to iRight)
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(x, i);
- const BYTE *const entry = (BYTE *)&src_pal[pixel[i]];
- r += (weight * (double)entry[FI_RGBA_RED]);
- g += (weight * (double)entry[FI_RGBA_GREEN]);
- b += (weight * (double)entry[FI_RGBA_BLUE]);
- }
-
- // clamp and place result in destination pixel
- dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
- dst_bits += 3;
- }
- }
- }
- break;
-
- case 32:
- {
- // transparently convert the transparent 8-bit image
- // to 32 bpp; we always have got a palette here
- for (unsigned y = 0; y < height; y++) {
- // scale each row
- const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
- BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
-
- for (unsigned x = 0; x < dst_width; x++) {
- // loop through row
- const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
- const BYTE * const pixel = src_bits + iLeft;
- double r = 0, g = 0, b = 0, a = 0;
-
- // for(i = iLeft to iRight)
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(x, i);
- const BYTE * const entry = (BYTE *)&src_pal[pixel[i]];
- r += (weight * (double)entry[FI_RGBA_RED]);
- g += (weight * (double)entry[FI_RGBA_GREEN]);
- b += (weight * (double)entry[FI_RGBA_BLUE]);
- a += (weight * (double)entry[FI_RGBA_ALPHA]);
- }
-
- // clamp and place result in destination pixel
- dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_ALPHA] = (BYTE)CLAMP<int>((int)(a + 0.5), 0, 0xFF);
- dst_bits += 4;
- }
- }
- }
- break;
- }
- }
- break;
-
- case 16:
- {
- // transparently convert the 16-bit non-transparent image
- // to 24 bpp
- if (IS_FORMAT_RGB565(src)) {
- // image has 565 format
- for (unsigned y = 0; y < height; y++) {
- // scale each row
- const WORD * const src_bits = (WORD *)FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x / sizeof(WORD);
- BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
-
- for (unsigned x = 0; x < dst_width; x++) {
- // loop through row
- const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
- const WORD *pixel = src_bits + iLeft;
- double r = 0, g = 0, b = 0;
-
- // for(i = iLeft to iRight)
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(x, i);
- r += (weight * (double)((*pixel & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT));
- g += (weight * (double)((*pixel & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT));
- b += (weight * (double)((*pixel & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT));
- pixel++;
- }
-
- // clamp and place result in destination pixel
- dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(((r * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(((g * 0xFF) / 0x3F) + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(((b * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
- dst_bits += 3;
- }
- }
- } else {
- // image has 555 format
- for (unsigned y = 0; y < height; y++) {
- // scale each row
- const WORD * const src_bits = (WORD *)FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
- BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
-
- for (unsigned x = 0; x < dst_width; x++) {
- // loop through row
- const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
- const WORD *pixel = src_bits + iLeft;
- double r = 0, g = 0, b = 0;
-
- // for(i = iLeft to iRight)
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(x, i);
- r += (weight * (double)((*pixel & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT));
- g += (weight * (double)((*pixel & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT));
- b += (weight * (double)((*pixel & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT));
- pixel++;
- }
-
- // clamp and place result in destination pixel
- dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(((r * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(((g * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(((b * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
- dst_bits += 3;
- }
- }
- }
- }
- break;
-
- case 24:
- {
- // scale the 24-bit non-transparent image
- // into a 24 bpp destination image
- for (unsigned y = 0; y < height; y++) {
- // scale each row
- const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x * 3;
- BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
-
- for (unsigned x = 0; x < dst_width; x++) {
- // loop through row
- const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
- const BYTE * pixel = src_bits + iLeft * 3;
- double r = 0, g = 0, b = 0;
-
- // for(i = iLeft to iRight)
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(x, i);
- r += (weight * (double)pixel[FI_RGBA_RED]);
- g += (weight * (double)pixel[FI_RGBA_GREEN]);
- b += (weight * (double)pixel[FI_RGBA_BLUE]);
- pixel += 3;
- }
-
- // clamp and place result in destination pixel
- dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
- dst_bits += 3;
- }
- }
- }
- break;
-
- case 32:
- {
- // scale the 32-bit transparent image
- // into a 32 bpp destination image
- for (unsigned y = 0; y < height; y++) {
- // scale each row
- const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x * 4;
- BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
-
- for (unsigned x = 0; x < dst_width; x++) {
- // loop through row
- const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
- const BYTE *pixel = src_bits + iLeft * 4;
- double r = 0, g = 0, b = 0, a = 0;
-
- // for(i = iLeft to iRight)
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(x, i);
- r += (weight * (double)pixel[FI_RGBA_RED]);
- g += (weight * (double)pixel[FI_RGBA_GREEN]);
- b += (weight * (double)pixel[FI_RGBA_BLUE]);
- a += (weight * (double)pixel[FI_RGBA_ALPHA]);
- pixel += 4;
- }
-
- // clamp and place result in destination pixel
- dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_ALPHA] = (BYTE)CLAMP<int>((int)(a + 0.5), 0, 0xFF);
- dst_bits += 4;
- }
- }
- }
- break;
- }
- }
- break;
-
- case FIT_UINT16:
- {
- // Calculate the number of words per pixel (1 for 16-bit, 3 for 48-bit or 4 for 64-bit)
- const unsigned wordspp = (FreeImage_GetLine(src) / src_width) / sizeof(WORD);
-
- for (unsigned y = 0; y < height; y++) {
- // scale each row
- const WORD *src_bits = (WORD*)FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x / sizeof(WORD);
- WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y);
-
- for (unsigned x = 0; x < dst_width; x++) {
- // loop through row
- const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
- const WORD *pixel = src_bits + iLeft * wordspp;
- double value = 0;
-
- // for(i = iLeft to iRight)
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(x, i);
- value += (weight * (double)pixel[0]);
- pixel++;
- }
-
- // clamp and place result in destination pixel
- dst_bits[0] = (WORD)CLAMP<int>((int)(value + 0.5), 0, 0xFFFF);
- dst_bits += wordspp;
- }
- }
- }
- break;
-
- case FIT_RGB16:
- {
- // Calculate the number of words per pixel (1 for 16-bit, 3 for 48-bit or 4 for 64-bit)
- const unsigned wordspp = (FreeImage_GetLine(src) / src_width) / sizeof(WORD);
-
- for (unsigned y = 0; y < height; y++) {
- // scale each row
- const WORD *src_bits = (WORD*)FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x / sizeof(WORD);
- WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y);
-
- for (unsigned x = 0; x < dst_width; x++) {
- // loop through row
- const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
- const WORD *pixel = src_bits + iLeft * wordspp;
- double r = 0, g = 0, b = 0;
-
- // for(i = iLeft to iRight)
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(x, i);
- r += (weight * (double)pixel[0]);
- g += (weight * (double)pixel[1]);
- b += (weight * (double)pixel[2]);
- pixel += wordspp;
- }
-
- // clamp and place result in destination pixel
- dst_bits[0] = (WORD)CLAMP<int>((int)(r + 0.5), 0, 0xFFFF);
- dst_bits[1] = (WORD)CLAMP<int>((int)(g + 0.5), 0, 0xFFFF);
- dst_bits[2] = (WORD)CLAMP<int>((int)(b + 0.5), 0, 0xFFFF);
- dst_bits += wordspp;
- }
- }
- }
- break;
-
- case FIT_RGBA16:
- {
- // Calculate the number of words per pixel (1 for 16-bit, 3 for 48-bit or 4 for 64-bit)
- const unsigned wordspp = (FreeImage_GetLine(src) / src_width) / sizeof(WORD);
-
- for (unsigned y = 0; y < height; y++) {
- // scale each row
- const WORD *src_bits = (WORD*)FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x / sizeof(WORD);
- WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y);
-
- for (unsigned x = 0; x < dst_width; x++) {
- // loop through row
- const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
- const WORD *pixel = src_bits + iLeft * wordspp;
- double r = 0, g = 0, b = 0, a = 0;
-
- // for(i = iLeft to iRight)
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(x, i);
- r += (weight * (double)pixel[0]);
- g += (weight * (double)pixel[1]);
- b += (weight * (double)pixel[2]);
- a += (weight * (double)pixel[3]);
- pixel += wordspp;
- }
-
- // clamp and place result in destination pixel
- dst_bits[0] = (WORD)CLAMP<int>((int)(r + 0.5), 0, 0xFFFF);
- dst_bits[1] = (WORD)CLAMP<int>((int)(g + 0.5), 0, 0xFFFF);
- dst_bits[2] = (WORD)CLAMP<int>((int)(b + 0.5), 0, 0xFFFF);
- dst_bits[3] = (WORD)CLAMP<int>((int)(a + 0.5), 0, 0xFFFF);
- dst_bits += wordspp;
- }
- }
- }
- break;
-
- case FIT_FLOAT:
- case FIT_RGBF:
- case FIT_RGBAF:
- {
- // Calculate the number of floats per pixel (1 for 32-bit, 3 for 96-bit or 4 for 128-bit)
- const unsigned floatspp = (FreeImage_GetLine(src) / src_width) / sizeof(float);
-
- for(unsigned y = 0; y < height; y++) {
- // scale each row
- const float *src_bits = (float*)FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x / sizeof(float);
- float *dst_bits = (float*)FreeImage_GetScanLine(dst, y);
-
- for(unsigned x = 0; x < dst_width; x++) {
- // loop through row
- const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
- double value[4] = {0, 0, 0, 0}; // 4 = 128 bpp max
-
- for(unsigned i = iLeft; i < iRight; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(x, i-iLeft);
-
- unsigned index = i * floatspp; // pixel index
- for (unsigned j = 0; j < floatspp; j++) {
- value[j] += (weight * (double)src_bits[index++]);
- }
- }
-
- // place result in destination pixel
- for (unsigned j = 0; j < floatspp; j++) {
- dst_bits[j] = (float)value[j];
- }
-
- dst_bits += floatspp;
- }
- }
- }
- break;
- }
-}
-
-/// Performs vertical image filtering
-void CResizeEngine::verticalFilter(FIBITMAP *const src, unsigned width, unsigned src_height, unsigned src_offset_x, unsigned src_offset_y, const RGBQUAD *const src_pal, FIBITMAP *const dst, unsigned dst_height) {
-
- // allocate and calculate the contributions
- CWeightsTable weightsTable(m_pFilter, dst_height, src_height);
-
- // step through columns
- switch(FreeImage_GetImageType(src)) {
- case FIT_BITMAP:
- {
- const unsigned dst_pitch = FreeImage_GetPitch(dst);
- BYTE * const dst_base = FreeImage_GetBits(dst);
-
- switch(FreeImage_GetBPP(src)) {
- case 1:
- {
- const unsigned src_pitch = FreeImage_GetPitch(src);
- const BYTE * const src_base = FreeImage_GetBits(src)
- + src_offset_y * src_pitch + (src_offset_x >> 3);
-
- switch(FreeImage_GetBPP(dst)) {
- case 8:
- {
- // transparently convert the 1-bit non-transparent greyscale
- // image to 8 bpp
- if (src_pal) {
- // we have got a palette
- for (unsigned x = 0; x < width; x++) {
- // work on column x in dst
- BYTE *dst_bits = dst_base + x;
- const unsigned index = x >> 3;
- const unsigned mask = 0x80 >> (x & 0x07);
-
- // scale each column
- for (unsigned y = 0; y < dst_height; y++) {
- // loop through column
- const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
- const BYTE *src_bits = src_base + iLeft * src_pitch + index;
- double value = 0;
-
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const unsigned pixel = (*src_bits & mask) != 0;
- value += (weightsTable.getWeight(y, i)
- * (double)*(BYTE *)&src_pal[pixel]);
- src_bits += src_pitch;
- }
- value *= 0xFF;
-
- // clamp and place result in destination pixel
- *dst_bits = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
- dst_bits += dst_pitch;
- }
- }
- } else {
- // we do not have a palette
- for (unsigned x = 0; x < width; x++) {
- // work on column x in dst
- BYTE *dst_bits = dst_base + x;
- const unsigned index = x >> 3;
- const unsigned mask = 0x80 >> (x & 0x07);
-
- // scale each column
- for (unsigned y = 0; y < dst_height; y++) {
- // loop through column
- const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
- const BYTE *src_bits = src_base + iLeft * src_pitch + index;
- double value = 0;
-
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- value += (weightsTable.getWeight(y, i)
- * (double)((*src_bits & mask) != 0));
- src_bits += src_pitch;
- }
- value *= 0xFF;
-
- // clamp and place result in destination pixel
- *dst_bits = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
- dst_bits += dst_pitch;
- }
- }
- }
- }
- break;
-
- case 24:
- {
- // transparently convert the non-transparent 1-bit image
- // to 24 bpp; we always have got a palette here
- for (unsigned x = 0; x < width; x++) {
- // work on column x in dst
- BYTE *dst_bits = dst_base + x * 3;
- const unsigned index = x >> 3;
- const unsigned mask = 0x80 >> (x & 0x07);
-
- // scale each column
- for (unsigned y = 0; y < dst_height; y++) {
- // loop through column
- const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
- const BYTE *src_bits = src_base + iLeft * src_pitch + index;
- double r = 0, g = 0, b = 0;
-
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(y, i);
- const unsigned pixel = (*src_bits & mask) != 0;
- const BYTE * const entry = (BYTE *)&src_pal[pixel];
- r += (weight * (double)entry[FI_RGBA_RED]);
- g += (weight * (double)entry[FI_RGBA_GREEN]);
- b += (weight * (double)entry[FI_RGBA_BLUE]);
- src_bits += src_pitch;
- }
-
- // clamp and place result in destination pixel
- dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
- dst_bits += dst_pitch;
- }
- }
- }
- break;
-
- case 32:
- {
- // transparently convert the transparent 1-bit image
- // to 32 bpp; we always have got a palette here
- for (unsigned x = 0; x < width; x++) {
- // work on column x in dst
- BYTE *dst_bits = dst_base + x * 4;
- const unsigned index = x >> 3;
- const unsigned mask = 0x80 >> (x & 0x07);
-
- // scale each column
- for (unsigned y = 0; y < dst_height; y++) {
- // loop through column
- const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
- const BYTE *src_bits = src_base + iLeft * src_pitch + index;
- double r = 0, g = 0, b = 0, a = 0;
-
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(y, i);
- const unsigned pixel = (*src_bits & mask) != 0;
- const BYTE * const entry = (BYTE *)&src_pal[pixel];
- r += (weight * (double)entry[FI_RGBA_RED]);
- g += (weight * (double)entry[FI_RGBA_GREEN]);
- b += (weight * (double)entry[FI_RGBA_BLUE]);
- a += (weight * (double)entry[FI_RGBA_ALPHA]);
- src_bits += src_pitch;
- }
-
- // clamp and place result in destination pixel
- dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_ALPHA] = (BYTE)CLAMP<int>((int)(a + 0.5), 0, 0xFF);
- dst_bits += dst_pitch;
- }
- }
- }
- break;
- }
- }
- break;
-
- case 4:
- {
- const unsigned src_pitch = FreeImage_GetPitch(src);
- const BYTE *const src_base = FreeImage_GetBits(src) + src_offset_y * src_pitch + (src_offset_x >> 1);
-
- switch(FreeImage_GetBPP(dst)) {
- case 8:
- {
- // transparently convert the non-transparent 4-bit greyscale image
- // to 8 bpp; we always have got a palette for 4-bit images
- for (unsigned x = 0; x < width; x++) {
- // work on column x in dst
- BYTE *dst_bits = dst_base + x;
- const unsigned index = x >> 1;
-
- // scale each column
- for (unsigned y = 0; y < dst_height; y++) {
- // loop through column
- const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
- const BYTE *src_bits = src_base + iLeft * src_pitch + index;
- double value = 0;
-
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const unsigned pixel = x & 0x01 ? *src_bits & 0x0F : *src_bits >> 4;
- value += (weightsTable.getWeight(y, i)
- * (double)*(BYTE *)&src_pal[pixel]);
- src_bits += src_pitch;
- }
-
- // clamp and place result in destination pixel
- *dst_bits = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
- dst_bits += dst_pitch;
- }
- }
- }
- break;
-
- case 24:
- {
- // transparently convert the non-transparent 4-bit image
- // to 24 bpp; we always have got a palette for 4-bit images
- for (unsigned x = 0; x < width; x++) {
- // work on column x in dst
- BYTE *dst_bits = dst_base + x * 3;
- const unsigned index = x >> 1;
-
- // scale each column
- for (unsigned y = 0; y < dst_height; y++) {
- // loop through column
- const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
- const BYTE *src_bits = src_base + iLeft * src_pitch + index;
- double r = 0, g = 0, b = 0;
-
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(y, i);
- const unsigned pixel = x & 0x01 ? *src_bits & 0x0F : *src_bits >> 4;
- const BYTE *const entry = (BYTE *)&src_pal[pixel];
- r += (weight * (double)entry[FI_RGBA_RED]);
- g += (weight * (double)entry[FI_RGBA_GREEN]);
- b += (weight * (double)entry[FI_RGBA_BLUE]);
- src_bits += src_pitch;
- }
-
- // clamp and place result in destination pixel
- dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
- dst_bits += dst_pitch;
- }
- }
- }
- break;
-
- case 32:
- {
- // transparently convert the transparent 4-bit image
- // to 32 bpp; we always have got a palette for 4-bit images
- for (unsigned x = 0; x < width; x++) {
- // work on column x in dst
- BYTE *dst_bits = dst_base + x * 4;
- const unsigned index = x >> 1;
-
- // scale each column
- for (unsigned y = 0; y < dst_height; y++) {
- // loop through column
- const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
- const BYTE *src_bits = src_base + iLeft * src_pitch + index;
- double r = 0, g = 0, b = 0, a = 0;
-
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(y, i);
- const unsigned pixel = x & 0x01 ? *src_bits & 0x0F : *src_bits >> 4;
- const BYTE *const entry = (BYTE *)&src_pal[pixel];
- r += (weight * (double)entry[FI_RGBA_RED]);
- g += (weight * (double)entry[FI_RGBA_GREEN]);
- b += (weight * (double)entry[FI_RGBA_BLUE]);
- a += (weight * (double)entry[FI_RGBA_ALPHA]);
- src_bits += src_pitch;
- }
-
- // clamp and place result in destination pixel
- dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_ALPHA] = (BYTE)CLAMP<int>((int)(a + 0.5), 0, 0xFF);
- dst_bits += dst_pitch;
- }
- }
- }
- break;
- }
- }
- break;
-
- case 8:
- {
- const unsigned src_pitch = FreeImage_GetPitch(src);
- const BYTE *const src_base = FreeImage_GetBits(src) + src_offset_y * src_pitch + src_offset_x;
-
- switch(FreeImage_GetBPP(dst)) {
- case 8:
- {
- // scale the 8-bit non-transparent greyscale image
- // into an 8 bpp destination image
- if (src_pal) {
- // we have got a palette
- for (unsigned x = 0; x < width; x++) {
- // work on column x in dst
- BYTE *dst_bits = dst_base + x;
-
- // scale each column
- for (unsigned y = 0; y < dst_height; y++) {
- // loop through column
- const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
- const BYTE *src_bits = src_base + iLeft * src_pitch + x;
- double value = 0;
-
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- value += (weightsTable.getWeight(y, i)
- * (double)*(BYTE *)&src_pal[*src_bits]);
- src_bits += src_pitch;
- }
-
- // clamp and place result in destination pixel
- *dst_bits = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
- dst_bits += dst_pitch;
- }
- }
- } else {
- // we do not have a palette
- for (unsigned x = 0; x < width; x++) {
- // work on column x in dst
- BYTE *dst_bits = dst_base + x;
-
- // scale each column
- for (unsigned y = 0; y < dst_height; y++) {
- // loop through column
- const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
- const BYTE *src_bits = src_base + iLeft * src_pitch + x;
- double value = 0;
-
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- value += (weightsTable.getWeight(y, i)
- * (double)*src_bits);
- src_bits += src_pitch;
- }
-
- // clamp and place result in destination pixel
- *dst_bits = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
- dst_bits += dst_pitch;
- }
- }
- }
- }
- break;
-
- case 24:
- {
- // transparently convert the non-transparent 8-bit image
- // to 24 bpp; we always have got a palette here
- for (unsigned x = 0; x < width; x++) {
- // work on column x in dst
- BYTE *dst_bits = dst_base + x * 3;
-
- // scale each column
- for (unsigned y = 0; y < dst_height; y++) {
- // loop through column
- const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
- const BYTE *src_bits = src_base + iLeft * src_pitch + x;
- double r = 0, g = 0, b = 0;
-
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(y, i);
- const BYTE * const entry = (BYTE *)&src_pal[*src_bits];
- r += (weight * (double)entry[FI_RGBA_RED]);
- g += (weight * (double)entry[FI_RGBA_GREEN]);
- b += (weight * (double)entry[FI_RGBA_BLUE]);
- src_bits += src_pitch;
- }
-
- // clamp and place result in destination pixel
- dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
- dst_bits += dst_pitch;
- }
- }
- }
- break;
-
- case 32:
- {
- // transparently convert the transparent 8-bit image
- // to 32 bpp; we always have got a palette here
- for (unsigned x = 0; x < width; x++) {
- // work on column x in dst
- BYTE *dst_bits = dst_base + x * 4;
-
- // scale each column
- for (unsigned y = 0; y < dst_height; y++) {
- // loop through column
- const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
- const BYTE *src_bits = src_base + iLeft * src_pitch + x;
- double r = 0, g = 0, b = 0, a = 0;
-
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(y, i);
- const BYTE * const entry = (BYTE *)&src_pal[*src_bits];
- r += (weight * (double)entry[FI_RGBA_RED]);
- g += (weight * (double)entry[FI_RGBA_GREEN]);
- b += (weight * (double)entry[FI_RGBA_BLUE]);
- a += (weight * (double)entry[FI_RGBA_ALPHA]);
- src_bits += src_pitch;
- }
-
- // clamp and place result in destination pixel
- dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_ALPHA] = (BYTE)CLAMP<int>((int)(a + 0.5), 0, 0xFF);
- dst_bits += dst_pitch;
- }
- }
- }
- break;
- }
- }
- break;
-
- case 16:
- {
- // transparently convert the 16-bit non-transparent image
- // to 24 bpp
- const unsigned src_pitch = FreeImage_GetPitch(src) / sizeof(WORD);
- const WORD *const src_base = (WORD *)FreeImage_GetBits(src) + src_offset_y * src_pitch + src_offset_x;
-
- if (IS_FORMAT_RGB565(src)) {
- // image has 565 format
- for (unsigned x = 0; x < width; x++) {
- // work on column x in dst
- BYTE *dst_bits = dst_base + x * 3;
-
- // scale each column
- for (unsigned y = 0; y < dst_height; y++) {
- // loop through column
- const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
- const WORD *src_bits = src_base + iLeft * src_pitch + x;
- double r = 0, g = 0, b = 0;
-
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(y, i);
- r += (weight * (double)((*src_bits & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT));
- g += (weight * (double)((*src_bits & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT));
- b += (weight * (double)((*src_bits & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT));
- src_bits += src_pitch;
- }
-
- // clamp and place result in destination pixel
- dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(((r * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(((g * 0xFF) / 0x3F) + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(((b * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
- dst_bits += dst_pitch;
- }
- }
- } else {
- // image has 555 format
- for (unsigned x = 0; x < width; x++) {
- // work on column x in dst
- BYTE *dst_bits = dst_base + x * 3;
-
- // scale each column
- for (unsigned y = 0; y < dst_height; y++) {
- // loop through column
- const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
- const WORD *src_bits = src_base + iLeft * src_pitch + x;
- double r = 0, g = 0, b = 0;
-
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(y, i);
- r += (weight * (double)((*src_bits & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT));
- g += (weight * (double)((*src_bits & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT));
- b += (weight * (double)((*src_bits & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT));
- src_bits += src_pitch;
- }
-
- // clamp and place result in destination pixel
- dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(((r * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(((g * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(((b * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
- dst_bits += dst_pitch;
- }
- }
- }
- }
- break;
-
- case 24:
- {
- // scale the 24-bit transparent image
- // into a 24 bpp destination image
- const unsigned src_pitch = FreeImage_GetPitch(src);
- const BYTE *const src_base = FreeImage_GetBits(src) + src_offset_y * src_pitch + src_offset_x * 3;
-
- for (unsigned x = 0; x < width; x++) {
- // work on column x in dst
- const unsigned index = x * 3;
- BYTE *dst_bits = dst_base + index;
-
- // scale each column
- for (unsigned y = 0; y < dst_height; y++) {
- // loop through column
- const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
- const BYTE *src_bits = src_base + iLeft * src_pitch + index;
- double r = 0, g = 0, b = 0;
-
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(y, i);
- r += (weight * (double)src_bits[FI_RGBA_RED]);
- g += (weight * (double)src_bits[FI_RGBA_GREEN]);
- b += (weight * (double)src_bits[FI_RGBA_BLUE]);
- src_bits += src_pitch;
- }
-
- // clamp and place result in destination pixel
- dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int) (r + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int) (g + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int) (b + 0.5), 0, 0xFF);
- dst_bits += dst_pitch;
- }
- }
- }
- break;
-
- case 32:
- {
- // scale the 32-bit transparent image
- // into a 32 bpp destination image
- const unsigned src_pitch = FreeImage_GetPitch(src);
- const BYTE *const src_base = FreeImage_GetBits(src) + src_offset_y * src_pitch + src_offset_x * 4;
-
- for (unsigned x = 0; x < width; x++) {
- // work on column x in dst
- const unsigned index = x * 4;
- BYTE *dst_bits = dst_base + index;
-
- // scale each column
- for (unsigned y = 0; y < dst_height; y++) {
- // loop through column
- const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
- const BYTE *src_bits = src_base + iLeft * src_pitch + index;
- double r = 0, g = 0, b = 0, a = 0;
-
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(y, i);
- r += (weight * (double)src_bits[FI_RGBA_RED]);
- g += (weight * (double)src_bits[FI_RGBA_GREEN]);
- b += (weight * (double)src_bits[FI_RGBA_BLUE]);
- a += (weight * (double)src_bits[FI_RGBA_ALPHA]);
- src_bits += src_pitch;
- }
-
- // clamp and place result in destination pixel
- dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int) (r + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int) (g + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int) (b + 0.5), 0, 0xFF);
- dst_bits[FI_RGBA_ALPHA] = (BYTE)CLAMP<int>((int) (a + 0.5), 0, 0xFF);
- dst_bits += dst_pitch;
- }
- }
- }
- break;
- }
- }
- break;
-
- case FIT_UINT16:
- {
- // Calculate the number of words per pixel (1 for 16-bit, 3 for 48-bit or 4 for 64-bit)
- const unsigned wordspp = (FreeImage_GetLine(src) / width) / sizeof(WORD);
-
- const unsigned dst_pitch = FreeImage_GetPitch(dst) / sizeof(WORD);
- WORD *const dst_base = (WORD *)FreeImage_GetBits(dst);
-
- const unsigned src_pitch = FreeImage_GetPitch(src) / sizeof(WORD);
- const WORD *const src_base = (WORD *)FreeImage_GetBits(src) + src_offset_y * src_pitch + src_offset_x * wordspp;
-
- for (unsigned x = 0; x < width; x++) {
- // work on column x in dst
- const unsigned index = x * wordspp; // pixel index
- WORD *dst_bits = dst_base + index;
-
- // scale each column
- for (unsigned y = 0; y < dst_height; y++) {
- // loop through column
- const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
- const WORD *src_bits = src_base + iLeft * src_pitch + index;
- double value = 0;
-
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(y, i);
- value += (weight * (double)src_bits[0]);
- src_bits += src_pitch;
- }
-
- // clamp and place result in destination pixel
- dst_bits[0] = (WORD)CLAMP<int>((int)(value + 0.5), 0, 0xFFFF);
-
- dst_bits += dst_pitch;
- }
- }
- }
- break;
-
- case FIT_RGB16:
- {
- // Calculate the number of words per pixel (1 for 16-bit, 3 for 48-bit or 4 for 64-bit)
- const unsigned wordspp = (FreeImage_GetLine(src) / width) / sizeof(WORD);
-
- const unsigned dst_pitch = FreeImage_GetPitch(dst) / sizeof(WORD);
- WORD *const dst_base = (WORD *)FreeImage_GetBits(dst);
-
- const unsigned src_pitch = FreeImage_GetPitch(src) / sizeof(WORD);
- const WORD *const src_base = (WORD *)FreeImage_GetBits(src) + src_offset_y * src_pitch + src_offset_x * wordspp;
-
- for (unsigned x = 0; x < width; x++) {
- // work on column x in dst
- const unsigned index = x * wordspp; // pixel index
- WORD *dst_bits = dst_base + index;
-
- // scale each column
- for (unsigned y = 0; y < dst_height; y++) {
- // loop through column
- const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
- const WORD *src_bits = src_base + iLeft * src_pitch + index;
- double r = 0, g = 0, b = 0;
-
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(y, i);
- r += (weight * (double)src_bits[0]);
- g += (weight * (double)src_bits[1]);
- b += (weight * (double)src_bits[2]);
-
- src_bits += src_pitch;
- }
-
- // clamp and place result in destination pixel
- dst_bits[0] = (WORD)CLAMP<int>((int)(r + 0.5), 0, 0xFFFF);
- dst_bits[1] = (WORD)CLAMP<int>((int)(g + 0.5), 0, 0xFFFF);
- dst_bits[2] = (WORD)CLAMP<int>((int)(b + 0.5), 0, 0xFFFF);
-
- dst_bits += dst_pitch;
- }
- }
- }
- break;
-
- case FIT_RGBA16:
- {
- // Calculate the number of words per pixel (1 for 16-bit, 3 for 48-bit or 4 for 64-bit)
- const unsigned wordspp = (FreeImage_GetLine(src) / width) / sizeof(WORD);
-
- const unsigned dst_pitch = FreeImage_GetPitch(dst) / sizeof(WORD);
- WORD *const dst_base = (WORD *)FreeImage_GetBits(dst);
-
- const unsigned src_pitch = FreeImage_GetPitch(src) / sizeof(WORD);
- const WORD *const src_base = (WORD *)FreeImage_GetBits(src) + src_offset_y * src_pitch + src_offset_x * wordspp;
-
- for (unsigned x = 0; x < width; x++) {
- // work on column x in dst
- const unsigned index = x * wordspp; // pixel index
- WORD *dst_bits = dst_base + index;
-
- // scale each column
- for (unsigned y = 0; y < dst_height; y++) {
- // loop through column
- const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
- const WORD *src_bits = src_base + iLeft * src_pitch + index;
- double r = 0, g = 0, b = 0, a = 0;
-
- for (unsigned i = 0; i < iLimit; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(y, i);
- r += (weight * (double)src_bits[0]);
- g += (weight * (double)src_bits[1]);
- b += (weight * (double)src_bits[2]);
- a += (weight * (double)src_bits[3]);
-
- src_bits += src_pitch;
- }
-
- // clamp and place result in destination pixel
- dst_bits[0] = (WORD)CLAMP<int>((int)(r + 0.5), 0, 0xFFFF);
- dst_bits[1] = (WORD)CLAMP<int>((int)(g + 0.5), 0, 0xFFFF);
- dst_bits[2] = (WORD)CLAMP<int>((int)(b + 0.5), 0, 0xFFFF);
- dst_bits[3] = (WORD)CLAMP<int>((int)(a + 0.5), 0, 0xFFFF);
-
- dst_bits += dst_pitch;
- }
- }
- }
- break;
-
- case FIT_FLOAT:
- case FIT_RGBF:
- case FIT_RGBAF:
- {
- // Calculate the number of floats per pixel (1 for 32-bit, 3 for 96-bit or 4 for 128-bit)
- const unsigned floatspp = (FreeImage_GetLine(src) / width) / sizeof(float);
-
- const unsigned dst_pitch = FreeImage_GetPitch(dst) / sizeof(float);
- float *const dst_base = (float *)FreeImage_GetBits(dst);
-
- const unsigned src_pitch = FreeImage_GetPitch(src) / sizeof(float);
- const float *const src_base = (float *)FreeImage_GetBits(src) + src_offset_y * src_pitch + src_offset_x * floatspp;
-
- for (unsigned x = 0; x < width; x++) {
- // work on column x in dst
- const unsigned index = x * floatspp; // pixel index
- float *dst_bits = (float *)dst_base + index;
-
- // scale each column
- for (unsigned y = 0; y < dst_height; y++) {
- // loop through column
- const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- const unsigned iRight = weightsTable.getRightBoundary(y); // retrieve right boundary
- const float *src_bits = src_base + iLeft * src_pitch + index;
- double value[4] = {0, 0, 0, 0}; // 4 = 128 bpp max
-
- for (unsigned i = iLeft; i < iRight; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- const double weight = weightsTable.getWeight(y, i - iLeft);
- for (unsigned j = 0; j < floatspp; j++) {
- value[j] += (weight * (double)src_bits[j]);
- }
- src_bits += src_pitch;
- }
-
- // place result in destination pixel
- for (unsigned j = 0; j < floatspp; j++) {
- dst_bits[j] = (float)value[j];
- }
- dst_bits += dst_pitch;
- }
- }
- }
- break;
- }
-}
+// ==========================================================
+// Upsampling / downsampling classes
+//
+// Design and implementation by
+// - Hervé Drolon (drolon@infonie.fr)
+// - Detlev Vendt (detlev.vendt@brillit.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 "Resize.h"
+
+/**
+Returns the color type of a bitmap. In contrast to FreeImage_GetColorType,
+this function optionally supports a boolean OUT parameter, that receives TRUE,
+if the specified bitmap is greyscale, that is, it consists of grey colors only.
+Although it returns the same value as returned by FreeImage_GetColorType for all
+image types, this extended function primarily is intended for palletized images,
+since the boolean pointed to by 'bIsGreyscale' remains unchanged for RGB(A/F)
+images. However, the outgoing boolean is properly maintained for palletized images,
+as well as for any non-RGB image type, like FIT_UINTxx and FIT_DOUBLE, for example.
+@param dib A pointer to a FreeImage bitmap to calculate the extended color type for
+@param bIsGreyscale A pointer to a boolean, that receives TRUE, if the specified bitmap
+is greyscale, that is, it consists of grey colors only. This parameter can be NULL.
+@return the color type of the specified bitmap
+*/
+static FREE_IMAGE_COLOR_TYPE
+GetExtendedColorType(FIBITMAP *dib, BOOL *bIsGreyscale) {
+ const unsigned bpp = FreeImage_GetBPP(dib);
+ const unsigned size = CalculateUsedPaletteEntries(bpp);
+ const RGBQUAD * const pal = FreeImage_GetPalette(dib);
+ FREE_IMAGE_COLOR_TYPE color_type = FIC_MINISBLACK;
+ BOOL bIsGrey = TRUE;
+
+ switch (bpp) {
+ case 1:
+ {
+ for (unsigned i = 0; i < size; i++) {
+ if ((pal[i].rgbRed != pal[i].rgbGreen) || (pal[i].rgbRed != pal[i].rgbBlue)) {
+ color_type = FIC_PALETTE;
+ bIsGrey = FALSE;
+ break;
+ }
+ }
+ if (bIsGrey) {
+ if (pal[0].rgbBlue == 255 && pal[1].rgbBlue == 0) {
+ color_type = FIC_MINISWHITE;
+ } else if (pal[0].rgbBlue != 0 || pal[1].rgbBlue != 255) {
+ color_type = FIC_PALETTE;
+ }
+ }
+ break;
+ }
+
+ case 4:
+ case 8:
+ {
+ for (unsigned i = 0; i < size; i++) {
+ if ((pal[i].rgbRed != pal[i].rgbGreen) || (pal[i].rgbRed != pal[i].rgbBlue)) {
+ color_type = FIC_PALETTE;
+ bIsGrey = FALSE;
+ break;
+ }
+ if (color_type != FIC_PALETTE && pal[i].rgbBlue != i) {
+ if ((size - i - 1) != pal[i].rgbBlue) {
+ color_type = FIC_PALETTE;
+ if (!bIsGreyscale) {
+ // exit loop if we're not setting
+ // bIsGreyscale parameter
+ break;
+ }
+ } else {
+ color_type = FIC_MINISWHITE;
+ }
+ }
+ }
+ break;
+ }
+
+ default:
+ {
+ color_type = FreeImage_GetColorType(dib);
+ bIsGrey = (color_type == FIC_MINISBLACK) ? TRUE : FALSE;
+ break;
+ }
+
+ }
+ if (bIsGreyscale) {
+ *bIsGreyscale = bIsGrey;
+ }
+
+ return color_type;
+}
+
+/**
+Returns a pointer to an RGBA palette, created from the specified bitmap.
+The RGBA palette is a copy of the specified bitmap's palette, that, additionally
+contains the bitmap's transparency information in the rgbReserved member
+of the palette's RGBQUAD elements.
+@param dib A pointer to a FreeImage bitmap to create the RGBA palette from.
+@param buffer A pointer to the buffer to store the RGBA palette.
+@return A pointer to the newly created RGBA palette or NULL, if the specified
+bitmap is no palletized standard bitmap. If non-NULL, the returned value is
+actually the pointer passed in parameter 'buffer'.
+*/
+static inline RGBQUAD *
+GetRGBAPalette(FIBITMAP *dib, RGBQUAD * const buffer) {
+ // clone the palette
+ const unsigned ncolors = FreeImage_GetColorsUsed(dib);
+ if (ncolors == 0) {
+ return NULL;
+ }
+ memcpy(buffer, FreeImage_GetPalette(dib), ncolors * sizeof(RGBQUAD));
+ // merge the transparency table
+ const unsigned ntransp = MIN(ncolors, FreeImage_GetTransparencyCount(dib));
+ const BYTE * const tt = FreeImage_GetTransparencyTable(dib);
+ for (unsigned i = 0; i < ntransp; i++) {
+ buffer[i].rgbReserved = tt[i];
+ }
+ for (unsigned i = ntransp; i < ncolors; i++) {
+ buffer[i].rgbReserved = 255;
+ }
+ return buffer;
+}
+
+// --------------------------------------------------------------------------
+
+CWeightsTable::CWeightsTable(CGenericFilter *pFilter, unsigned uDstSize, unsigned uSrcSize) {
+ double dWidth;
+ double dFScale;
+ const double dFilterWidth = pFilter->GetWidth();
+
+ // scale factor
+ const double dScale = double(uDstSize) / double(uSrcSize);
+
+ if(dScale < 1.0) {
+ // minification
+ dWidth = dFilterWidth / dScale;
+ dFScale = dScale;
+ } else {
+ // magnification
+ dWidth = dFilterWidth;
+ dFScale = 1.0;
+ }
+
+ // allocate a new line contributions structure
+ //
+ // window size is the number of sampled pixels
+ m_WindowSize = 2 * (int)ceil(dWidth) + 1;
+ // length of dst line (no. of rows / cols)
+ m_LineLength = uDstSize;
+
+ // allocate list of contributions
+ m_WeightTable = (Contribution*)malloc(m_LineLength * sizeof(Contribution));
+ for(unsigned u = 0; u < m_LineLength; u++) {
+ // allocate contributions for every pixel
+ m_WeightTable[u].Weights = (double*)malloc(m_WindowSize * sizeof(double));
+ }
+
+ // offset for discrete to continuous coordinate conversion
+ const double dOffset = (0.5 / dScale);
+
+ for(unsigned u = 0; u < m_LineLength; u++) {
+ // scan through line of contributions
+
+ // inverse mapping (discrete dst 'u' to continous src 'dCenter')
+ const double dCenter = (double)u / dScale + dOffset;
+
+ // find the significant edge points that affect the pixel
+ const int iLeft = MAX(0, (int)(dCenter - dWidth + 0.5));
+ const int iRight = MIN((int)(dCenter + dWidth + 0.5), int(uSrcSize));
+
+ m_WeightTable[u].Left = iLeft;
+ m_WeightTable[u].Right = iRight;
+
+ double dTotalWeight = 0; // sum of weights (initialized to zero)
+ for(int iSrc = iLeft; iSrc < iRight; iSrc++) {
+ // calculate weights
+ const double weight = dFScale * pFilter->Filter(dFScale * ((double)iSrc + 0.5 - dCenter));
+ // assert((iSrc-iLeft) < m_WindowSize);
+ m_WeightTable[u].Weights[iSrc-iLeft] = weight;
+ dTotalWeight += weight;
+ }
+ if((dTotalWeight > 0) && (dTotalWeight != 1)) {
+ // normalize weight of neighbouring points
+ for(int iSrc = iLeft; iSrc < iRight; iSrc++) {
+ // normalize point
+ m_WeightTable[u].Weights[iSrc-iLeft] /= dTotalWeight;
+ }
+ }
+
+ // simplify the filter, discarding null weights at the right
+ {
+ int iTrailing = iRight - iLeft - 1;
+ while(m_WeightTable[u].Weights[iTrailing] == 0) {
+ m_WeightTable[u].Right--;
+ iTrailing--;
+ if(m_WeightTable[u].Right == m_WeightTable[u].Left) {
+ break;
+ }
+ }
+
+ }
+
+ } // next dst pixel
+}
+
+CWeightsTable::~CWeightsTable() {
+ for(unsigned u = 0; u < m_LineLength; u++) {
+ // free contributions for every pixel
+ free(m_WeightTable[u].Weights);
+ }
+ // free list of pixels contributions
+ free(m_WeightTable);
+}
+
+// --------------------------------------------------------------------------
+
+FIBITMAP* CResizeEngine::scale(FIBITMAP *src, unsigned dst_width, unsigned dst_height, unsigned src_left, unsigned src_top, unsigned src_width, unsigned src_height, unsigned flags) {
+
+ const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(src);
+ const unsigned src_bpp = FreeImage_GetBPP(src);
+
+ // determine the image's color type
+ BOOL bIsGreyscale = FALSE;
+ FREE_IMAGE_COLOR_TYPE color_type;
+ if (src_bpp <= 8) {
+ color_type = GetExtendedColorType(src, &bIsGreyscale);
+ } else {
+ color_type = FIC_RGB;
+ }
+
+ // determine the required bit depth of the destination image
+ unsigned dst_bpp;
+ unsigned dst_bpp_s1 = 0;
+ if (color_type == FIC_PALETTE && !bIsGreyscale) {
+ // non greyscale FIC_PALETTE images require a high-color destination
+ // image (24- or 32-bits depending on the image's transparent state)
+ dst_bpp = FreeImage_IsTransparent(src) ? 32 : 24;
+ } else if (src_bpp <= 8) {
+ // greyscale images require an 8-bit destination image
+ // (or a 32-bit image if the image is transparent);
+ // however, if flag FI_RESCALE_TRUE_COLOR is set, we will return
+ // a true color (24 bpp) image
+ if (FreeImage_IsTransparent(src)) {
+ dst_bpp = 32;
+ // additionally, for transparent images we always need a
+ // palette including transparency information (an RGBA palette)
+ // so, set color_type accordingly
+ color_type = FIC_PALETTE;
+ } else {
+ dst_bpp = ((flags & FI_RESCALE_TRUE_COLOR) == FI_RESCALE_TRUE_COLOR) ? 24 : 8;
+ // in any case, we use a fast 8-bit temporary image for the
+ // first filter operation (stage 1, either horizontal or
+ // vertical) and implicitly convert to 24 bpp (if requested
+ // by flag FI_RESCALE_TRUE_COLOR) during the second filter
+ // operation
+ dst_bpp_s1 = 8;
+ }
+ } else if (src_bpp == 16 && image_type == FIT_BITMAP) {
+ // 16-bit 555 and 565 RGB images require a high-color destination
+ // image (fixed to 24 bits, since 16-bit RGBs don't support
+ // transparency in FreeImage)
+ dst_bpp = 24;
+ } else {
+ // bit depth remains unchanged for all other images
+ dst_bpp = src_bpp;
+ }
+
+ // make 'stage 1' bpp a copy of the destination bpp if it
+ // was not explicitly set
+ if (dst_bpp_s1 == 0) {
+ dst_bpp_s1 = dst_bpp;
+ }
+
+ // early exit if destination size is equal to source size
+ if ((src_width == dst_width) && (src_height == dst_height)) {
+ FIBITMAP *out = src;
+ FIBITMAP *tmp = src;
+ if ((src_width != FreeImage_GetWidth(src)) || (src_height != FreeImage_GetHeight(src))) {
+ out = FreeImage_Copy(tmp, src_left, src_top, src_left + src_width, src_top + src_height);
+ tmp = out;
+ }
+ if (src_bpp != dst_bpp) {
+ switch (dst_bpp) {
+ case 8:
+ out = FreeImage_ConvertToGreyscale(tmp);
+ break;
+ case 24:
+ out = FreeImage_ConvertTo24Bits(tmp);
+ break;
+ case 32:
+ out = FreeImage_ConvertTo32Bits(tmp);
+ break;
+ default:
+ break;
+ }
+ if (tmp != src) {
+ FreeImage_Unload(tmp);
+ tmp = NULL;
+ }
+ }
+
+ return (out != src) ? out : FreeImage_Clone(src);
+ }
+
+ RGBQUAD pal_buffer[256];
+ RGBQUAD *src_pal = NULL;
+
+ // provide the source image's palette to the rescaler for
+ // FIC_PALETTE type images (this includes palletized greyscale
+ // images with an unordered palette as well as transparent images)
+ if (color_type == FIC_PALETTE) {
+ if (dst_bpp == 32) {
+ // a 32-bit destination image signals transparency, so
+ // create an RGBA palette from the source palette
+ src_pal = GetRGBAPalette(src, pal_buffer);
+ } else {
+ src_pal = FreeImage_GetPalette(src);
+ }
+ }
+
+ // allocate the dst image
+ FIBITMAP *dst = FreeImage_AllocateT(image_type, dst_width, dst_height, dst_bpp, 0, 0, 0);
+ if (!dst) {
+ return NULL;
+ }
+
+ if (dst_bpp == 8) {
+ RGBQUAD * const dst_pal = FreeImage_GetPalette(dst);
+ if (color_type == FIC_MINISWHITE) {
+ // build an inverted greyscale palette
+ CREATE_GREYSCALE_PALETTE_REVERSE(dst_pal, 256);
+ }
+ /*
+ else {
+ // build a default greyscale palette
+ // Currently, FreeImage_AllocateT already creates a default
+ // greyscale palette for 8 bpp images, so we can skip this here.
+ CREATE_GREYSCALE_PALETTE(dst_pal, 256);
+ }
+ */
+ }
+
+ // calculate x and y offsets; since FreeImage uses bottom-up bitmaps, the
+ // value of src_offset_y is measured from the bottom of the image
+ unsigned src_offset_x = src_left;
+ unsigned src_offset_y = FreeImage_GetHeight(src) - src_height - src_top;
+
+ /*
+ Decide which filtering order (xy or yx) is faster for this mapping.
+ --- The theory ---
+ Try to minimize calculations by counting the number of convolution multiplies
+ if(dst_width*src_height <= src_width*dst_height) {
+ // xy filtering
+ } else {
+ // yx filtering
+ }
+ --- The practice ---
+ Try to minimize calculations by counting the number of vertical convolutions (the most time consuming task)
+ if(dst_width*dst_height <= src_width*dst_height) {
+ // xy filtering
+ } else {
+ // yx filtering
+ }
+ */
+
+ if (dst_width <= src_width) {
+ // xy filtering
+ // -------------
+
+ FIBITMAP *tmp = NULL;
+
+ if (src_width != dst_width) {
+ // source and destination widths are different so, we must
+ // filter horizontally
+ if (src_height != dst_height) {
+ // source and destination heights are also different so, we need
+ // a temporary image
+ tmp = FreeImage_AllocateT(image_type, dst_width, src_height, dst_bpp_s1, 0, 0, 0);
+ if (!tmp) {
+ FreeImage_Unload(dst);
+ return NULL;
+ }
+ } else {
+ // source and destination heights are equal so, we can directly
+ // scale into destination image (second filter method will not
+ // be invoked)
+ tmp = dst;
+ }
+
+ // scale source image horizontally into temporary (or destination) image
+ horizontalFilter(src, src_height, src_width, src_offset_x, src_offset_y, src_pal, tmp, dst_width);
+
+ // set x and y offsets to zero for the second filter method
+ // invocation (the temporary image only contains the portion of
+ // the image to be rescaled with no offsets)
+ src_offset_x = 0;
+ src_offset_y = 0;
+
+ // also ensure, that the second filter method gets no source
+ // palette (the temporary image is palletized only, if it is
+ // greyscale; in that case, it is an 8-bit image with a linear
+ // palette so, the source palette is not needed or will even be
+ // mismatching, if the source palette is unordered)
+ src_pal = NULL;
+ } else {
+ // source and destination widths are equal so, just copy the
+ // image pointer
+ tmp = src;
+ }
+
+ if (src_height != dst_height) {
+ // source and destination heights are different so, scale
+ // temporary (or source) image vertically into destination image
+ verticalFilter(tmp, dst_width, src_height, src_offset_x, src_offset_y, src_pal, dst, dst_height);
+ }
+
+ // free temporary image, if not pointing to either src or dst
+ if (tmp != src && tmp != dst) {
+ FreeImage_Unload(tmp);
+ }
+
+ } else {
+ // yx filtering
+ // -------------
+
+ // Remark:
+ // The yx filtering branch could be more optimized by taking into,
+ // account that (src_width != dst_width) is always true, which
+ // follows from the above condition, which selects filtering order.
+ // Since (dst_width <= src_width) == TRUE selects xy filtering,
+ // both widths must be different when performing yx filtering.
+ // However, to make the code more robust, not depending on that
+ // condition and more symmetric to the xy filtering case, these
+ // (src_width != dst_width) conditions are still in place.
+
+ FIBITMAP *tmp = NULL;
+
+ if (src_height != dst_height) {
+ // source and destination heights are different so, we must
+ // filter vertically
+ if (src_width != dst_width) {
+ // source and destination widths are also different so, we need
+ // a temporary image
+ tmp = FreeImage_AllocateT(image_type, src_width, dst_height, dst_bpp_s1, 0, 0, 0);
+ if (!tmp) {
+ FreeImage_Unload(dst);
+ return NULL;
+ }
+ } else {
+ // source and destination widths are equal so, we can directly
+ // scale into destination image (second filter method will not
+ // be invoked)
+ tmp = dst;
+ }
+
+ // scale source image vertically into temporary (or destination) image
+ verticalFilter(src, src_width, src_height, src_offset_x, src_offset_y, src_pal, tmp, dst_height);
+
+ // set x and y offsets to zero for the second filter method
+ // invocation (the temporary image only contains the portion of
+ // the image to be rescaled with no offsets)
+ src_offset_x = 0;
+ src_offset_y = 0;
+
+ // also ensure, that the second filter method gets no source
+ // palette (the temporary image is palletized only, if it is
+ // greyscale; in that case, it is an 8-bit image with a linear
+ // palette so, the source palette is not needed or will even be
+ // mismatching, if the source palette is unordered)
+ src_pal = NULL;
+
+ } else {
+ // source and destination heights are equal so, just copy the
+ // image pointer
+ tmp = src;
+ }
+
+ if (src_width != dst_width) {
+ // source and destination heights are different so, scale
+ // temporary (or source) image horizontally into destination image
+ horizontalFilter(tmp, dst_height, src_width, src_offset_x, src_offset_y, src_pal, dst, dst_width);
+ }
+
+ // free temporary image, if not pointing to either src or dst
+ if (tmp != src && tmp != dst) {
+ FreeImage_Unload(tmp);
+ }
+ }
+
+ return dst;
+}
+
+void CResizeEngine::horizontalFilter(FIBITMAP *const src, unsigned height, unsigned src_width, unsigned src_offset_x, unsigned src_offset_y, const RGBQUAD *const src_pal, FIBITMAP *const dst, unsigned dst_width) {
+
+ // allocate and calculate the contributions
+ CWeightsTable weightsTable(m_pFilter, dst_width, src_width);
+
+ // step through rows
+ switch(FreeImage_GetImageType(src)) {
+ case FIT_BITMAP:
+ {
+ switch(FreeImage_GetBPP(src)) {
+ case 1:
+ {
+ switch(FreeImage_GetBPP(dst)) {
+ case 8:
+ {
+ // transparently convert the 1-bit non-transparent greyscale image to 8 bpp
+ src_offset_x >>= 3;
+ if (src_pal) {
+ // we have got a palette
+ for (unsigned y = 0; y < height; y++) {
+ // scale each row
+ const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
+ BYTE * const dst_bits = FreeImage_GetScanLine(dst, y);
+
+ for (unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
+ double value = 0;
+
+ for (unsigned i = iLeft; i < iRight; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const unsigned pixel = (src_bits[i >> 3] & (0x80 >> (i & 0x07))) != 0;
+ value += (weightsTable.getWeight(x, i - iLeft) * (double)*(BYTE *)&src_pal[pixel]);
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[x] = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
+ }
+ }
+ } else {
+ // we do not have a palette
+ for (unsigned y = 0; y < height; y++) {
+ // scale each row
+ const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
+ BYTE * const dst_bits = FreeImage_GetScanLine(dst, y);
+
+ for (unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
+ double value = 0;
+
+ for (unsigned i = iLeft; i < iRight; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const unsigned pixel = (src_bits[i >> 3] & (0x80 >> (i & 0x07))) != 0;
+ value += (weightsTable.getWeight(x, i - iLeft) * (double)pixel);
+ }
+ value *= 0xFF;
+
+ // clamp and place result in destination pixel
+ dst_bits[x] = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
+ }
+ }
+ }
+ }
+ break;
+
+ case 24:
+ {
+ // transparently convert the non-transparent 1-bit image to 24 bpp
+ src_offset_x >>= 3;
+ if (src_pal) {
+ // we have got a palette
+ for (unsigned y = 0; y < height; y++) {
+ // scale each row
+ const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
+ BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
+
+ for (unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
+ double r = 0, g = 0, b = 0;
+
+ for (unsigned i = iLeft; i < iRight; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(x, i - iLeft);
+ const unsigned pixel = (src_bits[i >> 3] & (0x80 >> (i & 0x07))) != 0;
+ const BYTE * const entry = (BYTE *)&src_pal[pixel];
+ r += (weight * (double)entry[FI_RGBA_RED]);
+ g += (weight * (double)entry[FI_RGBA_GREEN]);
+ b += (weight * (double)entry[FI_RGBA_BLUE]);
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
+ dst_bits += 3;
+ }
+ }
+ } else {
+ // we do not have a palette
+ for (unsigned y = 0; y < height; y++) {
+ // scale each row
+ const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
+ BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
+
+ for (unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
+ double value = 0;
+
+ for (unsigned i = iLeft; i < iRight; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const unsigned pixel = (src_bits[i >> 3] & (0x80 >> (i & 0x07))) != 0;
+ value += (weightsTable.getWeight(x, i - iLeft) * (double)pixel);
+ }
+ value *= 0xFF;
+
+ // clamp and place result in destination pixel
+ const BYTE bval = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_RED] = bval;
+ dst_bits[FI_RGBA_GREEN] = bval;
+ dst_bits[FI_RGBA_BLUE] = bval;
+ dst_bits += 3;
+ }
+ }
+ }
+ }
+ break;
+
+ case 32:
+ {
+ // transparently convert the transparent 1-bit image to 32 bpp;
+ // we always have got a palette here
+ src_offset_x >>= 3;
+
+ for (unsigned y = 0; y < height; y++) {
+ // scale each row
+ const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
+ BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
+
+ for (unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
+ double r = 0, g = 0, b = 0, a = 0;
+
+ for (unsigned i = iLeft; i < iRight; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(x, i - iLeft);
+ const unsigned pixel = (src_bits[i >> 3] & (0x80 >> (i & 0x07))) != 0;
+ const BYTE * const entry = (BYTE *)&src_pal[pixel];
+ r += (weight * (double)entry[FI_RGBA_RED]);
+ g += (weight * (double)entry[FI_RGBA_GREEN]);
+ b += (weight * (double)entry[FI_RGBA_BLUE]);
+ a += (weight * (double)entry[FI_RGBA_ALPHA]);
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_ALPHA] = (BYTE)CLAMP<int>((int)(a + 0.5), 0, 0xFF);
+ dst_bits += 4;
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ case 4:
+ {
+ switch(FreeImage_GetBPP(dst)) {
+ case 8:
+ {
+ // transparently convert the non-transparent 4-bit greyscale image to 8 bpp;
+ // we always have got a palette for 4-bit images
+ src_offset_x >>= 1;
+
+ for (unsigned y = 0; y < height; y++) {
+ // scale each row
+ const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
+ BYTE * const dst_bits = FreeImage_GetScanLine(dst, y);
+
+ for (unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
+ double value = 0;
+
+ for (unsigned i = iLeft; i < iRight; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const unsigned pixel = i & 0x01 ? src_bits[i >> 1] & 0x0F : src_bits[i >> 1] >> 4;
+ value += (weightsTable.getWeight(x, i - iLeft) * (double)*(BYTE *)&src_pal[pixel]);
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[x] = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
+ }
+ }
+ }
+ break;
+
+ case 24:
+ {
+ // transparently convert the non-transparent 4-bit image to 24 bpp;
+ // we always have got a palette for 4-bit images
+ src_offset_x >>= 1;
+
+ for (unsigned y = 0; y < height; y++) {
+ // scale each row
+ const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
+ BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
+
+ for (unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
+ double r = 0, g = 0, b = 0;
+
+ for (unsigned i = iLeft; i < iRight; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(x, i - iLeft);
+ const unsigned pixel = i & 0x01 ? src_bits[i >> 1] & 0x0F : src_bits[i >> 1] >> 4;
+ const BYTE * const entry = (BYTE *)&src_pal[pixel];
+ r += (weight * (double)entry[FI_RGBA_RED]);
+ g += (weight * (double)entry[FI_RGBA_GREEN]);
+ b += (weight * (double)entry[FI_RGBA_BLUE]);
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
+ dst_bits += 3;
+ }
+ }
+ }
+ break;
+
+ case 32:
+ {
+ // transparently convert the transparent 4-bit image to 32 bpp;
+ // we always have got a palette for 4-bit images
+ src_offset_x >>= 1;
+
+ for (unsigned y = 0; y < height; y++) {
+ // scale each row
+ const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
+ BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
+
+ for (unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
+ double r = 0, g = 0, b = 0, a = 0;
+
+ for (unsigned i = iLeft; i < iRight; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(x, i - iLeft);
+ const unsigned pixel = i & 0x01 ? src_bits[i >> 1] & 0x0F : src_bits[i >> 1] >> 4;
+ const BYTE * const entry = (BYTE *)&src_pal[pixel];
+ r += (weight * (double)entry[FI_RGBA_RED]);
+ g += (weight * (double)entry[FI_RGBA_GREEN]);
+ b += (weight * (double)entry[FI_RGBA_BLUE]);
+ a += (weight * (double)entry[FI_RGBA_ALPHA]);
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_ALPHA] = (BYTE)CLAMP<int>((int)(a + 0.5), 0, 0xFF);
+ dst_bits += 4;
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ case 8:
+ {
+ switch(FreeImage_GetBPP(dst)) {
+ case 8:
+ {
+ // scale the 8-bit non-transparent greyscale image
+ // into an 8 bpp destination image
+ if (src_pal) {
+ // we have got a palette
+ for (unsigned y = 0; y < height; y++) {
+ // scale each row
+ const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
+ BYTE * const dst_bits = FreeImage_GetScanLine(dst, y);
+
+ for (unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
+ const BYTE * const pixel = src_bits + iLeft;
+ double value = 0;
+
+ // for(i = iLeft to iRight)
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ value += (weightsTable.getWeight(x, i) * (double)*(BYTE *)&src_pal[pixel[i]]);
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[x] = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
+ }
+ }
+ } else {
+ // we do not have a palette
+ for (unsigned y = 0; y < height; y++) {
+ // scale each row
+ const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
+ BYTE * const dst_bits = FreeImage_GetScanLine(dst, y);
+
+ for (unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
+ const BYTE * const pixel = src_bits + iLeft;
+ double value = 0;
+
+ // for(i = iLeft to iRight)
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ value += (weightsTable.getWeight(x, i) * (double)pixel[i]);
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[x] = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
+ }
+ }
+ }
+ }
+ break;
+
+ case 24:
+ {
+ // transparently convert the non-transparent 8-bit image to 24 bpp
+ if (src_pal) {
+ // we have got a palette
+ for (unsigned y = 0; y < height; y++) {
+ // scale each row
+ const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
+ BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
+
+ for (unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
+ const BYTE * const pixel = src_bits + iLeft;
+ double r = 0, g = 0, b = 0;
+
+ // for(i = iLeft to iRight)
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(x, i);
+ const BYTE *const entry = (BYTE *)&src_pal[pixel[i]];
+ r += (weight * (double)entry[FI_RGBA_RED]);
+ g += (weight * (double)entry[FI_RGBA_GREEN]);
+ b += (weight * (double)entry[FI_RGBA_BLUE]);
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
+ dst_bits += 3;
+ }
+ }
+ } else {
+ // we do not have a palette
+ for (unsigned y = 0; y < height; y++) {
+ // scale each row
+ const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
+ BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
+
+ for (unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
+ const BYTE * const pixel = src_bits + iLeft;
+ double value = 0;
+
+ // for(i = iLeft to iRight)
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(x, i);
+ value += (weight * (double)pixel[i]);
+ }
+
+ // clamp and place result in destination pixel
+ const BYTE bval = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_RED] = bval;
+ dst_bits[FI_RGBA_GREEN] = bval;
+ dst_bits[FI_RGBA_BLUE] = bval;
+ dst_bits += 3;
+ }
+ }
+ }
+ }
+ break;
+
+ case 32:
+ {
+ // transparently convert the transparent 8-bit image to 32 bpp;
+ // we always have got a palette here
+ for (unsigned y = 0; y < height; y++) {
+ // scale each row
+ const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
+ BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
+
+ for (unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
+ const BYTE * const pixel = src_bits + iLeft;
+ double r = 0, g = 0, b = 0, a = 0;
+
+ // for(i = iLeft to iRight)
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(x, i);
+ const BYTE * const entry = (BYTE *)&src_pal[pixel[i]];
+ r += (weight * (double)entry[FI_RGBA_RED]);
+ g += (weight * (double)entry[FI_RGBA_GREEN]);
+ b += (weight * (double)entry[FI_RGBA_BLUE]);
+ a += (weight * (double)entry[FI_RGBA_ALPHA]);
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_ALPHA] = (BYTE)CLAMP<int>((int)(a + 0.5), 0, 0xFF);
+ dst_bits += 4;
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ case 16:
+ {
+ // transparently convert the 16-bit non-transparent image to 24 bpp
+ if (IS_FORMAT_RGB565(src)) {
+ // image has 565 format
+ for (unsigned y = 0; y < height; y++) {
+ // scale each row
+ const WORD * const src_bits = (WORD *)FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x / sizeof(WORD);
+ BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
+
+ for (unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
+ const WORD *pixel = src_bits + iLeft;
+ double r = 0, g = 0, b = 0;
+
+ // for(i = iLeft to iRight)
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(x, i);
+ r += (weight * (double)((*pixel & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT));
+ g += (weight * (double)((*pixel & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT));
+ b += (weight * (double)((*pixel & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT));
+ pixel++;
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(((r * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(((g * 0xFF) / 0x3F) + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(((b * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
+ dst_bits += 3;
+ }
+ }
+ } else {
+ // image has 555 format
+ for (unsigned y = 0; y < height; y++) {
+ // scale each row
+ const WORD * const src_bits = (WORD *)FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x;
+ BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
+
+ for (unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
+ const WORD *pixel = src_bits + iLeft;
+ double r = 0, g = 0, b = 0;
+
+ // for(i = iLeft to iRight)
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(x, i);
+ r += (weight * (double)((*pixel & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT));
+ g += (weight * (double)((*pixel & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT));
+ b += (weight * (double)((*pixel & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT));
+ pixel++;
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(((r * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(((g * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(((b * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
+ dst_bits += 3;
+ }
+ }
+ }
+ }
+ break;
+
+ case 24:
+ {
+ // scale the 24-bit non-transparent image into a 24 bpp destination image
+ for (unsigned y = 0; y < height; y++) {
+ // scale each row
+ const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x * 3;
+ BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
+
+ for (unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
+ const BYTE * pixel = src_bits + iLeft * 3;
+ double r = 0, g = 0, b = 0;
+
+ // for(i = iLeft to iRight)
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(x, i);
+ r += (weight * (double)pixel[FI_RGBA_RED]);
+ g += (weight * (double)pixel[FI_RGBA_GREEN]);
+ b += (weight * (double)pixel[FI_RGBA_BLUE]);
+ pixel += 3;
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
+ dst_bits += 3;
+ }
+ }
+ }
+ break;
+
+ case 32:
+ {
+ // scale the 32-bit transparent image into a 32 bpp destination image
+ for (unsigned y = 0; y < height; y++) {
+ // scale each row
+ const BYTE * const src_bits = FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x * 4;
+ BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
+
+ for (unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
+ const BYTE *pixel = src_bits + iLeft * 4;
+ double r = 0, g = 0, b = 0, a = 0;
+
+ // for(i = iLeft to iRight)
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(x, i);
+ r += (weight * (double)pixel[FI_RGBA_RED]);
+ g += (weight * (double)pixel[FI_RGBA_GREEN]);
+ b += (weight * (double)pixel[FI_RGBA_BLUE]);
+ a += (weight * (double)pixel[FI_RGBA_ALPHA]);
+ pixel += 4;
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_ALPHA] = (BYTE)CLAMP<int>((int)(a + 0.5), 0, 0xFF);
+ dst_bits += 4;
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ case FIT_UINT16:
+ {
+ // Calculate the number of words per pixel (1 for 16-bit, 3 for 48-bit or 4 for 64-bit)
+ const unsigned wordspp = (FreeImage_GetLine(src) / src_width) / sizeof(WORD);
+
+ for (unsigned y = 0; y < height; y++) {
+ // scale each row
+ const WORD *src_bits = (WORD*)FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x / sizeof(WORD);
+ WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y);
+
+ for (unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
+ const WORD *pixel = src_bits + iLeft * wordspp;
+ double value = 0;
+
+ // for(i = iLeft to iRight)
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(x, i);
+ value += (weight * (double)pixel[0]);
+ pixel++;
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[0] = (WORD)CLAMP<int>((int)(value + 0.5), 0, 0xFFFF);
+ dst_bits += wordspp;
+ }
+ }
+ }
+ break;
+
+ case FIT_RGB16:
+ {
+ // Calculate the number of words per pixel (1 for 16-bit, 3 for 48-bit or 4 for 64-bit)
+ const unsigned wordspp = (FreeImage_GetLine(src) / src_width) / sizeof(WORD);
+
+ for (unsigned y = 0; y < height; y++) {
+ // scale each row
+ const WORD *src_bits = (WORD*)FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x / sizeof(WORD);
+ WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y);
+
+ for (unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
+ const WORD *pixel = src_bits + iLeft * wordspp;
+ double r = 0, g = 0, b = 0;
+
+ // for(i = iLeft to iRight)
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(x, i);
+ r += (weight * (double)pixel[0]);
+ g += (weight * (double)pixel[1]);
+ b += (weight * (double)pixel[2]);
+ pixel += wordspp;
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[0] = (WORD)CLAMP<int>((int)(r + 0.5), 0, 0xFFFF);
+ dst_bits[1] = (WORD)CLAMP<int>((int)(g + 0.5), 0, 0xFFFF);
+ dst_bits[2] = (WORD)CLAMP<int>((int)(b + 0.5), 0, 0xFFFF);
+ dst_bits += wordspp;
+ }
+ }
+ }
+ break;
+
+ case FIT_RGBA16:
+ {
+ // Calculate the number of words per pixel (1 for 16-bit, 3 for 48-bit or 4 for 64-bit)
+ const unsigned wordspp = (FreeImage_GetLine(src) / src_width) / sizeof(WORD);
+
+ for (unsigned y = 0; y < height; y++) {
+ // scale each row
+ const WORD *src_bits = (WORD*)FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x / sizeof(WORD);
+ WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y);
+
+ for (unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(x) - iLeft; // retrieve right boundary
+ const WORD *pixel = src_bits + iLeft * wordspp;
+ double r = 0, g = 0, b = 0, a = 0;
+
+ // for(i = iLeft to iRight)
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(x, i);
+ r += (weight * (double)pixel[0]);
+ g += (weight * (double)pixel[1]);
+ b += (weight * (double)pixel[2]);
+ a += (weight * (double)pixel[3]);
+ pixel += wordspp;
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[0] = (WORD)CLAMP<int>((int)(r + 0.5), 0, 0xFFFF);
+ dst_bits[1] = (WORD)CLAMP<int>((int)(g + 0.5), 0, 0xFFFF);
+ dst_bits[2] = (WORD)CLAMP<int>((int)(b + 0.5), 0, 0xFFFF);
+ dst_bits[3] = (WORD)CLAMP<int>((int)(a + 0.5), 0, 0xFFFF);
+ dst_bits += wordspp;
+ }
+ }
+ }
+ break;
+
+ case FIT_FLOAT:
+ case FIT_RGBF:
+ case FIT_RGBAF:
+ {
+ // Calculate the number of floats per pixel (1 for 32-bit, 3 for 96-bit or 4 for 128-bit)
+ const unsigned floatspp = (FreeImage_GetLine(src) / src_width) / sizeof(float);
+
+ for(unsigned y = 0; y < height; y++) {
+ // scale each row
+ const float *src_bits = (float*)FreeImage_GetScanLine(src, y + src_offset_y) + src_offset_x / sizeof(float);
+ float *dst_bits = (float*)FreeImage_GetScanLine(dst, y);
+
+ for(unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
+ double value[4] = {0, 0, 0, 0}; // 4 = 128 bpp max
+
+ for(unsigned i = iLeft; i < iRight; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(x, i-iLeft);
+
+ unsigned index = i * floatspp; // pixel index
+ for (unsigned j = 0; j < floatspp; j++) {
+ value[j] += (weight * (double)src_bits[index++]);
+ }
+ }
+
+ // place result in destination pixel
+ for (unsigned j = 0; j < floatspp; j++) {
+ dst_bits[j] = (float)value[j];
+ }
+
+ dst_bits += floatspp;
+ }
+ }
+ }
+ break;
+ }
+}
+
+/// Performs vertical image filtering
+void CResizeEngine::verticalFilter(FIBITMAP *const src, unsigned width, unsigned src_height, unsigned src_offset_x, unsigned src_offset_y, const RGBQUAD *const src_pal, FIBITMAP *const dst, unsigned dst_height) {
+
+ // allocate and calculate the contributions
+ CWeightsTable weightsTable(m_pFilter, dst_height, src_height);
+
+ // step through columns
+ switch(FreeImage_GetImageType(src)) {
+ case FIT_BITMAP:
+ {
+ const unsigned dst_pitch = FreeImage_GetPitch(dst);
+ BYTE * const dst_base = FreeImage_GetBits(dst);
+
+ switch(FreeImage_GetBPP(src)) {
+ case 1:
+ {
+ const unsigned src_pitch = FreeImage_GetPitch(src);
+ const BYTE * const src_base = FreeImage_GetBits(src) + src_offset_y * src_pitch + (src_offset_x >> 3);
+
+ switch(FreeImage_GetBPP(dst)) {
+ case 8:
+ {
+ // transparently convert the 1-bit non-transparent greyscale image to 8 bpp
+ if (src_pal) {
+ // we have got a palette
+ for (unsigned x = 0; x < width; x++) {
+ // work on column x in dst
+ BYTE *dst_bits = dst_base + x;
+ const unsigned index = x >> 3;
+ const unsigned mask = 0x80 >> (x & 0x07);
+
+ // scale each column
+ for (unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
+ const BYTE *src_bits = src_base + iLeft * src_pitch + index;
+ double value = 0;
+
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const unsigned pixel = (*src_bits & mask) != 0;
+ value += (weightsTable.getWeight(y, i) * (double)*(BYTE *)&src_pal[pixel]);
+ src_bits += src_pitch;
+ }
+ value *= 0xFF;
+
+ // clamp and place result in destination pixel
+ *dst_bits = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
+ dst_bits += dst_pitch;
+ }
+ }
+ } else {
+ // we do not have a palette
+ for (unsigned x = 0; x < width; x++) {
+ // work on column x in dst
+ BYTE *dst_bits = dst_base + x;
+ const unsigned index = x >> 3;
+ const unsigned mask = 0x80 >> (x & 0x07);
+
+ // scale each column
+ for (unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
+ const BYTE *src_bits = src_base + iLeft * src_pitch + index;
+ double value = 0;
+
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ value += (weightsTable.getWeight(y, i) * (double)((*src_bits & mask) != 0));
+ src_bits += src_pitch;
+ }
+ value *= 0xFF;
+
+ // clamp and place result in destination pixel
+ *dst_bits = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
+ dst_bits += dst_pitch;
+ }
+ }
+ }
+ }
+ break;
+
+ case 24:
+ {
+ // transparently convert the non-transparent 1-bit image to 24 bpp
+ if (src_pal) {
+ // we have got a palette
+ for (unsigned x = 0; x < width; x++) {
+ // work on column x in dst
+ BYTE *dst_bits = dst_base + x * 3;
+ const unsigned index = x >> 3;
+ const unsigned mask = 0x80 >> (x & 0x07);
+
+ // scale each column
+ for (unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
+ const BYTE *src_bits = src_base + iLeft * src_pitch + index;
+ double r = 0, g = 0, b = 0;
+
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(y, i);
+ const unsigned pixel = (*src_bits & mask) != 0;
+ const BYTE * const entry = (BYTE *)&src_pal[pixel];
+ r += (weight * (double)entry[FI_RGBA_RED]);
+ g += (weight * (double)entry[FI_RGBA_GREEN]);
+ b += (weight * (double)entry[FI_RGBA_BLUE]);
+ src_bits += src_pitch;
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
+ dst_bits += dst_pitch;
+ }
+ }
+ } else {
+ // we do not have a palette
+ for (unsigned x = 0; x < width; x++) {
+ // work on column x in dst
+ BYTE *dst_bits = dst_base + x * 3;
+ const unsigned index = x >> 3;
+ const unsigned mask = 0x80 >> (x & 0x07);
+
+ // scale each column
+ for (unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
+ const BYTE *src_bits = src_base + iLeft * src_pitch + index;
+ double value = 0;
+
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ value += (weightsTable.getWeight(y, i) * (double)((*src_bits & mask) != 0));
+ src_bits += src_pitch;
+ }
+ value *= 0xFF;
+
+ // clamp and place result in destination pixel
+ const BYTE bval = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_RED] = bval;
+ dst_bits[FI_RGBA_GREEN] = bval;
+ dst_bits[FI_RGBA_BLUE] = bval;
+ dst_bits += dst_pitch;
+ }
+ }
+ }
+ }
+ break;
+
+ case 32:
+ {
+ // transparently convert the transparent 1-bit image to 32 bpp;
+ // we always have got a palette here
+ for (unsigned x = 0; x < width; x++) {
+ // work on column x in dst
+ BYTE *dst_bits = dst_base + x * 4;
+ const unsigned index = x >> 3;
+ const unsigned mask = 0x80 >> (x & 0x07);
+
+ // scale each column
+ for (unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
+ const BYTE *src_bits = src_base + iLeft * src_pitch + index;
+ double r = 0, g = 0, b = 0, a = 0;
+
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(y, i);
+ const unsigned pixel = (*src_bits & mask) != 0;
+ const BYTE * const entry = (BYTE *)&src_pal[pixel];
+ r += (weight * (double)entry[FI_RGBA_RED]);
+ g += (weight * (double)entry[FI_RGBA_GREEN]);
+ b += (weight * (double)entry[FI_RGBA_BLUE]);
+ a += (weight * (double)entry[FI_RGBA_ALPHA]);
+ src_bits += src_pitch;
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_ALPHA] = (BYTE)CLAMP<int>((int)(a + 0.5), 0, 0xFF);
+ dst_bits += dst_pitch;
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ case 4:
+ {
+ const unsigned src_pitch = FreeImage_GetPitch(src);
+ const BYTE *const src_base = FreeImage_GetBits(src) + src_offset_y * src_pitch + (src_offset_x >> 1);
+
+ switch(FreeImage_GetBPP(dst)) {
+ case 8:
+ {
+ // transparently convert the non-transparent 4-bit greyscale image to 8 bpp;
+ // we always have got a palette for 4-bit images
+ for (unsigned x = 0; x < width; x++) {
+ // work on column x in dst
+ BYTE *dst_bits = dst_base + x;
+ const unsigned index = x >> 1;
+
+ // scale each column
+ for (unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
+ const BYTE *src_bits = src_base + iLeft * src_pitch + index;
+ double value = 0;
+
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const unsigned pixel = x & 0x01 ? *src_bits & 0x0F : *src_bits >> 4;
+ value += (weightsTable.getWeight(y, i) * (double)*(BYTE *)&src_pal[pixel]);
+ src_bits += src_pitch;
+ }
+
+ // clamp and place result in destination pixel
+ *dst_bits = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
+ dst_bits += dst_pitch;
+ }
+ }
+ }
+ break;
+
+ case 24:
+ {
+ // transparently convert the non-transparent 4-bit image to 24 bpp;
+ // we always have got a palette for 4-bit images
+ for (unsigned x = 0; x < width; x++) {
+ // work on column x in dst
+ BYTE *dst_bits = dst_base + x * 3;
+ const unsigned index = x >> 1;
+
+ // scale each column
+ for (unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
+ const BYTE *src_bits = src_base + iLeft * src_pitch + index;
+ double r = 0, g = 0, b = 0;
+
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(y, i);
+ const unsigned pixel = x & 0x01 ? *src_bits & 0x0F : *src_bits >> 4;
+ const BYTE *const entry = (BYTE *)&src_pal[pixel];
+ r += (weight * (double)entry[FI_RGBA_RED]);
+ g += (weight * (double)entry[FI_RGBA_GREEN]);
+ b += (weight * (double)entry[FI_RGBA_BLUE]);
+ src_bits += src_pitch;
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
+ dst_bits += dst_pitch;
+ }
+ }
+ }
+ break;
+
+ case 32:
+ {
+ // transparently convert the transparent 4-bit image to 32 bpp;
+ // we always have got a palette for 4-bit images
+ for (unsigned x = 0; x < width; x++) {
+ // work on column x in dst
+ BYTE *dst_bits = dst_base + x * 4;
+ const unsigned index = x >> 1;
+
+ // scale each column
+ for (unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
+ const BYTE *src_bits = src_base + iLeft * src_pitch + index;
+ double r = 0, g = 0, b = 0, a = 0;
+
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(y, i);
+ const unsigned pixel = x & 0x01 ? *src_bits & 0x0F : *src_bits >> 4;
+ const BYTE *const entry = (BYTE *)&src_pal[pixel];
+ r += (weight * (double)entry[FI_RGBA_RED]);
+ g += (weight * (double)entry[FI_RGBA_GREEN]);
+ b += (weight * (double)entry[FI_RGBA_BLUE]);
+ a += (weight * (double)entry[FI_RGBA_ALPHA]);
+ src_bits += src_pitch;
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_ALPHA] = (BYTE)CLAMP<int>((int)(a + 0.5), 0, 0xFF);
+ dst_bits += dst_pitch;
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ case 8:
+ {
+ const unsigned src_pitch = FreeImage_GetPitch(src);
+ const BYTE *const src_base = FreeImage_GetBits(src) + src_offset_y * src_pitch + src_offset_x;
+
+ switch(FreeImage_GetBPP(dst)) {
+ case 8:
+ {
+ // scale the 8-bit non-transparent greyscale image into an 8 bpp destination image
+ if (src_pal) {
+ // we have got a palette
+ for (unsigned x = 0; x < width; x++) {
+ // work on column x in dst
+ BYTE *dst_bits = dst_base + x;
+
+ // scale each column
+ for (unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
+ const BYTE *src_bits = src_base + iLeft * src_pitch + x;
+ double value = 0;
+
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ value += (weightsTable.getWeight(y, i) * (double)*(BYTE *)&src_pal[*src_bits]);
+ src_bits += src_pitch;
+ }
+
+ // clamp and place result in destination pixel
+ *dst_bits = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
+ dst_bits += dst_pitch;
+ }
+ }
+ } else {
+ // we do not have a palette
+ for (unsigned x = 0; x < width; x++) {
+ // work on column x in dst
+ BYTE *dst_bits = dst_base + x;
+
+ // scale each column
+ for (unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
+ const BYTE *src_bits = src_base + iLeft * src_pitch + x;
+ double value = 0;
+
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ value += (weightsTable.getWeight(y, i) * (double)*src_bits);
+ src_bits += src_pitch;
+ }
+
+ // clamp and place result in destination pixel
+ *dst_bits = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
+ dst_bits += dst_pitch;
+ }
+ }
+ }
+ }
+ break;
+
+ case 24:
+ {
+ // transparently convert the non-transparent 8-bit image to 24 bpp
+ if (src_pal) {
+ // we have got a palette
+ for (unsigned x = 0; x < width; x++) {
+ // work on column x in dst
+ BYTE *dst_bits = dst_base + x * 3;
+
+ // scale each column
+ for (unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
+ const BYTE *src_bits = src_base + iLeft * src_pitch + x;
+ double r = 0, g = 0, b = 0;
+
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(y, i);
+ const BYTE * const entry = (BYTE *)&src_pal[*src_bits];
+ r += (weight * (double)entry[FI_RGBA_RED]);
+ g += (weight * (double)entry[FI_RGBA_GREEN]);
+ b += (weight * (double)entry[FI_RGBA_BLUE]);
+ src_bits += src_pitch;
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
+ dst_bits += dst_pitch;
+ }
+ }
+ } else {
+ // we do not have a palette
+ for (unsigned x = 0; x < width; x++) {
+ // work on column x in dst
+ BYTE *dst_bits = dst_base + x * 3;
+
+ // scale each column
+ for (unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
+ const BYTE *src_bits = src_base + iLeft * src_pitch + x;
+ double value = 0;
+
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ value += (weightsTable.getWeight(y, i) * (double)*src_bits);
+ src_bits += src_pitch;
+ }
+
+ // clamp and place result in destination pixel
+ const BYTE bval = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_RED] = bval;
+ dst_bits[FI_RGBA_GREEN] = bval;
+ dst_bits[FI_RGBA_BLUE] = bval;
+ dst_bits += dst_pitch;
+ }
+ }
+ }
+ }
+ break;
+
+ case 32:
+ {
+ // transparently convert the transparent 8-bit image to 32 bpp;
+ // we always have got a palette here
+ for (unsigned x = 0; x < width; x++) {
+ // work on column x in dst
+ BYTE *dst_bits = dst_base + x * 4;
+
+ // scale each column
+ for (unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
+ const BYTE *src_bits = src_base + iLeft * src_pitch + x;
+ double r = 0, g = 0, b = 0, a = 0;
+
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(y, i);
+ const BYTE * const entry = (BYTE *)&src_pal[*src_bits];
+ r += (weight * (double)entry[FI_RGBA_RED]);
+ g += (weight * (double)entry[FI_RGBA_GREEN]);
+ b += (weight * (double)entry[FI_RGBA_BLUE]);
+ a += (weight * (double)entry[FI_RGBA_ALPHA]);
+ src_bits += src_pitch;
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(r + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(g + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(b + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_ALPHA] = (BYTE)CLAMP<int>((int)(a + 0.5), 0, 0xFF);
+ dst_bits += dst_pitch;
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ case 16:
+ {
+ // transparently convert the 16-bit non-transparent image to 24 bpp
+ const unsigned src_pitch = FreeImage_GetPitch(src) / sizeof(WORD);
+ const WORD *const src_base = (WORD *)FreeImage_GetBits(src) + src_offset_y * src_pitch + src_offset_x;
+
+ if (IS_FORMAT_RGB565(src)) {
+ // image has 565 format
+ for (unsigned x = 0; x < width; x++) {
+ // work on column x in dst
+ BYTE *dst_bits = dst_base + x * 3;
+
+ // scale each column
+ for (unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
+ const WORD *src_bits = src_base + iLeft * src_pitch + x;
+ double r = 0, g = 0, b = 0;
+
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(y, i);
+ r += (weight * (double)((*src_bits & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT));
+ g += (weight * (double)((*src_bits & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT));
+ b += (weight * (double)((*src_bits & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT));
+ src_bits += src_pitch;
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(((r * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(((g * 0xFF) / 0x3F) + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(((b * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
+ dst_bits += dst_pitch;
+ }
+ }
+ } else {
+ // image has 555 format
+ for (unsigned x = 0; x < width; x++) {
+ // work on column x in dst
+ BYTE *dst_bits = dst_base + x * 3;
+
+ // scale each column
+ for (unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
+ const WORD *src_bits = src_base + iLeft * src_pitch + x;
+ double r = 0, g = 0, b = 0;
+
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(y, i);
+ r += (weight * (double)((*src_bits & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT));
+ g += (weight * (double)((*src_bits & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT));
+ b += (weight * (double)((*src_bits & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT));
+ src_bits += src_pitch;
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int)(((r * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int)(((g * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int)(((b * 0xFF) / 0x1F) + 0.5), 0, 0xFF);
+ dst_bits += dst_pitch;
+ }
+ }
+ }
+ }
+ break;
+
+ case 24:
+ {
+ // scale the 24-bit transparent image into a 24 bpp destination image
+ const unsigned src_pitch = FreeImage_GetPitch(src);
+ const BYTE *const src_base = FreeImage_GetBits(src) + src_offset_y * src_pitch + src_offset_x * 3;
+
+ for (unsigned x = 0; x < width; x++) {
+ // work on column x in dst
+ const unsigned index = x * 3;
+ BYTE *dst_bits = dst_base + index;
+
+ // scale each column
+ for (unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
+ const BYTE *src_bits = src_base + iLeft * src_pitch + index;
+ double r = 0, g = 0, b = 0;
+
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(y, i);
+ r += (weight * (double)src_bits[FI_RGBA_RED]);
+ g += (weight * (double)src_bits[FI_RGBA_GREEN]);
+ b += (weight * (double)src_bits[FI_RGBA_BLUE]);
+ src_bits += src_pitch;
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int) (r + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int) (g + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int) (b + 0.5), 0, 0xFF);
+ dst_bits += dst_pitch;
+ }
+ }
+ }
+ break;
+
+ case 32:
+ {
+ // scale the 32-bit transparent image into a 32 bpp destination image
+ const unsigned src_pitch = FreeImage_GetPitch(src);
+ const BYTE *const src_base = FreeImage_GetBits(src) + src_offset_y * src_pitch + src_offset_x * 4;
+
+ for (unsigned x = 0; x < width; x++) {
+ // work on column x in dst
+ const unsigned index = x * 4;
+ BYTE *dst_bits = dst_base + index;
+
+ // scale each column
+ for (unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
+ const BYTE *src_bits = src_base + iLeft * src_pitch + index;
+ double r = 0, g = 0, b = 0, a = 0;
+
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(y, i);
+ r += (weight * (double)src_bits[FI_RGBA_RED]);
+ g += (weight * (double)src_bits[FI_RGBA_GREEN]);
+ b += (weight * (double)src_bits[FI_RGBA_BLUE]);
+ a += (weight * (double)src_bits[FI_RGBA_ALPHA]);
+ src_bits += src_pitch;
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[FI_RGBA_RED] = (BYTE)CLAMP<int>((int) (r + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_GREEN] = (BYTE)CLAMP<int>((int) (g + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_BLUE] = (BYTE)CLAMP<int>((int) (b + 0.5), 0, 0xFF);
+ dst_bits[FI_RGBA_ALPHA] = (BYTE)CLAMP<int>((int) (a + 0.5), 0, 0xFF);
+ dst_bits += dst_pitch;
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ case FIT_UINT16:
+ {
+ // Calculate the number of words per pixel (1 for 16-bit, 3 for 48-bit or 4 for 64-bit)
+ const unsigned wordspp = (FreeImage_GetLine(src) / width) / sizeof(WORD);
+
+ const unsigned dst_pitch = FreeImage_GetPitch(dst) / sizeof(WORD);
+ WORD *const dst_base = (WORD *)FreeImage_GetBits(dst);
+
+ const unsigned src_pitch = FreeImage_GetPitch(src) / sizeof(WORD);
+ const WORD *const src_base = (WORD *)FreeImage_GetBits(src) + src_offset_y * src_pitch + src_offset_x * wordspp;
+
+ for (unsigned x = 0; x < width; x++) {
+ // work on column x in dst
+ const unsigned index = x * wordspp; // pixel index
+ WORD *dst_bits = dst_base + index;
+
+ // scale each column
+ for (unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
+ const WORD *src_bits = src_base + iLeft * src_pitch + index;
+ double value = 0;
+
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(y, i);
+ value += (weight * (double)src_bits[0]);
+ src_bits += src_pitch;
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[0] = (WORD)CLAMP<int>((int)(value + 0.5), 0, 0xFFFF);
+
+ dst_bits += dst_pitch;
+ }
+ }
+ }
+ break;
+
+ case FIT_RGB16:
+ {
+ // Calculate the number of words per pixel (1 for 16-bit, 3 for 48-bit or 4 for 64-bit)
+ const unsigned wordspp = (FreeImage_GetLine(src) / width) / sizeof(WORD);
+
+ const unsigned dst_pitch = FreeImage_GetPitch(dst) / sizeof(WORD);
+ WORD *const dst_base = (WORD *)FreeImage_GetBits(dst);
+
+ const unsigned src_pitch = FreeImage_GetPitch(src) / sizeof(WORD);
+ const WORD *const src_base = (WORD *)FreeImage_GetBits(src) + src_offset_y * src_pitch + src_offset_x * wordspp;
+
+ for (unsigned x = 0; x < width; x++) {
+ // work on column x in dst
+ const unsigned index = x * wordspp; // pixel index
+ WORD *dst_bits = dst_base + index;
+
+ // scale each column
+ for (unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
+ const WORD *src_bits = src_base + iLeft * src_pitch + index;
+ double r = 0, g = 0, b = 0;
+
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(y, i);
+ r += (weight * (double)src_bits[0]);
+ g += (weight * (double)src_bits[1]);
+ b += (weight * (double)src_bits[2]);
+
+ src_bits += src_pitch;
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[0] = (WORD)CLAMP<int>((int)(r + 0.5), 0, 0xFFFF);
+ dst_bits[1] = (WORD)CLAMP<int>((int)(g + 0.5), 0, 0xFFFF);
+ dst_bits[2] = (WORD)CLAMP<int>((int)(b + 0.5), 0, 0xFFFF);
+
+ dst_bits += dst_pitch;
+ }
+ }
+ }
+ break;
+
+ case FIT_RGBA16:
+ {
+ // Calculate the number of words per pixel (1 for 16-bit, 3 for 48-bit or 4 for 64-bit)
+ const unsigned wordspp = (FreeImage_GetLine(src) / width) / sizeof(WORD);
+
+ const unsigned dst_pitch = FreeImage_GetPitch(dst) / sizeof(WORD);
+ WORD *const dst_base = (WORD *)FreeImage_GetBits(dst);
+
+ const unsigned src_pitch = FreeImage_GetPitch(src) / sizeof(WORD);
+ const WORD *const src_base = (WORD *)FreeImage_GetBits(src) + src_offset_y * src_pitch + src_offset_x * wordspp;
+
+ for (unsigned x = 0; x < width; x++) {
+ // work on column x in dst
+ const unsigned index = x * wordspp; // pixel index
+ WORD *dst_bits = dst_base + index;
+
+ // scale each column
+ for (unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iLimit = weightsTable.getRightBoundary(y) - iLeft; // retrieve right boundary
+ const WORD *src_bits = src_base + iLeft * src_pitch + index;
+ double r = 0, g = 0, b = 0, a = 0;
+
+ for (unsigned i = 0; i < iLimit; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(y, i);
+ r += (weight * (double)src_bits[0]);
+ g += (weight * (double)src_bits[1]);
+ b += (weight * (double)src_bits[2]);
+ a += (weight * (double)src_bits[3]);
+
+ src_bits += src_pitch;
+ }
+
+ // clamp and place result in destination pixel
+ dst_bits[0] = (WORD)CLAMP<int>((int)(r + 0.5), 0, 0xFFFF);
+ dst_bits[1] = (WORD)CLAMP<int>((int)(g + 0.5), 0, 0xFFFF);
+ dst_bits[2] = (WORD)CLAMP<int>((int)(b + 0.5), 0, 0xFFFF);
+ dst_bits[3] = (WORD)CLAMP<int>((int)(a + 0.5), 0, 0xFFFF);
+
+ dst_bits += dst_pitch;
+ }
+ }
+ }
+ break;
+
+ case FIT_FLOAT:
+ case FIT_RGBF:
+ case FIT_RGBAF:
+ {
+ // Calculate the number of floats per pixel (1 for 32-bit, 3 for 96-bit or 4 for 128-bit)
+ const unsigned floatspp = (FreeImage_GetLine(src) / width) / sizeof(float);
+
+ const unsigned dst_pitch = FreeImage_GetPitch(dst) / sizeof(float);
+ float *const dst_base = (float *)FreeImage_GetBits(dst);
+
+ const unsigned src_pitch = FreeImage_GetPitch(src) / sizeof(float);
+ const float *const src_base = (float *)FreeImage_GetBits(src) + src_offset_y * src_pitch + src_offset_x * floatspp;
+
+ for (unsigned x = 0; x < width; x++) {
+ // work on column x in dst
+ const unsigned index = x * floatspp; // pixel index
+ float *dst_bits = (float *)dst_base + index;
+
+ // scale each column
+ for (unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iRight = weightsTable.getRightBoundary(y); // retrieve right boundary
+ const float *src_bits = src_base + iLeft * src_pitch + index;
+ double value[4] = {0, 0, 0, 0}; // 4 = 128 bpp max
+
+ for (unsigned i = iLeft; i < iRight; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(y, i - iLeft);
+ for (unsigned j = 0; j < floatspp; j++) {
+ value[j] += (weight * (double)src_bits[j]);
+ }
+ src_bits += src_pitch;
+ }
+
+ // place result in destination pixel
+ for (unsigned j = 0; j < floatspp; j++) {
+ dst_bits[j] = (float)value[j];
+ }
+ dst_bits += dst_pitch;
+ }
+ }
+ }
+ break;
+ }
+}
diff --git a/plugins/AdvaImg/src/FreeImageToolkit/Resize.h b/plugins/AdvaImg/src/FreeImageToolkit/Resize.h
index ca382efa60..ce1d7328d7 100644
--- a/plugins/AdvaImg/src/FreeImageToolkit/Resize.h
+++ b/plugins/AdvaImg/src/FreeImageToolkit/Resize.h
@@ -1,196 +1,196 @@
-// ==========================================================
-// Upsampling / downsampling classes
-//
-// Design and implementation by
-// - Hervé Drolon (drolon@infonie.fr)
-// - Detlev Vendt (detlev.vendt@brillit.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!
-// ==========================================================
-
-#ifndef _RESIZE_H_
-#define _RESIZE_H_
-
-#include "FreeImage.h"
-#include "Utilities.h"
-#include "Filters.h"
-
-/**
- Filter weights table.<br>
- This class stores contribution information for an entire line (row or column).
-*/
-class CWeightsTable
-{
-/**
- Sampled filter weight table.<br>
- Contribution information for a single pixel
-*/
-typedef struct {
- /// Normalized weights of neighboring pixels
- double *Weights;
- /// Bounds of source pixels window
- unsigned Left, Right;
-} Contribution;
-
-private:
- /// Row (or column) of contribution weights
- Contribution *m_WeightTable;
- /// Filter window size (of affecting source pixels)
- unsigned m_WindowSize;
- /// Length of line (no. of rows / cols)
- unsigned m_LineLength;
-
-public:
- /**
- Constructor<br>
- Allocate and compute the weights table
- @param pFilter Filter used for upsampling or downsampling
- @param uDstSize Length (in pixels) of the destination line buffer
- @param uSrcSize Length (in pixels) of the source line buffer
- */
- CWeightsTable(CGenericFilter *pFilter, unsigned uDstSize, unsigned uSrcSize);
-
- /**
- Destructor<br>
- Destroy the weights table
- */
- ~CWeightsTable();
-
- /** Retrieve a filter weight, given source and destination positions
- @param dst_pos Pixel position in destination line buffer
- @param src_pos Pixel position in source line buffer
- @return Returns the filter weight
- */
- double getWeight(unsigned dst_pos, unsigned src_pos) {
- return m_WeightTable[dst_pos].Weights[src_pos];
- }
-
- /** Retrieve left boundary of source line buffer
- @param dst_pos Pixel position in destination line buffer
- @return Returns the left boundary of source line buffer
- */
- unsigned getLeftBoundary(unsigned dst_pos) {
- return m_WeightTable[dst_pos].Left;
- }
-
- /** Retrieve right boundary of source line buffer
- @param dst_pos Pixel position in destination line buffer
- @return Returns the right boundary of source line buffer
- */
- unsigned getRightBoundary(unsigned dst_pos) {
- return m_WeightTable[dst_pos].Right;
- }
-};
-
-// ---------------------------------------------
-
-/**
- CResizeEngine<br>
- This class performs filtered zoom. It scales an image to the desired dimensions with
- any of the CGenericFilter derived filter class.<br>
- It works with FIT_BITMAP buffers, WORD buffers (FIT_UINT16, FIT_RGB16, FIT_RGBA16)
- and float buffers (FIT_FLOAT, FIT_RGBF, FIT_RGBAF).<br><br>
-
- <b>References</b> : <br>
- [1] Paul Heckbert, C code to zoom raster images up or down, with nice filtering.
- UC Berkeley, August 1989. [online] http://www-2.cs.cmu.edu/afs/cs.cmu.edu/Web/People/ph/heckbert.html
- [2] Eran Yariv, Two Pass Scaling using Filters. The Code Project, December 1999.
- [online] http://www.codeproject.com/bitmap/2_pass_scaling.asp
-
-*/
-class CResizeEngine
-{
-private:
- /// Pointer to the FIR / IIR filter
- CGenericFilter* m_pFilter;
-
-public:
-
- /**
- Constructor
- @param filter FIR /IIR filter to be used
- */
- CResizeEngine(CGenericFilter* filter):m_pFilter(filter) {}
-
- /// Destructor
- virtual ~CResizeEngine() {}
-
- /** Scale an image to the desired dimensions.
-
- Method CResizeEngine::scale, as well as the two filtering methods
- CResizeEngine::horizontalFilter and CResizeEngine::verticalFilter take
- four additional parameters, that define a rectangle in the source
- image to be rescaled.
-
- These are src_left, src_top, src_width and src_height and should work
- like these of function FreeImage_Copy. However, src_left and src_top are
- actually named src_offset_x and src_offset_y in the filtering methods.
-
- Additionally, since src_height and dst_height are always the same for
- method horizontalFilter as src_width and dst_width are always the same
- for verticalFilter, these have been stripped down to a single parameter
- height and width for horizontalFilter and verticalFilter respectively.
-
- Currently, method scale is called with the actual size of the source
- image. However, in a future version, we could provide a new function
- called FreeImage_RescaleRect that rescales only part of an image.
-
- @param src Pointer to the source image
- @param dst_width Destination image width
- @param dst_height Destination image height
- @param src_left Left boundary of the source rectangle to be scaled
- @param src_top Top boundary of the source rectangle to be scaled
- @param src_width Width of the source rectangle to be scaled
- @param src_height Height of the source rectangle to be scaled
- @return Returns the scaled image if successful, returns NULL otherwise
- */
- FIBITMAP* scale(FIBITMAP *src, unsigned dst_width, unsigned dst_height, unsigned src_left, unsigned src_top, unsigned src_width, unsigned src_height);
-
-private:
-
- /**
- Performs horizontal image filtering
-
- @param src Source image
- @param height Source / Destination image height
- @param src_width Source image width
- @param src_offset_x
- @param src_offset_y
- @param src_pal
- @param dst Destination image
- @param dst_width Destination image width
- */
- void horizontalFilter(FIBITMAP * const src, const unsigned height, const unsigned src_width,
- const unsigned src_offset_x, const unsigned src_offset_y, const RGBQUAD * const src_pal,
- FIBITMAP * const dst, const unsigned dst_width);
-
- /**
- Performs vertical image filtering
- @param src Source image
- @param width Source / Destination image width
- @param src_height Source image height
- @param src_offset_x
- @param src_offset_y
- @param src_pal
- @param dst Destination image
- @param dst_height Destination image height
- */
- void verticalFilter(FIBITMAP * const src, const unsigned width, const unsigned src_height,
- const unsigned src_offset_x, const unsigned src_offset_y, const RGBQUAD * const src_pal,
- FIBITMAP * const dst, const unsigned dst_height);
-};
-
-#endif // _RESIZE_H_
+// ==========================================================
+// Upsampling / downsampling classes
+//
+// Design and implementation by
+// - Hervé Drolon (drolon@infonie.fr)
+// - Detlev Vendt (detlev.vendt@brillit.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!
+// ==========================================================
+
+#ifndef _RESIZE_H_
+#define _RESIZE_H_
+
+#include "FreeImage.h"
+#include "Utilities.h"
+#include "Filters.h"
+
+/**
+ Filter weights table.<br>
+ This class stores contribution information for an entire line (row or column).
+*/
+class CWeightsTable
+{
+/**
+ Sampled filter weight table.<br>
+ Contribution information for a single pixel
+*/
+typedef struct {
+ /// Normalized weights of neighboring pixels
+ double *Weights;
+ /// Bounds of source pixels window
+ unsigned Left, Right;
+} Contribution;
+
+private:
+ /// Row (or column) of contribution weights
+ Contribution *m_WeightTable;
+ /// Filter window size (of affecting source pixels)
+ unsigned m_WindowSize;
+ /// Length of line (no. of rows / cols)
+ unsigned m_LineLength;
+
+public:
+ /**
+ Constructor<br>
+ Allocate and compute the weights table
+ @param pFilter Filter used for upsampling or downsampling
+ @param uDstSize Length (in pixels) of the destination line buffer
+ @param uSrcSize Length (in pixels) of the source line buffer
+ */
+ CWeightsTable(CGenericFilter *pFilter, unsigned uDstSize, unsigned uSrcSize);
+
+ /**
+ Destructor<br>
+ Destroy the weights table
+ */
+ ~CWeightsTable();
+
+ /** Retrieve a filter weight, given source and destination positions
+ @param dst_pos Pixel position in destination line buffer
+ @param src_pos Pixel position in source line buffer
+ @return Returns the filter weight
+ */
+ double getWeight(unsigned dst_pos, unsigned src_pos) {
+ return m_WeightTable[dst_pos].Weights[src_pos];
+ }
+
+ /** Retrieve left boundary of source line buffer
+ @param dst_pos Pixel position in destination line buffer
+ @return Returns the left boundary of source line buffer
+ */
+ unsigned getLeftBoundary(unsigned dst_pos) {
+ return m_WeightTable[dst_pos].Left;
+ }
+
+ /** Retrieve right boundary of source line buffer
+ @param dst_pos Pixel position in destination line buffer
+ @return Returns the right boundary of source line buffer
+ */
+ unsigned getRightBoundary(unsigned dst_pos) {
+ return m_WeightTable[dst_pos].Right;
+ }
+};
+
+// ---------------------------------------------
+
+/**
+ CResizeEngine<br>
+ This class performs filtered zoom. It scales an image to the desired dimensions with
+ any of the CGenericFilter derived filter class.<br>
+ It works with FIT_BITMAP buffers, WORD buffers (FIT_UINT16, FIT_RGB16, FIT_RGBA16)
+ and float buffers (FIT_FLOAT, FIT_RGBF, FIT_RGBAF).<br><br>
+
+ <b>References</b> : <br>
+ [1] Paul Heckbert, C code to zoom raster images up or down, with nice filtering.
+ UC Berkeley, August 1989. [online] http://www-2.cs.cmu.edu/afs/cs.cmu.edu/Web/People/ph/heckbert.html
+ [2] Eran Yariv, Two Pass Scaling using Filters. The Code Project, December 1999.
+ [online] http://www.codeproject.com/bitmap/2_pass_scaling.asp
+
+*/
+class CResizeEngine
+{
+private:
+ /// Pointer to the FIR / IIR filter
+ CGenericFilter* m_pFilter;
+
+public:
+
+ /**
+ Constructor
+ @param filter FIR /IIR filter to be used
+ */
+ CResizeEngine(CGenericFilter* filter):m_pFilter(filter) {}
+
+ /// Destructor
+ virtual ~CResizeEngine() {}
+
+ /** Scale an image to the desired dimensions.
+
+ Method CResizeEngine::scale, as well as the two filtering methods
+ CResizeEngine::horizontalFilter and CResizeEngine::verticalFilter take
+ four additional parameters, that define a rectangle in the source
+ image to be rescaled.
+
+ These are src_left, src_top, src_width and src_height and should work
+ like these of function FreeImage_Copy. However, src_left and src_top are
+ actually named src_offset_x and src_offset_y in the filtering methods.
+
+ Additionally, since src_height and dst_height are always the same for
+ method horizontalFilter as src_width and dst_width are always the same
+ for verticalFilter, these have been stripped down to a single parameter
+ height and width for horizontalFilter and verticalFilter respectively.
+
+ Currently, method scale is called with the actual size of the source
+ image. However, in a future version, we could provide a new function
+ called FreeImage_RescaleRect that rescales only part of an image.
+
+ @param src Pointer to the source image
+ @param dst_width Destination image width
+ @param dst_height Destination image height
+ @param src_left Left boundary of the source rectangle to be scaled
+ @param src_top Top boundary of the source rectangle to be scaled
+ @param src_width Width of the source rectangle to be scaled
+ @param src_height Height of the source rectangle to be scaled
+ @return Returns the scaled image if successful, returns NULL otherwise
+ */
+ FIBITMAP* scale(FIBITMAP *src, unsigned dst_width, unsigned dst_height, unsigned src_left, unsigned src_top, unsigned src_width, unsigned src_height, unsigned flags);
+
+private:
+
+ /**
+ Performs horizontal image filtering
+
+ @param src Source image
+ @param height Source / Destination image height
+ @param src_width Source image width
+ @param src_offset_x
+ @param src_offset_y
+ @param src_pal
+ @param dst Destination image
+ @param dst_width Destination image width
+ */
+ void horizontalFilter(FIBITMAP * const src, const unsigned height, const unsigned src_width,
+ const unsigned src_offset_x, const unsigned src_offset_y, const RGBQUAD * const src_pal,
+ FIBITMAP * const dst, const unsigned dst_width);
+
+ /**
+ Performs vertical image filtering
+ @param src Source image
+ @param width Source / Destination image width
+ @param src_height Source image height
+ @param src_offset_x
+ @param src_offset_y
+ @param src_pal
+ @param dst Destination image
+ @param dst_height Destination image height
+ */
+ void verticalFilter(FIBITMAP * const src, const unsigned width, const unsigned src_height,
+ const unsigned src_offset_x, const unsigned src_offset_y, const RGBQUAD * const src_pal,
+ FIBITMAP * const dst, const unsigned dst_height);
+};
+
+#endif // _RESIZE_H_
diff --git a/plugins/AdvaImg/src/MapIntrospector.h b/plugins/AdvaImg/src/MapIntrospector.h
new file mode 100644
index 0000000000..091ba68b26
--- /dev/null
+++ b/plugins/AdvaImg/src/MapIntrospector.h
@@ -0,0 +1,212 @@
+// ==========================================================
+// STL MapIntrospector class
+//
+// Design and implementation by
+// - Carsten Klein (cklein05@users.sourceforge.net)
+//
+// This file is part of FreeImage 3
+//
+// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
+// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
+// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
+// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
+// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
+// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
+// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
+// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
+// THIS DISCLAIMER.
+//
+// Use at your own risk!
+// ==========================================================
+
+#ifndef MAPINTROSPECTOR_H_
+#define MAPINTROSPECTOR_H_
+
+// we need at least one C++ header included,
+// that defines the C++ Standard Library's version macro,
+// that is used below to identify the library.
+#include <cstdlib>
+
+/**
+Class MapIntrospector - STL std::map Introspector
+
+The MapIntrospector is a helper class used to calculate or estimate part
+of the internal memory footprint of a std::map, that is the memory used
+by N entries, where N is provided as an argument. This class is used by
+function FreeImage_GetMemorySize, which aims to get the total memory
+usage for a FreeImage bitmap.
+
+The type argument _Maptype must take the type of the std::map to be
+introspected.
+
+This class accounts for 'internal' memory per entry only, that is, the
+size returned does neither include the actual size of the std::map class
+itself, nor does it include the size of referenced keys and values (also
+the actual bytes required for std::string type keys or values are not
+counted). For example, the total memory usage should be something like:
+
+typedef std::map<std::string, double> DBLMAP
+DBLMAP MyMap;
+
+int total_size = sizeof(DBLMAP) + MapIntrospector<DBLMAP>::GetNodesMemorySize(MyMap.size())
+for (DBLMAP::iterator i = MyMap->begin(); i != MyMap->end(); i++) {
+ std::string key = i->first;
+ total_size += key.capacity();
+}
+
+So, basically, this class' task is to get the (constant) number of bytes
+per entry, which is multiplied by N (parameter node_count) and returned
+in method GetNodesMemorySize. Since this heavily depends on the actually
+used C++ Standard Library, this class must be implemented specifically
+for each C++ Standard Library.
+
+At current, there is an implementation available for these C++ Standard
+Libraries:
+
+- Microsoft C++ Standard Library
+- GNU Standard C++ Library v3, libstdc++-v3
+- LLVM "libc++" C++ Standard Library (untested)
+- Unknown C++ Standard Library
+
+Volunteers for testing as well as for providing support for other/new
+libraries are welcome.
+
+The 'Unknown C++ Standard Library' case is used if no other known C++
+Standard Library was detected. It uses a typical _Node structure to
+declare an estimated memory consumption for a node.
+*/
+
+#if defined(_CPPLIB_VER) // Microsoft C++ Standard Library
+/**
+ The Microsoft C++ Standard Library uses the protected structure _Node
+ of class std::_Tree_nod to represent a node. This class is used by
+ std::_Tree, the base class of std::map. So, since std::map is derived
+ from std::_Tree (and _Node is protected), we can get access to this
+ structure by deriving from std::map.
+
+ Additionally, the Microsoft C++ Standard Library uses a separately
+ allocated end node for its balanced red-black tree so, actually, there
+ are size() + 1 nodes present in memory.
+
+ With all that in place, the total memory for all nodes in std::map
+ is simply (node_count + 1) * sizeof(_Node).
+*/
+template<class _Maptype>
+class MapIntrospector: private _Maptype {
+public:
+ static size_t GetNodesMemorySize(size_t node_count) {
+ return (node_count + 1) * sizeof(_Node);
+ }
+};
+
+#elif defined(__GLIBCXX__) // GNU Standard C++ Library v3, libstdc++-v3
+/**
+ The GNU Standard C++ Library v3 uses structure std::_Rb_tree_node<_Val>,
+ which is publicly declared in the standard namespace. Its value type
+ _Val is actually the map's value_type std::map::value_type.
+
+ So, the total memory for all nodes in std::map is simply
+ node_count * sizeof(std::_Rb_tree_node<_Val>), _Val being the map's
+ value_type.
+*/
+template<class _Maptype>
+class MapIntrospector {
+private:
+ typedef typename _Maptype::value_type _Val;
+
+public:
+ static size_t GetNodesMemorySize(size_t node_count) {
+ return node_count * sizeof(std::_Rb_tree_node<_Val>);
+ }
+};
+
+#elif defined(_LIBCPP_VERSION) // "libc++" C++ Standard Library (LLVM)
+/*
+ The "libc++" C++ Standard Library uses structure
+ std::__tree_node<_Val, void*> for regular nodes and one instance of
+ structure std::__tree_end_node<void*> for end nodes, which both are
+ publicly declared in the standard namespace. Its value type _Val is
+ actually the map's value_type std::map::value_type.
+
+ So, the total memory for all nodes in std::map is simply
+ node_count * sizeof(std::__tree_node<_Val, void*>)
+ + sizeof(std::__tree_end_node<void*>).
+
+ REMARK: this implementation is not yet tested!
+*/
+template<class _Maptype>
+class MapIntrospector {
+private:
+ typedef typename _Maptype::value_type _Val;
+
+public:
+ static size_t GetNodesMemorySize(size_t node_count) {
+ return node_count * sizeof(std::__tree_node<_Val, void*>) + sizeof(std::__tree_end_node<void*>);
+ }
+};
+
+//#elif defined(_ADD_YOUR_CPP_STD_LIBRARY_HERE_)
+
+#else // Unknown C++ Standard Library
+/**
+ If we do not know the actual C++ Standard Library and so, have no
+ access to any internal types, we can just make some assumptions about
+ the implementation and memory usage.
+
+ However, all implementations will probably be based on a balanced
+ red-black tree, will also store the map's value_type in each node and
+ need some extra information like the node's color. For a binary tree,
+ at least two pointers, one for left and one for right are required.
+ Since it is handy, many implementations also have a parent pointer.
+
+ We let the compiler calculate the size of the above mentioned items by
+ using a fake structure. By using a real structure (in contrast to just
+ adding numbers/bytes) we'll get correct pointer sizes as well as any
+ padding applied for free.
+*/
+template<class _Maptype>
+class MapIntrospector {
+private:
+ /* Define some handy typedefs to build up the structure. */
+
+ /**
+ Each node will likely store the value_type of the mapping,
+ that is a std::pair<_Key, _Value>.
+ */
+ typedef typename _Maptype::value_type _Val;
+
+ /**
+ We will need some pointers, since std::map is likely implemented
+ as a balanced red-black tree.
+ */
+ typedef void* _Ptr;
+
+ /**
+ Space for some extra information (like the node's color).
+ An int should be sufficient.
+ */
+ typedef int _Ext;
+
+ /* The memory required for each node will likely look like this
+ structure. We will just multiply sizeof(_Node) by the number
+ of nodes to get the total memory of all nodes. By using the
+ size of the structure, we will also take care of the compiler's
+ default padding.
+ */
+ typedef struct {
+ _Ptr _parent_node;
+ _Ptr _left_node;
+ _Ptr _right_node;
+ _Val _value;
+ _Ext _extra_info;
+ } _Node;
+
+public:
+ static size_t GetNodesMemorySize(size_t node_count) {
+ return node_count * sizeof(_Node);
+ }
+};
+
+#endif // Standard C++ Library
+
+#endif // MAPINTROSPECTOR_H_
diff --git a/plugins/AdvaImg/src/Metadata/Exif.cpp b/plugins/AdvaImg/src/Metadata/Exif.cpp
index abc840607b..35265cb2ab 100644
--- a/plugins/AdvaImg/src/Metadata/Exif.cpp
+++ b/plugins/AdvaImg/src/Metadata/Exif.cpp
@@ -120,15 +120,15 @@ ReadInt32(BOOL msb_order, const void *buffer) {
return value;
}
-static unsigned short
+static WORD
ReadUint16(BOOL msb_order, const void *buffer) {
- unsigned short value;
+ WORD value;
if(msb_order) {
- value = (unsigned short) ((((BYTE*) buffer)[0] << 8) | ((BYTE*) buffer)[1]);
+ value = (WORD) ((((BYTE*) buffer)[0] << 8) | ((BYTE*) buffer)[1]);
return value;
}
- value = (unsigned short) ((((BYTE*) buffer)[1] << 8) | ((BYTE*) buffer)[0]);
+ value = (WORD) ((((BYTE*) buffer)[1] << 8) | ((BYTE*) buffer)[0]);
return value;
}
@@ -146,9 +146,9 @@ Process a IFD offset
Returns the offset and the metadata model for this tag
*/
static void
-processIFDOffset(FITAG *tag, char *pval, BOOL msb_order, DWORD *subdirOffset, TagLib::MDMODEL *md_model) {
+processIFDOffset(FITAG *tag, const char *pval, BOOL msb_order, DWORD *subdirOffset, TagLib::MDMODEL *md_model) {
// get the IFD offset
- *subdirOffset = (DWORD) ReadUint32(msb_order, pval);
+ *subdirOffset = ReadUint32(msb_order, pval);
// select a tag info table
switch(FreeImage_GetTagID(tag)) {
@@ -162,7 +162,6 @@ processIFDOffset(FITAG *tag, char *pval, BOOL msb_order, DWORD *subdirOffset, Ta
*md_model = TagLib::EXIF_INTEROP;
break;
}
-
}
/**
@@ -170,7 +169,7 @@ Process a maker note IFD offset
Returns the offset and the metadata model for this tag
*/
static void
-processMakerNote(FIBITMAP *dib, char *pval, BOOL msb_order, DWORD *subdirOffset, TagLib::MDMODEL *md_model) {
+processMakerNote(FIBITMAP *dib, const char *pval, BOOL msb_order, DWORD *subdirOffset, TagLib::MDMODEL *md_model) {
FITAG *tagMake = NULL;
*subdirOffset = 0;
@@ -238,12 +237,12 @@ processMakerNote(FIBITMAP *dib, char *pval, BOOL msb_order, DWORD *subdirOffset,
}
} else if ((memcmp("FUJIFILM", pval, 8) == 0) || (Maker && (FreeImage_strnicmp("Fujifilm", Maker, 8) == 0))) {
// Fujifile Makernote
- // Fujifilm's Makernote always use Intel order altough the Exif section maybe in Intel order or in Motorola order.
+ // Fujifilm's Makernote always use little-endian order altough the Exif section maybe in little-endian order or in big-endian order.
// If msb_order == TRUE, the Makernote won't be read:
// the value of ifdStart will be 0x0c000000 instead of 0x0000000c and the MakerNote section will be discarded later
// in jpeg_read_exif_dir because the IFD is too high
*md_model = TagLib::EXIF_MAKERNOTE_FUJIFILM;
- DWORD ifdStart = (DWORD) ReadUint32(msb_order, pval + 8);
+ DWORD ifdStart = ReadUint32(msb_order, pval + 8);
*subdirOffset = ifdStart;
}
else if(memcmp("KYOCERA\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x00\x00\x00", pval, 22) == 0) {
@@ -519,14 +518,15 @@ Process Exif directory
@param dib Input FIBITMAP
@param tiffp Pointer to the TIFF header
-@param offset 0th IFD offset
-@param length Length of the datafile
-@param msb_order Endianess order of the datafile
+@param dwOffsetIfd0 Offset to the 0th IFD (first IFD)
+@param dwLength Length of the Exif file
+@param dwProfileOffset File offset to be used when reading 'offset/value' tags
+@param msb_order Endianness order of the Exif file (TRUE if big-endian, FALSE if little-endian)
@param starting_md_model Metadata model of the IFD (should be TagLib::EXIF_MAIN for a jpeg)
@return Returns TRUE if sucessful, returns FALSE otherwise
*/
static BOOL
-jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, unsigned long offset, unsigned int length, BOOL msb_order, TagLib::MDMODEL starting_md_model) {
+jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, DWORD dwOffsetIfd0, DWORD dwLength, DWORD dwProfileOffset, BOOL msb_order, TagLib::MDMODEL starting_md_model) {
WORD de, nde;
std::stack<WORD> destack; // directory entries stack
@@ -553,7 +553,7 @@ jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, unsigned long offset, unsig
// set the pointer to the first IFD (0th IFD) and follow it were it leads.
- const BYTE *ifd0th = (BYTE*)tiffp + offset;
+ const BYTE *ifd0th = (BYTE*)tiffp + (size_t)dwOffsetIfd0;
const BYTE *ifdp = ifd0th;
@@ -577,6 +577,10 @@ jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, unsigned long offset, unsig
// determine how many entries there are in the current IFD
nde = ReadUint16(msb_order, ifdp);
+ if (((size_t)(ifdp - tiffp) + 12 * nde) > (size_t)dwLength) {
+ // suspicious IFD offset, ignore
+ continue;
+ }
for(; de < nde; de++) {
char *pde = NULL; // pointer to the directory entry
@@ -590,7 +594,9 @@ jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, unsigned long offset, unsig
pde = (char*) DIR_ENTRY_ADDR(ifdp, de);
// get the tag ID
- FreeImage_SetTagID(tag, ReadUint16(msb_order, pde));
+ WORD tag_id = ReadUint16(msb_order, pde);
+ FreeImage_SetTagID(tag, tag_id);
+
// get the tag type
WORD tag_type = (WORD)ReadUint16(msb_order, pde + 2);
if((tag_type - 1) >= EXIF_NUM_FORMATS) {
@@ -602,7 +608,9 @@ jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, unsigned long offset, unsig
FreeImage_SetTagType(tag, (FREE_IMAGE_MDTYPE)tag_type);
// get number of components
- FreeImage_SetTagCount(tag, ReadUint32(msb_order, pde + 4));
+ DWORD tag_count = ReadUint32(msb_order, pde + 4);
+ FreeImage_SetTagCount(tag, tag_count);
+
// check that tag length (size of the tag value in bytes) will fit in a DWORD
unsigned tag_data_width = FreeImage_TagDataWidth(FreeImage_GetTagType(tag));
if (tag_data_width != 0 && FreeImage_GetTagCount(tag) > ~(DWORD)0 / tag_data_width) {
@@ -616,17 +624,21 @@ jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, unsigned long offset, unsig
// 4 bytes or less and value is in the dir entry itself
pval = pde + 8;
} else {
- // if its bigger than 4 bytes, the directory entry contains an offset
- // first check if offset exceeds buffer, at this stage FreeImage_GetTagLength may return invalid data
+ // if its bigger than 4 bytes, the directory entry contains an offset
DWORD offset_value = ReadUint32(msb_order, pde + 8);
- if(offset_value > length) {
+ // the offset can be relative to tiffp or to an external reference (see JPEG-XR)
+ if(dwProfileOffset) {
+ offset_value -= dwProfileOffset;
+ }
+ // first check if offset exceeds buffer, at this stage FreeImage_GetTagLength may return invalid data
+ if(offset_value > dwLength) {
// a problem occured : delete the tag (not free'd after)
FreeImage_DeleteTag(tag);
// jump to next entry
continue;
}
// now check that length does not exceed the buffer size
- if(FreeImage_GetTagLength(tag) > length - offset_value){
+ if(FreeImage_GetTagLength(tag) > dwLength - offset_value){
// a problem occured : delete the tag (not free'd after)
FreeImage_DeleteTag(tag);
// jump to next entry
@@ -659,10 +671,10 @@ jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, unsigned long offset, unsig
next_ifd = (BYTE*)tiffp + sub_offset;
}
- if((sub_offset < (DWORD) length) && (next_mdmodel != TagLib::UNKNOWN)) {
+ if((sub_offset < dwLength) && (next_mdmodel != TagLib::UNKNOWN)) {
// push our current directory state onto the stack
ifdstack.push(ifdp);
- // bump to the next entry
+ // jump to the next entry
de++;
destack.push(de);
@@ -708,7 +720,7 @@ jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, unsigned long offset, unsig
const WORD entriesCount0th = ReadUint16(msb_order, ifd0th);
DWORD next_offset = ReadUint32(msb_order, DIR_ENTRY_ADDR(ifd0th, entriesCount0th));
- if((next_offset == 0) || (next_offset >= length)) {
+ if((next_offset == 0) || (next_offset >= dwLength)) {
return TRUE; //< no thumbnail
}
@@ -726,7 +738,7 @@ jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, unsigned long offset, unsig
// check for buffer overflow
const size_t remaining = (size_t)base + 12 - (size_t)tiffp;
- if(remaining >= length) {
+ if(remaining >= dwLength) {
// bad IFD1 directory, ignore it
return FALSE;
}
@@ -734,9 +746,9 @@ jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, unsigned long offset, unsig
// get the tag ID
WORD tag = ReadUint16(msb_order, base);
// get the tag type
- WORD type = ReadUint16(msb_order, base + sizeof(WORD));
+ /*WORD type = */ReadUint16(msb_order, base + sizeof(WORD));
// get number of components
- DWORD count = ReadUint32(msb_order, base + sizeof(WORD) + sizeof(WORD));
+ /*DWORD count = */ReadUint32(msb_order, base + sizeof(WORD) + sizeof(WORD));
// get the tag value
DWORD offset = ReadUint32(msb_order, base + sizeof(WORD) + sizeof(WORD) + sizeof(DWORD));
@@ -768,7 +780,7 @@ jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, unsigned long offset, unsig
return TRUE;
}
- if(thOffset + thSize > length) {
+ if(thOffset + thSize > dwLength) {
return TRUE;
}
@@ -791,43 +803,45 @@ jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, unsigned long offset, unsig
// --------------------------------------------------------------------------
/**
- Read and decode 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
+Read and decode JPEG_APP1 marker (Exif profile)
+@param dib Input FIBITMAP
+@param data Pointer to the APP1 marker
+@param length APP1 marker length
+@return Returns TRUE if successful, FALSE otherwise
*/
BOOL
-jpeg_read_exif_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned datalen) {
+jpeg_read_exif_profile(FIBITMAP *dib, const BYTE *data, unsigned length) {
// marker identifying string for Exif = "Exif\0\0"
BYTE exif_signature[6] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 };
- BYTE lsb_first[4] = { 0x49, 0x49, 0x2A, 0x00 }; // Intel order
- BYTE msb_first[4] = { 0x4D, 0x4D, 0x00, 0x2A }; // Motorola order
+ BYTE lsb_first[4] = { 0x49, 0x49, 0x2A, 0x00 }; // Classic TIFF signature - little-endian order
+ BYTE msb_first[4] = { 0x4D, 0x4D, 0x00, 0x2A }; // Classic TIFF signature - big-endian order
- unsigned int length = datalen;
- BYTE *profile = (BYTE*)dataptr;
+ // profile size is up to 32-bit
+ DWORD dwProfileLength = (DWORD)length;
+ BYTE *pbProfile = (BYTE*)data;
// verify the identifying string
+ if(memcmp(exif_signature, pbProfile, sizeof(exif_signature)) == 0) {
+ // This is an Exif profile
+ // should contain a TIFF header with up to 2 IFDs (IFD stands for 'Image File Directory')
+ // 0th IFD : the image attributes, 1st IFD : may be used for thumbnail
- if(memcmp(exif_signature, profile, sizeof(exif_signature)) == 0) {
- // Exif profile - TIFF header with 2 IFDs. 0th - the image attributes, 1st - may be used for thumbnail
-
- profile += sizeof(exif_signature);
- length -= sizeof(exif_signature);
+ pbProfile += sizeof(exif_signature);
+ dwProfileLength -= sizeof(exif_signature);
// read the TIFF header (8 bytes)
// check the endianess order
- BOOL bMotorolaOrder = TRUE;
+ BOOL bBigEndian = TRUE;
- if(memcmp(profile, lsb_first, sizeof(lsb_first)) == 0) {
- // Exif section in Intel order
- bMotorolaOrder = FALSE;
+ if(memcmp(pbProfile, lsb_first, sizeof(lsb_first)) == 0) {
+ // Exif section is in little-endian order
+ bBigEndian = FALSE;
} else {
- if(memcmp(profile, msb_first, sizeof(msb_first)) == 0) {
- // Exif section in Motorola order
- bMotorolaOrder = TRUE;
+ if(memcmp(pbProfile, msb_first, sizeof(msb_first)) == 0) {
+ // Exif section is in big-endian order
+ bBigEndian = TRUE;
} else {
// Invalid Exif alignment marker
return FALSE;
@@ -835,8 +849,8 @@ jpeg_read_exif_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned datalen) {
}
// this is the offset to the first IFD (Image File Directory)
- unsigned long first_offset = ReadUint32(bMotorolaOrder, profile + 4);
- if (first_offset > length) {
+ DWORD dwFirstOffset = ReadUint32(bBigEndian, pbProfile + 4);
+ if (dwFirstOffset > dwProfileLength) {
// bad Exif data
return FALSE;
}
@@ -844,7 +858,7 @@ jpeg_read_exif_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned datalen) {
/*
Note: as FreeImage 3.14.0, this test is no longer needed for images with similar suspicious offset
=> tested with Pentax Optio 230, FujiFilm SP-2500 and Canon EOS 300D
- if (first_offset < 8 || first_offset > 16) {
+ if (dwFirstOffset < 8 || dwFirstOffset > 16) {
// This is usually set to 8
// but PENTAX Optio 230 has it set differently, and uses it as offset.
FreeImage_OutputMessageProc(FIF_JPEG, "Exif: Suspicious offset of first IFD value");
@@ -853,18 +867,22 @@ jpeg_read_exif_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned datalen) {
*/
// process Exif directories, starting with Exif-TIFF IFD
- return jpeg_read_exif_dir(dib, profile, first_offset, length, bMotorolaOrder, TagLib::EXIF_MAIN);
+ return jpeg_read_exif_dir(dib, pbProfile, dwFirstOffset, dwProfileLength, 0, bBigEndian, TagLib::EXIF_MAIN);
}
return FALSE;
}
+// ==========================================================
+// Exif JPEG helper routines
+// ==========================================================
+
/**
- 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
+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
*/
BOOL
jpeg_read_exif_profile_raw(FIBITMAP *dib, const BYTE *profile, unsigned length) {
@@ -898,38 +916,48 @@ jpeg_read_exif_profile_raw(FIBITMAP *dib, const BYTE *profile, unsigned length)
return FALSE;
}
+// ==========================================================
+// Exif JPEG-XR helper routines
+// ==========================================================
+
/**
Read and decode JPEG-XR Exif IFD
@param dib Input FIBITMAP
@param profile Pointer to the Exif marker
@param length Exif marker length
+@param file_offset Reference offset in the original file of each tag value whose length is > 4
@return Returns TRUE if successful, FALSE otherwise
*/
BOOL
-jpegxr_read_exif_profile(FIBITMAP *dib, const BYTE *profile, unsigned length) {
+jpegxr_read_exif_profile(FIBITMAP *dib, const BYTE *profile, unsigned length, unsigned file_offset) {
// assume Little Endian order
- BOOL bMotorolaOrder = FALSE;
+ BOOL bBigEndian = FALSE;
// process Exif specific IFD
- return jpeg_read_exif_dir(dib, profile, 0, length, bMotorolaOrder, TagLib::EXIF_EXIF);
+ return jpeg_read_exif_dir(dib, profile, 0, length, file_offset, bBigEndian, TagLib::EXIF_EXIF);
}
/**
Read and decode JPEG-XR Exif-GPS IFD
@param dib Input FIBITMAP
-@param profile Pointer to the Exif-GPS marker
-@param length Exif-GPS marker length
+@param profile Pointer to the Exif-GPS profile
+@param length Exif-GPS profile length
+@param file_offset Reference offset in the original file of each tag value whose length is > 4
@return Returns TRUE if successful, FALSE otherwise
*/
BOOL
-jpegxr_read_exif_gps_profile(FIBITMAP *dib, const BYTE *profile, unsigned length) {
+jpegxr_read_exif_gps_profile(FIBITMAP *dib, const BYTE *profile, unsigned length, unsigned file_offset) {
// assume Little Endian order
- BOOL bMotorolaOrder = FALSE;
+ BOOL bBigEndian = FALSE;
// process Exif GPS IFD
- return jpeg_read_exif_dir(dib, profile, 0, length, bMotorolaOrder, TagLib::EXIF_GPS);
+ return jpeg_read_exif_dir(dib, profile, 0, length, file_offset, bBigEndian, TagLib::EXIF_GPS);
}
+// ==========================================================
+// Exif common helper routines
+// ==========================================================
+
/**
Rotate a dib according to Exif info
@param dib Input / Output dib to rotate
@@ -943,49 +971,283 @@ RotateExif(FIBITMAP **dib) {
// 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;
+ if((tag != NULL) && (FreeImage_GetTagID(tag) == TAG_ORIENTATION)) {
+ const WORD orientation = *((WORD *)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;
+ }
+ }
+ }
+}
+
+// ==========================================================
+// Exif TIFF JPEG-XR helper routines
+// ==========================================================
+
+class PredicateTagIDCompare {
+public:
+ bool operator()(FITAG *a, FITAG *b) {
+ WORD tag_id_a = FreeImage_GetTagID(a);
+ WORD tag_id_b = FreeImage_GetTagID(b);
+ return (tag_id_a < tag_id_b);
+ }
+};
+
+/**
+Write a metadata model as a TIF IFD to a FIMEMORY handle.
+The entries in the TIF IFD are sorted in ascending order by tag id.
+The last entry is written as 0 (4 bytes) which means no more IFD to follow.
+Supported metadata models are
+<ul>
+<li>FIMD_EXIF_MAIN
+<li>FIMD_EXIF_EXIF
+<li>FIMD_EXIF_GPS
+<li>FIMD_EXIF_INTEROP
+</ul>
+The end of the buffer is filled with 4 bytes equal to 0 (end of IFD offset)
+
+@param dib Input FIBITMAP
+@param md_model Metadata model to write
+@param hmem Memory handle
+@return Returns TRUE if successful, FALSE otherwise
+@see tiff_get_ifd_profile
+*/
+static BOOL
+tiff_write_ifd(FIBITMAP *dib, FREE_IMAGE_MDMODEL md_model, FIMEMORY *hmem) {
+ FITAG *tag = NULL;
+ FIMETADATA *mdhandle = NULL;
+ std::vector<FITAG*> vTagList;
+ TagLib::MDMODEL internal_md_model;
+
+ DWORD ifd_offset = 0; // WORD-aligned IFD value offset
+
+ const BYTE empty_byte = 0;
+
+ // start of the file
+ const long start_of_file = FreeImage_TellMemory(hmem);
+
+ // get the metadata count
+ unsigned metadata_count = FreeImage_GetMetadataCount(md_model, dib);
+ if(metadata_count == 0) {
+ return FALSE;
+ }
+
+ TagLib& s = TagLib::instance();
+
+ // check for supported metadata models
+ switch(md_model) {
+ case FIMD_EXIF_MAIN:
+ internal_md_model = TagLib::EXIF_MAIN;
+ break;
+ case FIMD_EXIF_EXIF:
+ internal_md_model = TagLib::EXIF_EXIF;
+ break;
+ case FIMD_EXIF_GPS:
+ internal_md_model = TagLib::EXIF_GPS;
+ break;
+ case FIMD_EXIF_INTEROP:
+ internal_md_model = TagLib::EXIF_INTEROP;
+ break;
+ default:
+ return FALSE;
+ }
+
+ try {
+ // 1) according to the TIFF specifications,
+ // the entries in a TIF IFD must be sorted in ascending order by tag id
+
+ // store the tags into a vector
+ vTagList.reserve(metadata_count);
+ mdhandle = FreeImage_FindFirstMetadata(md_model, dib, &tag);
+ if(mdhandle) {
+ // parse the tags and store them inside vTagList
+ do {
+ // rewrite the tag id using FreeImage internal database
+ // (in case the tag id is wrong or missing)
+ const char *key = FreeImage_GetTagKey(tag);
+ int tag_id = s.getTagID(internal_md_model, key);
+ if(tag_id != -1) {
+ // this is a known tag, set the tag ID
+ FreeImage_SetTagID(tag, (WORD)tag_id);
+ // record the tag
+ vTagList.push_back(tag);
+ }
+ // else ignore this tag
+ } while(FreeImage_FindNextMetadata(mdhandle, &tag));
+
+ FreeImage_FindCloseMetadata(mdhandle);
+
+ // sort the vector by tag id
+ std::sort(vTagList.begin(), vTagList.end(), PredicateTagIDCompare());
+
+ // update the metadata_count
+ metadata_count = (unsigned)vTagList.size();
+
+ } else {
+ throw(1);
+ }
+
+ // 2) prepare the place for each IFD entries.
+
+ /*
+ An Image File Directory (IFD) consists of a 2-byte count of the number of directory entries (i.e., the number of fields),
+ followed by a sequence of 12-byte field entries,
+ followed by a 4-byte offset of the next IFD (or 0 if none). Do not forget to write the 4 bytes of 0 after the last IFD.
+ */
+
+ {
+ // prepare place for 2 bytes for number of entries + 12 bytes for each entry
+ unsigned ifd_size = 2 + 12 * metadata_count;
+ FreeImage_WriteMemory(&empty_byte, 1, ifd_size, hmem);
+ // record the offset used to write values > 4-bytes
+ ifd_offset = FreeImage_TellMemory(hmem);
+ // rewind
+ FreeImage_SeekMemory(hmem, start_of_file, SEEK_SET);
+ }
+
+ // 3) write each IFD entry in tag id ascending order
+
+ // number of directory entries
+ WORD nde = (WORD)metadata_count;
+ FreeImage_WriteMemory(&nde, 1, 2, hmem);
+
+ // for each entry ...
+ for(unsigned i = 0; i < metadata_count; i++) {
+ FITAG *tag = vTagList[i];
+ // tag id
+ WORD tag_id = FreeImage_GetTagID(tag);
+ FreeImage_WriteMemory(&tag_id, 1, 2, hmem);
+ // tag type (compliant with TIFF specification)
+ WORD tag_type = (WORD)FreeImage_GetTagType(tag);
+ FreeImage_WriteMemory(&tag_type, 1, 2, hmem);
+ // tag count
+ DWORD tag_count = FreeImage_GetTagCount(tag);
+ FreeImage_WriteMemory(&tag_count, 1, 4, hmem);
+ // tag value or offset (results are in BYTE's units)
+ unsigned tag_length = FreeImage_GetTagLength(tag);
+ if(tag_length <= 4) {
+ // 4 bytes or less, write the value (left justified)
+ const BYTE *tag_value = (BYTE*)FreeImage_GetTagValue(tag);
+ FreeImage_WriteMemory(tag_value, 1, tag_length, hmem);
+ for(unsigned k = tag_length; k < 4; k++) {
+ FreeImage_WriteMemory(&empty_byte, 1, 1, hmem);
}
+ } else {
+ // write an offset
+ FreeImage_WriteMemory(&ifd_offset, 1, 4, hmem);
+ // write the value
+ long current_position = FreeImage_TellMemory(hmem);
+ FreeImage_SeekMemory(hmem, ifd_offset, SEEK_SET);
+ FreeImage_WriteMemory(FreeImage_GetTagValue(tag), 1, tag_length, hmem);
+ if(tag_length & 1) {
+ // align to the next WORD boundary
+ FreeImage_WriteMemory(&empty_byte, 1, 1, hmem);
+ }
+ // next offset to use
+ ifd_offset = FreeImage_TellMemory(hmem);
+ // rewind
+ FreeImage_SeekMemory(hmem, current_position, SEEK_SET);
}
}
+
+ // end-of-IFD or next IFD (0 == none)
+ FreeImage_SeekMemory(hmem, ifd_offset, SEEK_SET);
+ FreeImage_WriteMemory(&empty_byte, 1, 4, hmem);
+
+ return TRUE;
+ }
+ catch(int) {
+ return FALSE;
+ }
+}
+
+/**
+Write a metadata model as a TIF IFD, returns the IFD as a buffer.
+The buffer is allocated by the function and must be freed by the caller, using 'free'.
+@param dib Input FIBITMAP
+@param md_model Metadata model to write
+@param ppbProfile Returned buffer
+@param uProfileLength Returned buffer size
+@return Returns TRUE if successful, FALSE otherwise
+@see tiff_write_ifd
+*/
+BOOL
+tiff_get_ifd_profile(FIBITMAP *dib, FREE_IMAGE_MDMODEL md_model, BYTE **ppbProfile, unsigned *uProfileLength) {
+ FIMEMORY *hmem = NULL;
+
+ try {
+ // open a memory stream
+ hmem = FreeImage_OpenMemory(NULL, 0);
+ if(!hmem) {
+ throw(1);
+ }
+
+ // write the metadata model as a TIF IFD
+ BOOL bResult = tiff_write_ifd(dib, md_model, hmem);
+
+ if(bResult) {
+ BYTE *data = NULL;
+ DWORD size_in_bytes = 0;
+
+ // get a pointer to the stream buffer
+ FreeImage_AcquireMemory(hmem, &data, &size_in_bytes);
+
+ // (re-)allocate output buffer
+ BYTE *pbProfile = *ppbProfile;
+ pbProfile = (BYTE*)realloc(pbProfile, size_in_bytes);
+ if(!pbProfile) {
+ throw(1);
+ } else {
+ // copy IFD
+ memcpy(pbProfile, data, size_in_bytes);
+ *ppbProfile = pbProfile;
+ *uProfileLength = size_in_bytes;
+ }
+ }
+
+ // free the memory stream
+ FreeImage_CloseMemory(hmem);
+
+ return bResult;
+
+ } catch(int) {
+ FreeImage_CloseMemory(hmem);
+ return FALSE;
}
}
diff --git a/plugins/AdvaImg/src/Metadata/FreeImageTag.cpp b/plugins/AdvaImg/src/Metadata/FreeImageTag.cpp
index f8af31f9eb..cc12a5d16b 100644
--- a/plugins/AdvaImg/src/Metadata/FreeImageTag.cpp
+++ b/plugins/AdvaImg/src/Metadata/FreeImageTag.cpp
@@ -295,11 +295,6 @@ FreeImage_SetTagValue(FITAG *tag, const void *value) {
// FITAG internal helper functions
// --------------------------------------------------------------------------
-/**
-Given a FREE_IMAGE_MDTYPE, calculate the size of this type in bytes unit
-@param type Input data type
-@return Returns the size of the data type, in bytes unit
-*/
unsigned
FreeImage_TagDataWidth(FREE_IMAGE_MDTYPE type) {
static const unsigned format_bytes[] = {
@@ -328,3 +323,31 @@ FreeImage_TagDataWidth(FREE_IMAGE_MDTYPE type) {
format_bytes[type] : 0;
}
+size_t
+FreeImage_GetTagMemorySize(FITAG *tag) {
+ size_t size = 0;
+ if (tag) {
+ FITAGHEADER *tag_header = (FITAGHEADER *)tag->data;
+ size += sizeof(FITAG);
+ size += sizeof(FITAGHEADER);
+ if (tag_header->key) {
+ size += strlen(tag_header->key) + 1;
+ }
+ if (tag_header->description) {
+ size += strlen(tag_header->description) + 1;
+ }
+ if (tag_header->value) {
+ switch (tag_header->type) {
+ case FIDT_ASCII:
+ // for ASCII strings, the value of the count part of an ASCII tag entry includes the NULL.
+ // however, FreeImage adds another '\0' to be sure that this last character is present.
+ size += tag_header->length + 1;
+ break;
+ default:
+ size += tag_header->length;
+ break;
+ }
+ }
+ }
+ return size;
+}
diff --git a/plugins/AdvaImg/src/Metadata/FreeImageTag.h b/plugins/AdvaImg/src/Metadata/FreeImageTag.h
index f9021ace27..beb8bc84b2 100644
--- a/plugins/AdvaImg/src/Metadata/FreeImageTag.h
+++ b/plugins/AdvaImg/src/Metadata/FreeImageTag.h
@@ -291,14 +291,22 @@
// Helper functions to deal with the FITAG structure
// --------------------------------------------------------------------------
-/**
+/**
Describes the tag format descriptor
+Given a FREE_IMAGE_MDTYPE, calculate the size of this type in bytes unit
@param type Tag data type
-@return Returns the width of a single element, in bytes
+@return Returns the size of the data type, in bytes
@see FREE_IMAGE_MDTYPE
*/
unsigned FreeImage_TagDataWidth(FREE_IMAGE_MDTYPE type);
+/**
+Calculate the memory size required by a tag, including the size of the structure
+@param tag The tag to examine
+@return Retuns the memory size used by a tag
+*/
+size_t FreeImage_GetTagMemorySize(FITAG *tag);
+
// --------------------------------------------------------------------------
/**
@@ -467,13 +475,18 @@ static const char *g_TagLib_ExifRawFieldName = "ExifRaw";
extern "C" {
#endif
-// JPEG Exif profile
+// JPEG / JPEG-XR Exif profile (see Exif.cpp)
+// --------------------------------------------------------------------------
BOOL jpeg_read_exif_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned datalen);
BOOL jpeg_read_exif_profile_raw(FIBITMAP *dib, const BYTE *profile, unsigned length);
-BOOL jpegxr_read_exif_profile(FIBITMAP *dib, const BYTE *profile, unsigned length);
-BOOL jpegxr_read_exif_gps_profile(FIBITMAP *dib, const BYTE *profile, unsigned length);
+BOOL jpegxr_read_exif_profile(FIBITMAP *dib, const BYTE *profile, unsigned length, unsigned file_offset);
+BOOL jpegxr_read_exif_gps_profile(FIBITMAP *dib, const BYTE *profile, unsigned length, unsigned file_offset);
+
+BOOL tiff_get_ifd_profile(FIBITMAP *dib, FREE_IMAGE_MDMODEL md_model, BYTE **ppbProfile, unsigned *uProfileLength);
-// JPEG / TIFF IPTC profile
+
+// JPEG / TIFF IPTC profile (see IPTC.cpp)
+// --------------------------------------------------------------------------
BOOL read_iptc_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned int datalen);
BOOL write_iptc_profile(FIBITMAP *dib, BYTE **profile, unsigned *profile_size);
diff --git a/plugins/AdvaImg/src/Metadata/XTIFF.cpp b/plugins/AdvaImg/src/Metadata/XTIFF.cpp
index 681eed12c5..d5be902ad4 100644
--- a/plugins/AdvaImg/src/Metadata/XTIFF.cpp
+++ b/plugins/AdvaImg/src/Metadata/XTIFF.cpp
@@ -48,14 +48,14 @@
For ReadCount, WriteCount, -1 = unknown.
*/
static const TIFFFieldInfo xtiffFieldInfo[] = {
- { TIFFTAG_GEOPIXELSCALE, -1, -1, TIFF_DOUBLE, FIELD_CUSTOM, TRUE, TRUE, "GeoPixelScale" },
- { TIFFTAG_INTERGRAPH_MATRIX, -1, -1, TIFF_DOUBLE, FIELD_CUSTOM, TRUE, TRUE, "Intergraph TransformationMatrix" },
- { TIFFTAG_GEOTRANSMATRIX, -1, -1, TIFF_DOUBLE, FIELD_CUSTOM, TRUE, TRUE, "GeoTransformationMatrix" },
- { TIFFTAG_GEOTIEPOINTS, -1, -1, TIFF_DOUBLE, FIELD_CUSTOM, TRUE, TRUE, "GeoTiePoints" },
- { TIFFTAG_GEOKEYDIRECTORY,-1,-1, TIFF_SHORT, FIELD_CUSTOM, TRUE, TRUE, "GeoKeyDirectory" },
- { TIFFTAG_GEODOUBLEPARAMS, -1, -1, TIFF_DOUBLE, FIELD_CUSTOM, TRUE, TRUE, "GeoDoubleParams" },
- { TIFFTAG_GEOASCIIPARAMS, -1, -1, TIFF_ASCII, FIELD_CUSTOM, TRUE, FALSE, "GeoASCIIParams" },
- { TIFFTAG_JPL_CARTO_IFD, 1, 1, TIFF_LONG, FIELD_CUSTOM, TRUE, TRUE, "JPL Carto IFD offset" } /** Don't use this! **/
+ { TIFFTAG_GEOPIXELSCALE, -1, -1, TIFF_DOUBLE, FIELD_CUSTOM, TRUE, TRUE, (char*)"GeoPixelScale" },
+ { TIFFTAG_INTERGRAPH_MATRIX, -1, -1, TIFF_DOUBLE, FIELD_CUSTOM, TRUE, TRUE, (char*)"Intergraph TransformationMatrix" },
+ { TIFFTAG_GEOTRANSMATRIX, -1, -1, TIFF_DOUBLE, FIELD_CUSTOM, TRUE, TRUE, (char*)"GeoTransformationMatrix" },
+ { TIFFTAG_GEOTIEPOINTS, -1, -1, TIFF_DOUBLE, FIELD_CUSTOM, TRUE, TRUE, (char*)"GeoTiePoints" },
+ { TIFFTAG_GEOKEYDIRECTORY,-1,-1, TIFF_SHORT, FIELD_CUSTOM, TRUE, TRUE, (char*)"GeoKeyDirectory" },
+ { TIFFTAG_GEODOUBLEPARAMS, -1, -1, TIFF_DOUBLE, FIELD_CUSTOM, TRUE, TRUE, (char*)"GeoDoubleParams" },
+ { TIFFTAG_GEOASCIIPARAMS, -1, -1, TIFF_ASCII, FIELD_CUSTOM, TRUE, FALSE, (char*) "GeoASCIIParams" },
+ { TIFFTAG_JPL_CARTO_IFD, 1, 1, TIFF_LONG, FIELD_CUSTOM, TRUE, TRUE, (char*)"JPL Carto IFD offset" } /** Don't use this! **/
};
static void
@@ -82,19 +82,22 @@ _XTIFFDefaultDirectory(TIFF *tif) {
the default directory method, we call it now to
allow it to set up the rest of its own methods.
*/
- if (_ParentExtender)
+ if (_ParentExtender) {
(*_ParentExtender)(tif);
+ }
}
/**
-XTIFF Initializer -- sets up the callback procedure for the TIFF module
+XTIFF Initializer -- sets up the callback procedure for the TIFF module.
+@see PluginTIFF::InitTIFF
*/
void
XTIFFInitialize(void) {
static int first_time = 1;
- if (! first_time)
+ if (! first_time) {
return; /* Been there. Done that. */
+ }
first_time = 0;
// Grab the inherited method and install
@@ -105,15 +108,28 @@ XTIFFInitialize(void) {
// GeoTIFF tag reading / writing
// ----------------------------------------------------------
-void
+BOOL
tiff_read_geotiff_profile(TIFF *tif, FIBITMAP *dib) {
char defaultKey[16];
- size_t tag_size = sizeof(xtiffFieldInfo) / sizeof(xtiffFieldInfo[0]);
+ // first check for a mandatory tag
+ {
+ short tag_count = 0;
+ void* data = NULL;
+
+ if(!TIFFGetField(tif, TIFFTAG_GEOKEYDIRECTORY, &tag_count, &data)) {
+ // no GeoTIFF tag here
+ return TRUE;
+ }
+ }
+
+ // next, read GeoTIFF tags
+
+ const size_t tag_size = sizeof(xtiffFieldInfo) / sizeof(xtiffFieldInfo[0]);
TagLib& tag_lib = TagLib::instance();
- for(unsigned i = 0; i < tag_size; i++) {
+ for(size_t i = 0; i < tag_size; i++) {
const TIFFFieldInfo *fieldInfo = &xtiffFieldInfo[i];
@@ -123,8 +139,9 @@ tiff_read_geotiff_profile(TIFF *tif, FIBITMAP *dib) {
if(TIFFGetField(tif, fieldInfo->field_tag, &params)) {
// create a tag
FITAG *tag = FreeImage_CreateTag();
- if(!tag)
- return;
+ if(!tag) {
+ return FALSE;
+ }
WORD tag_id = (WORD)fieldInfo->field_tag;
@@ -147,8 +164,9 @@ tiff_read_geotiff_profile(TIFF *tif, FIBITMAP *dib) {
if(TIFFGetField(tif, fieldInfo->field_tag, &tag_count, &data)) {
// create a tag
FITAG *tag = FreeImage_CreateTag();
- if(!tag)
- return;
+ if(!tag) {
+ return FALSE;
+ }
WORD tag_id = (WORD)fieldInfo->field_tag;
FREE_IMAGE_MDTYPE tag_type = (FREE_IMAGE_MDTYPE)fieldInfo->field_type;
@@ -167,21 +185,24 @@ tiff_read_geotiff_profile(TIFF *tif, FIBITMAP *dib) {
}
}
} // for(tag_size)
+
+ return TRUE;
}
-void
+BOOL
tiff_write_geotiff_profile(TIFF *tif, FIBITMAP *dib) {
char defaultKey[16];
if(FreeImage_GetMetadataCount(FIMD_GEOTIFF, dib) == 0) {
- return;
+ // no GeoTIFF tag here
+ return TRUE;
}
- size_t tag_size = sizeof(xtiffFieldInfo) / sizeof(xtiffFieldInfo[0]);
+ const size_t tag_size = sizeof(xtiffFieldInfo) / sizeof(xtiffFieldInfo[0]);
TagLib& tag_lib = TagLib::instance();
- for(unsigned i = 0; i < tag_size; i++) {
+ for(size_t i = 0; i < tag_size; i++) {
const TIFFFieldInfo *fieldInfo = &xtiffFieldInfo[i];
FITAG *tag = NULL;
@@ -195,93 +216,133 @@ tiff_write_geotiff_profile(TIFF *tif, FIBITMAP *dib) {
}
}
}
+
+ return TRUE;
}
// ----------------------------------------------------------
-// EXIF tag reading & writing
+// TIFF EXIF tag reading & writing
// ----------------------------------------------------------
/**
-Read a single exif tag
+Read a single Exif tag
+
+@param tif TIFF handle
+@param tag_id TIFF Tag ID
+@param dib Image being read
+@param md_model Metadata model where to store the tag
+@return Returns TRUE if successful, returns FALSE otherwise
*/
static BOOL
-tiff_read_exif_tag(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib, TagLib& tagLib, TIFFDirectory *td, uint32 tag) {
- const TIFFField *fip;
- uint32 value_count;
+tiff_read_exif_tag(TIFF *tif, uint32 tag_id, FIBITMAP *dib, TagLib::MDMODEL md_model) {
+ uint32 value_count = 0;
int mem_alloc = 0;
void *raw_data = NULL;
- if(tag == TIFFTAG_EXIFIFD) {
+ if(tag_id == TIFFTAG_EXIFIFD) {
+ // Exif IFD offset - skip this tag
+ // md_model should be EXIF_MAIN, the Exif IFD is processed later using the EXIF_EXIF metadata model
return TRUE;
}
+ if((tag_id == TIFFTAG_GPSIFD) && (md_model == TagLib::EXIF_MAIN)) {
+ // Exif GPS IFD offset - skip this tag
+ // should be processed in another way ...
+ return TRUE;
+ }
+
+ TagLib& tagLib = TagLib::instance();
// get the tag key - use NULL to avoid reading GeoTIFF tags
- const char *key = tagLib.getTagFieldName(md_model, (WORD)tag, NULL);
+ const char *key = tagLib.getTagFieldName(md_model, (WORD)tag_id, NULL);
if(key == NULL) {
return TRUE;
}
- fip = TIFFFieldWithTag(tif, tag);
+ const TIFFField *fip = TIFFFieldWithTag(tif, tag_id);
if(fip == NULL) {
return TRUE;
}
- if(fip->field_passcount) { //<- "passcount" means "returns count"
- if (fip->field_readcount != TIFF_VARIABLE2) { //<- TIFF_VARIABLE2 means "uses LONG count"
+ if(TIFFFieldPassCount(fip)) {
+ // a count value is required for 'TIFFGetField'
- // assume TIFF_VARIABLE (uses SHORT count)
- uint16 value_count16;
- if(TIFFGetField(tif, tag, &value_count16, &raw_data) != 1) {
+ if (TIFFFieldReadCount(fip) != TIFF_VARIABLE2) {
+ // a count is required, it will be of type uint16
+ uint16 value_count16 = 0;
+ if(TIFFGetField(tif, tag_id, &value_count16, &raw_data) != 1) {
+ // stop, ignore error
return TRUE;
}
value_count = value_count16;
} else {
- if(TIFFGetField(tif, tag, &value_count, &raw_data) != 1) {
+ // a count is required, it will be of type uint32
+ uint32 value_count32 = 0;
+ if(TIFFGetField(tif, tag_id, &value_count32, &raw_data) != 1) {
+ // stop, ignore error
return TRUE;
}
+ value_count = value_count32;
}
- } else {
+ } else {
// determine count
- if (fip->field_readcount == TIFF_VARIABLE || fip->field_readcount == TIFF_VARIABLE2) {
+ if (TIFFFieldReadCount(fip) == TIFF_VARIABLE || TIFFFieldReadCount(fip) == TIFF_VARIABLE2) {
value_count = 1;
- } else if (fip->field_readcount == TIFF_SPP) {
- value_count = td->td_samplesperpixel;
+ } else if (TIFFFieldReadCount(fip) == TIFF_SPP) {
+ uint16 spp;
+ TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
+ value_count = spp;
} else {
- value_count = fip->field_readcount;
+ value_count = TIFFFieldReadCount(fip);
}
// access fields as pointers to data
// (### determining this is NOT robust... and hardly can be. It is implemented looking the _TIFFVGetField code)
- if(fip->field_tag == TIFFTAG_TRANSFERFUNCTION) {
+ if(TIFFFieldTag(fip) == TIFFTAG_TRANSFERFUNCTION) {
// reading this tag cause a bug probably located somewhere inside libtiff
return TRUE;
}
- if ((fip->field_type == TIFF_ASCII
- || fip->field_readcount == TIFF_VARIABLE
- || fip->field_readcount == TIFF_VARIABLE2
- || fip->field_readcount == TIFF_SPP
+ if ((TIFFFieldDataType(fip) == TIFF_ASCII
+ || TIFFFieldReadCount(fip) == TIFF_VARIABLE
+ || TIFFFieldReadCount(fip) == TIFF_VARIABLE2
+ || TIFFFieldReadCount(fip) == TIFF_SPP
|| value_count > 1)
- && fip->field_tag != TIFFTAG_PAGENUMBER
- && fip->field_tag != TIFFTAG_HALFTONEHINTS
- && fip->field_tag != TIFFTAG_YCBCRSUBSAMPLING
- && fip->field_tag != TIFFTAG_DOTRANGE
+ && TIFFFieldTag(fip) != TIFFTAG_PAGENUMBER
+ && TIFFFieldTag(fip) != TIFFTAG_HALFTONEHINTS
+ && TIFFFieldTag(fip) != TIFFTAG_YCBCRSUBSAMPLING
+ && TIFFFieldTag(fip) != TIFFTAG_DOTRANGE
- && fip->field_tag != TIFFTAG_BITSPERSAMPLE //<- these two are tricky -
- && fip->field_tag != TIFFTAG_COMPRESSION //<- they are defined as TIFF_VARIABLE but in reality return a single value
+ && TIFFFieldTag(fip) != TIFFTAG_BITSPERSAMPLE //<- these two are tricky -
+ && TIFFFieldTag(fip) != TIFFTAG_COMPRESSION //<- they are defined as TIFF_VARIABLE but in reality return a single value
) {
- if(TIFFGetField(tif, tag, &raw_data) != 1) {
+ if(TIFFGetField(tif, tag_id, &raw_data) != 1) {
+ // stop, ignore error
return TRUE;
}
} else {
+ int value_size = 0;
// access fields as values
- const int value_size = _TIFFDataSize(fip->field_type);
+ // Note:
+ // For TIFF_RATIONAL values, TIFFDataWidth() returns 8, but LibTIFF use internaly 4-byte float to represent rationals.
+ {
+ TIFFDataType tag_type = TIFFFieldDataType(fip);
+ switch(tag_type) {
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ value_size = 4;
+ break;
+ default:
+ value_size = TIFFDataWidth(tag_type);
+ break;
+ }
+ }
+
raw_data = _TIFFmalloc(value_size * value_count);
mem_alloc = 1;
int ok = FALSE;
@@ -291,18 +352,18 @@ tiff_read_exif_tag(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib, TagLib& t
switch(value_count)
{
case 1:
- ok = TIFFGetField(tif, tag, raw_data);
+ ok = TIFFGetField(tif, tag_id, raw_data);
break;
case 2:
- ok = TIFFGetField(tif, tag, raw_data, (BYTE*)(raw_data) + value_size*1);
+ ok = TIFFGetField(tif, tag_id, raw_data, (BYTE*)(raw_data) + value_size*1);
break;
/* # we might need more in the future:
case 3:
- ok = TIFFGetField(tif, tag, raw_data, (BYTE*)(raw_data) + value_size*1, (BYTE*)(raw_data) + value_size*2);
+ ok = TIFFGetField(tif, tag_id, raw_data, (BYTE*)(raw_data) + value_size*1, (BYTE*)(raw_data) + value_size*2);
break;
*/
default:
- FreeImage_OutputMessageProc(FIF_TIFF, "Unimplemented variable number of parameters for Tiff Tag %s", fip->field_name);
+ FreeImage_OutputMessageProc(FIF_TIFF, "Unimplemented variable number of parameters for Tiff Tag %s", TIFFFieldName(fip));
break;
}
if(ok != 1) {
@@ -322,62 +383,62 @@ tiff_read_exif_tag(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib, TagLib& t
return FALSE;
}
- FreeImage_SetTagID(fitag, (WORD)tag);
+ FreeImage_SetTagID(fitag, (WORD)tag_id);
FreeImage_SetTagKey(fitag, key);
- switch(fip->field_type) {
+ switch(TIFFFieldDataType(fip)) {
case TIFF_BYTE:
FreeImage_SetTagType(fitag, FIDT_BYTE);
- FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
FreeImage_SetTagCount(fitag, value_count);
FreeImage_SetTagValue(fitag, raw_data);
break;
case TIFF_UNDEFINED:
FreeImage_SetTagType(fitag, FIDT_UNDEFINED);
- FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
FreeImage_SetTagCount(fitag, value_count);
FreeImage_SetTagValue(fitag, raw_data);
break;
case TIFF_SBYTE:
FreeImage_SetTagType(fitag, FIDT_SBYTE);
- FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
FreeImage_SetTagCount(fitag, value_count);
FreeImage_SetTagValue(fitag, raw_data);
break;
case TIFF_SHORT:
FreeImage_SetTagType(fitag, FIDT_SHORT);
- FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
FreeImage_SetTagCount(fitag, value_count);
FreeImage_SetTagValue(fitag, raw_data);
break;
case TIFF_SSHORT:
FreeImage_SetTagType(fitag, FIDT_SSHORT);
- FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
FreeImage_SetTagCount(fitag, value_count);
FreeImage_SetTagValue(fitag, raw_data);
break;
case TIFF_LONG:
FreeImage_SetTagType(fitag, FIDT_LONG);
- FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
FreeImage_SetTagCount(fitag, value_count);
FreeImage_SetTagValue(fitag, raw_data);
break;
case TIFF_IFD:
FreeImage_SetTagType(fitag, FIDT_IFD);
- FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
FreeImage_SetTagCount(fitag, value_count);
FreeImage_SetTagValue(fitag, raw_data);
break;
case TIFF_SLONG:
FreeImage_SetTagType(fitag, FIDT_SLONG);
- FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
FreeImage_SetTagCount(fitag, value_count);
FreeImage_SetTagValue(fitag, raw_data);
break;
@@ -392,7 +453,7 @@ tiff_read_exif_tag(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib, TagLib& t
rvalue[2*i+1] = rational.getDenominator();
}
FreeImage_SetTagType(fitag, FIDT_RATIONAL);
- FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
FreeImage_SetTagCount(fitag, value_count);
FreeImage_SetTagValue(fitag, rvalue);
free(rvalue);
@@ -409,7 +470,7 @@ tiff_read_exif_tag(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib, TagLib& t
rvalue[2*i+1] = rational.getDenominator();
}
FreeImage_SetTagType(fitag, FIDT_RATIONAL);
- FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
FreeImage_SetTagCount(fitag, value_count);
FreeImage_SetTagValue(fitag, rvalue);
free(rvalue);
@@ -418,35 +479,35 @@ tiff_read_exif_tag(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib, TagLib& t
case TIFF_FLOAT:
FreeImage_SetTagType(fitag, FIDT_FLOAT);
- FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
FreeImage_SetTagCount(fitag, value_count);
FreeImage_SetTagValue(fitag, raw_data);
break;
case TIFF_DOUBLE:
FreeImage_SetTagType(fitag, FIDT_DOUBLE);
- FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
FreeImage_SetTagCount(fitag, value_count);
FreeImage_SetTagValue(fitag, raw_data);
break;
case TIFF_LONG8: // BigTIFF 64-bit unsigned integer
FreeImage_SetTagType(fitag, FIDT_LONG8);
- FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
FreeImage_SetTagCount(fitag, value_count);
FreeImage_SetTagValue(fitag, raw_data);
break;
case TIFF_IFD8: // BigTIFF 64-bit unsigned integer (offset)
FreeImage_SetTagType(fitag, FIDT_IFD8);
- FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
FreeImage_SetTagCount(fitag, value_count);
FreeImage_SetTagValue(fitag, raw_data);
break;
case TIFF_SLONG8: // BigTIFF 64-bit signed integer
FreeImage_SetTagType(fitag, FIDT_SLONG8);
- FreeImage_SetTagLength(fitag, TIFFDataWidth(fip->field_type) * value_count);
+ FreeImage_SetTagLength(fitag, TIFFDataWidth( TIFFFieldDataType(fip) ) * value_count);
FreeImage_SetTagCount(fitag, value_count);
FreeImage_SetTagValue(fitag, raw_data);
break;
@@ -454,7 +515,7 @@ tiff_read_exif_tag(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib, TagLib& t
case TIFF_ASCII:
default: {
size_t length = 0;
- if(!mem_alloc && (fip->field_type == TIFF_ASCII) && (fip->field_readcount == TIFF_VARIABLE)) {
+ if(!mem_alloc && (TIFFFieldDataType(fip) == TIFF_ASCII) && (TIFFFieldReadCount(fip) == TIFF_VARIABLE)) {
// when metadata tag is of type ASCII and it's value is of variable size (TIFF_VARIABLE),
// tiff_read_exif_tag function gives length of 1 so all strings are truncated ...
// ... try to avoid this by using an explicit calculation for 'length'
@@ -462,7 +523,7 @@ tiff_read_exif_tag(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib, TagLib& t
}
else {
// remember that raw_data = _TIFFmalloc(value_size * value_count);
- const int value_size = _TIFFDataSize(fip->field_type);
+ const int value_size = TIFFDataWidth( TIFFFieldDataType(fip) );
length = value_size * value_count;
}
FreeImage_SetTagType(fitag, FIDT_ASCII);
@@ -473,7 +534,7 @@ tiff_read_exif_tag(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib, TagLib& t
break;
}
- const char *description = tagLib.getTagDescription(md_model, (WORD)tag);
+ const char *description = tagLib.getTagDescription(md_model, (WORD)tag_id);
if(description) {
FreeImage_SetTagDescription(fitag, description);
}
@@ -491,21 +552,22 @@ tiff_read_exif_tag(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib, TagLib& t
/**
Read all known exif tags
+
+@param tif TIFF handle
+@param md_model Metadata model where to store the tags
+@param dib Image being read
+@return Returns TRUE if successful, returns FALSE otherwise
*/
BOOL
tiff_read_exif_tags(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib) {
- int i;
- short count;
TagLib& tagLib = TagLib::instance();
- TIFFDirectory *td = &tif->tif_dir;
-
- count = (short) TIFFGetTagListCount(tif);
- for(i = 0; i < count; i++) {
- uint32 tag = TIFFGetTagListEntry(tif, i);
+ const int count = TIFFGetTagListCount(tif);
+ for(int i = 0; i < count; i++) {
+ uint32 tag_id = TIFFGetTagListEntry(tif, i);
// read the tag
- if (!tiff_read_exif_tag(tif, md_model, dib, tagLib, td, tag))
+ if (!tiff_read_exif_tag(tif, tag_id, dib, md_model))
return FALSE;
}
@@ -514,22 +576,26 @@ tiff_read_exif_tags(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib) {
// loop over all Core Directory Tags
// ### uses private data, but there is no other way
if(md_model == TagLib::EXIF_MAIN) {
+ const TIFFDirectory *td = &tif->tif_dir;
uint32 lastTag = 0; //<- used to prevent reading some tags twice (as stored in tif_fieldinfo)
for (int fi = 0, nfi = (int)tif->tif_nfields; nfi > 0; nfi--, fi++) {
const TIFFField *fld = tif->tif_fields[fi];
- if(fld->field_tag == lastTag)
+ const uint32 tag_id = TIFFFieldTag(fld);
+
+ if(tag_id == lastTag) {
continue;
+ }
// test if tag value is set
- // (lifted directly form LibTiff _TIFFWriteDirectory)
+ // (lifted directly from LibTiff _TIFFWriteDirectory)
if( fld->field_bit == FIELD_CUSTOM ) {
- int ci, is_set = FALSE;
+ int is_set = FALSE;
- for( ci = 0; ci < td->td_customValueCount; ci++ ) {
+ for(int ci = 0; ci < td->td_customValueCount; ci++ ) {
is_set |= (td->td_customValues[ci].info == fld);
}
@@ -543,16 +609,14 @@ tiff_read_exif_tags(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib) {
// process *all* other tags (some will be ignored)
- tiff_read_exif_tag(tif, md_model, dib, tagLib, td, fld->field_tag);
-
+ tiff_read_exif_tag(tif, tag_id, dib, md_model);
- lastTag = fld->field_tag;
+ lastTag = tag_id;
}
}
return TRUE;
-
}
@@ -562,27 +626,47 @@ Skip tags that are already handled by the LibTIFF writing process
static BOOL
skip_write_field(TIFF* tif, uint32 tag) {
switch (tag) {
- case TIFFTAG_SAMPLEFORMAT:
+ case TIFFTAG_SUBFILETYPE:
+ case TIFFTAG_OSUBFILETYPE:
case TIFFTAG_IMAGEWIDTH:
case TIFFTAG_IMAGELENGTH:
- case TIFFTAG_SAMPLESPERPIXEL:
case TIFFTAG_BITSPERSAMPLE:
+ case TIFFTAG_COMPRESSION:
case TIFFTAG_PHOTOMETRIC:
- case TIFFTAG_PLANARCONFIG:
+ case TIFFTAG_THRESHHOLDING:
+ case TIFFTAG_CELLWIDTH:
+ case TIFFTAG_CELLLENGTH:
+ case TIFFTAG_FILLORDER:
+ case TIFFTAG_STRIPOFFSETS:
+ case TIFFTAG_ORIENTATION:
+ case TIFFTAG_SAMPLESPERPIXEL:
case TIFFTAG_ROWSPERSTRIP:
case TIFFTAG_STRIPBYTECOUNTS:
- case TIFFTAG_STRIPOFFSETS:
- case TIFFTAG_RESOLUTIONUNIT:
+ case TIFFTAG_MINSAMPLEVALUE:
+ case TIFFTAG_MAXSAMPLEVALUE:
case TIFFTAG_XRESOLUTION:
case TIFFTAG_YRESOLUTION:
- case TIFFTAG_SUBFILETYPE:
+ case TIFFTAG_PLANARCONFIG:
+ case TIFFTAG_FREEOFFSETS:
+ case TIFFTAG_FREEBYTECOUNTS:
+ case TIFFTAG_GRAYRESPONSEUNIT:
+ case TIFFTAG_GRAYRESPONSECURVE:
+ case TIFFTAG_GROUP3OPTIONS:
+ case TIFFTAG_GROUP4OPTIONS:
+ case TIFFTAG_RESOLUTIONUNIT:
case TIFFTAG_PAGENUMBER:
- case TIFFTAG_COLORMAP:
- case TIFFTAG_ORIENTATION:
- case TIFFTAG_COMPRESSION:
+ case TIFFTAG_COLORRESPONSEUNIT:
case TIFFTAG_PREDICTOR:
- case TIFFTAG_GROUP3OPTIONS:
- case TIFFTAG_FILLORDER:
+ case TIFFTAG_COLORMAP:
+ case TIFFTAG_HALFTONEHINTS:
+ case TIFFTAG_TILEWIDTH:
+ case TIFFTAG_TILELENGTH:
+ case TIFFTAG_TILEOFFSETS:
+ case TIFFTAG_TILEBYTECOUNTS:
+ case TIFFTAG_EXTRASAMPLES:
+ case TIFFTAG_SAMPLEFORMAT:
+ case TIFFTAG_SMINSAMPLEVALUE:
+ case TIFFTAG_SMAXSAMPLEVALUE:
// skip always, values have been set in SaveOneTIFF()
return TRUE;
break;
@@ -618,6 +702,11 @@ skip_write_field(TIFF* tif, uint32 tag) {
/**
Write all known exif tags
+
+@param tif TIFF handle
+@param md_model Metadata model from where to load the tags
+@param dib Image being written
+@return Returns TRUE if successful, returns FALSE otherwise
*/
BOOL
tiff_write_exif_tags(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib) {
@@ -636,19 +725,21 @@ tiff_write_exif_tags(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib) {
for (int fi = 0, nfi = (int)tif->tif_nfields; nfi > 0; nfi--, fi++) {
const TIFFField *fld = tif->tif_fields[fi];
+
+ const uint32 tag_id = TIFFFieldTag(fld);
- if(skip_write_field(tif, fld->field_tag)) {
+ if(skip_write_field(tif, tag_id)) {
// skip tags that are already handled by the LibTIFF writing process
continue;
}
FITAG *tag = NULL;
// get the tag key
- const char *key = tag_lib.getTagFieldName(TagLib::EXIF_MAIN, (WORD)fld->field_tag, defaultKey);
+ const char *key = tag_lib.getTagFieldName(TagLib::EXIF_MAIN, (WORD)tag_id, defaultKey);
if(FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, key, &tag)) {
FREE_IMAGE_MDTYPE tag_type = FreeImage_GetTagType(tag);
- TIFFDataType tif_tag_type = fld->field_type;
+ TIFFDataType tif_tag_type = TIFFFieldDataType(fld);
// check for identical formats
@@ -658,15 +749,15 @@ tiff_write_exif_tags(TIFF *tif, TagLib::MDMODEL md_model, FIBITMAP *dib) {
continue;
}
// type of storage may differ (e.g. rationnal array vs float array type)
- if(_TIFFDataSize(tif_tag_type) != FreeImage_TagDataWidth(tag_type)) {
+ if((unsigned)_TIFFDataSize(tif_tag_type) != FreeImage_TagDataWidth(tag_type)) {
// skip tag or _TIFFmemcpy will fail
continue;
}
if(tag_type == FIDT_ASCII) {
- TIFFSetField(tif, fld->field_tag, FreeImage_GetTagValue(tag));
+ TIFFSetField(tif, tag_id, FreeImage_GetTagValue(tag));
} else {
- TIFFSetField(tif, fld->field_tag, FreeImage_GetTagCount(tag), FreeImage_GetTagValue(tag));
+ TIFFSetField(tif, tag_id, FreeImage_GetTagCount(tag), FreeImage_GetTagValue(tag));
}
}
}
diff --git a/plugins/AdvaImg/src/Quantizers.h b/plugins/AdvaImg/src/Quantizers.h
index 2a671fad1c..3db12d387d 100644
--- a/plugins/AdvaImg/src/Quantizers.h
+++ b/plugins/AdvaImg/src/Quantizers.h
@@ -3,6 +3,7 @@
//
// Design and implementation by:
// - Hervé Drolon <drolon@infonie.fr>
+// - Carsten Klein (cklein05@users.sourceforge.net)
//
// This file is part of FreeImage 3
//
@@ -223,3 +224,131 @@ public:
};
+/**
+ * LFPQUANT - Lossless Fast Pseudo-Quantization Algorithm
+ *
+ * The Lossless Fast Pseudo-Quantization algorithm is no real quantization
+ * algorithm, since it makes no attempt to create a palette, that is suitable
+ * for all colors of the 24-bit source image. However, it provides very fast
+ * conversions from 24-bit to 8-bit images, if the number of distinct colors
+ * in the source image is not greater than the desired palette size. If the
+ * number of colors in the source image is exceeded, the Quantize method of
+ * this implementation stops the process and returns NULL.
+ *
+ * This implementation uses a very fast hash map implementation to collect
+ * the source image's colors. It turned out that a customized implementation
+ * of a hash table with open addressing (using linear probing) provides the
+ * best performance. The hash table has 512 entries, which prevents the load
+ * factor to exceed 0.5 as we have 256 entries at most. Each entry consumes
+ * 64 bits, so the whole hash table takes 4KB of memory.
+ *
+ * For large images, the LFPQuantizer is typically up to three times faster
+ * than the WuQuantizer.
+ */
+class LFPQuantizer {
+public:
+ /** Constructor */
+ LFPQuantizer(unsigned PaletteSize);
+
+ /** Destructor */
+ ~LFPQuantizer();
+
+ /**
+ * Quantizer
+ * @param dib input 24-bit or 32-bit bitmap to be quantized
+ * @return returns the pseudo-quantized 8-bit bitmap
+ */
+ FIBITMAP* Quantize(FIBITMAP *dib, int ReserveSize, RGBQUAD *ReservePalette);
+
+protected:
+ /** The maximum size of a palette. */
+ static const unsigned MAX_SIZE = 256;
+
+ /**
+ * The size of the hash table. Must be a power of 2. By sizing it
+ * MAX_SIZE * 2, we ensure the load factor not to exceed 0.5 at any
+ * time, since we will have MAX_SIZE entries at most.
+ */
+ static const unsigned MAP_SIZE = MAX_SIZE * 2;
+
+ /**
+ * With open addressing we need a special value for empty buckets.
+ * Both entry.color and entry.index are 0xFFFFFFFF for an empty
+ * entry.
+ */
+ static const unsigned EMPTY_BUCKET = 0xFFFFFFFF;
+
+ /**
+ * This structure defines a single entry in the hash table. We use
+ * color as the entry's key.
+ */
+ typedef struct MapEntry {
+ unsigned color;
+ unsigned index;
+ } MapEntry;
+
+ /** The hash table. */
+ MapEntry *m_map;
+
+ /**
+ * The current size of the newly created palette. Since the provided
+ * reserve palette could contain duplicates, this is not necessarily
+ * the number of entries in the hash table. Initialized to zero.
+ */
+ unsigned m_size;
+
+ /**
+ * The desired maximum number of entries in the newly created palette.
+ * If m_size exceeds this value, the palette is full and the
+ * quantization process is stopped. Initialized to the desired
+ * palette size.
+ */
+ unsigned m_limit;
+
+ /**
+ * The palette index used for the next color added. Initialized to
+ * zero (the reserve palette is put to the end of the palette).
+ */
+ unsigned m_index;
+
+ /**
+ * Ensures that hash codes that differ only by constant multiples
+ * at each bit position have a bounded number of collisions.
+ * @param h the initial (aka raw) hash code
+ * @return the modified hash code
+ */
+ static inline unsigned hash(unsigned h) {
+ h ^= (h >> 20) ^ (h >> 12);
+ return h ^ (h >> 7) ^ (h >> 4);
+ }
+
+ /**
+ * Returns the palette index of the specified color. Tries to put the
+ * color into the map, if it's not already present in the map. In that
+ * case, a new index is used for the color. Returns -1, if adding the
+ * color would exceed the desired maximum number of colors in the
+ * palette.
+ * @param color the color to get the index from
+ * @return the palette index of the specified color or -1, if there
+ * is no space left in the palette
+ */
+ int GetIndexForColor(unsigned color);
+
+ /**
+ * Adds the specified number of entries of the specified reserve
+ * palette to the newly created palette.
+ * @param *palette a pointer to the reserve palette to copy from
+ * @param size the number of entries to copy
+ */
+ void AddReservePalette(const void *palette, unsigned size);
+
+ /**
+ * Copies the newly created palette into the specified destination
+ * palettte. Although unused palette entries are not overwritten in
+ * the destination palette, it is assumed to have space for at
+ * least 256 entries.
+ * @param palette a pointer to the destination palette
+ */
+ void WritePalette(void *palette);
+
+};
diff --git a/plugins/AdvaImg/src/Utilities.h b/plugins/AdvaImg/src/Utilities.h
index c967de9ccc..79b0c1d59d 100644
--- a/plugins/AdvaImg/src/Utilities.h
+++ b/plugins/AdvaImg/src/Utilities.h
@@ -5,6 +5,7 @@
// - Floris van den Berg (flvdberg@wxs.nl)
// - Hervé Drolon <drolon@infonie.fr>
// - Ryan Rubley (ryan@lostreality.org)
+// - Mihail Naydenov (mnaydenov@users.sourceforge.net)
//
// This file is part of FreeImage 3
//
@@ -72,12 +73,13 @@ Allocate a FIBITMAP with possibly no pixel data
(i.e. only header data and some or all metadata)
@param header_only If TRUE, allocate a 'header only' FIBITMAP, otherwise allocate a full FIBITMAP
@param type Image type
-@param width
-@param height
-@param bpp
-@param red_mask
-@param green_mask
-@param blue_mask
+@param width Image width
+@param height Image height
+@param bpp Number of bits per pixel
+@param red_mask Image red mask
+@param green_mask Image green mask
+@param blue_mask Image blue mask
+@return Returns the allocated FIBITMAP
@see FreeImage_AllocateT
*/
DLL_API FIBITMAP * DLL_CALLCONV FreeImage_AllocateHeaderT(BOOL header_only, FREE_IMAGE_TYPE type, int width, int height, int bpp FI_DEFAULT(8), unsigned red_mask FI_DEFAULT(0), unsigned green_mask FI_DEFAULT(0), unsigned blue_mask FI_DEFAULT(0));
@@ -86,17 +88,34 @@ DLL_API FIBITMAP * DLL_CALLCONV FreeImage_AllocateHeaderT(BOOL header_only, FREE
Allocate a FIBITMAP of type FIT_BITMAP, with possibly no pixel data
(i.e. only header data and some or all metadata)
@param header_only If TRUE, allocate a 'header only' FIBITMAP, otherwise allocate a full FIBITMAP
-@param width
-@param height
-@param bpp
-@param red_mask
-@param green_mask
-@param blue_mask
+@param width Image width
+@param height Image height
+@param bpp Number of bits per pixel
+@param red_mask Image red mask
+@param green_mask Image green mask
+@param blue_mask Image blue mask
+@return Returns the allocated FIBITMAP
@see FreeImage_Allocate
*/
DLL_API FIBITMAP * DLL_CALLCONV FreeImage_AllocateHeader(BOOL header_only, int width, int height, int bpp, unsigned red_mask FI_DEFAULT(0), unsigned green_mask FI_DEFAULT(0), unsigned blue_mask FI_DEFAULT(0));
/**
+Allocate a FIBITMAP with no pixel data and wrap a user provided pixel buffer
+@param ext_bits Pointer to external user's pixel buffer
+@param ext_pitch Pointer to external user's pixel buffer pitch
+@param type Image type
+@param width Image width
+@param height Image height
+@param bpp Number of bits per pixel
+@param red_mask Image red mask
+@param green_mask Image green mask
+@param blue_mask Image blue mask
+@return Returns the allocated FIBITMAP
+@see FreeImage_ConvertFromRawBitsEx
+*/
+DLL_API FIBITMAP * DLL_CALLCONV FreeImage_AllocateHeaderForBits(BYTE *ext_bits, unsigned ext_pitch, FREE_IMAGE_TYPE type, int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask);
+
+/**
Helper for 16-bit FIT_BITMAP
@see FreeImage_GetRGBMasks
*/
@@ -276,7 +295,7 @@ CalculateUsedPaletteEntries(unsigned bit_count) {
inline unsigned char *
CalculateScanLine(unsigned char *bits, unsigned pitch, int scanline) {
- return (bits + (pitch * scanline));
+ return bits ? (bits + ((size_t)pitch * scanline)) : NULL;
}
// ----------------------------------------------------------
@@ -458,7 +477,7 @@ A Standard Default Color Space for the Internet - sRGB.
*/
#define LUMA_REC709(r, g, b) (0.2126F * r + 0.7152F * g + 0.0722F * b)
-#define GREY(r, g, b) (BYTE)LUMA_REC709(r, g, b)
+#define GREY(r, g, b) (BYTE)(LUMA_REC709(r, g, b) + 0.5F)
/*
#define GREY(r, g, b) (BYTE)(((WORD)r * 77 + (WORD)g * 150 + (WORD)b * 29) >> 8) // .299R + .587G + .114B
*/