// ========================================================== // 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); }