summaryrefslogtreecommitdiff
path: root/plugins/FreeImage/Source/FreeImageToolkit/Colors.cpp
diff options
context:
space:
mode:
authorKirill Volinsky <mataes2007@gmail.com>2012-05-18 22:10:43 +0000
committerKirill Volinsky <mataes2007@gmail.com>2012-05-18 22:10:43 +0000
commit725f68b6808a8a30778f58223fac75386f082785 (patch)
treeccba410760749d45139e5e78fd5e08f416ade1a0 /plugins/FreeImage/Source/FreeImageToolkit/Colors.cpp
parentf920ef497f3299ae24fe783ce03bdd93b419f764 (diff)
plugins folders renaming
git-svn-id: http://svn.miranda-ng.org/main/trunk@61 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/FreeImage/Source/FreeImageToolkit/Colors.cpp')
-rw-r--r--plugins/FreeImage/Source/FreeImageToolkit/Colors.cpp967
1 files changed, 967 insertions, 0 deletions
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.<br>
+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.<br>
+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. <b>The size of 'LUT' is assumed to be 256.</b>
+@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<br>
+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<br>
+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. <b>The size of 'histo' is assumed to be 256.</b>
+@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(). <b>The
+ size of 'LUT' is assumed to be 256.</b>
+ @param brightness Percentage brightness value where -100 <= brightness <= 100<br>
+ 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<br>
+ 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<br>
+ 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<br>
+ 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.<br>
+ 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 <i>count</i> colors specified in <i>srccolors</i> to
+ these specified in <i>dstcolors</i>. Thereby, color <i>srccolors[N]</i>,
+ if found in the image, will be replaced by color <i>dstcolors[N]</i>. If
+ parameter <i>swap</i> is TRUE, additionally all colors specified in
+ <i>dstcolors</i> are also mapped to these specified in <i>srccolors</i>. For
+ high color images, the actual image data will be modified whereas, for
+ palletized images only the palette will be changed.<br>
+
+ The function returns the number of pixels changed or zero, if no pixels were
+ changed.
+
+ Both arrays <i>srccolors</i> and <i>dstcolors</i> are assumed not to hold less
+ than <i>count</i> colors.<br>
+
+ 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).<br>
+
+ <b>Note, that this behaviour is different from what FreeImage_ApplyPaletteIndexMapping()
+ does, which modifies the actual image data on palletized images.</b>
+
+ @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
+ <i>srccolors</i> and <i>dstcolors</i>.
+ @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 <i>color_a</i> and <i>color_b</i>
+ 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.<br>
+
+ <b>Note, that this behaviour is different from what FreeImage_SwapPaletteIndices()
+ does, which modifies the actual image data on palletized images.</b><br>
+
+ This is just a thin wrapper for FreeImage_ApplyColorMapping() and resolves to:<br>
+ <i>return FreeImage_ApplyColorMapping(dib, color_a, color_b, 1, ignore_alpha, TRUE);</i>
+
+ @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 <i>count</i> palette indices specified in
+ <i>srcindices</i> to these specified in <i>dstindices</i>. Thereby, index
+ <i>srcindices[N]</i>, if present in the image, will be replaced by index
+ <i>dstindices[N]</i>. If parameter <i>swap</i> is TRUE, additionally all indices
+ specified in <i>dstindices</i> are also mapped to these specified in
+ <i>srcindices</i>.<br>
+
+ The function returns the number of pixels changed or zero, if no pixels were
+ changed.
+
+ Both arrays <i>srcindices</i> and <i>dstindices</i> are assumed not to hold less
+ than <i>count</i> indices.<br>
+
+ <b>Note, that this behaviour is different from what FreeImage_ApplyColorMapping()
+ does, which modifies the actual image data on palletized images.</b>
+
+ @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
+ <i>srcindices</i> and <i>dstindices</i>.
+ @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 <i>index_a</i> and
+ <i>index_b</i> on a palletized image. Therefore, not the palette, but the
+ actual image data will be modified.<br>
+
+ <b>Note, that this behaviour is different from what FreeImage_SwapColors() does
+ on palletized images, which only swaps the colors in the palette.</b><br>
+
+ This is just a thin wrapper for FreeImage_ApplyColorMapping() and resolves to:<br>
+ <i>return FreeImage_ApplyPaletteIndexMapping(dib, index_a, index_b, 1, TRUE);</i>
+
+ @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);
+}
+