From 48540940b6c28bb4378abfeb500ec45a625b37b6 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Tue, 15 May 2012 10:38:20 +0000 Subject: initial commit git-svn-id: http://svn.miranda-ng.org/main/trunk@2 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- .../freeimage/Source/FreeImageToolkit/Colors.cpp | 967 +++++++++++++++++++++ 1 file changed, 967 insertions(+) create mode 100644 plugins/freeimage/Source/FreeImageToolkit/Colors.cpp (limited to 'plugins/freeimage/Source/FreeImageToolkit/Colors.cpp') diff --git a/plugins/freeimage/Source/FreeImageToolkit/Colors.cpp b/plugins/freeimage/Source/FreeImageToolkit/Colors.cpp new file mode 100644 index 0000000000..13b61195ba --- /dev/null +++ b/plugins/freeimage/Source/FreeImageToolkit/Colors.cpp @@ -0,0 +1,967 @@ +// ========================================================== +// Color manipulation routines +// +// Design and implementation by +// - Hervé Drolon (drolon@infonie.fr) +// - Carsten Klein (c.klein@datagis.com) +// - Mihail Naydenov (mnaydenov@users.sourceforge.net) +// +// This file is part of FreeImage 3 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include "FreeImage.h" +#include "Utilities.h" + +// ---------------------------------------------------------- +// Macros + structures +// ---------------------------------------------------------- + +#define GET_HI_NIBBLE(byte) ((byte) >> 4) +#define SET_HI_NIBBLE(byte, n) byte &= 0x0F, byte |= ((n) << 4) +#define GET_LO_NIBBLE(byte) ((byte) & 0x0F) +#define SET_LO_NIBBLE(byte, n) byte &= 0xF0, byte |= ((n) & 0x0F) +#define GET_NIBBLE(cn, byte) ((cn) ? (GET_HI_NIBBLE(byte)) : (GET_LO_NIBBLE(byte))) +#define SET_NIBBLE(cn, byte, n) if (cn) SET_HI_NIBBLE(byte, n); else SET_LO_NIBBLE(byte, n) + +// ---------------------------------------------------------- + + +/** @brief Inverts each pixel data. + +@param src Input image to be processed. +@return Returns TRUE if successful, FALSE otherwise. +*/ +BOOL DLL_CALLCONV +FreeImage_Invert(FIBITMAP *src) { + + if (!FreeImage_HasPixels(src)) return FALSE; + + unsigned i, x, y, k; + + const unsigned width = FreeImage_GetWidth(src); + const unsigned height = FreeImage_GetHeight(src); + const unsigned bpp = FreeImage_GetBPP(src); + + FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(src); + + if(image_type == FIT_BITMAP) { + switch(bpp) { + case 1 : + case 4 : + case 8 : + { + // if the dib has a colormap, just invert it + // else, keep the linear grayscale + + if (FreeImage_GetColorType(src) == FIC_PALETTE) { + RGBQUAD *pal = FreeImage_GetPalette(src); + + for(i = 0; i < FreeImage_GetColorsUsed(src); i++) { + pal[i].rgbRed = 255 - pal[i].rgbRed; + pal[i].rgbGreen = 255 - pal[i].rgbGreen; + pal[i].rgbBlue = 255 - pal[i].rgbBlue; + } + } else { + for(y = 0; y < height; y++) { + BYTE *bits = FreeImage_GetScanLine(src, y); + + for (x = 0; x < FreeImage_GetLine(src); x++) { + bits[x] = ~bits[x]; + } + } + } + + break; + } + + case 24 : + case 32 : + { + // Calculate the number of bytes per pixel (3 for 24-bit or 4 for 32-bit) + const unsigned bytespp = FreeImage_GetLine(src) / width; + + for(y = 0; y < height; y++) { + BYTE *bits = FreeImage_GetScanLine(src, y); + for(x = 0; x < width; x++) { + for(k = 0; k < bytespp; k++) { + bits[k] = ~bits[k]; + } + bits += bytespp; + } + } + + break; + } + default: + return FALSE; + } + } + 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); + + for(y = 0; y < height; y++) { + WORD *bits = (WORD*)FreeImage_GetScanLine(src, y); + for(x = 0; x < width; x++) { + for(k = 0; k < wordspp; k++) { + bits[k] = ~bits[k]; + } + bits += wordspp; + } + } + } + else { + // anything else ... + return FALSE; + } + + return TRUE; +} + +/** @brief Perfoms an histogram transformation on a 8, 24 or 32-bit image +according to the values of a lookup table (LUT). + +The transformation is done as follows.
+Image 8-bit : if the image has a color palette, the LUT is applied to this palette, +otherwise, it is applied to the grey values.
+Image 24-bit & 32-bit : if channel == FICC_RGB, the same LUT is applied to each color +plane (R,G, and B). Otherwise, the LUT is applied to the specified channel only. +@param src Input image to be processed. +@param LUT Lookup table. The size of 'LUT' is assumed to be 256. +@param channel The color channel to be processed (only used with 24 & 32-bit DIB). +@return Returns TRUE if successful, FALSE otherwise. +@see FREE_IMAGE_COLOR_CHANNEL +*/ +BOOL DLL_CALLCONV +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)) + return FALSE; + + int bpp = FreeImage_GetBPP(src); + if((bpp != 8) && (bpp != 24) && (bpp != 32)) + return FALSE; + + // apply the LUT + switch(bpp) { + + case 8 : + { + // if the dib has a colormap, apply the LUT to it + // else, apply the LUT to pixel values + + if(FreeImage_GetColorType(src) == FIC_PALETTE) { + RGBQUAD *rgb = FreeImage_GetPalette(src); + for (unsigned pal = 0; pal < FreeImage_GetColorsUsed(src); pal++) { + rgb->rgbRed = LUT[rgb->rgbRed]; + rgb->rgbGreen = LUT[rgb->rgbGreen]; + rgb->rgbBlue = LUT[rgb->rgbBlue]; + rgb++; + } + } + else { + for(y = 0; y < FreeImage_GetHeight(src); y++) { + bits = FreeImage_GetScanLine(src, y); + for(x = 0; x < FreeImage_GetWidth(src); x++) { + bits[x] = LUT[ bits[x] ]; + } + } + } + + break; + } + + case 24 : + case 32 : + { + int bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src); + + switch(channel) { + case FICC_RGB : + for(y = 0; y < FreeImage_GetHeight(src); y++) { + bits = FreeImage_GetScanLine(src, y); + for(x = 0; x < FreeImage_GetWidth(src); x++) { + bits[FI_RGBA_BLUE] = LUT[ bits[FI_RGBA_BLUE] ]; // B + bits[FI_RGBA_GREEN] = LUT[ bits[FI_RGBA_GREEN] ]; // G + bits[FI_RGBA_RED] = LUT[ bits[FI_RGBA_RED] ]; // R + + bits += bytespp; + } + } + break; + + case FICC_BLUE : + for(y = 0; y < FreeImage_GetHeight(src); y++) { + bits = FreeImage_GetScanLine(src, y); + for(x = 0; x < FreeImage_GetWidth(src); x++) { + bits[FI_RGBA_BLUE] = LUT[ bits[FI_RGBA_BLUE] ]; // B + + bits += bytespp; + } + } + break; + + case FICC_GREEN : + for(y = 0; y < FreeImage_GetHeight(src); y++) { + bits = FreeImage_GetScanLine(src, y); + for(x = 0; x < FreeImage_GetWidth(src); x++) { + bits[FI_RGBA_GREEN] = LUT[ bits[FI_RGBA_GREEN] ]; // G + + bits += bytespp; + } + } + break; + + case FICC_RED : + for(y = 0; y < FreeImage_GetHeight(src); y++) { + bits = FreeImage_GetScanLine(src, y); + for(x = 0; x < FreeImage_GetWidth(src); x++) { + bits[FI_RGBA_RED] = LUT[ bits[FI_RGBA_RED] ]; // R + + bits += bytespp; + } + } + break; + + case FICC_ALPHA : + if(32 == bpp) { + for(y = 0; y < FreeImage_GetHeight(src); y++) { + bits = FreeImage_GetScanLine(src, y); + for(x = 0; x < FreeImage_GetWidth(src); x++) { + bits[FI_RGBA_ALPHA] = LUT[ bits[FI_RGBA_ALPHA] ]; // A + + bits += bytespp; + } + } + } + break; + + default: + break; + } + break; + } + } + + return TRUE; +} + +/** @brief Performs gamma correction on a 8, 24 or 32-bit image. + +@param src Input image to be processed. +@param gamma Gamma value to use. A value of 1.0 leaves the image alone, +less than one darkens it, and greater than one lightens it. +@return Returns TRUE if successful, FALSE otherwise. +*/ +BOOL DLL_CALLCONV +FreeImage_AdjustGamma(FIBITMAP *src, double gamma) { + BYTE LUT[256]; // Lookup table + + if(!FreeImage_HasPixels(src) || (gamma <= 0)) + return FALSE; + + // Build the lookup table + + double exponent = 1 / gamma; + double v = 255.0 * (double)pow((double)255, -exponent); + for(int i = 0; i < 256; i++) { + double color = (double)pow((double)i, exponent) * v; + if(color > 255) + color = 255; + LUT[i] = (BYTE)floor(color + 0.5); + } + + // Apply the gamma correction + return FreeImage_AdjustCurve(src, LUT, FICC_RGB); +} + +/** @brief Adjusts the brightness of a 8, 24 or 32-bit image by a certain amount. + +@param src Input image to be processed. +@param percentage Where -100 <= percentage <= 100
+A value 0 means no change, less than 0 will make the image darker +and greater than 0 will make the image brighter. +@return Returns TRUE if successful, FALSE otherwise. +*/ +BOOL DLL_CALLCONV +FreeImage_AdjustBrightness(FIBITMAP *src, double percentage) { + BYTE LUT[256]; // Lookup table + double value; + + if(!FreeImage_HasPixels(src)) + return FALSE; + + // Build the lookup table + const double scale = (100 + percentage) / 100; + for(int i = 0; i < 256; i++) { + value = i * scale; + value = MAX(0.0, MIN(value, 255.0)); + LUT[i] = (BYTE)floor(value + 0.5); + } + return FreeImage_AdjustCurve(src, LUT, FICC_RGB); +} + +/** @brief Adjusts the contrast of a 8, 24 or 32-bit image by a certain amount. + +@param src Input image to be processed. +@param percentage Where -100 <= percentage <= 100
+A value 0 means no change, less than 0 will decrease the contrast +and greater than 0 will increase the contrast of the image. +@return Returns TRUE if successful, FALSE otherwise. +*/ +BOOL DLL_CALLCONV +FreeImage_AdjustContrast(FIBITMAP *src, double percentage) { + BYTE LUT[256]; // Lookup table + double value; + + if(!FreeImage_HasPixels(src)) + return FALSE; + + // Build the lookup table + const double scale = (100 + percentage) / 100; + for(int i = 0; i < 256; i++) { + value = 128 + (i - 128) * scale; + value = MAX(0.0, MIN(value, 255.0)); + LUT[i] = (BYTE)floor(value + 0.5); + } + return FreeImage_AdjustCurve(src, LUT, FICC_RGB); +} + +/** @brief Computes image histogram + +For 24-bit and 32-bit images, histogram can be computed from red, green, blue and +black channels. For 8-bit images, histogram is computed from the black channel. Other +bit depth is not supported (nothing is done). +@param src Input image to be processed. +@param histo Histogram array to fill. The size of 'histo' is assumed to be 256. +@param channel Color channel to use +@return Returns TRUE if succesful, returns FALSE if the image bit depth isn't supported. +*/ +BOOL DLL_CALLCONV +FreeImage_GetHistogram(FIBITMAP *src, DWORD *histo, FREE_IMAGE_COLOR_CHANNEL channel) { + BYTE pixel; + BYTE *bits = NULL; + unsigned x, y; + + if(!FreeImage_HasPixels(src) || !histo) return FALSE; + + unsigned width = FreeImage_GetWidth(src); + unsigned height = FreeImage_GetHeight(src); + unsigned bpp = FreeImage_GetBPP(src); + + if(bpp == 8) { + // clear histogram array + memset(histo, 0, 256 * sizeof(DWORD)); + // compute histogram for black channel + for(y = 0; y < height; y++) { + bits = FreeImage_GetScanLine(src, y); + for(x = 0; x < width; x++) { + // get pixel value + pixel = bits[x]; + histo[pixel]++; + } + } + return TRUE; + } + else if((bpp == 24) || (bpp == 32)) { + int bytespp = bpp / 8; // bytes / pixel + + // clear histogram array + memset(histo, 0, 256 * sizeof(DWORD)); + + switch(channel) { + case FICC_RED: + // compute histogram for red channel + for(y = 0; y < height; y++) { + bits = FreeImage_GetScanLine(src, y); + for(x = 0; x < width; x++) { + pixel = bits[FI_RGBA_RED]; // R + histo[pixel]++; + bits += bytespp; + } + } + return TRUE; + + case FICC_GREEN: + // compute histogram for green channel + for(y = 0; y < height; y++) { + bits = FreeImage_GetScanLine(src, y); + for(x = 0; x < width; x++) { + pixel = bits[FI_RGBA_GREEN]; // G + histo[pixel]++; + bits += bytespp; + } + } + return TRUE; + + case FICC_BLUE: + // compute histogram for blue channel + for(y = 0; y < height; y++) { + bits = FreeImage_GetScanLine(src, y); + for(x = 0; x < width; x++) { + pixel = bits[FI_RGBA_BLUE]; // B + histo[pixel]++; + bits += bytespp; + } + } + return TRUE; + + case FICC_BLACK: + case FICC_RGB: + // compute histogram for black channel + for(y = 0; y < height; y++) { + bits = FreeImage_GetScanLine(src, y); + for(x = 0; x < width; x++) { + // RGB to GREY conversion + pixel = GREY(bits[FI_RGBA_RED], bits[FI_RGBA_GREEN], bits[FI_RGBA_BLUE]); + histo[pixel]++; + bits += bytespp; + } + } + return TRUE; + + default: + return FALSE; + } + } + + return FALSE; +} + +// ---------------------------------------------------------- + + +/** @brief Creates a lookup table to be used with FreeImage_AdjustCurve() which + may adjust brightness and contrast, correct gamma and invert the image with a + single call to FreeImage_AdjustCurve(). + + This function creates a lookup table to be used with FreeImage_AdjustCurve() + which may adjust brightness and contrast, correct gamma and invert the image + with a single call to FreeImage_AdjustCurve(). If more than one of these image + display properties need to be adjusted, using a combined lookup table should be + preferred over calling each adjustment function separately. That's particularly + true for huge images or if performance is an issue. Then, the expensive process + of iterating over all pixels of an image is performed only once and not up to + four times. + + Furthermore, the lookup table created does not depend on the order, in which + each single adjustment operation is performed. Due to rounding and byte casting + issues, it actually matters in which order individual adjustment operations + are performed. Both of the following snippets most likely produce different + results: + + // snippet 1: contrast, brightness + FreeImage_AdjustContrast(dib, 15.0); + FreeImage_AdjustBrightness(dib, 50.0); + + // snippet 2: brightness, contrast + FreeImage_AdjustBrightness(dib, 50.0); + FreeImage_AdjustContrast(dib, 15.0); + + Better and even faster would be snippet 3: + + // snippet 3: + BYTE LUT[256]; + FreeImage_GetAdjustColorsLookupTable(LUT, 50.0, 15.0, 1.0, FALSE); + FreeImage_AdjustCurve(dib, LUT, FICC_RGB); + + This function is also used internally by FreeImage_AdjustColors(), which does + not return the lookup table, but uses it to call FreeImage_AdjustCurve() on the + passed image. + + @param LUT Output lookup table to be used with FreeImage_AdjustCurve(). The + size of 'LUT' is assumed to be 256. + @param brightness Percentage brightness value where -100 <= brightness <= 100
+ A value of 0 means no change, less than 0 will make the image darker and greater + than 0 will make the image brighter. + @param contrast Percentage contrast value where -100 <= contrast <= 100
+ A value of 0 means no change, less than 0 will decrease the contrast + and greater than 0 will increase the contrast of the image. + @param gamma Gamma value to be used for gamma correction. A value of 1.0 leaves + the image alone, less than one darkens it, and greater than one lightens it. + This parameter must not be zero or smaller than zero. If so, it will be ignored + and no gamma correction will be performed using the lookup table created. + @param invert If set to TRUE, the image will be inverted. + @return Returns the number of adjustments applied to the resulting lookup table + compared to a blind lookup table. + */ +int DLL_CALLCONV +FreeImage_GetAdjustColorsLookupTable(BYTE *LUT, double brightness, double contrast, double gamma, BOOL invert) { + double dblLUT[256]; + double value; + int result = 0; + + if ((brightness == 0.0) && (contrast == 0.0) && (gamma == 1.0) && (!invert)) { + // nothing to do, if all arguments have their default values + // return a blind LUT + for (int i = 0; i < 256; i++) { + LUT[i] = (BYTE)i; + } + return 0; + } + + // first, create a blind LUT, which does nothing to the image + for (int i = 0; i < 256; i++) { + dblLUT[i] = i; + } + + if (contrast != 0.0) { + // modify lookup table with contrast adjustment data + const double v = (100.0 + contrast) / 100.0; + for (int i = 0; i < 256; i++) { + value = 128 + (dblLUT[i] - 128) * v; + dblLUT[i] = MAX(0.0, MIN(value, 255.0)); + } + result++; + } + + if (brightness != 0.0) { + // modify lookup table with brightness adjustment data + const double v = (100.0 + brightness) / 100.0; + for (int i = 0; i < 256; i++) { + value = dblLUT[i] * v; + dblLUT[i] = MAX(0.0, MIN(value, 255.0)); + } + result++; + } + + if ((gamma > 0) && (gamma != 1.0)) { + // modify lookup table with gamma adjustment data + double exponent = 1 / gamma; + const double v = 255.0 * (double)pow((double)255, -exponent); + for (int i = 0; i < 256; i++) { + value = pow(dblLUT[i], exponent) * v; + dblLUT[i] = MAX(0.0, MIN(value, 255.0)); + } + result++; + } + + if (!invert) { + for (int i = 0; i < 256; i++) { + LUT[i] = (BYTE)floor(dblLUT[i] + 0.5); + } + } else { + for (int i = 0; i < 256; i++) { + LUT[i] = 255 - (BYTE)floor(dblLUT[i] + 0.5); + } + result++; + } + // return the number of adjustments made + return result; +} + +/** @brief Adjusts an image's brightness, contrast and gamma as well as it may + optionally invert the image within a single operation. + + This function adjusts an image's brightness, contrast and gamma as well as it + may optionally invert the image within a single operation. If more than one of + these image display properties need to be adjusted, using this function should + be preferred over calling each adjustment function separately. That's + particularly true for huge images or if performance is an issue. + + This function relies on FreeImage_GetAdjustColorsLookupTable(), which creates a + single lookup table, that combines all adjustment operations requested. + + Furthermore, the lookup table created by FreeImage_GetAdjustColorsLookupTable() + does not depend on the order, in which each single adjustment operation is + performed. Due to rounding and byte casting issues, it actually matters in which + order individual adjustment operations are performed. Both of the following + snippets most likely produce different results: + + // snippet 1: contrast, brightness + FreeImage_AdjustContrast(dib, 15.0); + FreeImage_AdjustBrightness(dib, 50.0); + + // snippet 2: brightness, contrast + FreeImage_AdjustBrightness(dib, 50.0); + FreeImage_AdjustContrast(dib, 15.0); + + Better and even faster would be snippet 3: + + // snippet 3: + FreeImage_AdjustColors(dib, 50.0, 15.0, 1.0, FALSE); + + @param dib Input/output image to be processed. + @param brightness Percentage brightness value where -100 <= brightness <= 100
+ A value of 0 means no change, less than 0 will make the image darker and greater + than 0 will make the image brighter. + @param contrast Percentage contrast value where -100 <= contrast <= 100
+ A value of 0 means no change, less than 0 will decrease the contrast + and greater than 0 will increase the contrast of the image. + @param gamma Gamma value to be used for gamma correction. A value of 1.0 leaves + the image alone, less than one darkens it, and greater than one lightens it.
+ This parameter must not be zero or smaller than zero. If so, it will be ignored + and no gamma correction will be performed on the image. + @param invert If set to TRUE, the image will be inverted. + @return Returns TRUE on success, FALSE otherwise (e.g. when the bitdeph of the + source dib cannot be handled). + */ +BOOL DLL_CALLCONV +FreeImage_AdjustColors(FIBITMAP *dib, double brightness, double contrast, double gamma, BOOL invert) { + BYTE LUT[256]; + + if (!FreeImage_HasPixels(dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP)) { + return FALSE; + } + + int bpp = FreeImage_GetBPP(dib); + if ((bpp != 8) && (bpp != 24) && (bpp != 32)) { + return FALSE; + } + + if (FreeImage_GetAdjustColorsLookupTable(LUT, brightness, contrast, gamma, invert)) { + return FreeImage_AdjustCurve(dib, LUT, FICC_RGB); + } + return FALSE; +} + +/** @brief Applies color mapping for one or several colors on a 1-, 4- or 8-bit + palletized or a 16-, 24- or 32-bit high color image. + + This function maps up to count colors specified in srccolors to + these specified in dstcolors. Thereby, color srccolors[N], + if found in the image, will be replaced by color dstcolors[N]. If + parameter swap is TRUE, additionally all colors specified in + dstcolors are also mapped to these specified in srccolors. For + high color images, the actual image data will be modified whereas, for + palletized images only the palette will be changed.
+ + The function returns the number of pixels changed or zero, if no pixels were + changed. + + Both arrays srccolors and dstcolors are assumed not to hold less + than count colors.
+ + For 16-bit images, all colors specified are transparently converted to their + proper 16-bit representation (either in RGB555 or RGB565 format, which is + determined by the image's red- green- and blue-mask).
+ + Note, that this behaviour is different from what FreeImage_ApplyPaletteIndexMapping() + does, which modifies the actual image data on palletized images. + + @param dib Input/output image to be processed. + @param srccolors Array of colors to be used as the mapping source. + @param dstcolors Array of colors to be used as the mapping destination. + @param count The number of colors to be mapped. This is the size of both + srccolors and dstcolors. + @param ignore_alpha If TRUE, 32-bit images and colors are treated as 24-bit. + @param swap If TRUE, source and destination colors are swapped, that is, + each destination color is also mapped to the corresponding source color. + @return Returns the total number of pixels changed. + */ +unsigned DLL_CALLCONV +FreeImage_ApplyColorMapping(FIBITMAP *dib, RGBQUAD *srccolors, RGBQUAD *dstcolors, unsigned count, BOOL ignore_alpha, BOOL swap) { + unsigned result = 0; + + if (!FreeImage_HasPixels(dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP)) { + return 0; + } + + // validate parameters + if ((!srccolors) || (!dstcolors)|| (count < 1)) { + return 0; + } + + int bpp = FreeImage_GetBPP(dib); + switch (bpp) { + case 1: + case 4: + case 8: { + unsigned size = FreeImage_GetColorsUsed(dib); + RGBQUAD *pal = FreeImage_GetPalette(dib); + RGBQUAD *a, *b; + for (unsigned x = 0; x < size; x++) { + for (unsigned j = 0; j < count; j++) { + a = srccolors; + b = dstcolors; + for (int i = (swap ? 0 : 1); i < 2; i++) { + if ((pal[x].rgbBlue == a[j].rgbBlue)&&(pal[x].rgbGreen == a[j].rgbGreen) &&(pal[x].rgbRed== a[j].rgbRed)) { + pal[x].rgbBlue = b[j].rgbBlue; + pal[x].rgbGreen = b[j].rgbGreen; + pal[x].rgbRed = b[j].rgbRed; + result++; + j = count; + break; + } + a = dstcolors; + b = srccolors; + } + } + } + return result; + } + case 16: { + WORD *src16 = (WORD *)malloc(sizeof(WORD) * count); + if (NULL == src16) { + return 0; + } + + WORD *dst16 = (WORD *)malloc(sizeof(WORD) * count); + if (NULL == dst16) { + free(src16); + return 0; + } + + for (unsigned j = 0; j < count; j++) { + src16[j] = RGBQUAD_TO_WORD(dib, (srccolors + j)); + dst16[j] = RGBQUAD_TO_WORD(dib, (dstcolors + j)); + } + + unsigned height = FreeImage_GetHeight(dib); + unsigned width = FreeImage_GetWidth(dib); + WORD *a, *b; + for (unsigned y = 0; y < height; y++) { + WORD *bits = (WORD *)FreeImage_GetScanLine(dib, y); + for (unsigned x = 0; x < width; x++, bits++) { + for (unsigned j = 0; j < count; j++) { + a = src16; + b = dst16; + for (int i = (swap ? 0 : 1); i < 2; i++) { + if (*bits == a[j]) { + *bits = b[j]; + result++; + j = count; + break; + } + a = dst16; + b = src16; + } + } + } + } + free(src16); + free(dst16); + return result; + } + case 24: { + unsigned height = FreeImage_GetHeight(dib); + unsigned width = FreeImage_GetWidth(dib); + RGBQUAD *a, *b; + for (unsigned y = 0; y < height; y++) { + BYTE *bits = FreeImage_GetScanLine(dib, y); + for (unsigned x = 0; x < width; x++, bits += 3) { + for (unsigned j = 0; j < count; j++) { + a = srccolors; + b = dstcolors; + for (int i = (swap ? 0 : 1); i < 2; i++) { + if ((bits[FI_RGBA_BLUE] == a[j].rgbBlue) && (bits[FI_RGBA_GREEN] == a[j].rgbGreen) &&(bits[FI_RGBA_RED] == a[j].rgbRed)) { + bits[FI_RGBA_BLUE] = b[j].rgbBlue; + bits[FI_RGBA_GREEN] = b[j].rgbGreen; + bits[FI_RGBA_RED] = b[j].rgbRed; + result++; + j = count; + break; + } + a = dstcolors; + b = srccolors; + } + } + } + } + return result; + } + case 32: { + unsigned height = FreeImage_GetHeight(dib); + unsigned width = FreeImage_GetWidth(dib); + RGBQUAD *a, *b; + for (unsigned y = 0; y < height; y++) { + BYTE *bits = FreeImage_GetScanLine(dib, y); + for (unsigned x = 0; x < width; x++, bits += 4) { + for (unsigned j = 0; j < count; j++) { + a = srccolors; + b = dstcolors; + for (int i = (swap ? 0 : 1); i < 2; i++) { + if ((bits[FI_RGBA_BLUE] == a[j].rgbBlue) &&(bits[FI_RGBA_GREEN] == a[j].rgbGreen) &&(bits[FI_RGBA_RED] == a[j].rgbRed) + &&((ignore_alpha) || (bits[FI_RGBA_ALPHA] == a[j].rgbReserved))) { + bits[FI_RGBA_BLUE] = b[j].rgbBlue; + bits[FI_RGBA_GREEN] = b[j].rgbGreen; + bits[FI_RGBA_RED] = b[j].rgbRed; + if (!ignore_alpha) { + bits[FI_RGBA_ALPHA] = b[j].rgbReserved; + } + result++; + j = count; + break; + } + a = dstcolors; + b = srccolors; + } + } + } + } + return result; + } + default: { + return 0; + } + } +} + +/** @brief Swaps two specified colors on a 1-, 4- or 8-bit palletized + or a 16-, 24- or 32-bit high color image. + + This function swaps the two specified colors color_a and color_b + on a palletized or high color image. For high color images, the actual image + data will be modified whereas, for palletized images only the palette will be + changed.
+ + Note, that this behaviour is different from what FreeImage_SwapPaletteIndices() + does, which modifies the actual image data on palletized images.
+ + This is just a thin wrapper for FreeImage_ApplyColorMapping() and resolves to:
+ return FreeImage_ApplyColorMapping(dib, color_a, color_b, 1, ignore_alpha, TRUE); + + @param dib Input/output image to be processed. + @param color_a On of the two colors to be swapped. + @param color_b The other of the two colors to be swapped. + @param ignore_alpha If TRUE, 32-bit images and colors are treated as 24-bit. + @return Returns the total number of pixels changed. + */ +unsigned DLL_CALLCONV +FreeImage_SwapColors(FIBITMAP *dib, RGBQUAD *color_a, RGBQUAD *color_b, BOOL ignore_alpha) { + return FreeImage_ApplyColorMapping(dib, color_a, color_b, 1, ignore_alpha, TRUE); +} + +/** @brief Applies palette index mapping for one or several indices on a 1-, 4- + or 8-bit palletized image. + + This function maps up to count palette indices specified in + srcindices to these specified in dstindices. Thereby, index + srcindices[N], if present in the image, will be replaced by index + dstindices[N]. If parameter swap is TRUE, additionally all indices + specified in dstindices are also mapped to these specified in + srcindices.
+ + The function returns the number of pixels changed or zero, if no pixels were + changed. + + Both arrays srcindices and dstindices are assumed not to hold less + than count indices.
+ + Note, that this behaviour is different from what FreeImage_ApplyColorMapping() + does, which modifies the actual image data on palletized images. + + @param dib Input/output image to be processed. + @param srcindices Array of palette indices to be used as the mapping source. + @param dstindices Array of palette indices to be used as the mapping destination. + @param count The number of palette indices to be mapped. This is the size of both + srcindices and dstindices. + @param swap If TRUE, source and destination palette indices are swapped, that is, + each destination index is also mapped to the corresponding source index. + @return Returns the total number of pixels changed. + */ +unsigned DLL_CALLCONV +FreeImage_ApplyPaletteIndexMapping(FIBITMAP *dib, BYTE *srcindices, BYTE *dstindices, unsigned count, BOOL swap) { + unsigned result = 0; + + if (!FreeImage_HasPixels(dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP)) { + return 0; + } + + // validate parameters + if ((!srcindices) || (!dstindices)|| (count < 1)) { + return 0; + } + + unsigned height = FreeImage_GetHeight(dib); + unsigned width = FreeImage_GetLine(dib); + BYTE *a, *b; + + int bpp = FreeImage_GetBPP(dib); + switch (bpp) { + case 1: { + + return result; + } + case 4: { + int skip_last = (FreeImage_GetWidth(dib) & 0x01); + unsigned max_x = width - 1; + for (unsigned y = 0; y < height; y++) { + BYTE *bits = FreeImage_GetScanLine(dib, y); + for (unsigned x = 0; x < width; x++) { + int start = ((skip_last) && (x == max_x)) ? 1 : 0; + for (int cn = start; cn < 2; cn++) { + for (unsigned j = 0; j < count; j++) { + a = srcindices; + b = dstindices; + for (int i = ((swap) ? 0 : 1); i < 2; i++) { + if (GET_NIBBLE(cn, bits[x]) == (a[j] & 0x0F)) { + SET_NIBBLE(cn, bits[x], b[j]); + result++; + j = count; + break; + } + a = dstindices; + b = srcindices; + } + } + } + } + } + return result; + } + case 8: { + for (unsigned y = 0; y < height; y++) { + BYTE *bits = FreeImage_GetScanLine(dib, y); + for (unsigned x = 0; x < width; x++) { + for (unsigned j = 0; j < count; j++) { + a = srcindices; + b = dstindices; + for (int i = ((swap) ? 0 : 1); i < 2; i++) { + if (bits[x] == a[j]) { + bits[x] = b[j]; + result++; + j = count; + break; + } + a = dstindices; + b = srcindices; + } + } + } + } + return result; + } + default: { + return 0; + } + } +} + +/** @brief Swaps two specified palette indices on a 1-, 4- or 8-bit palletized + image. + + This function swaps the two specified palette indices index_a and + index_b on a palletized image. Therefore, not the palette, but the + actual image data will be modified.
+ + Note, that this behaviour is different from what FreeImage_SwapColors() does + on palletized images, which only swaps the colors in the palette.
+ + This is just a thin wrapper for FreeImage_ApplyColorMapping() and resolves to:
+ return FreeImage_ApplyPaletteIndexMapping(dib, index_a, index_b, 1, TRUE); + + @param dib Input/output image to be processed. + @param index_a On of the two palette indices to be swapped. + @param index_b The other of the two palette indices to be swapped. + @return Returns the total number of pixels changed. + */ +unsigned DLL_CALLCONV +FreeImage_SwapPaletteIndices(FIBITMAP *dib, BYTE *index_a, BYTE *index_b) { + return FreeImage_ApplyPaletteIndexMapping(dib, index_a, index_b, 1, TRUE); +} + -- cgit v1.2.3