summaryrefslogtreecommitdiff
path: root/plugins/AdvaImg/src/FreeImageToolkit
diff options
context:
space:
mode:
authorKirill Volinsky <mataes2007@gmail.com>2013-01-03 14:34:48 +0000
committerKirill Volinsky <mataes2007@gmail.com>2013-01-03 14:34:48 +0000
commiteb680766d56e815086397361b286fd8055fb5377 (patch)
tree7994cdb0d9077f645ba7fd06bdd2cde32cf599d4 /plugins/AdvaImg/src/FreeImageToolkit
parentec61686c3d96f49eb7f40a4208690a0781d63e29 (diff)
FreeImage updated to 3.15.4
removed not used formats git-svn-id: http://svn.miranda-ng.org/main/trunk@2926 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/AdvaImg/src/FreeImageToolkit')
-rw-r--r--plugins/AdvaImg/src/FreeImageToolkit/BSplineRotate.cpp20
-rw-r--r--plugins/AdvaImg/src/FreeImageToolkit/Background.cpp895
-rw-r--r--plugins/AdvaImg/src/FreeImageToolkit/Channels.cpp42
-rw-r--r--plugins/AdvaImg/src/FreeImageToolkit/ClassicRotate.cpp38
-rw-r--r--plugins/AdvaImg/src/FreeImageToolkit/Colors.cpp16
-rw-r--r--plugins/AdvaImg/src/FreeImageToolkit/CopyPaste.cpp44
-rw-r--r--plugins/AdvaImg/src/FreeImageToolkit/Display.cpp10
-rw-r--r--plugins/AdvaImg/src/FreeImageToolkit/JPEGTransform.cpp14
-rw-r--r--plugins/AdvaImg/src/FreeImageToolkit/MultigridPoissonSolver.cpp30
-rw-r--r--plugins/AdvaImg/src/FreeImageToolkit/Rescale.cpp400
-rw-r--r--plugins/AdvaImg/src/FreeImageToolkit/Resize.cpp2648
-rw-r--r--plugins/AdvaImg/src/FreeImageToolkit/Resize.h340
12 files changed, 3358 insertions, 1139 deletions
diff --git a/plugins/AdvaImg/src/FreeImageToolkit/BSplineRotate.cpp b/plugins/AdvaImg/src/FreeImageToolkit/BSplineRotate.cpp
index e4be1d0bd2..690db87d8c 100644
--- a/plugins/AdvaImg/src/FreeImageToolkit/BSplineRotate.cpp
+++ b/plugins/AdvaImg/src/FreeImageToolkit/BSplineRotate.cpp
@@ -556,7 +556,7 @@ Rotate8Bit(FIBITMAP *dib, double angle, double x_shift, double y_shift, double x
// allocate output image
FIBITMAP *dst = FreeImage_Allocate(width, height, bpp);
- if (!dst)
+ if(!dst)
return NULL;
// buid a grey scale palette
RGBQUAD *pal = FreeImage_GetPalette(dst);
@@ -566,7 +566,7 @@ Rotate8Bit(FIBITMAP *dib, double angle, double x_shift, double y_shift, double x
// allocate a temporary array
ImageRasterArray = (double*)malloc(width * height * sizeof(double));
- if (!ImageRasterArray) {
+ if(!ImageRasterArray) {
FreeImage_Unload(dst);
return NULL;
}
@@ -583,7 +583,7 @@ Rotate8Bit(FIBITMAP *dib, double angle, double x_shift, double y_shift, double x
// convert between a representation based on image samples
// and a representation based on image B-spline coefficients
bResult = SamplesToCoefficients(ImageRasterArray, width, height, spline);
- if (!bResult) {
+ if(!bResult) {
FreeImage_Unload(dst);
free(ImageRasterArray);
return NULL;
@@ -611,7 +611,7 @@ Rotate8Bit(FIBITMAP *dib, double angle, double x_shift, double y_shift, double x
x1 = x0 + a11 * (double)x;
y1 = y0 + a21 * (double)x;
if(use_mask) {
- if ((x1 <= -0.5) || (((double)width - 0.5) <= x1) || (y1 <= -0.5) || (((double)height - 0.5) <= y1)) {
+ if((x1 <= -0.5) || (((double)width - 0.5) <= x1) || (y1 <= -0.5) || (((double)height - 0.5) <= y1)) {
p = 0;
}
else {
@@ -652,7 +652,7 @@ FreeImage_RotateEx(FIBITMAP *dib, double angle, double x_shift, double y_shift,
BYTE *src_bits, *dst_bits;
FIBITMAP *src8 = NULL, *dst8 = NULL, *dst = NULL;
- if (!FreeImage_HasPixels(dib)) return NULL;
+ if(!FreeImage_HasPixels(dib)) return NULL;
try {
@@ -666,20 +666,20 @@ FreeImage_RotateEx(FIBITMAP *dib, double angle, double x_shift, double y_shift,
}
return dst_8;
}
- if ((bpp == 24) || (bpp == 32)) {
+ if((bpp == 24) || (bpp == 32)) {
// allocate dst image
int width = FreeImage_GetWidth(dib);
int height = FreeImage_GetHeight(dib);
- if ( bpp == 24 ) {
+ if( bpp == 24 ) {
dst = FreeImage_Allocate(width, height, bpp, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
} else {
dst = FreeImage_Allocate(width, height, bpp, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
}
- if (!dst) throw(1);
+ if(!dst) throw(1);
// allocate a temporary 8-bit dib (no need to build a palette)
src8 = FreeImage_Allocate(width, height, 8);
- if (!src8) throw(1);
+ if(!src8) throw(1);
// process each channel separately
// -------------------------------
@@ -698,7 +698,7 @@ FreeImage_RotateEx(FIBITMAP *dib, double angle, double x_shift, double y_shift,
// process channel
dst8 = Rotate8Bit(src8, angle, x_shift, y_shift, x_origin, y_origin, ROTATE_CUBIC, use_mask);
- if (!dst8) throw(1);
+ if(!dst8) throw(1);
// insert channel to destination dib
for(y = 0; y < height; y++) {
diff --git a/plugins/AdvaImg/src/FreeImageToolkit/Background.cpp b/plugins/AdvaImg/src/FreeImageToolkit/Background.cpp
new file mode 100644
index 0000000000..06b31aa332
--- /dev/null
+++ b/plugins/AdvaImg/src/FreeImageToolkit/Background.cpp
@@ -0,0 +1,895 @@
+// ==========================================================
+// Background filling routines
+//
+// Design and implementation by
+// - Carsten Klein (c.klein@datagis.com)
+//
+// This file is part of FreeImage 3
+//
+// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
+// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
+// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
+// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
+// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
+// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
+// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
+// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
+// THIS DISCLAIMER.
+//
+// Use at your own risk!
+// ==========================================================
+
+#include "FreeImage.h"
+#include "Utilities.h"
+
+/** @brief Determines, whether a palletized image is visually greyscale or not.
+
+ Unlike with FreeImage_GetColorType, which returns either FIC_MINISBLACK or
+ FIC_MINISWHITE for a greyscale image with a linear ramp palette, the return
+ value of this function does not depend on the palette's order, but only on the
+ palette's individual colors.
+ @param dib The image to be tested.
+ @return Returns TRUE if the palette of the image specified contains only
+ greyscales, FALSE otherwise.
+ */
+static BOOL
+IsVisualGreyscaleImage(FIBITMAP *dib) {
+
+ switch (FreeImage_GetBPP(dib)) {
+ case 1:
+ case 4:
+ case 8: {
+ unsigned ncolors = FreeImage_GetColorsUsed(dib);
+ RGBQUAD *rgb = FreeImage_GetPalette(dib);
+ for (unsigned i = 0; i< ncolors; i++) {
+ if ((rgb->rgbRed != rgb->rgbGreen) || (rgb->rgbRed != rgb->rgbBlue)) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+ default: {
+ return (FreeImage_GetColorType(dib) == FIC_MINISBLACK);
+ }
+ }
+}
+
+/** @brief Looks up a specified color in a FIBITMAP's palette and returns the color's
+ palette index or -1 if the color was not found.
+
+ Unlike with FreeImage_GetColorType, which returns either FIC_MINISBLACK or
+ FIC_MINISWHITE for a greyscale image with a linear ramp palette, the return
+ value of this function does not depend on the palette's order, but only on the
+ palette's individual colors.
+ @param dib The image, whose palette should be searched through.
+ @param color The color to be searched in the palette.
+ @param options Options that affect the color search process.
+ @param color_type A pointer, that optionally specifies the image's color type as
+ returned by FreeImage_GetColorType. If invalid or NULL, this function determines the
+ color type with FreeImage_GetColorType.
+ @return Returns the specified color's palette index, the color's rgbReserved member
+ if option FI_COLOR_ALPHA_IS_INDEX was specified or -1, if the color was not found
+ in the image's palette or if the specified image is non-palletized.
+ */
+static int
+GetPaletteIndex(FIBITMAP *dib, const RGBQUAD *color, int options, FREE_IMAGE_COLOR_TYPE *color_type) {
+
+ int result = -1;
+
+ if ((!dib) || (!color)) {
+ return result;
+ }
+
+ int bpp = FreeImage_GetBPP(dib);
+
+ // First check trivial case: return color->rgbReserved if only
+ // FI_COLOR_ALPHA_IS_INDEX is set.
+ if ((options & FI_COLOR_ALPHA_IS_INDEX) == FI_COLOR_ALPHA_IS_INDEX) {
+ if (bpp == 1) {
+ return color->rgbReserved & 0x01;
+ } else if (bpp == 4) {
+ return color->rgbReserved & 0x0F;
+ }
+ return color->rgbReserved;
+ }
+
+ if (bpp == 8) {
+ FREE_IMAGE_COLOR_TYPE ct =
+ (color_type == NULL || *color_type < 0) ?
+ FreeImage_GetColorType(dib) : *color_type;
+ if (ct == FIC_MINISBLACK) {
+ return GREY(color->rgbRed, color->rgbGreen, color->rgbBlue);
+ }
+ if (ct == FIC_MINISWHITE) {
+ return 255 - GREY(color->rgbRed, color->rgbGreen, color->rgbBlue);
+ }
+ } else if (bpp > 8) {
+ // for palettized images only
+ return result;
+ }
+
+ if (options & FI_COLOR_FIND_EQUAL_COLOR) {
+
+ // Option FI_COLOR_ALPHA_IS_INDEX is implicit here so, set
+ // index to color->rgbReserved
+ result = color->rgbReserved;
+ if (bpp == 1) {
+ result &= 0x01;
+ } else if (bpp == 4) {
+ result &= 0x0F;
+ }
+
+ unsigned ucolor;
+ if (!IsVisualGreyscaleImage(dib)) {
+ ucolor = (*((unsigned *)color)) & 0xFFFFFF;
+ } else {
+ ucolor = GREY(color->rgbRed, color->rgbGreen, color->rgbBlue) * 0x010101;
+ //ucolor = (ucolor | (ucolor << 8) | (ucolor << 16));
+ }
+ unsigned ncolors = FreeImage_GetColorsUsed(dib);
+ unsigned *palette = (unsigned *)FreeImage_GetPalette(dib);
+ for (unsigned i = 0; i < ncolors; i++) {
+ if ((palette[i] & 0xFFFFFF) == ucolor) {
+ result = i;
+ break;
+ }
+ }
+ } else {
+ unsigned minimum = UINT_MAX;
+ unsigned ncolors = FreeImage_GetColorsUsed(dib);
+ BYTE *palette = (BYTE *)FreeImage_GetPalette(dib);
+ BYTE red, green, blue;
+ if (!IsVisualGreyscaleImage(dib)) {
+ red = color->rgbRed;
+ green = color->rgbGreen;
+ blue = color->rgbBlue;
+ } else {
+ red = GREY(color->rgbRed, color->rgbGreen, color->rgbBlue);
+ green = blue = red;
+ }
+ for (unsigned i = 0; i < ncolors; i++) {
+ unsigned m = abs(palette[FI_RGBA_BLUE] - blue)
+ + abs(palette[FI_RGBA_GREEN] - green)
+ + abs(palette[FI_RGBA_RED] - red);
+ if (m < minimum) {
+ minimum = m;
+ result = i;
+ if (m == 0) {
+ break;
+ }
+ }
+ palette += sizeof(RGBQUAD);
+ }
+ }
+ return result;
+}
+
+/** @brief Blends an alpha-transparent foreground color over an opaque background
+ color.
+
+ This function blends the alpha-transparent foreground color fgcolor over the
+ background color bgcolor. The background color is considered fully opaque,
+ whatever it's alpha value contains, whereas the foreground color is considered
+ to be a real RGBA color with an alpha value, which is used for the blend
+ operation. The resulting color is returned through the blended parameter.
+ @param bgcolor The background color for the blend operation.
+ @param fgcolor The foreground color for the blend operation. This color's alpha
+ value, stored in the rgbReserved member, is the alpha value used for the blend
+ operation.
+ @param blended This out parameter takes the blended color and so, returns it to
+ the caller. This color's alpha value will be 0xFF (255) so, the blended color
+ itself has no transparency. The this argument is not changed, if the function
+ fails.
+ @return Returns TRUE on success, FALSE otherwise. This function fails if any of
+ the color arguments is a null pointer.
+ */
+static BOOL
+GetAlphaBlendedColor(const RGBQUAD *bgcolor, const RGBQUAD *fgcolor, RGBQUAD *blended) {
+
+ if ((!bgcolor) || (!fgcolor) || (!blended)) {
+ return FALSE;
+ }
+
+ BYTE alpha = fgcolor->rgbReserved;
+ BYTE not_alpha = ~alpha;
+
+ blended->rgbRed = (BYTE)( ((WORD)fgcolor->rgbRed * alpha + not_alpha * (WORD)bgcolor->rgbRed) >> 8 );
+ blended->rgbGreen = (BYTE)( ((WORD)fgcolor->rgbGreen * alpha + not_alpha * (WORD)bgcolor->rgbGreen) >> 8) ;
+ blended->rgbBlue = (BYTE)( ((WORD)fgcolor->rgbRed * alpha + not_alpha * (WORD)bgcolor->rgbBlue) >> 8 );
+ blended->rgbReserved = 0xFF;
+
+ return TRUE;
+}
+
+/** @brief Fills a FIT_BITMAP image with the specified color.
+
+ This function does the dirty work for FreeImage_FillBackground for FIT_BITMAP
+ images.
+ @param dib The image to be filled.
+ @param color The color, the specified image should be filled with.
+ @param options Options that affect the color search process for palletized images.
+ @return Returns TRUE on success, FALSE otherwise. This function fails if any of
+ the dib and color is NULL or the provided image is not a FIT_BITMAP image.
+ */
+static BOOL
+FillBackgroundBitmap(FIBITMAP *dib, const RGBQUAD *color, int options) {
+
+ if ((!dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP)) {
+ return FALSE;;
+ }
+
+ if (!color) {
+ return FALSE;
+ }
+
+ const RGBQUAD *color_intl = color;
+ unsigned bpp = FreeImage_GetBPP(dib);
+ unsigned width = FreeImage_GetWidth(dib);
+ unsigned height = FreeImage_GetHeight(dib);
+
+ FREE_IMAGE_COLOR_TYPE color_type = FreeImage_GetColorType(dib);
+
+ // get a pointer to the first scanline (bottom line)
+ BYTE *src_bits = FreeImage_GetScanLine(dib, 0);
+ BYTE *dst_bits = src_bits;
+
+ BOOL supports_alpha = ((bpp >= 24) || ((bpp == 8) && (color_type != FIC_PALETTE)));
+
+ // Check for RGBA case if bitmap supports alpha
+ // blending (8-bit greyscale, 24- or 32-bit images)
+ if (supports_alpha && (options & FI_COLOR_IS_RGBA_COLOR)) {
+
+ if (color->rgbReserved == 0) {
+ // the fill color is fully transparent; we are done
+ return TRUE;
+ }
+
+ // Only if the fill color is NOT fully opaque, draw it with
+ // the (much) slower FreeImage_DrawLine function and return.
+ // Since we do not have the FreeImage_DrawLine function in this
+ // 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
+ // image (bottom-left pixel).
+ RGBQUAD bgcolor;
+ if (bpp == 8) {
+ bgcolor = FreeImage_GetPalette(dib)[*src_bits];
+ } 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: {
+ unsigned bytes = (width / 8);
+ memset(dst_bits, ((index == 1) ? 0xFF : 0x00), bytes);
+ //int n = width % 8;
+ int n = width & 7;
+ if (n) {
+ if (index == 1) {
+ // set n leftmost bits
+ dst_bits[bytes] |= (0xFF << (8 - n));
+ } else {
+ // clear n leftmost bits
+ dst_bits[bytes] &= (0xFF >> n);
+ }
+ }
+ break;
+ }
+ case 4: {
+ unsigned bytes = (width / 2);
+ memset(dst_bits, (index | (index << 4)), bytes);
+ //if (bytes % 2) {
+ if (bytes & 1) {
+ dst_bits[bytes] &= 0x0F;
+ dst_bits[bytes] |= (index << 4);
+ }
+ break;
+ }
+ case 8: {
+ memset(dst_bits, index, FreeImage_GetLine(dib));
+ break;
+ }
+ case 16: {
+ WORD wcolor = RGBQUAD_TO_WORD(dib, color_intl);
+ for (unsigned x = 0; x < width; x++) {
+ ((WORD *)dst_bits)[x] = wcolor;
+ }
+ break;
+ }
+ case 24: {
+ RGBTRIPLE rgbt = *((RGBTRIPLE *)color_intl);
+ for (unsigned x = 0; x < width; x++) {
+ ((RGBTRIPLE *)dst_bits)[x] = rgbt;
+ }
+ break;
+ }
+ case 32: {
+ RGBQUAD rgbq;
+ rgbq.rgbBlue = ((RGBTRIPLE *)color_intl)->rgbtBlue;
+ rgbq.rgbGreen = ((RGBTRIPLE *)color_intl)->rgbtGreen;
+ rgbq.rgbRed = ((RGBTRIPLE *)color_intl)->rgbtRed;
+ rgbq.rgbReserved = 0xFF;
+ for (unsigned x = 0; x < width; x++) {
+ ((RGBQUAD *)dst_bits)[x] = rgbq;
+ }
+ break;
+ }
+ default:
+ return FALSE;
+ }
+
+ // Then, copy the first scanline into all following scanlines.
+ // 'src_bits' is a pointer to the first scanline and is already
+ // set up correctly.
+ if (src_bits) {
+ unsigned pitch = FreeImage_GetPitch(dib);
+ unsigned bytes = FreeImage_GetLine(dib);
+ dst_bits = src_bits + pitch;
+ for (unsigned y = 1; y < height; y++) {
+ memcpy(dst_bits, src_bits, bytes);
+ dst_bits += pitch;
+ }
+ }
+ return TRUE;
+}
+
+/** @brief Fills an image with the specified color.
+
+ This function sets all pixels of an image to the color provided through the color
+ parameter. Since this should work for all image types supported by FreeImage, the
+ pointer color must point to a memory location, which is at least as large as the
+ image's color value, if this size is greater than 4 bytes. As the color is specified
+ by an RGBQUAD structure for all images of type FIT_BITMAP (including all palletized
+ images), the smallest possible size of this memory is the size of the RGBQUAD structure,
+ which uses 4 bytes.
+
+ So, color must point to a double, if the image to be filled is of type FIT_DOUBLE and
+ point to a RGBF structure if the image is of type FIT_RGBF and so on.
+
+ However, the fill color is always specified through a RGBQUAD structure for all images
+ of type FIT_BITMAP. So, for 32- and 24-bit images, the red, green and blue members of
+ the RGBQUAD structure are directly used for the image's red, green and blue channel
+ respectively. Although alpha transparent RGBQUAD colors are supported, the alpha channel
+ of a 32-bit image never gets modified by this function. A fill color with an alpha value
+ smaller than 255 gets blended with the image's actual background color, which is determined
+ from the image's bottom-left pixel. So, currently using alpha enabled colors, assumes the
+ image to be unicolor before the fill operation. However, the RGBQUAD's rgbReserved member is
+ only taken into account, if option FI_COLOR_IS_RGBA_COLOR has been specified.
+
+ For 16-bit images, the red-, green- and blue components of the specified color are
+ transparently translated into either the 16-bit 555 or 565 representation. This depends
+ on the image's actual red- green- and blue masks.
+
+ Special attention must be payed for palletized images. Generally, the RGB color specified
+ is looked up in the image's palette. The found palette index is then used to fill the image.
+ There are some option flags, that affect this lookup process:
+
+ no option specified (0x00) Uses the color, that is nearest to the specified color.
+ This is the default behavior and should always find a
+ color in the palette. However, the visual result may
+ far from what was expected and mainly depends on the
+ image's palette.
+
+ FI_COLOR_FIND_EQUAL_COLOR (0x02) Searches the image's palette for the specified color
+ but only uses the returned palette index, if the specified
+ color exactly matches the palette entry. Of course,
+ depending on the image's actual palette entries, this
+ operation may fail. In this case, the function falls back
+ to option FI_COLOR_ALPHA_IS_INDEX and uses the RGBQUAD's
+ rgbReserved member (or its low nibble for 4-bit images
+ or its least significant bit (LSB) for 1-bit images) as
+ the palette index used for the fill operation.
+
+ FI_COLOR_ALPHA_IS_INDEX (0x04) Does not perform any color lookup from the palette, but
+ uses the RGBQUAD's alpha channel member rgbReserved as
+ the palette index to be used for the fill operation.
+ However, for 4-bit images, only the low nibble of the
+ rgbReserved member are used and for 1-bit images, only
+ the least significant bit (LSB) is used.
+
+ This function fails if any of dib and color is NULL.
+
+ @param dib The image to be filled.
+ @param color A pointer to the color value to be used for filling the image. The
+ memory pointed to by this pointer is always assumed to be at least as large as the
+ image's color value, but never smaller than the size of an RGBQUAD structure.
+ @param options Options that affect the color search process for palletized images.
+ @return Returns TRUE on success, FALSE otherwise. This function fails if any of
+ dib and color is NULL.
+ */
+BOOL DLL_CALLCONV
+FreeImage_FillBackground(FIBITMAP *dib, const void *color, int options) {
+
+ if (!FreeImage_HasPixels(dib)) {
+ return FALSE;
+ }
+
+ if (!color) {
+ return FALSE;
+ }
+
+ // handle FIT_BITMAP images with FreeImage_FillBackground()
+ if (FreeImage_GetImageType(dib) == FIT_BITMAP) {
+ return FillBackgroundBitmap(dib, (RGBQUAD *)color, options);
+ }
+
+ // first, construct the first scanline (bottom line)
+ unsigned bytespp = (FreeImage_GetBPP(dib) / 8);
+ BYTE *src_bits = FreeImage_GetScanLine(dib, 0);
+ BYTE *dst_bits = src_bits;
+ for (unsigned x = 0; x < FreeImage_GetWidth(dib); x++) {
+ memcpy(dst_bits, color, bytespp);
+ dst_bits += bytespp;
+ }
+
+ // then, copy the first scanline into all following scanlines
+ unsigned height = FreeImage_GetHeight(dib);
+ unsigned pitch = FreeImage_GetPitch(dib);
+ unsigned bytes = FreeImage_GetLine(dib);
+ dst_bits = src_bits + pitch;
+ for (unsigned y = 1; y < height; y++) {
+ memcpy(dst_bits, src_bits, bytes);
+ dst_bits += pitch;
+ }
+ return TRUE;
+}
+
+/** @brief Allocates a new image of the specified type, width, height and bit depth and
+ optionally fills it with the specified color.
+
+ This function is an extension to FreeImage_AllocateT, which additionally supports specifying
+ a palette to be set for the newly create image, as well as specifying a background color,
+ the newly created image should initially be filled with.
+
+ Basically, this function internally relies on function FreeImage_AllocateT, followed by a
+ call to FreeImage_FillBackground. This is why both parameters color and options behave the
+ same as it is documented for function FreeImage_FillBackground. So, please refer to the
+ documentation of FreeImage_FillBackground to learn more about parameters color and options.
+
+ The palette specified through parameter palette is only copied to the newly created
+ image, if its image type is FIT_BITMAP and the desired bit depth is smaller than or equal
+ to 8 bits per pixel. In other words, the palette parameter is only taken into account for
+ palletized images. However, if the preceding conditions match and if palette is not NULL,
+ the memory pointed to by the palette pointer is assumed to be at least as large as size
+ of a fully populated palette for the desired bit depth. So, for an 8-bit image, this size
+ is 256 x sizeof(RGBQUAD), for an 4-bit image it is 16 x sizeof(RGBQUAD) and it is
+ 2 x sizeof(RGBQUAD) for a 1-bit image. In other words, this function does not support
+ partial palettes.
+
+ However, specifying a palette is not necessarily needed, even for palletized images. This
+ function is capable of implicitly creating a palette, if parameter palette is NULL. If the
+ specified background color is a greyscale value (red = green = blue) or if option
+ FI_COLOR_ALPHA_IS_INDEX is specified, a greyscale palette is created. For a 1-bit image, only
+ if the specified background color is either black or white, a monochrome palette, consisting
+ of black and white only is created. In any case, the darker colors are stored at the smaller
+ palette indices.
+
+ If the specified background color is not a greyscale value, or is neither black nor white
+ for a 1-bit image, solely this single color is injected into the otherwise black-initialized
+ palette. For this operation, option FI_COLOR_ALPHA_IS_INDEX is implicit, so the specified
+ color is applied to the palette entry, specified by the background color's rgbReserved
+ member. The image is then filled with this palette index.
+
+ This function returns a newly created image as function FreeImage_AllocateT does, if both
+ parameters color and palette are NULL. If only color is NULL, the palette pointed to by
+ parameter palette is initially set for the new image, if a palletized image of type
+ FIT_BITMAP is created. However, in the latter case, this function returns an image, whose
+ pixels are all initialized with zeros so, the image will be filled with the color of the
+ first palette entry.
+
+ @param type Specifies the image type of the new image.
+ @param width The desired width in pixels of the new image.
+ @param height The desired height in pixels of the new image.
+ @param bpp The desired bit depth of the new image.
+ @param color A pointer to the color value to be used for filling the image. The
+ memory pointed to by this pointer is always assumed to be at least as large as the
+ image's color value but never smaller than the size of an RGBQUAD structure.
+ @param options Options that affect the color search process for palletized images.
+ @param red_mask Specifies the bits used to store the red components of a pixel.
+ @param green_mask Specifies the bits used to store the green components of a pixel.
+ @param blue_mask Specifies the bits used to store the blue components of a pixel.
+ @return Returns a pointer to a newly allocated image on success, NULL otherwise.
+ */
+FIBITMAP * DLL_CALLCONV
+FreeImage_AllocateExT(FREE_IMAGE_TYPE type, int width, int height, int bpp, const void *color, int options, const RGBQUAD *palette, unsigned red_mask, unsigned green_mask, unsigned blue_mask) {
+
+ FIBITMAP *bitmap = FreeImage_AllocateT(type, width, height, bpp, red_mask, green_mask, blue_mask);
+
+ if (!color) {
+ if ((palette) && (type == FIT_BITMAP) && (bpp <= 8)) {
+ memcpy(FreeImage_GetPalette(bitmap), palette, FreeImage_GetColorsUsed(bitmap) * sizeof(RGBQUAD));
+ }
+ return bitmap;
+ }
+
+ if (bitmap != NULL) {
+
+ // Only fill the new bitmap if the specified color
+ // differs from "black", that is not all bytes of the
+ // color are equal to zero.
+ switch (bpp) {
+ case 1: {
+ // although 1-bit implies FIT_BITMAP, better get an unsigned
+ // color and palette
+ unsigned *urgb = (unsigned *)color;
+ unsigned *upal = (unsigned *)FreeImage_GetPalette(bitmap);
+ RGBQUAD rgbq = RGBQUAD();
+
+ if (palette != NULL) {
+ // clone the specified palette
+ memcpy(FreeImage_GetPalette(bitmap), palette, 2 * sizeof(RGBQUAD));
+ } else if (options & FI_COLOR_ALPHA_IS_INDEX) {
+ CREATE_GREYSCALE_PALETTE(upal, 2);
+ } else {
+ // check, whether the specified color is either black or white
+ if ((*urgb & 0xFFFFFF) == 0x000000) {
+ // in any case build a FIC_MINISBLACK palette
+ CREATE_GREYSCALE_PALETTE(upal, 2);
+ color = &rgbq;
+ } else if ((*urgb & 0xFFFFFF) == 0xFFFFFF) {
+ // in any case build a FIC_MINISBLACK palette
+ CREATE_GREYSCALE_PALETTE(upal, 2);
+ rgbq.rgbReserved = 1;
+ color = &rgbq;
+ } else {
+ // Otherwise inject the specified color into the so far
+ // black-only palette. We use color->rgbReserved as the
+ // desired palette index.
+ BYTE index = ((RGBQUAD *)color)->rgbReserved & 0x01;
+ upal[index] = *urgb & 0x00FFFFFF;
+ }
+ options |= FI_COLOR_ALPHA_IS_INDEX;
+ }
+ // and defer to FreeImage_FillBackground
+ FreeImage_FillBackground(bitmap, color, options);
+ break;
+ }
+ case 4: {
+ // 4-bit implies FIT_BITMAP so, get a RGBQUAD color
+ RGBQUAD *rgb = (RGBQUAD *)color;
+ RGBQUAD *pal = FreeImage_GetPalette(bitmap);
+ RGBQUAD rgbq = RGBQUAD();
+
+ if (palette != NULL) {
+ // clone the specified palette
+ memcpy(pal, palette, 16 * sizeof(RGBQUAD));
+ } else if (options & FI_COLOR_ALPHA_IS_INDEX) {
+ CREATE_GREYSCALE_PALETTE(pal, 16);
+ } else {
+ // check, whether the specified color is a grey one
+ if ((rgb->rgbRed == rgb->rgbGreen) && (rgb->rgbRed == rgb->rgbBlue)) {
+ // if so, build a greyscale palette
+ CREATE_GREYSCALE_PALETTE(pal, 16);
+ rgbq.rgbReserved = rgb->rgbRed >> 4;
+ color = &rgbq;
+ } else {
+ // Otherwise inject the specified color into the so far
+ // black-only palette. We use color->rgbReserved as the
+ // desired palette index.
+ BYTE index = (rgb->rgbReserved & 0x0F);
+ ((unsigned *)pal)[index] = *((unsigned *)rgb) & 0x00FFFFFF;
+ }
+ options |= FI_COLOR_ALPHA_IS_INDEX;
+ }
+ // and defer to FreeImage_FillBackground
+ FreeImage_FillBackground(bitmap, color, options);
+ break;
+ }
+ case 8: {
+ // 8-bit implies FIT_BITMAP so, get a RGBQUAD color
+ RGBQUAD *rgb = (RGBQUAD *)color;
+ RGBQUAD *pal = FreeImage_GetPalette(bitmap);
+ RGBQUAD rgbq;
+
+ if (palette != NULL) {
+ // clone the specified palette
+ memcpy(pal, palette, 256 * sizeof(RGBQUAD));
+ } else if (options & FI_COLOR_ALPHA_IS_INDEX) {
+ CREATE_GREYSCALE_PALETTE(pal, 256);
+ } else {
+ // check, whether the specified color is a grey one
+ if ((rgb->rgbRed == rgb->rgbGreen) && (rgb->rgbRed == rgb->rgbBlue)) {
+ // if so, build a greyscale palette
+ CREATE_GREYSCALE_PALETTE(pal, 256);
+ rgbq.rgbReserved = rgb->rgbRed;
+ color = &rgbq;
+ } else {
+ // Otherwise inject the specified color into the so far
+ // black-only palette. We use color->rgbReserved as the
+ // desired palette index.
+ BYTE index = rgb->rgbReserved;
+ ((unsigned *)pal)[index] = *((unsigned *)rgb) & 0x00FFFFFF;
+ }
+ options |= FI_COLOR_ALPHA_IS_INDEX;
+ }
+ // and defer to FreeImage_FillBackground
+ FreeImage_FillBackground(bitmap, color, options);
+ break;
+ }
+ case 16: {
+ WORD wcolor = (type == FIT_BITMAP) ?
+ RGBQUAD_TO_WORD(bitmap, ((RGBQUAD *)color)) : *((WORD *)color);
+ if (wcolor != 0) {
+ FreeImage_FillBackground(bitmap, color, options);
+ }
+ break;
+ }
+ default: {
+ int bytespp = bpp / 8;
+ for (int i = 0; i < bytespp; i++) {
+ if (((BYTE *)color)[i] != 0) {
+ FreeImage_FillBackground(bitmap, color, options);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ return bitmap;
+}
+
+/** @brief Allocates a new image of the specified width, height and bit depth and optionally
+ fills it with the specified color.
+
+ This function is an extension to FreeImage_Allocate, which additionally supports specifying
+ a palette to be set for the newly create image, as well as specifying a background color,
+ the newly created image should initially be filled with.
+
+ Basically, this function internally relies on function FreeImage_Allocate, followed by a
+ call to FreeImage_FillBackground. This is why both parameters color and options behave the
+ same as it is documented for function FreeImage_FillBackground. So, please refer to the
+ documentation of FreeImage_FillBackground to learn more about parameters color and options.
+
+ The palette specified through parameter palette is only copied to the newly created
+ image, if the desired bit depth is smaller than or equal to 8 bits per pixel. In other words,
+ the palette parameter is only taken into account for palletized images. However, if the
+ image to be created is a palletized image and if palette is not NULL, the memory pointed to
+ by the palette pointer is assumed to be at least as large as size of a fully populated
+ palette for the desired bit depth. So, for an 8-bit image, this size is 256 x sizeof(RGBQUAD),
+ for an 4-bit image it is 16 x sizeof(RGBQUAD) and it is 2 x sizeof(RGBQUAD) for a 1-bit
+ image. In other words, this function does not support partial palettes.
+
+ However, specifying a palette is not necessarily needed, even for palletized images. This
+ function is capable of implicitly creating a palette, if parameter palette is NULL. If the
+ specified background color is a greyscale value (red = green = blue) or if option
+ FI_COLOR_ALPHA_IS_INDEX is specified, a greyscale palette is created. For a 1-bit image, only
+ if the specified background color is either black or white, a monochrome palette, consisting
+ of black and white only is created. In any case, the darker colors are stored at the smaller
+ palette indices.
+
+ If the specified background color is not a greyscale value, or is neither black nor white
+ for a 1-bit image, solely this single color is injected into the otherwise black-initialized
+ palette. For this operation, option FI_COLOR_ALPHA_IS_INDEX is implicit, so the specified
+ color is applied to the palette entry, specified by the background color's rgbReserved
+ member. The image is then filled with this palette index.
+
+ This function returns a newly created image as function FreeImage_Allocate does, if both
+ parameters color and palette are NULL. If only color is NULL, the palette pointed to by
+ parameter palette is initially set for the new image, if a palletized image of type
+ FIT_BITMAP is created. However, in the latter case, this function returns an image, whose
+ pixels are all initialized with zeros so, the image will be filled with the color of the
+ first palette entry.
+
+ @param width The desired width in pixels of the new image.
+ @param height The desired height in pixels of the new image.
+ @param bpp The desired bit depth of the new image.
+ @param color A pointer to an RGBQUAD structure, that provides the color to be used for
+ filling the image.
+ @param options Options that affect the color search process for palletized images.
+ @param red_mask Specifies the bits used to store the red components of a pixel.
+ @param green_mask Specifies the bits used to store the green components of a pixel.
+ @param blue_mask Specifies the bits used to store the blue components of a pixel.
+ @return Returns a pointer to a newly allocated image on success, NULL otherwise.
+ */
+FIBITMAP * DLL_CALLCONV
+FreeImage_AllocateEx(int width, int height, int bpp, const RGBQUAD *color, int options, const RGBQUAD *palette, unsigned red_mask, unsigned green_mask, unsigned blue_mask) {
+ return FreeImage_AllocateExT(FIT_BITMAP, width, height, bpp, ((void *)color), options, palette, red_mask, green_mask, blue_mask);
+}
+
+/** @brief Enlarges or shrinks an image selectively per side and fills newly added areas
+ with the specified background color.
+
+ This function enlarges or shrinks an image selectively per side. The main purpose of this
+ function is to add borders to an image. To add a border to any of the image's sides, a
+ positive integer value must be passed in any of the parameters left, top, right or bottom.
+ This value represents the border's width in pixels. Newly created parts of the image (the
+ border areas) are filled with the specified color. Specifying a negative integer value for
+ a certain side, will shrink or crop the image on this side. Consequently, specifying zero
+ for a certain side will not change the image's extension on that side.
+
+ So, calling this function with all parameters left, top, right and bottom set to zero, is
+ effectively the same as calling function FreeImage_Clone; setting all parameters left, top,
+ right and bottom to value equal to or smaller than zero, my easily be substituted by a call
+ to function FreeImage_Copy. Both these cases produce a new image, which is guaranteed not to
+ be larger than the input image. Thus, since the specified color is not needed in these cases,
+ the pointer color may be NULL.
+
+ Both parameters color and options work according to function FreeImage_FillBackground. So,
+ please refer to the documentation of FreeImage_FillBackground to learn more about parameters
+ color and options. For palletized images, the palette of the input image src is
+ transparently copied to the newly created enlarged or shrunken image, so any color
+ look-ups are performed on this palette.
+
+ Here are some examples, that illustrate, how to use the parameters left, top, right and
+ bottom:
+
+ // create a white color
+ RGBQUAD c;
+ c.rgbRed = 0xFF;
+ c.rgbGreen = 0xFF;
+ c.rgbBlue = 0xFF;
+ c.rgbReserved = 0x00;
+
+ // add a white, symmetric 10 pixel wide border to the image
+ dib2 = FreeImage_EnlargeCanvas(dib, 10, 10, 10, 10, &c, FI_COLOR_IS_RGB_COLOR);
+
+ // add white, 20 pixel wide stripes to the top and bottom side of the image
+ dib3 = FreeImage_EnlargeCanvas(dib, 0, 20, 0, 20, &c, FI_COLOR_IS_RGB_COLOR);
+
+ // add white, 30 pixel wide stripes to the right side of the image and
+ // cut off the 40 leftmost pixel columns
+ dib3 = FreeImage_EnlargeCanvas(dib, -40, 0, 30, 0, &c, FI_COLOR_IS_RGB_COLOR);
+
+ This function fails if either the input image is NULL or the pointer to the color is
+ NULL, while at least on of left, top, right and bottom is greater than zero. This
+ function also returns NULL, if the new image's size will be negative in either x- or
+ y-direction.
+
+ @param dib The image to be enlarged or shrunken.
+ @param left The number of pixels, the image should be enlarged on its left side. Negative
+ values shrink the image on its left side.
+ @param top The number of pixels, the image should be enlarged on its top side. Negative
+ values shrink the image on its top side.
+ @param right The number of pixels, the image should be enlarged on its right side. Negative
+ values shrink the image on its right side.
+ @param bottom The number of pixels, the image should be enlarged on its bottom side. Negative
+ values shrink the image on its bottom side.
+ @param color The color, the enlarged sides of the image should be filled with.
+ @param options Options that affect the color search process for palletized images.
+ @return Returns a pointer to a newly allocated enlarged or shrunken image on success,
+ NULL otherwise. This function fails if either the input image is NULL or the pointer to the
+ color is NULL, while at least on of left, top, right and bottom is greater than zero. This
+ function also returns NULL, if the new image's size will be negative in either x- or
+ y-direction.
+ */
+FIBITMAP * DLL_CALLCONV
+FreeImage_EnlargeCanvas(FIBITMAP *src, int left, int top, int right, int bottom, const void *color, int options) {
+
+ if(!FreeImage_HasPixels(src)) return NULL;
+
+ // Just return a clone of the image, if left, top, right and bottom are
+ // all zero.
+ if ((left == 0) && (right == 0) && (top == 0) && (bottom == 0)) {
+ return FreeImage_Clone(src);
+ }
+
+ int width = FreeImage_GetWidth(src);
+ int height = FreeImage_GetHeight(src);
+
+ // Relay on FreeImage_Copy, if all parameters left, top, right and
+ // bottom are smaller than or equal zero. The color pointer may be
+ // NULL in this case.
+ if ((left <= 0) && (right <= 0) && (top <= 0) && (bottom <= 0)) {
+ return FreeImage_Copy(src, -left, -top, width + right, height + bottom);
+ }
+
+ // From here, we need a valid color, since the image will be enlarged on
+ // at least one side. So, fail if we don't have a valid color pointer.
+ if (!color) {
+ return NULL;
+ }
+
+ if (((left < 0) && (-left >= width)) || ((right < 0) && (-right >= width)) ||
+ ((top < 0) && (-top >= height)) || ((bottom < 0) && (-bottom >= height))) {
+ return NULL;
+ }
+
+ unsigned newWidth = width + left + right;
+ unsigned newHeight = height + top + bottom;
+
+ FREE_IMAGE_TYPE type = FreeImage_GetImageType(src);
+ unsigned bpp = FreeImage_GetBPP(src);
+
+ FIBITMAP *dst = FreeImage_AllocateExT(
+ type, newWidth, newHeight, bpp, color, options,
+ FreeImage_GetPalette(src),
+ FreeImage_GetRedMask(src),
+ FreeImage_GetGreenMask(src),
+ FreeImage_GetBlueMask(src));
+
+ if (!dst) {
+ return NULL;
+ }
+
+ if ((type == FIT_BITMAP) && (bpp <= 4)) {
+ FIBITMAP *copy = FreeImage_Copy(src,
+ ((left >= 0) ? 0 : -left),
+ ((top >= 0) ? 0 : -top),
+ ((width+right)>width)?width:(width+right),
+ ((height+bottom)>height)?height:(height+bottom));
+
+ if (!copy) {
+ FreeImage_Unload(dst);
+ return NULL;
+ }
+
+ if (!FreeImage_Paste(dst, copy,
+ ((left <= 0) ? 0 : left),
+ ((top <= 0) ? 0 : top), 256)) {
+ FreeImage_Unload(copy);
+ FreeImage_Unload(dst);
+ return NULL;
+ }
+
+ FreeImage_Unload(copy);
+
+ } else {
+
+ int bytespp = bpp / 8;
+ BYTE *srcPtr = FreeImage_GetScanLine(src, height - 1 - ((top >= 0) ? 0 : -top));
+ BYTE *dstPtr = FreeImage_GetScanLine(dst, newHeight - 1 - ((top <= 0) ? 0 : top));
+
+ unsigned srcPitch = FreeImage_GetPitch(src);
+ unsigned dstPitch = FreeImage_GetPitch(dst);
+
+ int lineWidth = bytespp * (width + MIN(0, left) + MIN(0, right));
+ int lines = height + MIN(0, top) + MIN(0, bottom);
+
+ if (left <= 0) {
+ srcPtr += (-left * bytespp);
+ } else {
+ dstPtr += (left * bytespp);
+ }
+
+ for (int i = 0; i < lines; i++) {
+ memcpy(dstPtr, srcPtr, lineWidth);
+ srcPtr -= srcPitch;
+ dstPtr -= dstPitch;
+ }
+ }
+
+ // copy metadata from src to dst
+ FreeImage_CloneMetadata(dst, src);
+
+ // copy transparency table
+ FreeImage_SetTransparencyTable(dst, FreeImage_GetTransparencyTable(src), FreeImage_GetTransparencyCount(src));
+
+ // copy background color
+ RGBQUAD bkcolor;
+ if( FreeImage_GetBackgroundColor(src, &bkcolor) ) {
+ FreeImage_SetBackgroundColor(dst, &bkcolor);
+ }
+
+ // clone resolution
+ FreeImage_SetDotsPerMeterX(dst, FreeImage_GetDotsPerMeterX(src));
+ FreeImage_SetDotsPerMeterY(dst, FreeImage_GetDotsPerMeterY(src));
+
+ // clone ICC profile
+ FIICCPROFILE *src_profile = FreeImage_GetICCProfile(src);
+ 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/Channels.cpp b/plugins/AdvaImg/src/FreeImageToolkit/Channels.cpp
index f6e6c5509c..5f01ad815f 100644
--- a/plugins/AdvaImg/src/FreeImageToolkit/Channels.cpp
+++ b/plugins/AdvaImg/src/FreeImageToolkit/Channels.cpp
@@ -31,7 +31,7 @@
FIBITMAP * DLL_CALLCONV
FreeImage_GetChannel(FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel) {
- if (!FreeImage_HasPixels(src)) return NULL;
+ if(!FreeImage_HasPixels(src)) return NULL;
FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(src);
unsigned bpp = FreeImage_GetBPP(src);
@@ -63,7 +63,7 @@ FreeImage_GetChannel(FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel) {
unsigned width = FreeImage_GetWidth(src);
unsigned height = FreeImage_GetHeight(src);
FIBITMAP *dst = FreeImage_Allocate(width, height, 8) ;
- if (!dst) return NULL;
+ if(!dst) return NULL;
// build a greyscale palette
RGBQUAD *pal = FreeImage_GetPalette(dst);
for(int i = 0; i < 256; i++) {
@@ -90,7 +90,7 @@ FreeImage_GetChannel(FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel) {
}
// 48-bit RGB or 64-bit RGBA images
- if ((image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) {
+ if((image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) {
int c;
// select the channel to extract (always RGB[A])
@@ -116,7 +116,7 @@ FreeImage_GetChannel(FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel) {
unsigned width = FreeImage_GetWidth(src);
unsigned height = FreeImage_GetHeight(src);
FIBITMAP *dst = FreeImage_AllocateT(FIT_UINT16, width, height) ;
- if (!dst) return NULL;
+ if(!dst) return NULL;
// perform extraction
@@ -138,7 +138,7 @@ FreeImage_GetChannel(FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel) {
}
// 96-bit RGBF or 128-bit RGBAF images
- if ((image_type == FIT_RGBF) || (image_type == FIT_RGBAF)) {
+ if((image_type == FIT_RGBF) || (image_type == FIT_RGBAF)) {
int c;
// select the channel to extract (always RGB[A])
@@ -164,7 +164,7 @@ FreeImage_GetChannel(FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel) {
unsigned width = FreeImage_GetWidth(src);
unsigned height = FreeImage_GetHeight(src);
FIBITMAP *dst = FreeImage_AllocateT(FIT_FLOAT, width, height) ;
- if (!dst) return NULL;
+ if(!dst) return NULL;
// perform extraction
@@ -199,32 +199,32 @@ BOOL DLL_CALLCONV
FreeImage_SetChannel(FIBITMAP *dst, FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel) {
int c;
- if (!FreeImage_HasPixels(src) || !FreeImage_HasPixels(dst)) return FALSE;
+ if(!FreeImage_HasPixels(src) || !FreeImage_HasPixels(dst)) return FALSE;
// src and dst images should have the same width and height
unsigned src_width = FreeImage_GetWidth(src);
unsigned src_height = FreeImage_GetHeight(src);
unsigned dst_width = FreeImage_GetWidth(dst);
unsigned dst_height = FreeImage_GetHeight(dst);
- if ((src_width != dst_width) || (src_height != dst_height))
+ if((src_width != dst_width) || (src_height != dst_height))
return FALSE;
// src image should be grayscale, dst image should be RGB or RGBA
FREE_IMAGE_COLOR_TYPE src_type = FreeImage_GetColorType(src);
FREE_IMAGE_COLOR_TYPE dst_type = FreeImage_GetColorType(dst);
- if ((dst_type != FIC_RGB) && (dst_type != FIC_RGBALPHA) || (src_type != FIC_MINISBLACK)) {
+ if((dst_type != FIC_RGB) && (dst_type != FIC_RGBALPHA) || (src_type != FIC_MINISBLACK)) {
return FALSE;
}
FREE_IMAGE_TYPE src_image_type = FreeImage_GetImageType(src);
FREE_IMAGE_TYPE dst_image_type = FreeImage_GetImageType(dst);
- if ((dst_image_type == FIT_BITMAP) && (src_image_type == FIT_BITMAP)) {
+ if((dst_image_type == FIT_BITMAP) && (src_image_type == FIT_BITMAP)) {
// src image should be grayscale, dst image should be 24- or 32-bit
unsigned src_bpp = FreeImage_GetBPP(src);
unsigned dst_bpp = FreeImage_GetBPP(dst);
- if ((src_bpp != 8) || (dst_bpp != 24) && (dst_bpp != 32))
+ if((src_bpp != 8) || (dst_bpp != 24) && (dst_bpp != 32))
return FALSE;
@@ -263,12 +263,12 @@ FreeImage_SetChannel(FIBITMAP *dst, FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL chan
return TRUE;
}
- if (((dst_image_type == FIT_RGB16) || (dst_image_type == FIT_RGBA16)) && (src_image_type == FIT_UINT16)) {
+ if(((dst_image_type == FIT_RGB16) || (dst_image_type == FIT_RGBA16)) && (src_image_type == FIT_UINT16)) {
// src image should be grayscale, dst image should be 48- or 64-bit
unsigned src_bpp = FreeImage_GetBPP(src);
unsigned dst_bpp = FreeImage_GetBPP(dst);
- if ((src_bpp != 16) || (dst_bpp != 48) && (dst_bpp != 64))
+ if((src_bpp != 16) || (dst_bpp != 48) && (dst_bpp != 64))
return FALSE;
@@ -307,12 +307,12 @@ FreeImage_SetChannel(FIBITMAP *dst, FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL chan
return TRUE;
}
- if (((dst_image_type == FIT_RGBF) || (dst_image_type == FIT_RGBAF)) && (src_image_type == FIT_FLOAT)) {
+ if(((dst_image_type == FIT_RGBF) || (dst_image_type == FIT_RGBAF)) && (src_image_type == FIT_FLOAT)) {
// src image should be grayscale, dst image should be 96- or 128-bit
unsigned src_bpp = FreeImage_GetBPP(src);
unsigned dst_bpp = FreeImage_GetBPP(dst);
- if ((src_bpp != 32) || (dst_bpp != 96) && (dst_bpp != 128))
+ if((src_bpp != 32) || (dst_bpp != 96) && (dst_bpp != 128))
return FALSE;
@@ -367,14 +367,14 @@ FreeImage_GetComplexChannel(FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel) {
double *dst_bits = NULL;
FIBITMAP *dst = NULL;
- if (!FreeImage_HasPixels(src)) return NULL;
+ if(!FreeImage_HasPixels(src)) return NULL;
if(FreeImage_GetImageType(src) == FIT_COMPLEX) {
// allocate a dib of type FIT_DOUBLE
unsigned width = FreeImage_GetWidth(src);
unsigned height = FreeImage_GetHeight(src);
dst = FreeImage_AllocateT(FIT_DOUBLE, width, height) ;
- if (!dst) return NULL;
+ if(!dst) return NULL;
// perform extraction
@@ -415,7 +415,7 @@ FreeImage_GetComplexChannel(FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel) {
src_bits = (FICOMPLEX *)FreeImage_GetScanLine(src, y);
dst_bits = (double *)FreeImage_GetScanLine(dst, y);
for(x = 0; x < width; x++) {
- if ((src_bits[x].r == 0) && (src_bits[x].i == 0)) {
+ if((src_bits[x].r == 0) && (src_bits[x].i == 0)) {
phase = 0;
} else {
phase = atan2(src_bits[x].i, src_bits[x].r);
@@ -446,12 +446,12 @@ FreeImage_SetComplexChannel(FIBITMAP *dst, FIBITMAP *src, FREE_IMAGE_COLOR_CHANN
double *src_bits = NULL;
FICOMPLEX *dst_bits = NULL;
- if (!FreeImage_HasPixels(src) || !FreeImage_HasPixels(dst)) return FALSE;
+ if(!FreeImage_HasPixels(src) || !FreeImage_HasPixels(dst)) return FALSE;
// src image should be of type FIT_DOUBLE, dst image should be of type FIT_COMPLEX
const FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(src);
const FREE_IMAGE_TYPE dst_type = FreeImage_GetImageType(dst);
- if ((src_type != FIT_DOUBLE) || (dst_type != FIT_COMPLEX))
+ if((src_type != FIT_DOUBLE) || (dst_type != FIT_COMPLEX))
return FALSE;
// src and dst images should have the same width and height
@@ -459,7 +459,7 @@ FreeImage_SetComplexChannel(FIBITMAP *dst, FIBITMAP *src, FREE_IMAGE_COLOR_CHANN
unsigned src_height = FreeImage_GetHeight(src);
unsigned dst_width = FreeImage_GetWidth(dst);
unsigned dst_height = FreeImage_GetHeight(dst);
- if ((src_width != dst_width) || (src_height != dst_height))
+ if((src_width != dst_width) || (src_height != dst_height))
return FALSE;
// select the channel to modify
diff --git a/plugins/AdvaImg/src/FreeImageToolkit/ClassicRotate.cpp b/plugins/AdvaImg/src/FreeImageToolkit/ClassicRotate.cpp
index d38d8c1bcd..83c2f92123 100644
--- a/plugins/AdvaImg/src/FreeImageToolkit/ClassicRotate.cpp
+++ b/plugins/AdvaImg/src/FreeImageToolkit/ClassicRotate.cpp
@@ -63,7 +63,7 @@ HorizontalSkewT(FIBITMAP *src, FIBITMAP *dst, int row, int iOffset, double weigh
// background
const T pxlBlack[4] = {0, 0, 0, 0 };
const T *pxlBkg = static_cast<const T*>(bkcolor); // assume at least bytespp and 4*sizeof(T) max
- if (!pxlBkg) {
+ if(!pxlBkg) {
// default background color is black
pxlBkg = pxlBlack;
}
@@ -98,7 +98,7 @@ HorizontalSkewT(FIBITMAP *src, FIBITMAP *dst, int row, int iOffset, double weigh
}
// check boundaries
iXPos = i + iOffset;
- if ((iXPos >= 0) && (iXPos < (int)dst_width)) {
+ if((iXPos >= 0) && (iXPos < (int)dst_width)) {
// update left over on source
for(unsigned j = 0; j < samples; j++) {
pxlSrc[j] = pxlSrc[j] - (pxlLeft[j] - pxlOldLeft[j]);
@@ -115,7 +115,7 @@ HorizontalSkewT(FIBITMAP *src, FIBITMAP *dst, int row, int iOffset, double weigh
// go to rightmost point of skew
iXPos = src_width + iOffset;
- if ((iXPos >= 0) && (iXPos < (int)dst_width)) {
+ if((iXPos >= 0) && (iXPos < (int)dst_width)) {
dst_bits = FreeImage_GetScanLine(dst, row) + iXPos * bytespp;
// If still in image bounds, put leftovers there
@@ -194,7 +194,7 @@ VerticalSkewT(FIBITMAP *src, FIBITMAP *dst, int col, int iOffset, double weight,
// background
const T pxlBlack[4] = {0, 0, 0, 0 };
const T *pxlBkg = static_cast<const T*>(bkcolor); // assume at least bytespp and 4*sizeof(T) max
- if (!pxlBkg) {
+ if(!pxlBkg) {
// default background color is black
pxlBkg = pxlBlack;
}
@@ -235,7 +235,7 @@ VerticalSkewT(FIBITMAP *src, FIBITMAP *dst, int col, int iOffset, double weight,
}
// check boundaries
iYPos = i + iOffset;
- if ((iYPos >= 0) && (iYPos < (int)dst_height)) {
+ if((iYPos >= 0) && (iYPos < (int)dst_height)) {
// update left over on source
for(unsigned j = 0; j < samples; j++) {
pxlSrc[j] = pxlSrc[j] - (pxlLeft[j] - pxlOldLeft[j]);
@@ -252,7 +252,7 @@ VerticalSkewT(FIBITMAP *src, FIBITMAP *dst, int col, int iOffset, double weight,
// go to bottom point of skew
iYPos = src_height + iOffset;
- if ((iYPos >= 0) && (iYPos < (int)dst_height)) {
+ if((iYPos >= 0) && (iYPos < (int)dst_height)) {
dst_bits = FreeImage_GetScanLine(dst, iYPos) + index;
// if still in image bounds, put leftovers there
@@ -367,7 +367,7 @@ Rotate90(FIBITMAP *src) {
}
}
}
- else if ((bpp == 8) || (bpp == 24) || (bpp == 32)) {
+ else if((bpp == 8) || (bpp == 24) || (bpp == 32)) {
// anything other than BW :
// This optimized version of rotation rotates image by smaller blocks. It is quite
// a bit faster than obvious algorithm, because it produces much less CPU cache misses.
@@ -472,7 +472,7 @@ Rotate180(FIBITMAP *src) {
}
break;
}
- // else if ((bpp == 8) || (bpp == 24) || (bpp == 32)) FALL TROUGH
+ // else if((bpp == 8) || (bpp == 24) || (bpp == 32)) FALL TROUGH
case FIT_UINT16:
case FIT_RGB16:
case FIT_RGBA16:
@@ -559,7 +559,7 @@ Rotate270(FIBITMAP *src) {
}
}
}
- else if ((bpp == 8) || (bpp == 24) || (bpp == 32)) {
+ else if((bpp == 8) || (bpp == 24) || (bpp == 32)) {
// anything other than BW :
// This optimized version of rotation rotates image by smaller blocks. It is quite
// a bit faster than obvious algorithm, because it produces much less CPU cache misses.
@@ -730,7 +730,7 @@ Rotate45(FIBITMAP *src, double dAngle, const void *bkcolor) {
}
else {
// Negative angle
- dOffset = dTan * ( (src_width - 1.0) * -dSinE + (1.0 - height_3));
+ dOffset = dTan * ( (src_width - 1.0) * -dSinE + (1.0 - height_3) );
}
for(u = 0; u < height_3; u++, dOffset += dTan) {
int iShear = int(floor(dOffset));
@@ -767,7 +767,7 @@ RotateAny(FIBITMAP *src, double dAngle, const void *bkcolor) {
// Bring angle to range of [0 .. 360)
dAngle += 360;
}
- if ((dAngle > 45) && (dAngle <= 135)) {
+ if((dAngle > 45) && (dAngle <= 135)) {
// Angle in (45 .. 135]
// Rotate image by 90 degrees into temporary image,
// so it requires only an extra rotation angle
@@ -775,7 +775,7 @@ RotateAny(FIBITMAP *src, double dAngle, const void *bkcolor) {
image = Rotate90(src);
dAngle -= 90;
}
- else if ((dAngle > 135) && (dAngle <= 225)) {
+ else if((dAngle > 135) && (dAngle <= 225)) {
// Angle in (135 .. 225]
// Rotate image by 180 degrees into temporary image,
// so it requires only an extra rotation angle
@@ -783,7 +783,7 @@ RotateAny(FIBITMAP *src, double dAngle, const void *bkcolor) {
image = Rotate180(src);
dAngle -= 180;
}
- else if ((dAngle > 225) && (dAngle <= 315)) {
+ else if((dAngle > 225) && (dAngle <= 315)) {
// Angle in (225 .. 315]
// Rotate image by 270 degrees into temporary image,
// so it requires only an extra rotation angle
@@ -825,7 +825,7 @@ RotateAny(FIBITMAP *src, double dAngle, const void *bkcolor) {
FIBITMAP *DLL_CALLCONV
FreeImage_Rotate(FIBITMAP *dib, double angle, const void *bkcolor) {
- if (!FreeImage_HasPixels(dib)) return NULL;
+ if(!FreeImage_HasPixels(dib)) return NULL;
if(0 == angle) {
return FreeImage_Clone(dib);
@@ -846,7 +846,7 @@ FreeImage_Rotate(FIBITMAP *dib, double angle, const void *bkcolor) {
// perform the rotation
FIBITMAP *dst = RotateAny(dib, angle, bkcolor);
- if (!dst) throw(1);
+ if(!dst) throw(1);
// build a greyscale palette
RGBQUAD *dst_pal = FreeImage_GetPalette(dst);
@@ -863,9 +863,9 @@ FreeImage_Rotate(FIBITMAP *dib, double angle, const void *bkcolor) {
return dst;
}
- else if ((bpp == 8) || (bpp == 24) || (bpp == 32)) {
+ else if((bpp == 8) || (bpp == 24) || (bpp == 32)) {
FIBITMAP *dst = RotateAny(dib, angle, bkcolor);
- if (!dst) throw(1);
+ if(!dst) throw(1);
if(bpp == 8) {
// copy original palette to rotated bitmap
@@ -878,7 +878,7 @@ FreeImage_Rotate(FIBITMAP *dib, double angle, const void *bkcolor) {
// copy background color
RGBQUAD bkcolor;
- if ( FreeImage_GetBackgroundColor(dib, &bkcolor)) {
+ if( FreeImage_GetBackgroundColor(dib, &bkcolor) ) {
FreeImage_SetBackgroundColor(dst, &bkcolor);
}
@@ -898,7 +898,7 @@ FreeImage_Rotate(FIBITMAP *dib, double angle, const void *bkcolor) {
case FIT_RGBAF:
{
FIBITMAP *dst = RotateAny(dib, angle, bkcolor);
- if (!dst) throw(1);
+ if(!dst) throw(1);
// copy metadata from src to dst
FreeImage_CloneMetadata(dst, dib);
diff --git a/plugins/AdvaImg/src/FreeImageToolkit/Colors.cpp b/plugins/AdvaImg/src/FreeImageToolkit/Colors.cpp
index 8b9bbd6482..67191768bb 100644
--- a/plugins/AdvaImg/src/FreeImageToolkit/Colors.cpp
+++ b/plugins/AdvaImg/src/FreeImageToolkit/Colors.cpp
@@ -108,7 +108,7 @@ FreeImage_Invert(FIBITMAP *src) {
return FALSE;
}
}
- else if ((image_type == FIT_UINT16) || (image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) {
+ else if((image_type == FIT_UINT16) || (image_type == FIT_RGB16) || (image_type == 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);
@@ -149,11 +149,11 @@ FreeImage_AdjustCurve(FIBITMAP *src, BYTE *LUT, FREE_IMAGE_COLOR_CHANNEL channel
unsigned x, y;
BYTE *bits = NULL;
- if (!FreeImage_HasPixels(src) || !LUT || (FreeImage_GetImageType(src) != FIT_BITMAP))
+ if(!FreeImage_HasPixels(src) || !LUT || (FreeImage_GetImageType(src) != FIT_BITMAP))
return FALSE;
int bpp = FreeImage_GetBPP(src);
- if ((bpp != 8) && (bpp != 24) && (bpp != 32))
+ if((bpp != 8) && (bpp != 24) && (bpp != 32))
return FALSE;
// apply the LUT
@@ -271,7 +271,7 @@ BOOL DLL_CALLCONV
FreeImage_AdjustGamma(FIBITMAP *src, double gamma) {
BYTE LUT[256]; // Lookup table
- if (!FreeImage_HasPixels(src) || (gamma <= 0))
+ if(!FreeImage_HasPixels(src) || (gamma <= 0))
return FALSE;
// Build the lookup table
@@ -302,7 +302,7 @@ FreeImage_AdjustBrightness(FIBITMAP *src, double percentage) {
BYTE LUT[256]; // Lookup table
double value;
- if (!FreeImage_HasPixels(src))
+ if(!FreeImage_HasPixels(src))
return FALSE;
// Build the lookup table
@@ -328,7 +328,7 @@ FreeImage_AdjustContrast(FIBITMAP *src, double percentage) {
BYTE LUT[256]; // Lookup table
double value;
- if (!FreeImage_HasPixels(src))
+ if(!FreeImage_HasPixels(src))
return FALSE;
// Build the lookup table
@@ -357,7 +357,7 @@ FreeImage_GetHistogram(FIBITMAP *src, DWORD *histo, FREE_IMAGE_COLOR_CHANNEL cha
BYTE *bits = NULL;
unsigned x, y;
- if (!FreeImage_HasPixels(src) || !histo) return FALSE;
+ if(!FreeImage_HasPixels(src) || !histo) return FALSE;
unsigned width = FreeImage_GetWidth(src);
unsigned height = FreeImage_GetHeight(src);
@@ -377,7 +377,7 @@ FreeImage_GetHistogram(FIBITMAP *src, DWORD *histo, FREE_IMAGE_COLOR_CHANNEL cha
}
return TRUE;
}
- else if ((bpp == 24) || (bpp == 32)) {
+ else if((bpp == 24) || (bpp == 32)) {
int bytespp = bpp / 8; // bytes / pixel
// clear histogram array
diff --git a/plugins/AdvaImg/src/FreeImageToolkit/CopyPaste.cpp b/plugins/AdvaImg/src/FreeImageToolkit/CopyPaste.cpp
index 753fdc736e..e4b8155739 100644
--- a/plugins/AdvaImg/src/FreeImageToolkit/CopyPaste.cpp
+++ b/plugins/AdvaImg/src/FreeImageToolkit/CopyPaste.cpp
@@ -58,12 +58,12 @@ Combine1(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned
BOOL value;
// check the bit depth of src and dst images
- if ((FreeImage_GetBPP(dst_dib) != 1) || (FreeImage_GetBPP(src_dib) != 1)) {
+ if((FreeImage_GetBPP(dst_dib) != 1) || (FreeImage_GetBPP(src_dib) != 1)) {
return FALSE;
}
// check the size of src image
- if ((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) {
+ if((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) {
return FALSE;
}
@@ -97,12 +97,12 @@ Combine4(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned
BOOL bOddStart, bOddEnd;
// check the bit depth of src and dst images
- if ((FreeImage_GetBPP(dst_dib) != 4) || (FreeImage_GetBPP(src_dib) != 4)) {
+ if((FreeImage_GetBPP(dst_dib) != 4) || (FreeImage_GetBPP(src_dib) != 4)) {
return FALSE;
}
// check the size of src image
- if ((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) {
+ if((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) {
return FALSE;
}
@@ -196,12 +196,12 @@ Combine4(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned
static BOOL
Combine8(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha) {
// check the bit depth of src and dst images
- if ((FreeImage_GetBPP(dst_dib) != 8) || (FreeImage_GetBPP(src_dib) != 8)) {
+ if((FreeImage_GetBPP(dst_dib) != 8) || (FreeImage_GetBPP(src_dib) != 8)) {
return FALSE;
}
// check the size of src image
- if ((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) {
+ if((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) {
return FALSE;
}
@@ -238,12 +238,12 @@ Combine8(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned
static BOOL
Combine16_555(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha) {
// check the bit depth of src and dst images
- if ((FreeImage_GetBPP(dst_dib) != 16) || (FreeImage_GetBPP(src_dib) != 16)) {
+ if((FreeImage_GetBPP(dst_dib) != 16) || (FreeImage_GetBPP(src_dib) != 16)) {
return FALSE;
}
// check the size of src image
- if ((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) {
+ if((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) {
return FALSE;
}
@@ -298,12 +298,12 @@ Combine16_555(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsi
static BOOL
Combine16_565(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha) {
// check the bit depth of src and dst images
- if ((FreeImage_GetBPP(dst_dib) != 16) || (FreeImage_GetBPP(src_dib) != 16)) {
+ if((FreeImage_GetBPP(dst_dib) != 16) || (FreeImage_GetBPP(src_dib) != 16)) {
return FALSE;
}
// check the size of src image
- if ((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) {
+ if((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) {
return FALSE;
}
@@ -362,12 +362,12 @@ Combine16_565(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsi
static BOOL
Combine24(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha) {
// check the bit depth of src and dst images
- if ((FreeImage_GetBPP(dst_dib) != 24) || (FreeImage_GetBPP(src_dib) != 24)) {
+ if((FreeImage_GetBPP(dst_dib) != 24) || (FreeImage_GetBPP(src_dib) != 24)) {
return FALSE;
}
// check the size of src image
- if ((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) {
+ if((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) {
return FALSE;
}
@@ -404,12 +404,12 @@ Combine24(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned
static BOOL
Combine32(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha) {
// check the bit depth of src and dst images
- if ((FreeImage_GetBPP(dst_dib) != 32) || (FreeImage_GetBPP(src_dib) != 32)) {
+ if((FreeImage_GetBPP(dst_dib) != 32) || (FreeImage_GetBPP(src_dib) != 32)) {
return FALSE;
}
// check the size of src image
- if ((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) {
+ if((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) {
return FALSE;
}
@@ -459,7 +459,7 @@ CombineSameType(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y) {
unsigned dst_pitch = FreeImage_GetPitch(dst_dib);
// check the size of src image
- if ((x + src_width > dst_width) || (y + src_height > dst_height)) {
+ if((x + src_width > dst_width) || (y + src_height > dst_height)) {
return FALSE;
}
@@ -493,7 +493,7 @@ Works with any bitmap type.
FIBITMAP * DLL_CALLCONV
FreeImage_Copy(FIBITMAP *src, int left, int top, int right, int bottom) {
- if (!FreeImage_HasPixels(src))
+ if(!FreeImage_HasPixels(src))
return NULL;
// normalize the rectangle
@@ -506,7 +506,7 @@ FreeImage_Copy(FIBITMAP *src, int left, int top, int right, int bottom) {
// check the size of the sub image
int src_width = FreeImage_GetWidth(src);
int src_height = FreeImage_GetHeight(src);
- if ((left < 0) || (right > src_width) || (top < 0) || (bottom > src_height)) {
+ if((left < 0) || (right > src_width) || (top < 0) || (bottom > src_height)) {
return NULL;
}
@@ -608,7 +608,7 @@ FreeImage_Copy(FIBITMAP *src, int left, int top, int right, int bottom) {
// copy background color
RGBQUAD bkcolor;
- if ( FreeImage_GetBackgroundColor(src, &bkcolor)) {
+ if( FreeImage_GetBackgroundColor(src, &bkcolor) ) {
FreeImage_SetBackgroundColor(dst, &bkcolor);
}
@@ -639,13 +639,13 @@ BOOL DLL_CALLCONV
FreeImage_Paste(FIBITMAP *dst, FIBITMAP *src, int left, int top, int alpha) {
BOOL bResult = FALSE;
- if (!FreeImage_HasPixels(src) || !FreeImage_HasPixels(dst)) return FALSE;
+ if(!FreeImage_HasPixels(src) || !FreeImage_HasPixels(dst)) return FALSE;
// check the size of src image
- if ((left < 0) || (top < 0)) {
+ if((left < 0) || (top < 0)) {
return FALSE;
}
- if ((left + FreeImage_GetWidth(src) > FreeImage_GetWidth(dst)) || (top + FreeImage_GetHeight(src) > FreeImage_GetHeight(dst))) {
+ if((left + FreeImage_GetWidth(src) > FreeImage_GetWidth(dst)) || (top + FreeImage_GetHeight(src) > FreeImage_GetHeight(dst))) {
return FALSE;
}
@@ -704,7 +704,7 @@ FreeImage_Paste(FIBITMAP *dst, FIBITMAP *src, int left, int top, int alpha) {
return FALSE;
}
- if (!clone) return FALSE;
+ if(!clone) return FALSE;
// paste src to dst
switch(FreeImage_GetBPP(dst)) {
diff --git a/plugins/AdvaImg/src/FreeImageToolkit/Display.cpp b/plugins/AdvaImg/src/FreeImageToolkit/Display.cpp
index 3e4807042d..245c5c3a18 100644
--- a/plugins/AdvaImg/src/FreeImageToolkit/Display.cpp
+++ b/plugins/AdvaImg/src/FreeImageToolkit/Display.cpp
@@ -40,20 +40,20 @@ For colour images, the computation is done separately for R, G, and B samples.
*/
FIBITMAP * DLL_CALLCONV
FreeImage_Composite(FIBITMAP *fg, BOOL useFileBkg, RGBQUAD *appBkColor, FIBITMAP *bg) {
- if (!FreeImage_HasPixels(fg)) return NULL;
+ if(!FreeImage_HasPixels(fg)) return NULL;
int width = FreeImage_GetWidth(fg);
int height = FreeImage_GetHeight(fg);
int bpp = FreeImage_GetBPP(fg);
- if ((bpp != 8) && (bpp != 32))
+ if((bpp != 8) && (bpp != 32))
return NULL;
if(bg) {
int bg_width = FreeImage_GetWidth(bg);
int bg_height = FreeImage_GetHeight(bg);
int bg_bpp = FreeImage_GetBPP(bg);
- if ((bg_width != width) || (bg_height != height) || (bg_bpp != 24))
+ if((bg_width != width) || (bg_height != height) || (bg_bpp != 24))
return NULL;
}
@@ -71,7 +71,7 @@ FreeImage_Composite(FIBITMAP *fg, BOOL useFileBkg, RGBQUAD *appBkColor, FIBITMAP
// allocate the composite image
FIBITMAP *composite = FreeImage_Allocate(width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
- if (!composite) return NULL;
+ if(!composite) return NULL;
// get the palette
RGBQUAD *pal = FreeImage_GetPalette(fg);
@@ -133,7 +133,7 @@ FreeImage_Composite(FIBITMAP *fg, BOOL useFileBkg, RGBQUAD *appBkColor, FIBITMAP
// background color
- if (!bHasBkColor) {
+ if(!bHasBkColor) {
if(bg) {
// get the background color from the background image
bkc.rgbBlue = bg_bits[FI_RGBA_BLUE];
diff --git a/plugins/AdvaImg/src/FreeImageToolkit/JPEGTransform.cpp b/plugins/AdvaImg/src/FreeImageToolkit/JPEGTransform.cpp
index 2d7399dcb2..5822f748a6 100644
--- a/plugins/AdvaImg/src/FreeImageToolkit/JPEGTransform.cpp
+++ b/plugins/AdvaImg/src/FreeImageToolkit/JPEGTransform.cpp
@@ -61,7 +61,7 @@ ls_jpeg_error_exit (j_common_ptr cinfo) {
(*cinfo->err->output_message)(cinfo);
// allow JPEG with a premature end of file
- if ((cinfo)->err->msg_parm.i[0] != 13) {
+ if((cinfo)->err->msg_parm.i[0] != 13) {
// let the memory manager delete any temp files before we die
jpeg_destroy(cinfo);
@@ -171,7 +171,7 @@ LosslessTransform(const FilenameIO *filenameIO, FREE_IMAGE_JPEG_OPERATION operat
// crop option
if(crop != NULL) {
- if (!jtransform_parse_crop_spec(&transfoptions, crop)) {
+ if(!jtransform_parse_crop_spec(&transfoptions, crop)) {
FreeImage_OutputMessageProc(FIF_JPEG, "Bogus crop argument %s", crop);
throw(1);
}
@@ -180,14 +180,14 @@ LosslessTransform(const FilenameIO *filenameIO, FREE_IMAGE_JPEG_OPERATION operat
// Open the input file
if(bUseUnicode) {
#ifdef _WIN32
- if ((fp = _wfopen(filenameIO->wsrc_file, L"rb")) == NULL) {
+ if((fp = _wfopen(filenameIO->wsrc_file, L"rb")) == NULL) {
FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open input file for reading");
}
#else
fp = NULL;
#endif // _WIN32
} else {
- if ((fp = fopen(filenameIO->src_file, "rb")) == NULL) {
+ if((fp = fopen(filenameIO->src_file, "rb")) == NULL) {
FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open %s for reading", filenameIO->src_file);
}
}
@@ -211,7 +211,7 @@ LosslessTransform(const FilenameIO *filenameIO, FREE_IMAGE_JPEG_OPERATION operat
// Prepare transformation workspace
// Fails right away if perfect flag is TRUE and transformation is not perfect
- if ( !jtransform_request_workspace(&srcinfo, &transfoptions)) {
+ if( !jtransform_request_workspace(&srcinfo, &transfoptions) ) {
FreeImage_OutputMessageProc(FIF_JPEG, "Transformation is not perfect");
throw(1);
}
@@ -237,14 +237,14 @@ LosslessTransform(const FilenameIO *filenameIO, FREE_IMAGE_JPEG_OPERATION operat
// Open the output file
if(bUseUnicode) {
#ifdef _WIN32
- if ((fp = _wfopen(filenameIO->wdst_file, L"wb")) == NULL) {
+ if((fp = _wfopen(filenameIO->wdst_file, L"wb")) == NULL) {
FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open output file for writing");
}
#else
fp = NULL;
#endif // _WIN32
} else {
- if ((fp = fopen(filenameIO->dst_file, "wb")) == NULL) {
+ if((fp = fopen(filenameIO->dst_file, "wb")) == NULL) {
FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open %s for writing", filenameIO->dst_file);
}
}
diff --git a/plugins/AdvaImg/src/FreeImageToolkit/MultigridPoissonSolver.cpp b/plugins/AdvaImg/src/FreeImageToolkit/MultigridPoissonSolver.cpp
index a31961447a..3b577cbd0a 100644
--- a/plugins/AdvaImg/src/FreeImageToolkit/MultigridPoissonSolver.cpp
+++ b/plugins/AdvaImg/src/FreeImageToolkit/MultigridPoissonSolver.cpp
@@ -68,7 +68,7 @@ static void fmg_restrict(FIBITMAP *UC, FIBITMAP *UF, int nc) {
// 0.5 * UF(row_uf, col_uf) + 0.125 * [ UF(row_uf+1, col_uf) + UF(row_uf-1, col_uf) + UF(row_uf, col_uf+1) + UF(row_uf, col_uf-1) ]
float *uc_pixel = uc_scan + col_uc;
const float *uf_center = uf_scan + col_uf;
- *uc_pixel = 0.5F * *uf_center + 0.125F * ( *(uf_center + uf_pitch) + *(uf_center - uf_pitch) + *(uf_center + 1) + *(uf_center - 1));
+ *uc_pixel = 0.5F * *uf_center + 0.125F * ( *(uf_center + uf_pitch) + *(uf_center - uf_pitch) + *(uf_center + 1) + *(uf_center - 1) );
}
uc_scan += uc_pitch;
}
@@ -158,8 +158,8 @@ static void fmg_prolongate(FIBITMAP *UF, FIBITMAP *UC, int nf) {
for(row_uf = 1; row_uf < nf-1; row_uf += 2) {
float *uf_scan = uf_bits + row_uf * uf_pitch;
for (col_uf = 0; col_uf < nf; col_uf += 2) {
- // calculate UF(row_uf, col_uf) = 0.5 * ( UF(row_uf+1, col_uf) + UF(row_uf-1, col_uf))
- uf_scan[col_uf] = 0.5F * ( *(uf_scan + uf_pitch + col_uf) + *(uf_scan - uf_pitch + col_uf));
+ // calculate UF(row_uf, col_uf) = 0.5 * ( UF(row_uf+1, col_uf) + UF(row_uf-1, col_uf) )
+ uf_scan[col_uf] = 0.5F * ( *(uf_scan + uf_pitch + col_uf) + *(uf_scan - uf_pitch + col_uf) );
}
}
}
@@ -168,7 +168,7 @@ static void fmg_prolongate(FIBITMAP *UF, FIBITMAP *UC, int nf) {
float *uf_scan = uf_bits;
for(row_uf = 0; row_uf < nf; row_uf++) {
for (col_uf = 1; col_uf < nf-1; col_uf += 2) {
- // calculate UF(row_uf, col_uf) = 0.5 * ( UF(row_uf, col_uf+1) + UF(row_uf, col_uf-1))
+ // calculate UF(row_uf, col_uf) = 0.5 * ( UF(row_uf, col_uf+1) + UF(row_uf, col_uf-1) )
uf_scan[col_uf] = 0.5F * ( uf_scan[col_uf + 1] + uf_scan[col_uf - 1] );
}
uf_scan += uf_pitch;
@@ -311,7 +311,7 @@ static BOOL fmg_mglin(FIBITMAP *U, int n, int ncycle) {
#define _CREATE_ARRAY_GRID_(array, array_size) \
array = (FIBITMAP**)malloc(array_size * sizeof(FIBITMAP*));\
- if (!array) throw(1);\
+ if(!array) throw(1);\
memset(array, 0, array_size * sizeof(FIBITMAP*))
#define _FREE_ARRAY_GRID_(array, array_size) \
@@ -351,7 +351,7 @@ static BOOL fmg_mglin(FIBITMAP *U, int n, int ncycle) {
// allocate storage for r.h.s. on grid (ng - 2) ...
IRHO[ngrid] = FreeImage_AllocateT(FIT_FLOAT, nn, nn);
- if (!IRHO[ngrid]) throw(1);
+ if(!IRHO[ngrid]) throw(1);
// ... and fill it by restricting from the fine grid
fmg_restrict(IRHO[ngrid], U, nn);
@@ -361,16 +361,16 @@ static BOOL fmg_mglin(FIBITMAP *U, int n, int ncycle) {
nn = nn/2 + 1;
ngrid--;
IRHO[ngrid] = FreeImage_AllocateT(FIT_FLOAT, nn, nn);
- if (!IRHO[ngrid]) throw(1);
+ if(!IRHO[ngrid]) throw(1);
fmg_restrict(IRHO[ngrid], IRHO[ngrid+1], nn);
}
nn = 3;
IU[0] = FreeImage_AllocateT(FIT_FLOAT, nn, nn);
- if (!IU[0]) throw(1);
+ if(!IU[0]) throw(1);
IRHS[0] = FreeImage_AllocateT(FIT_FLOAT, nn, nn);
- if (!IRHS[0]) throw(1);
+ if(!IRHS[0]) throw(1);
// initial solution on coarsest grid
fmg_solve(IU[0], IRHO[0]);
@@ -384,11 +384,11 @@ static BOOL fmg_mglin(FIBITMAP *U, int n, int ncycle) {
nn = 2*nn - 1;
IU[j] = FreeImage_AllocateT(FIT_FLOAT, nn, nn);
- if (!IU[j]) throw(1);
+ if(!IU[j]) throw(1);
IRHS[j] = FreeImage_AllocateT(FIT_FLOAT, nn, nn);
- if (!IRHS[j]) throw(1);
+ if(!IRHS[j]) throw(1);
IRES[j] = FreeImage_AllocateT(FIT_FLOAT, nn, nn);
- if (!IRES[j]) throw(1);
+ if(!IRES[j]) throw(1);
fmg_prolongate(IU[j], IU[j-1], nn);
@@ -464,7 +464,7 @@ where j is such that 2^j is the nearest larger dimension corresponding to MAX(im
*/
FIBITMAP* DLL_CALLCONV
FreeImage_MultigridPoissonSolver(FIBITMAP *Laplacian, int ncycle) {
- if (!FreeImage_HasPixels(Laplacian)) return NULL;
+ if(!FreeImage_HasPixels(Laplacian)) return NULL;
int width = FreeImage_GetWidth(Laplacian);
int height = FreeImage_GetHeight(Laplacian);
@@ -473,7 +473,7 @@ FreeImage_MultigridPoissonSolver(FIBITMAP *Laplacian, int ncycle) {
int n = MAX(width, height);
int size = 0;
while((n >>= 1) > 0) size++;
- if ((1 << size) < MAX(width, height)) {
+ if((1 << size) < MAX(width, height)) {
size++;
}
// size must be of the form 2^j + 1 for some integer j
@@ -481,7 +481,7 @@ FreeImage_MultigridPoissonSolver(FIBITMAP *Laplacian, int ncycle) {
// allocate a temporary square image I
FIBITMAP *I = FreeImage_AllocateT(FIT_FLOAT, size, size);
- if (!I) return NULL;
+ if(!I) return NULL;
// copy Laplacian into I and shift pixels to create a boundary
FreeImage_Paste(I, Laplacian, 1, 1, 255);
diff --git a/plugins/AdvaImg/src/FreeImageToolkit/Rescale.cpp b/plugins/AdvaImg/src/FreeImageToolkit/Rescale.cpp
index e79e5f456c..ffe667e7d4 100644
--- a/plugins/AdvaImg/src/FreeImageToolkit/Rescale.cpp
+++ b/plugins/AdvaImg/src/FreeImageToolkit/Rescale.cpp
@@ -1,231 +1,169 @@
-// ==========================================================
-// Upsampling / downsampling routine
-//
-// Design and implementation by
-// - Hervé Drolon (drolon@infonie.fr)
-//
-// This file is part of FreeImage 3
-//
-// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
-// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
-// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
-// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
-// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
-// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
-// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
-// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
-// THIS DISCLAIMER.
-//
-// Use at your own risk!
-// ==========================================================
-
-#include "Resize.h"
-
-FIBITMAP * DLL_CALLCONV
-FreeImage_Rescale(FIBITMAP *src, int dst_width, int dst_height, FREE_IMAGE_FILTER filter) {
- FIBITMAP *dst = NULL;
-
- if (!FreeImage_HasPixels(src) || (dst_width <= 0) || (dst_height <= 0) || (FreeImage_GetWidth(src) <= 0) || (FreeImage_GetHeight(src) <= 0)) {
- return NULL;
- }
-
- // select the filter
- CGenericFilter *pFilter = NULL;
- switch(filter) {
- case FILTER_BOX:
- pFilter = new(std::nothrow) CBoxFilter();
- break;
- case FILTER_BICUBIC:
- pFilter = new(std::nothrow) CBicubicFilter();
- break;
- case FILTER_BILINEAR:
- pFilter = new(std::nothrow) CBilinearFilter();
- break;
- case FILTER_BSPLINE:
- pFilter = new(std::nothrow) CBSplineFilter();
- break;
- case FILTER_CATMULLROM:
- pFilter = new(std::nothrow) CCatmullRomFilter();
- break;
- case FILTER_LANCZOS3:
- pFilter = new(std::nothrow) CLanczos3Filter();
- break;
- }
-
- if (!pFilter) {
- return NULL;
- }
-
- CResizeEngine Engine(pFilter);
-
- // perform upsampling or downsampling
-
- if ((FreeImage_GetBPP(src) == 4) || (FreeImage_GetColorType(src) == FIC_PALETTE)) {
- // special case for 4-bit images or color map indexed images ...
- if(FreeImage_IsTransparent(src) == FALSE) {
- FIBITMAP *src24 = NULL;
- FIBITMAP *dst24 = NULL;
- try {
- // transparent conversion to 24-bit (any transparency table will be destroyed)
- src24 = FreeImage_ConvertTo24Bits(src);
- if (!src24) throw(1);
- // perform upsampling or downsampling
- dst24 = Engine.scale(src24, dst_width, dst_height);
- if (!dst24) throw(1);
- FreeImage_Unload(src24); src24 = NULL;
- // color quantize to 8-bit
- dst = FreeImage_ColorQuantize(dst24, FIQ_NNQUANT);
- // free and return
- FreeImage_Unload(dst24);
- } catch(int) {
- if(src24) FreeImage_Unload(src24);
- if(dst24) FreeImage_Unload(dst24);
- }
- } else {
- FIBITMAP *src32 = NULL;
- try {
- // transparent conversion to 32-bit (keep transparency)
- src32 = FreeImage_ConvertTo32Bits(src);
- if (!src32) throw(1);
- // perform upsampling or downsampling
- dst = Engine.scale(src32, dst_width, dst_height);
- if (!dst) throw(1);
- // free and return
- FreeImage_Unload(src32);
- } catch(int) {
- if(src32) FreeImage_Unload(src32);
- if(dst) FreeImage_Unload(dst);
- }
- }
- }
- else if ((FreeImage_GetBPP(src) == 16) && (FreeImage_GetImageType(src) == FIT_BITMAP)) {
- // convert 16-bit RGB to 24-bit
- FIBITMAP *src24 = NULL;
- try {
- // transparent conversion to 24-bit (any transparency table will be destroyed)
- src24 = FreeImage_ConvertTo24Bits(src);
- if (!src24) throw(1);
- // perform upsampling or downsampling
- dst = Engine.scale(src24, dst_width, dst_height);
- if (!dst) throw(1);
- // free and return
- FreeImage_Unload(src24);
- } catch(int) {
- if(src24) FreeImage_Unload(src24);
- if(dst) FreeImage_Unload(dst);
- }
- }
- else {
- // normal case :
- // 1- or 8-bit greyscale, 24- or 32-bit RGB(A) images
- // 16-bit greyscale, 48- or 64-bit RGB(A) images
- // 32-bit float, 96- or 128-bit RGB(A) float images
- dst = Engine.scale(src, dst_width, dst_height);
- }
-
-
- delete pFilter;
-
- // copy metadata from src to dst
- FreeImage_CloneMetadata(dst, src);
-
- return dst;
-}
-
-FIBITMAP * DLL_CALLCONV
-FreeImage_MakeThumbnail(FIBITMAP *dib, int max_pixel_size, BOOL convert) {
- FIBITMAP *thumbnail = NULL;
- int new_width, new_height;
-
- if (!FreeImage_HasPixels(dib) || (max_pixel_size <= 0)) return NULL;
-
- int width = FreeImage_GetWidth(dib);
- int height = FreeImage_GetHeight(dib);
-
- if(max_pixel_size == 0) max_pixel_size = 1;
-
- if ((width < max_pixel_size) && (height < max_pixel_size)) {
- // image is smaller than the requested thumbnail
- return FreeImage_Clone(dib);
- }
-
- if(width > height) {
- new_width = max_pixel_size;
- // change image height with the same ratio
- double ratio = ((double)new_width / (double)width);
- new_height = (int)(height * ratio + 0.5);
- if(new_height == 0) new_height = 1;
- } else {
- new_height = max_pixel_size;
- // change image width with the same ratio
- double ratio = ((double)new_height / (double)height);
- new_width = (int)(width * ratio + 0.5);
- if(new_width == 0) new_width = 1;
- }
-
- const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
-
- // perform downsampling using a bilinear interpolation
-
- switch(image_type) {
- case FIT_BITMAP:
- case FIT_UINT16:
- case FIT_RGB16:
- case FIT_RGBA16:
- case FIT_FLOAT:
- case FIT_RGBF:
- case FIT_RGBAF:
- {
- FREE_IMAGE_FILTER filter = FILTER_BILINEAR;
- thumbnail = FreeImage_Rescale(dib, new_width, new_height, filter);
- }
- break;
-
- case FIT_INT16:
- case FIT_UINT32:
- case FIT_INT32:
- case FIT_DOUBLE:
- case FIT_COMPLEX:
- default:
- // cannot rescale this kind of image
- thumbnail = NULL;
- break;
- }
-
- if ((thumbnail != NULL) && (image_type != FIT_BITMAP) && convert) {
- // convert to a standard bitmap
- FIBITMAP *bitmap = NULL;
- switch(image_type) {
- case FIT_UINT16:
- bitmap = FreeImage_ConvertTo8Bits(thumbnail);
- break;
- case FIT_RGB16:
- bitmap = FreeImage_ConvertTo24Bits(thumbnail);
- break;
- case FIT_RGBA16:
- bitmap = FreeImage_ConvertTo32Bits(thumbnail);
- break;
- case FIT_FLOAT:
- bitmap = FreeImage_ConvertToStandardType(thumbnail, TRUE);
- break;
- case FIT_RGBF:
- bitmap = FreeImage_ToneMapping(thumbnail, FITMO_DRAGO03);
- break;
- case FIT_RGBAF:
- // no way to keep the transparency yet ...
- FIBITMAP *rgbf = FreeImage_ConvertToRGBF(thumbnail);
- bitmap = FreeImage_ToneMapping(rgbf, FITMO_DRAGO03);
- FreeImage_Unload(rgbf);
- break;
- }
- if(bitmap != NULL) {
- FreeImage_Unload(thumbnail);
- thumbnail = bitmap;
- }
- }
-
- // copy metadata from src to dst
- FreeImage_CloneMetadata(thumbnail, dib);
-
- return thumbnail;
-}
+// ==========================================================
+// Upsampling / downsampling routine
+//
+// Design and implementation by
+// - Hervé Drolon (drolon@infonie.fr)
+// - 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"
+
+FIBITMAP * DLL_CALLCONV
+FreeImage_Rescale(FIBITMAP *src, int dst_width, int dst_height, FREE_IMAGE_FILTER filter) {
+ FIBITMAP *dst = NULL;
+
+ if (!FreeImage_HasPixels(src) || (dst_width <= 0) || (dst_height <= 0) || (FreeImage_GetWidth(src) <= 0) || (FreeImage_GetHeight(src) <= 0)) {
+ return NULL;
+ }
+
+ // select the filter
+ CGenericFilter *pFilter = NULL;
+ switch (filter) {
+ case FILTER_BOX:
+ pFilter = new(std::nothrow) CBoxFilter();
+ break;
+ case FILTER_BICUBIC:
+ pFilter = new(std::nothrow) CBicubicFilter();
+ break;
+ case FILTER_BILINEAR:
+ pFilter = new(std::nothrow) CBilinearFilter();
+ break;
+ case FILTER_BSPLINE:
+ pFilter = new(std::nothrow) CBSplineFilter();
+ break;
+ case FILTER_CATMULLROM:
+ pFilter = new(std::nothrow) CCatmullRomFilter();
+ break;
+ case FILTER_LANCZOS3:
+ pFilter = new(std::nothrow) CLanczos3Filter();
+ break;
+ }
+
+ if (!pFilter) {
+ return NULL;
+ }
+
+ CResizeEngine Engine(pFilter);
+
+ dst = Engine.scale(src, dst_width, dst_height, 0, 0,
+ FreeImage_GetWidth(src), FreeImage_GetHeight(src));
+
+ delete pFilter;
+
+ // copy metadata from src to dst
+ FreeImage_CloneMetadata(dst, src);
+
+ return dst;
+}
+
+FIBITMAP * DLL_CALLCONV
+FreeImage_MakeThumbnail(FIBITMAP *dib, int max_pixel_size, BOOL convert) {
+ FIBITMAP *thumbnail = NULL;
+ int new_width, new_height;
+
+ if(!FreeImage_HasPixels(dib) || (max_pixel_size <= 0)) return NULL;
+
+ int width = FreeImage_GetWidth(dib);
+ int height = FreeImage_GetHeight(dib);
+
+ if(max_pixel_size == 0) max_pixel_size = 1;
+
+ if((width < max_pixel_size) && (height < max_pixel_size)) {
+ // image is smaller than the requested thumbnail
+ return FreeImage_Clone(dib);
+ }
+
+ if(width > height) {
+ new_width = max_pixel_size;
+ // change image height with the same ratio
+ double ratio = ((double)new_width / (double)width);
+ new_height = (int)(height * ratio + 0.5);
+ if(new_height == 0) new_height = 1;
+ } else {
+ new_height = max_pixel_size;
+ // change image width with the same ratio
+ double ratio = ((double)new_height / (double)height);
+ new_width = (int)(width * ratio + 0.5);
+ if(new_width == 0) new_width = 1;
+ }
+
+ const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
+
+ // perform downsampling using a bilinear interpolation
+
+ switch(image_type) {
+ case FIT_BITMAP:
+ case FIT_UINT16:
+ case FIT_RGB16:
+ case FIT_RGBA16:
+ case FIT_FLOAT:
+ case FIT_RGBF:
+ case FIT_RGBAF:
+ {
+ FREE_IMAGE_FILTER filter = FILTER_BILINEAR;
+ thumbnail = FreeImage_Rescale(dib, new_width, new_height, filter);
+ }
+ break;
+
+ case FIT_INT16:
+ case FIT_UINT32:
+ case FIT_INT32:
+ case FIT_DOUBLE:
+ case FIT_COMPLEX:
+ default:
+ // cannot rescale this kind of image
+ thumbnail = NULL;
+ break;
+ }
+
+ if((thumbnail != NULL) && (image_type != FIT_BITMAP) && convert) {
+ // convert to a standard bitmap
+ FIBITMAP *bitmap = NULL;
+ switch(image_type) {
+ case FIT_UINT16:
+ bitmap = FreeImage_ConvertTo8Bits(thumbnail);
+ break;
+ case FIT_RGB16:
+ bitmap = FreeImage_ConvertTo24Bits(thumbnail);
+ break;
+ case FIT_RGBA16:
+ bitmap = FreeImage_ConvertTo32Bits(thumbnail);
+ break;
+ case FIT_FLOAT:
+ bitmap = FreeImage_ConvertToStandardType(thumbnail, TRUE);
+ break;
+ case FIT_RGBF:
+ bitmap = FreeImage_ToneMapping(thumbnail, FITMO_DRAGO03);
+ break;
+ case FIT_RGBAF:
+ // no way to keep the transparency yet ...
+ FIBITMAP *rgbf = FreeImage_ConvertToRGBF(thumbnail);
+ bitmap = FreeImage_ToneMapping(rgbf, FITMO_DRAGO03);
+ FreeImage_Unload(rgbf);
+ break;
+ }
+ if(bitmap != NULL) {
+ FreeImage_Unload(thumbnail);
+ thumbnail = bitmap;
+ }
+ }
+
+ // 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 5421bd47ab..f342bb794e 100644
--- a/plugins/AdvaImg/src/FreeImageToolkit/Resize.cpp
+++ b/plugins/AdvaImg/src/FreeImageToolkit/Resize.cpp
@@ -1,656 +1,1992 @@
-// ==========================================================
-// Upsampling / downsampling classes
-//
-// Design and implementation by
-// - Hervé Drolon (drolon@infonie.fr)
-// - Detlev Vendt (detlev.vendt@brillit.de)
-//
-// This file is part of FreeImage 3
-//
-// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
-// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
-// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
-// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
-// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
-// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
-// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
-// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
-// THIS DISCLAIMER.
-//
-// Use at your own risk!
-// ==========================================================
-
-#include "Resize.h"
-
-/**
- Filter weights table.
- This class stores contribution information for an entire line (row or column).
-*/
-CWeightsTable::CWeightsTable(CGenericFilter *pFilter, unsigned uDstSize, unsigned uSrcSize) {
- unsigned u;
- double dWidth;
- double dFScale = 1.0;
- 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;
- }
-
- // allocate a new line contributions structure
- //
- // window size is the number of sampled pixels
- m_WindowSize = 2 * (int)ceil(dWidth) + 1;
- m_LineLength = uDstSize;
- // allocate list of contributions
- m_WeightTable = (Contribution*)malloc(m_LineLength * sizeof(Contribution));
- for(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) - 0.5;
-
-
- for(u = 0; u < m_LineLength; u++) {
- // scan through line of contributions
- const double dCenter = (double)u / dScale + dOffset; // reverse mapping
- // find the significant edge points that affect the pixel
- int iLeft = MAX (0, (int)floor (dCenter - dWidth));
- int iRight = MIN ((int)ceil (dCenter + dWidth), int(uSrcSize) - 1);
-
- // cut edge points to fit in filter window in case of spill-off
- if ((iRight - iLeft + 1) > int(m_WindowSize)) {
- if(iLeft < (int(uSrcSize) - 1 / 2)) {
- iLeft++;
- } else {
- iRight--;
- }
- }
-
- m_WeightTable[u].Left = iLeft;
- m_WeightTable[u].Right = iRight;
-
- int iSrc = 0;
- double dTotalWeight = 0; // zero sum of weights
- for(iSrc = iLeft; iSrc <= iRight; iSrc++) {
- // calculate weights
- const double weight = dFScale * pFilter->Filter(dFScale * (dCenter - (double)iSrc));
- m_WeightTable[u].Weights[iSrc-iLeft] = weight;
- dTotalWeight += weight;
- }
- if ((dTotalWeight > 0) && (dTotalWeight != 1)) {
- // normalize weight of neighbouring points
- for(iSrc = iLeft; iSrc <= iRight; iSrc++) {
- // normalize point
- m_WeightTable[u].Weights[iSrc-iLeft] /= dTotalWeight;
- }
- // simplify the filter, discarding null weights at the right
- iSrc = iRight - iLeft;
- while(m_WeightTable[u].Weights[iSrc] == 0){
- m_WeightTable[u].Right--;
- iSrc--;
- if(m_WeightTable[u].Right == m_WeightTable[u].Left)
- break;
- }
-
- }
- }
-}
-
-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);
-}
-
-// ---------------------------------------------
-
-/**
- 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 8-, 24- and 32-bit buffers.<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
-
-*/
-
-FIBITMAP* CResizeEngine::scale(FIBITMAP *src, unsigned dst_width, unsigned dst_height) {
- unsigned src_width = FreeImage_GetWidth(src);
- unsigned src_height = FreeImage_GetHeight(src);
-
- unsigned redMask = FreeImage_GetRedMask(src);
- unsigned greenMask = FreeImage_GetGreenMask(src);
- unsigned blueMask = FreeImage_GetBlueMask(src);
-
- unsigned bpp = FreeImage_GetBPP(src);
- if(bpp == 1) {
- // convert output to 8-bit
- bpp = 8;
- }
-
- FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(src);
-
- // allocate the dst image
- FIBITMAP *dst = FreeImage_AllocateT(image_type, dst_width, dst_height, bpp, redMask, greenMask, blueMask);
- if (!dst) return NULL;
-
- if(bpp == 8) {
- if(FreeImage_GetColorType(src) == FIC_MINISWHITE) {
- // build an inverted greyscale palette
- RGBQUAD *dst_pal = FreeImage_GetPalette(dst);
- for(unsigned i = 0; i < 256; i++) {
- dst_pal[i].rgbRed = dst_pal[i].rgbGreen = dst_pal[i].rgbBlue = (BYTE)(255 - i);
- }
- } else {
- // build a greyscale palette
- RGBQUAD *dst_pal = FreeImage_GetPalette(dst);
- for(unsigned i = 0; i < 256; i++) {
- dst_pal[i].rgbRed = dst_pal[i].rgbGreen = dst_pal[i].rgbBlue = (BYTE)i;
- }
- }
- }
-
- /**
- 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
- // -------------
-
- // allocate a temporary image
- FIBITMAP *tmp = FreeImage_AllocateT(image_type, dst_width, src_height, bpp, redMask, greenMask, blueMask);
- if (!tmp) {
- FreeImage_Unload(dst);
- return NULL;
- }
-
- // scale source image horizontally into temporary image
- horizontalFilter(src, src_width, src_height, tmp, dst_width, src_height);
-
- // scale temporary image vertically into result image
- verticalFilter(tmp, dst_width, src_height, dst, dst_width, dst_height);
-
- // free temporary image
- FreeImage_Unload(tmp);
-
- } else {
- // yx filtering
- // -------------
-
- // allocate a temporary image
- FIBITMAP *tmp = FreeImage_AllocateT(image_type, src_width, dst_height, bpp, redMask, greenMask, blueMask);
- if (!tmp) {
- FreeImage_Unload(dst);
- return NULL;
- }
-
- // scale source image vertically into temporary image
- verticalFilter(src, src_width, src_height, tmp, src_width, dst_height);
-
- // scale temporary image horizontally into result image
- horizontalFilter(tmp, src_width, dst_height, dst, dst_width, dst_height);
-
- // free temporary image
- FreeImage_Unload(tmp);
- }
-
- return dst;
-}
-
-
-/// Performs horizontal image filtering
-void CResizeEngine::horizontalFilter(FIBITMAP *src, unsigned src_width, unsigned src_height, FIBITMAP *dst, unsigned dst_width, unsigned dst_height) {
- if(dst_width == src_width) {
- // no scaling required, just copy
- switch(FreeImage_GetBPP(src)) {
- case 1:
- {
- if(FreeImage_GetBPP(dst) != 8) break;
- for(unsigned y = 0; y < dst_height; y++) {
- // convert each row
- BYTE *src_bits = FreeImage_GetScanLine(src, y);
- BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
- FreeImage_ConvertLine1To8(dst_bits, src_bits, dst_width);
- }
- }
- break;
-
- default:
- {
- const BYTE *src_bits = FreeImage_GetBits(src);
- BYTE *dst_bits = FreeImage_GetBits(dst);
- memcpy(dst_bits, src_bits, dst_height * FreeImage_GetPitch(dst));
- }
- break;
- }
- }
- else {
-
- // 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:
- {
- // scale and convert to 8-bit
- if(FreeImage_GetBPP(dst) != 8) break;
-
- for(unsigned y = 0; y < dst_height; y++) {
- // scale each row
- const BYTE *src_bits = FreeImage_GetScanLine(src, y);
- BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
-
- for(unsigned x = 0; x < dst_width; x++) {
- // loop through row
- double value = 0;
- const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
-
- 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 BYTE pixel = (src_bits[i >> 3] & (0x80 >> (i & 0x07))) != 0;
- value += (weight * (double)pixel);
- }
- value *= 255;
-
- // clamp and place result in destination pixel
- dst_bits[x] = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 255);
- }
- }
- }
- break;
-
- case 8:
- case 24:
- case 32:
- {
- // Calculate the number of bytes per pixel (1 for 8-bit, 3 for 24-bit or 4 for 32-bit)
- const unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);
-
- for(unsigned y = 0; y < dst_height; y++) {
- // scale each row
- const BYTE *src_bits = FreeImage_GetScanLine(src, y);
- BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
-
- for(unsigned x = 0; x < dst_width; x++) {
- // loop through row
- double value[4] = {0, 0, 0, 0}; // 4 = 32 bpp max
- const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
-
- 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 * bytespp; // pixel index
- for (unsigned j = 0; j < bytespp; j++) {
- value[j] += (weight * (double)src_bits[index++]);
- }
- }
-
- // clamp and place result in destination pixel
- for (unsigned j = 0; j < bytespp; j++) {
- dst_bits[j] = (BYTE)CLAMP<int>((int)(value[j] + 0.5), 0, 0xFF);
- }
-
- dst_bits += bytespp;
- }
- }
- }
- break;
- }
- }
- break;
-
- case FIT_UINT16:
- case FIT_RGB16:
- 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) / FreeImage_GetWidth(src)) / sizeof(WORD);
-
- for(unsigned y = 0; y < dst_height; y++) {
- // scale each row
- const WORD *src_bits = (WORD*)FreeImage_GetScanLine(src, y);
- WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y);
-
- for(unsigned x = 0; x < dst_width; x++) {
- // loop through row
- double value[4] = {0, 0, 0, 0}; // 4 = 64 bpp max
- const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
-
- 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 * wordspp; // pixel index
- for (unsigned j = 0; j < wordspp; j++) {
- value[j] += (weight * (double)src_bits[index++]);
- }
- }
-
- // clamp and place result in destination pixel
- for (unsigned j = 0; j < wordspp; j++) {
- dst_bits[j] = (WORD)CLAMP<int>((int)(value[j] + 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) / FreeImage_GetWidth(src)) / sizeof(float);
-
- for(unsigned y = 0; y < dst_height; y++) {
- // scale each row
- const float *src_bits = (float*)FreeImage_GetScanLine(src, y);
- float *dst_bits = (float*)FreeImage_GetScanLine(dst, y);
-
- for(unsigned x = 0; x < dst_width; x++) {
- // loop through row
- double value[4] = {0, 0, 0, 0}; // 4 = 128 bpp max
- const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
-
- 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 *src, unsigned src_width, unsigned src_height, FIBITMAP *dst, unsigned dst_width, unsigned dst_height) {
- if(src_height == dst_height) {
- // no scaling required, just copy
- switch(FreeImage_GetBPP(src)) {
- case 1:
- {
- if(FreeImage_GetBPP(dst) != 8) break;
- for(unsigned y = 0; y < dst_height; y++) {
- // convert each row
- BYTE *src_bits = FreeImage_GetScanLine(src, y);
- BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
- FreeImage_ConvertLine1To8(dst_bits, src_bits, dst_width);
- }
- }
- break;
-
- default:
- {
- const BYTE *src_bits = FreeImage_GetBits(src);
- BYTE *dst_bits = FreeImage_GetBits(dst);
- memcpy(dst_bits, src_bits, dst_height * FreeImage_GetPitch(dst));
- }
- break;
- }
-
- }
- else {
-
- // allocate and calculate the contributions
- CWeightsTable weightsTable(m_pFilter, dst_height, src_height);
-
- // step through columns
- switch(FreeImage_GetImageType(src)) {
- case FIT_BITMAP:
- {
- switch(FreeImage_GetBPP(src)) {
- case 1:
- {
- // scale and convert to 8-bit
- if(FreeImage_GetBPP(dst) != 8) break;
-
- const unsigned src_pitch = FreeImage_GetPitch(src);
- const unsigned dst_pitch = FreeImage_GetPitch(dst);
-
- for(unsigned x = 0; x < dst_width; x++) {
-
- // work on column x in dst
- BYTE *dst_bits = FreeImage_GetBits(dst) + x;
-
- // scale each column
- for(unsigned y = 0; y < dst_height; y++) {
- // loop through column
- double value = 0;
- const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- const unsigned iRight = weightsTable.getRightBoundary(y); // retrieve right boundary
-
- BYTE *src_bits = FreeImage_GetScanLine(src, iLeft);
-
- 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);
-
- const BYTE pixel = (src_bits[x >> 3] & (0x80 >> (x & 0x07))) != 0;
- value += (weight * (double)pixel);
-
- src_bits += src_pitch;
- }
- value *= 255;
-
- // clamp and place result in destination pixel
- *dst_bits = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
-
- dst_bits += dst_pitch;
- }
- }
- }
- break;
-
- case 8:
- case 24:
- case 32:
- {
- // Calculate the number of bytes per pixel (1 for 8-bit, 3 for 24-bit or 4 for 32-bit)
- const unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);
-
- const unsigned src_pitch = FreeImage_GetPitch(src);
- const unsigned dst_pitch = FreeImage_GetPitch(dst);
-
- for(unsigned x = 0; x < dst_width; x++) {
- const unsigned index = x * bytespp; // pixel index
-
- // work on column x in dst
- BYTE *dst_bits = FreeImage_GetBits(dst) + index;
-
- // scale each column
- for(unsigned y = 0; y < dst_height; y++) {
- // loop through column
- double value[4] = {0, 0, 0, 0}; // 4 = 32 bpp max
- const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- const unsigned iRight = weightsTable.getRightBoundary(y); // retrieve right boundary
-
- const BYTE *src_bits = FreeImage_GetScanLine(src, iLeft) + index;
-
- 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 < bytespp; j++) {
- value[j] += (weight * (double)src_bits[j]);
- }
-
- src_bits += src_pitch;
- }
-
- // clamp and place result in destination pixel
- for (unsigned j = 0; j < bytespp; j++) {
- dst_bits[j] = (BYTE)CLAMP<int>((int)(value[j] + 0.5), 0, 0xFF);
- }
-
- dst_bits += dst_pitch;
- }
- }
- }
- break;
- }
- }
- break;
-
- case FIT_UINT16:
- case FIT_RGB16:
- 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) / FreeImage_GetWidth(src)) / sizeof(WORD);
-
- const unsigned src_pitch = FreeImage_GetPitch(src) / sizeof(WORD);
- const unsigned dst_pitch = FreeImage_GetPitch(dst) / sizeof(WORD);
-
- for(unsigned x = 0; x < dst_width; x++) {
- const unsigned index = x * wordspp; // pixel index
-
- // work on column x in dst
- WORD *dst_bits = (WORD*)FreeImage_GetBits(dst) + index;
-
- // scale each column
- for(unsigned y = 0; y < dst_height; y++) {
- // loop through column
- double value[4] = {0, 0, 0, 0}; // 4 = 64 bpp max
- const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- const unsigned iRight = weightsTable.getRightBoundary(y); // retrieve right boundary
-
- const WORD *src_bits = (WORD*)FreeImage_GetScanLine(src, iLeft) + index;
-
- 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 < wordspp; j++) {
- value[j] += (weight * (double)src_bits[j]);
- }
-
- src_bits += src_pitch;
- }
-
- // clamp and place result in destination pixel
- for (unsigned j = 0; j < wordspp; j++) {
- dst_bits[j] = (WORD)CLAMP<int>((int)(value[j] + 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) / FreeImage_GetWidth(src)) / sizeof(float);
-
- const unsigned src_pitch = FreeImage_GetPitch(src) / sizeof(float);
- const unsigned dst_pitch = FreeImage_GetPitch(dst) / sizeof(float);
-
- for(unsigned x = 0; x < dst_width; x++) {
- const unsigned index = x * floatspp; // pixel index
-
- // work on column x in dst
- float *dst_bits = (float*)FreeImage_GetBits(dst) + index;
-
- // scale each column
- for(unsigned y = 0; y < dst_height; y++) {
- // loop through column
- double value[4] = {0, 0, 0, 0}; // 4 = 128 bpp max
- const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- const unsigned iRight = weightsTable.getRightBoundary(y); // retrieve right boundary
-
- const float *src_bits = (float*)FreeImage_GetScanLine(src, iLeft) + index;
-
- 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;
- }
-
- // clamp and 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) {
+ unsigned u;
+ double dWidth;
+ double dFScale = 1.0;
+ 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;
+ }
+
+ // allocate a new line contributions structure
+ //
+ // window size is the number of sampled pixels
+ m_WindowSize = 2 * (int)ceil(dWidth) + 1;
+ m_LineLength = uDstSize;
+ // allocate list of contributions
+ m_WeightTable = (Contribution*)malloc(m_LineLength * sizeof(Contribution));
+ for(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) - 0.5;
+
+ for(u = 0; u < m_LineLength; u++) {
+ // scan through line of contributions
+ const double dCenter = (double)u / dScale + dOffset; // reverse mapping
+ // find the significant edge points that affect the pixel
+ int iLeft = MAX (0, (int)floor (dCenter - dWidth));
+ int iRight = MIN ((int)ceil (dCenter + dWidth), int(uSrcSize) - 1);
+
+ // cut edge points to fit in filter window in case of spill-off
+ if((iRight - iLeft + 1) > int(m_WindowSize)) {
+ if(iLeft < (int(uSrcSize) - 1 / 2)) {
+ iLeft++;
+ } else {
+ iRight--;
+ }
+ }
+
+ m_WeightTable[u].Left = iLeft;
+ m_WeightTable[u].Right = iRight;
+
+ int iSrc = 0;
+ double dTotalWeight = 0; // zero sum of weights
+ for(iSrc = iLeft; iSrc <= iRight; iSrc++) {
+ // calculate weights
+ const double weight = dFScale * pFilter->Filter(dFScale * (dCenter - (double)iSrc));
+ m_WeightTable[u].Weights[iSrc-iLeft] = weight;
+ dTotalWeight += weight;
+ }
+ if((dTotalWeight > 0) && (dTotalWeight != 1)) {
+ // normalize weight of neighbouring points
+ for(iSrc = iLeft; iSrc <= iRight; iSrc++) {
+ // normalize point
+ m_WeightTable[u].Weights[iSrc-iLeft] /= dTotalWeight;
+ }
+ // simplify the filter, discarding null weights at the right
+ iSrc = iRight - iLeft;
+ while(m_WeightTable[u].Weights[iSrc] == 0) {
+ m_WeightTable[u].Right--;
+ iSrc--;
+ if(m_WeightTable[u].Right == m_WeightTable[u].Left) {
+ break;
+ }
+ }
+
+ }
+ }
+}
+
+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;
+ } 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)
+ 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;
+ }
+}
diff --git a/plugins/AdvaImg/src/FreeImageToolkit/Resize.h b/plugins/AdvaImg/src/FreeImageToolkit/Resize.h
index 0d5d0b451a..7fe1cdb112 100644
--- a/plugins/AdvaImg/src/FreeImageToolkit/Resize.h
+++ b/plugins/AdvaImg/src/FreeImageToolkit/Resize.h
@@ -1,145 +1,195 @@
-// ==========================================================
-// Upsampling / downsampling classes
-//
-// Design and implementation by
-// - Hervé Drolon (drolon@infonie.fr)
-// - Detlev Vendt (detlev.vendt@brillit.de)
-//
-// This file is part of FreeImage 3
-//
-// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
-// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
-// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
-// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
-// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
-// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
-// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
-// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
-// THIS DISCLAIMER.
-//
-// Use at your own risk!
-// ==========================================================
-
-#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 8-, 24- and 32-bit buffers.<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
- CResizeEngine(CGenericFilter* filter):m_pFilter(filter) {}
-
- /// Destructor
- virtual ~CResizeEngine() {}
-
- /** Scale an image to the desired dimensions
- @param src Pointer to the source image
- @param dst_width Destination image width
- @param dst_height Destination image height
- @return Returns the scaled image if successful, returns NULL otherwise
- */
- FIBITMAP* scale(FIBITMAP *src, unsigned dst_width, unsigned dst_height);
-
-private:
-
- /// Performs horizontal image filtering
- void horizontalFilter(FIBITMAP *src, unsigned src_width, unsigned src_height, FIBITMAP *dst, unsigned dst_width, unsigned dst_height);
-
- /// Performs vertical image filtering
- void verticalFilter(FIBITMAP *src, unsigned src_width, unsigned src_height, FIBITMAP *dst, unsigned dst_width, 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);
+
+private:
+
+ /**
+ Performs horizontal image filtering
+ @param src
+ @param height
+ @param src_width
+ @param src_offset_x
+ @param src_offset_y
+ @param src_pal
+ @param dst
+ @param dst_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
+ @param width
+ @param src_height
+ @param src_offset_x
+ @param src_offset_y
+ @param src_pal
+ @param dst
+ @param dst_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_