PageRenderTime 67ms CodeModel.GetById 9ms app.highlight 51ms RepoModel.GetById 1ms app.codeStats 0ms

/src/FreeImage/Source/FreeImageToolkit/Colors.cpp

https://bitbucket.org/cabalistic/ogredeps/
C++ | 967 lines | 567 code | 91 blank | 309 comment | 177 complexity | bb299c635590762e09c7c646947d2cce MD5 | raw file
  1// ==========================================================
  2// Color manipulation routines
  3//
  4// Design and implementation by
  5// - Hervé Drolon (drolon@infonie.fr)
  6// - Carsten Klein (c.klein@datagis.com)
  7// - Mihail Naydenov (mnaydenov@users.sourceforge.net)
  8//
  9// This file is part of FreeImage 3
 10//
 11// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
 12// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
 13// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
 14// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
 15// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
 16// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
 17// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
 18// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
 19// THIS DISCLAIMER.
 20//
 21// Use at your own risk!
 22// ==========================================================
 23
 24#include "FreeImage.h"
 25#include "Utilities.h"
 26
 27// ----------------------------------------------------------
 28//   Macros + structures
 29// ----------------------------------------------------------
 30
 31#define GET_HI_NIBBLE(byte)     ((byte) >> 4)
 32#define SET_HI_NIBBLE(byte, n)  byte &= 0x0F, byte |= ((n) << 4)
 33#define GET_LO_NIBBLE(byte)     ((byte) & 0x0F)
 34#define SET_LO_NIBBLE(byte, n)  byte &= 0xF0, byte |= ((n) & 0x0F)
 35#define GET_NIBBLE(cn, byte)    ((cn) ? (GET_HI_NIBBLE(byte)) : (GET_LO_NIBBLE(byte))) 
 36#define SET_NIBBLE(cn, byte, n) if (cn) SET_HI_NIBBLE(byte, n); else SET_LO_NIBBLE(byte, n) 
 37
 38// ----------------------------------------------------------
 39
 40
 41/** @brief Inverts each pixel data.
 42
 43@param src Input image to be processed.
 44@return Returns TRUE if successful, FALSE otherwise.
 45*/
 46BOOL DLL_CALLCONV 
 47FreeImage_Invert(FIBITMAP *src) {
 48
 49	if (!FreeImage_HasPixels(src)) return FALSE;
 50	
 51	unsigned i, x, y, k;
 52	
 53	const unsigned width = FreeImage_GetWidth(src);
 54	const unsigned height = FreeImage_GetHeight(src);
 55	const unsigned bpp = FreeImage_GetBPP(src);
 56
 57	FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(src);
 58
 59	if(image_type == FIT_BITMAP) {
 60		switch(bpp) {
 61			case 1 :
 62			case 4 :
 63			case 8 :
 64			{
 65				// if the dib has a colormap, just invert it
 66				// else, keep the linear grayscale
 67
 68				if (FreeImage_GetColorType(src) == FIC_PALETTE) {
 69					RGBQUAD *pal = FreeImage_GetPalette(src);
 70
 71					for(i = 0; i < FreeImage_GetColorsUsed(src); i++) {
 72						pal[i].rgbRed	= 255 - pal[i].rgbRed;
 73						pal[i].rgbGreen = 255 - pal[i].rgbGreen;
 74						pal[i].rgbBlue	= 255 - pal[i].rgbBlue;
 75					}
 76				} else {
 77					for(y = 0; y < height; y++) {
 78						BYTE *bits = FreeImage_GetScanLine(src, y);
 79
 80						for (x = 0; x < FreeImage_GetLine(src); x++) {
 81							bits[x] = ~bits[x];
 82						}
 83					}
 84				}
 85
 86				break;
 87			}		
 88
 89			case 24 :
 90			case 32 :
 91			{
 92				// Calculate the number of bytes per pixel (3 for 24-bit or 4 for 32-bit)
 93				const unsigned bytespp = FreeImage_GetLine(src) / width;
 94
 95				for(y = 0; y < height; y++) {
 96					BYTE *bits = FreeImage_GetScanLine(src, y);
 97					for(x = 0; x < width; x++) {
 98						for(k = 0; k < bytespp; k++) {
 99							bits[k] = ~bits[k];
100						}
101						bits += bytespp;
102					}
103				}
104
105				break;
106			}
107			default:
108				return FALSE;
109		}
110	}
111	else if((image_type == FIT_UINT16) || (image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) {
112		// Calculate the number of words per pixel (1 for 16-bit, 3 for 48-bit or 4 for 64-bit)
113		const unsigned wordspp = (FreeImage_GetLine(src) / width) / sizeof(WORD);
114
115		for(y = 0; y < height; y++) {
116			WORD *bits = (WORD*)FreeImage_GetScanLine(src, y);
117			for(x = 0; x < width; x++) {
118				for(k = 0; k < wordspp; k++) {
119					bits[k] = ~bits[k];
120				}
121				bits += wordspp;
122			}
123		}
124	}
125	else {
126		// anything else ... 
127		return FALSE;
128	}
129		
130	return TRUE;
131}
132
133/** @brief Perfoms an histogram transformation on a 8, 24 or 32-bit image 
134according to the values of a lookup table (LUT).
135
136The transformation is done as follows.<br>
137Image 8-bit : if the image has a color palette, the LUT is applied to this palette, 
138otherwise, it is applied to the grey values.<br>
139Image 24-bit & 32-bit : if channel == FICC_RGB, the same LUT is applied to each color
140plane (R,G, and B). Otherwise, the LUT is applied to the specified channel only.
141@param src Input image to be processed.
142@param LUT Lookup table. <b>The size of 'LUT' is assumed to be 256.</b>
143@param channel The color channel to be processed (only used with 24 & 32-bit DIB).
144@return Returns TRUE if successful, FALSE otherwise.
145@see FREE_IMAGE_COLOR_CHANNEL
146*/
147BOOL DLL_CALLCONV 
148FreeImage_AdjustCurve(FIBITMAP *src, BYTE *LUT, FREE_IMAGE_COLOR_CHANNEL channel) {
149	unsigned x, y;
150	BYTE *bits = NULL;
151
152	if(!FreeImage_HasPixels(src) || !LUT || (FreeImage_GetImageType(src) != FIT_BITMAP))
153		return FALSE;
154
155	int bpp = FreeImage_GetBPP(src);
156	if((bpp != 8) && (bpp != 24) && (bpp != 32))
157		return FALSE;
158
159	// apply the LUT
160	switch(bpp) {
161
162		case 8 :
163		{
164			// if the dib has a colormap, apply the LUT to it
165			// else, apply the LUT to pixel values
166
167			if(FreeImage_GetColorType(src) == FIC_PALETTE) {
168				RGBQUAD *rgb = FreeImage_GetPalette(src);
169				for (unsigned pal = 0; pal < FreeImage_GetColorsUsed(src); pal++) {
170					rgb->rgbRed   = LUT[rgb->rgbRed];
171					rgb->rgbGreen = LUT[rgb->rgbGreen];
172					rgb->rgbBlue  = LUT[rgb->rgbBlue];
173					rgb++;
174				}
175			}
176			else {
177				for(y = 0; y < FreeImage_GetHeight(src); y++) {
178					bits =  FreeImage_GetScanLine(src, y);
179					for(x = 0; x < FreeImage_GetWidth(src); x++) {
180						bits[x] = LUT[ bits[x] ];
181					}
182				}
183			}
184
185			break;
186		}
187
188		case 24 :
189		case 32 :
190		{
191			int bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);
192
193			switch(channel) {
194				case FICC_RGB :
195					for(y = 0; y < FreeImage_GetHeight(src); y++) {
196						bits =  FreeImage_GetScanLine(src, y);
197						for(x = 0; x < FreeImage_GetWidth(src); x++) {
198							bits[FI_RGBA_BLUE]	= LUT[ bits[FI_RGBA_BLUE] ];	// B
199							bits[FI_RGBA_GREEN] = LUT[ bits[FI_RGBA_GREEN] ];	// G
200							bits[FI_RGBA_RED]	= LUT[ bits[FI_RGBA_RED] ];		// R
201							
202							bits += bytespp;
203						}
204					}
205					break;
206
207				case FICC_BLUE :
208					for(y = 0; y < FreeImage_GetHeight(src); y++) {
209						bits =  FreeImage_GetScanLine(src, y);
210						for(x = 0; x < FreeImage_GetWidth(src); x++) {
211							bits[FI_RGBA_BLUE] = LUT[ bits[FI_RGBA_BLUE] ];		// B
212							
213							bits += bytespp;
214						}
215					}
216					break;
217
218				case FICC_GREEN :
219					for(y = 0; y < FreeImage_GetHeight(src); y++) {
220						bits =  FreeImage_GetScanLine(src, y);
221						for(x = 0; x < FreeImage_GetWidth(src); x++) {
222							bits[FI_RGBA_GREEN] = LUT[ bits[FI_RGBA_GREEN] ];	// G
223							
224							bits += bytespp;
225						}
226					}
227					break;
228
229				case FICC_RED :
230					for(y = 0; y < FreeImage_GetHeight(src); y++) {
231						bits =  FreeImage_GetScanLine(src, y);
232						for(x = 0; x < FreeImage_GetWidth(src); x++) {
233							bits[FI_RGBA_RED] = LUT[ bits[FI_RGBA_RED] ];		// R
234							
235							bits += bytespp;
236						}
237					}
238					break;
239					
240				case FICC_ALPHA :
241					if(32 == bpp) {
242						for(y = 0; y < FreeImage_GetHeight(src); y++) {
243							bits =  FreeImage_GetScanLine(src, y);
244							for(x = 0; x < FreeImage_GetWidth(src); x++) {
245								bits[FI_RGBA_ALPHA] = LUT[ bits[FI_RGBA_ALPHA] ];	// A
246								
247								bits += bytespp;
248							}
249						}
250					}
251					break;
252
253				default:
254					break;
255			}
256			break;
257		}
258	}
259
260	return TRUE;
261}
262
263/** @brief Performs gamma correction on a 8, 24 or 32-bit image.
264
265@param src Input image to be processed.
266@param gamma Gamma value to use. A value of 1.0 leaves the image alone, 
267less than one darkens it, and greater than one lightens it.
268@return Returns TRUE if successful, FALSE otherwise.
269*/
270BOOL DLL_CALLCONV 
271FreeImage_AdjustGamma(FIBITMAP *src, double gamma) {
272	BYTE LUT[256];		// Lookup table
273
274	if(!FreeImage_HasPixels(src) || (gamma <= 0))
275		return FALSE;
276	
277	// Build the lookup table
278
279	double exponent = 1 / gamma;
280	double v = 255.0 * (double)pow((double)255, -exponent);
281	for(int i = 0; i < 256; i++) {
282		double color = (double)pow((double)i, exponent) * v;
283		if(color > 255)
284			color = 255;
285		LUT[i] = (BYTE)floor(color + 0.5);
286	}
287
288	// Apply the gamma correction
289	return FreeImage_AdjustCurve(src, LUT, FICC_RGB);
290}
291
292/** @brief Adjusts the brightness of a 8, 24 or 32-bit image by a certain amount.
293
294@param src Input image to be processed.
295@param percentage Where -100 <= percentage <= 100<br>
296A value 0 means no change, less than 0 will make the image darker 
297and greater than 0 will make the image brighter.
298@return Returns TRUE if successful, FALSE otherwise.
299*/
300BOOL DLL_CALLCONV 
301FreeImage_AdjustBrightness(FIBITMAP *src, double percentage) {
302	BYTE LUT[256];		// Lookup table
303	double value;
304
305	if(!FreeImage_HasPixels(src))
306		return FALSE;
307	
308	// Build the lookup table
309	const double scale = (100 + percentage) / 100;
310	for(int i = 0; i < 256; i++) {
311		value = i * scale;
312		value = MAX(0.0, MIN(value, 255.0));
313		LUT[i] = (BYTE)floor(value + 0.5);
314	}
315	return FreeImage_AdjustCurve(src, LUT, FICC_RGB);
316}
317
318/** @brief Adjusts the contrast of a 8, 24 or 32-bit image by a certain amount.
319
320@param src Input image to be processed.
321@param percentage Where -100 <= percentage <= 100<br>
322A value 0 means no change, less than 0 will decrease the contrast 
323and greater than 0 will increase the contrast of the image.
324@return Returns TRUE if successful, FALSE otherwise.
325*/
326BOOL DLL_CALLCONV 
327FreeImage_AdjustContrast(FIBITMAP *src, double percentage) {
328	BYTE LUT[256];		// Lookup table
329	double value;
330
331	if(!FreeImage_HasPixels(src))
332		return FALSE;
333	
334	// Build the lookup table
335	const double scale = (100 + percentage) / 100;
336	for(int i = 0; i < 256; i++) {
337		value = 128 + (i - 128) * scale;
338		value = MAX(0.0, MIN(value, 255.0));
339		LUT[i] = (BYTE)floor(value + 0.5);
340	}
341	return FreeImage_AdjustCurve(src, LUT, FICC_RGB);
342}
343
344/** @brief Computes image histogram
345
346For 24-bit and 32-bit images, histogram can be computed from red, green, blue and 
347black channels. For 8-bit images, histogram is computed from the black channel. Other 
348bit depth is not supported (nothing is done).
349@param src Input image to be processed.
350@param histo Histogram array to fill. <b>The size of 'histo' is assumed to be 256.</b>
351@param channel Color channel to use
352@return Returns TRUE if succesful, returns FALSE if the image bit depth isn't supported.
353*/
354BOOL DLL_CALLCONV 
355FreeImage_GetHistogram(FIBITMAP *src, DWORD *histo, FREE_IMAGE_COLOR_CHANNEL channel) {
356	BYTE pixel;
357	BYTE *bits = NULL;
358	unsigned x, y;
359
360	if(!FreeImage_HasPixels(src) || !histo) return FALSE;
361
362	unsigned width  = FreeImage_GetWidth(src);
363	unsigned height = FreeImage_GetHeight(src);
364	unsigned bpp    = FreeImage_GetBPP(src);
365
366	if(bpp == 8) {
367		// clear histogram array
368		memset(histo, 0, 256 * sizeof(DWORD));
369		// compute histogram for black channel
370		for(y = 0; y < height; y++) {
371			bits = FreeImage_GetScanLine(src, y);
372			for(x = 0; x < width; x++) {
373				// get pixel value
374				pixel = bits[x];
375				histo[pixel]++;
376			}
377		}
378		return TRUE;
379	}
380	else if((bpp == 24) || (bpp == 32)) {
381		int bytespp = bpp / 8;	// bytes / pixel
382
383		// clear histogram array
384		memset(histo, 0, 256 * sizeof(DWORD));
385
386		switch(channel) {
387			case FICC_RED:
388				// compute histogram for red channel
389				for(y = 0; y < height; y++) {
390					bits =  FreeImage_GetScanLine(src, y);
391					for(x = 0; x < width; x++) {
392						pixel = bits[FI_RGBA_RED];	// R
393						histo[pixel]++;
394						bits += bytespp;
395					}
396				}
397				return TRUE;
398
399			case FICC_GREEN:
400				// compute histogram for green channel
401				for(y = 0; y < height; y++) {
402					bits =  FreeImage_GetScanLine(src, y);
403					for(x = 0; x < width; x++) {
404						pixel = bits[FI_RGBA_GREEN];	// G
405						histo[pixel]++;
406						bits += bytespp;
407					}
408				}
409				return TRUE;
410
411			case FICC_BLUE:
412				// compute histogram for blue channel
413				for(y = 0; y < height; y++) {
414					bits =  FreeImage_GetScanLine(src, y);
415					for(x = 0; x < width; x++) {
416						pixel = bits[FI_RGBA_BLUE];	// B
417						histo[pixel]++;
418						bits += bytespp;
419					}
420				}
421				return TRUE;
422
423			case FICC_BLACK:
424			case FICC_RGB:
425				// compute histogram for black channel
426				for(y = 0; y < height; y++) {
427					bits =  FreeImage_GetScanLine(src, y);
428					for(x = 0; x < width; x++) {
429						// RGB to GREY conversion
430						pixel = GREY(bits[FI_RGBA_RED], bits[FI_RGBA_GREEN], bits[FI_RGBA_BLUE]);
431						histo[pixel]++;
432						bits += bytespp;
433					}
434				}
435				return TRUE;
436				
437			default:
438				return FALSE;
439		}
440	}
441
442	return FALSE;
443}
444
445// ----------------------------------------------------------
446
447
448/** @brief Creates a lookup table to be used with FreeImage_AdjustCurve() which
449 may adjust brightness and contrast, correct gamma and invert the image with a
450 single call to FreeImage_AdjustCurve().
451 
452 This function creates a lookup table to be used with FreeImage_AdjustCurve()
453 which may adjust brightness and contrast, correct gamma and invert the image
454 with a single call to FreeImage_AdjustCurve(). If more than one of these image
455 display properties need to be adjusted, using a combined lookup table should be
456 preferred over calling each adjustment function separately. That's particularly
457 true for huge images or if performance is an issue. Then, the expensive process
458 of iterating over all pixels of an image is performed only once and not up to
459 four times.
460 
461 Furthermore, the lookup table created does not depend on the order, in which
462 each single adjustment operation is performed. Due to rounding and byte casting
463 issues, it actually matters in which order individual adjustment operations
464 are performed. Both of the following snippets most likely produce different
465 results:
466 
467 // snippet 1: contrast, brightness
468 FreeImage_AdjustContrast(dib, 15.0);
469 FreeImage_AdjustBrightness(dib, 50.0); 
470 
471 // snippet 2: brightness, contrast
472 FreeImage_AdjustBrightness(dib, 50.0);
473 FreeImage_AdjustContrast(dib, 15.0);
474 
475 Better and even faster would be snippet 3:
476 
477 // snippet 3:
478 BYTE LUT[256];
479 FreeImage_GetAdjustColorsLookupTable(LUT, 50.0, 15.0, 1.0, FALSE); 
480 FreeImage_AdjustCurve(dib, LUT, FICC_RGB);
481 
482 This function is also used internally by FreeImage_AdjustColors(), which does
483 not return the lookup table, but uses it to call FreeImage_AdjustCurve() on the
484 passed image.
485 
486 @param LUT Output lookup table to be used with FreeImage_AdjustCurve(). <b>The
487 size of 'LUT' is assumed to be 256.</b>
488 @param brightness Percentage brightness value where -100 <= brightness <= 100<br>
489 A value of 0 means no change, less than 0 will make the image darker and greater
490 than 0 will make the image brighter.
491 @param contrast Percentage contrast value where -100 <= contrast <= 100<br>
492 A value of 0 means no change, less than 0 will decrease the contrast
493 and greater than 0 will increase the contrast of the image.
494 @param gamma Gamma value to be used for gamma correction. A value of 1.0 leaves
495 the image alone, less than one darkens it, and greater than one lightens it.
496 This parameter must not be zero or smaller than zero. If so, it will be ignored
497 and no gamma correction will be performed using the lookup table created.
498 @param invert If set to TRUE, the image will be inverted.
499 @return Returns the number of adjustments applied to the resulting lookup table
500 compared to a blind lookup table.
501 */
502int DLL_CALLCONV
503FreeImage_GetAdjustColorsLookupTable(BYTE *LUT, double brightness, double contrast, double gamma, BOOL invert) {
504	double dblLUT[256];
505	double value;
506	int result = 0;
507
508	if ((brightness == 0.0) && (contrast == 0.0) && (gamma == 1.0) && (!invert)) {
509		// nothing to do, if all arguments have their default values
510		// return a blind LUT
511		for (int i = 0; i < 256; i++) {
512			LUT[i] = (BYTE)i;
513		}
514		return 0;
515	}
516
517	// first, create a blind LUT, which does nothing to the image
518	for (int i = 0; i < 256; i++) {
519		dblLUT[i] = i;
520	}
521
522	if (contrast != 0.0) {
523		// modify lookup table with contrast adjustment data
524		const double v = (100.0 + contrast) / 100.0;
525		for (int i = 0; i < 256; i++) {
526			value = 128 + (dblLUT[i] - 128) * v;
527			dblLUT[i] = MAX(0.0, MIN(value, 255.0));
528		}
529		result++;
530	}
531
532	if (brightness != 0.0) {
533		// modify lookup table with brightness adjustment data
534		const double v = (100.0 + brightness) / 100.0;
535		for (int i = 0; i < 256; i++) {
536			value = dblLUT[i] * v;
537			dblLUT[i] = MAX(0.0, MIN(value, 255.0));
538		}
539		result++;
540	}
541
542	if ((gamma > 0) && (gamma != 1.0)) {
543		// modify lookup table with gamma adjustment data
544		double exponent = 1 / gamma;
545		const double v = 255.0 * (double)pow((double)255, -exponent);
546		for (int i = 0; i < 256; i++) {
547			value = pow(dblLUT[i], exponent) * v;
548			dblLUT[i] = MAX(0.0, MIN(value, 255.0));
549		}
550		result++;
551	}
552
553	if (!invert) {
554		for (int i = 0; i < 256; i++) {
555			LUT[i] = (BYTE)floor(dblLUT[i] + 0.5);
556		}
557	} else {
558		for (int i = 0; i < 256; i++) {
559			LUT[i] = 255 - (BYTE)floor(dblLUT[i] + 0.5);
560		}
561		result++;
562	}
563	// return the number of adjustments made
564	return result;
565}
566
567/** @brief Adjusts an image's brightness, contrast and gamma as well as it may
568 optionally invert the image within a single operation.
569 
570 This function adjusts an image's brightness, contrast and gamma as well as it
571 may optionally invert the image within a single operation. If more than one of
572 these image display properties need to be adjusted, using this function should
573 be preferred over calling each adjustment function separately. That's
574 particularly true for huge images or if performance is an issue.
575 
576 This function relies on FreeImage_GetAdjustColorsLookupTable(), which creates a
577 single lookup table, that combines all adjustment operations requested.
578 
579 Furthermore, the lookup table created by FreeImage_GetAdjustColorsLookupTable()
580 does not depend on the order, in which each single adjustment operation is
581 performed. Due to rounding and byte casting issues, it actually matters in which
582 order individual adjustment operations are performed. Both of the following
583 snippets most likely produce different results:
584 
585 // snippet 1: contrast, brightness
586 FreeImage_AdjustContrast(dib, 15.0);
587 FreeImage_AdjustBrightness(dib, 50.0); 
588 
589 // snippet 2: brightness, contrast
590 FreeImage_AdjustBrightness(dib, 50.0);
591 FreeImage_AdjustContrast(dib, 15.0);
592 
593 Better and even faster would be snippet 3:
594 
595 // snippet 3:
596 FreeImage_AdjustColors(dib, 50.0, 15.0, 1.0, FALSE);
597 
598 @param dib Input/output image to be processed.
599 @param brightness Percentage brightness value where -100 <= brightness <= 100<br>
600 A value of 0 means no change, less than 0 will make the image darker and greater
601 than 0 will make the image brighter.
602 @param contrast Percentage contrast value where -100 <= contrast <= 100<br>
603 A value of 0 means no change, less than 0 will decrease the contrast
604 and greater than 0 will increase the contrast of the image.
605 @param gamma Gamma value to be used for gamma correction. A value of 1.0 leaves
606 the image alone, less than one darkens it, and greater than one lightens it.<br>
607 This parameter must not be zero or smaller than zero. If so, it will be ignored
608 and no gamma correction will be performed on the image.
609 @param invert If set to TRUE, the image will be inverted.
610 @return Returns TRUE on success, FALSE otherwise (e.g. when the bitdeph of the
611 source dib cannot be handled).
612 */
613BOOL DLL_CALLCONV
614FreeImage_AdjustColors(FIBITMAP *dib, double brightness, double contrast, double gamma, BOOL invert) {
615	BYTE LUT[256];
616
617	if (!FreeImage_HasPixels(dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP)) {
618		return FALSE;
619	}
620
621	int bpp = FreeImage_GetBPP(dib);
622	if ((bpp != 8) && (bpp != 24) && (bpp != 32)) {
623		return FALSE;
624	}
625
626	if (FreeImage_GetAdjustColorsLookupTable(LUT, brightness, contrast, gamma, invert)) {
627		return FreeImage_AdjustCurve(dib, LUT, FICC_RGB);
628	}
629	return FALSE;
630}
631
632/** @brief Applies color mapping for one or several colors on a 1-, 4- or 8-bit
633 palletized or a 16-, 24- or 32-bit high color image.
634
635 This function maps up to <i>count</i> colors specified in <i>srccolors</i> to
636 these specified in <i>dstcolors</i>. Thereby, color <i>srccolors[N]</i>,
637 if found in the image, will be replaced by color <i>dstcolors[N]</i>. If
638 parameter <i>swap</i> is TRUE, additionally all colors specified in
639 <i>dstcolors</i> are also mapped to these specified in <i>srccolors</i>. For
640 high color images, the actual image data will be modified whereas, for
641 palletized images only the palette will be changed.<br>
642
643 The function returns the number of pixels changed or zero, if no pixels were
644 changed. 
645
646 Both arrays <i>srccolors</i> and <i>dstcolors</i> are assumed not to hold less
647 than <i>count</i> colors.<br>
648
649 For 16-bit images, all colors specified are transparently converted to their 
650 proper 16-bit representation (either in RGB555 or RGB565 format, which is
651 determined by the image's red- green- and blue-mask).<br>
652
653 <b>Note, that this behaviour is different from what FreeImage_ApplyPaletteIndexMapping()
654 does, which modifies the actual image data on palletized images.</b>
655
656 @param dib Input/output image to be processed.
657 @param srccolors Array of colors to be used as the mapping source.
658 @param dstcolors Array of colors to be used as the mapping destination.
659 @param count The number of colors to be mapped. This is the size of both
660 <i>srccolors</i> and <i>dstcolors</i>.  
661 @param ignore_alpha If TRUE, 32-bit images and colors are treated as 24-bit.
662 @param swap If TRUE, source and destination colors are swapped, that is,
663 each destination color is also mapped to the corresponding source color.  
664 @return Returns the total number of pixels changed. 
665 */
666unsigned DLL_CALLCONV
667FreeImage_ApplyColorMapping(FIBITMAP *dib, RGBQUAD *srccolors, RGBQUAD *dstcolors, unsigned count, BOOL ignore_alpha, BOOL swap) {
668	unsigned result = 0;
669
670	if (!FreeImage_HasPixels(dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP)) {
671		return 0;
672	}
673
674	// validate parameters
675	if ((!srccolors) || (!dstcolors)|| (count < 1)) {
676		return 0;
677	}
678
679	int bpp = FreeImage_GetBPP(dib);
680	switch (bpp) {
681		case 1:
682		case 4:
683		case 8: {
684			unsigned size = FreeImage_GetColorsUsed(dib);
685			RGBQUAD *pal = FreeImage_GetPalette(dib);
686			RGBQUAD *a, *b;
687			for (unsigned x = 0; x < size; x++) {
688				for (unsigned j = 0; j < count; j++) {
689					a = srccolors;
690					b = dstcolors;
691					for (int i = (swap ? 0 : 1); i < 2; i++) {
692						if ((pal[x].rgbBlue == a[j].rgbBlue)&&(pal[x].rgbGreen == a[j].rgbGreen) &&(pal[x].rgbRed== a[j].rgbRed)) {
693							pal[x].rgbBlue = b[j].rgbBlue;
694							pal[x].rgbGreen = b[j].rgbGreen;
695							pal[x].rgbRed = b[j].rgbRed;
696							result++;
697							j = count;
698							break;
699						}
700						a = dstcolors;
701						b = srccolors;
702					}
703				}
704			}
705			return result;
706		}
707		case 16: {
708			WORD *src16 = (WORD *)malloc(sizeof(WORD) * count);
709			if (NULL == src16) {
710				return 0;
711			}
712
713			WORD *dst16 = (WORD *)malloc(sizeof(WORD) * count);
714			if (NULL == dst16) {
715				free(src16);
716				return 0;
717			}
718
719			for (unsigned j = 0; j < count; j++) {
720				src16[j] = RGBQUAD_TO_WORD(dib, (srccolors + j));
721				dst16[j] = RGBQUAD_TO_WORD(dib, (dstcolors + j));
722			}
723
724			unsigned height = FreeImage_GetHeight(dib);
725			unsigned width = FreeImage_GetWidth(dib);
726			WORD *a, *b;
727			for (unsigned y = 0; y < height; y++) {
728				WORD *bits = (WORD *)FreeImage_GetScanLine(dib, y);
729				for (unsigned x = 0; x < width; x++, bits++) {
730					for (unsigned j = 0; j < count; j++) {
731						a = src16;
732						b = dst16;
733						for (int i = (swap ? 0 : 1); i < 2; i++) {
734							if (*bits == a[j]) {
735								*bits = b[j];
736								result++;
737								j = count;
738								break;
739							}
740							a = dst16;
741							b = src16;
742						}
743					}
744				}
745			}
746			free(src16);
747			free(dst16);
748			return result;
749		}
750		case 24: {
751			unsigned height = FreeImage_GetHeight(dib);
752			unsigned width = FreeImage_GetWidth(dib);
753			RGBQUAD *a, *b;
754			for (unsigned y = 0; y < height; y++) {
755				BYTE *bits = FreeImage_GetScanLine(dib, y);
756				for (unsigned x = 0; x < width; x++, bits += 3) {
757					for (unsigned j = 0; j < count; j++) {
758						a = srccolors;
759						b = dstcolors;
760						for (int i = (swap ? 0 : 1); i < 2; i++) {
761							if ((bits[FI_RGBA_BLUE] == a[j].rgbBlue) && (bits[FI_RGBA_GREEN] == a[j].rgbGreen) &&(bits[FI_RGBA_RED] == a[j].rgbRed)) {
762								bits[FI_RGBA_BLUE] = b[j].rgbBlue;
763								bits[FI_RGBA_GREEN] = b[j].rgbGreen;
764								bits[FI_RGBA_RED] = b[j].rgbRed;
765								result++;
766								j = count;
767								break;
768							}
769							a = dstcolors;
770							b = srccolors;
771						}
772					}
773				}
774			}
775			return result;
776		}
777		case 32: {
778			unsigned height = FreeImage_GetHeight(dib);
779			unsigned width = FreeImage_GetWidth(dib);
780			RGBQUAD *a, *b;
781			for (unsigned y = 0; y < height; y++) {
782				BYTE *bits = FreeImage_GetScanLine(dib, y);
783				for (unsigned x = 0; x < width; x++, bits += 4) {
784					for (unsigned j = 0; j < count; j++) {
785						a = srccolors;
786						b = dstcolors;
787						for (int i = (swap ? 0 : 1); i < 2; i++) {
788							if ((bits[FI_RGBA_BLUE] == a[j].rgbBlue) &&(bits[FI_RGBA_GREEN] == a[j].rgbGreen) &&(bits[FI_RGBA_RED] == a[j].rgbRed)
789								&&((ignore_alpha) || (bits[FI_RGBA_ALPHA] == a[j].rgbReserved))) {
790								bits[FI_RGBA_BLUE] = b[j].rgbBlue;
791								bits[FI_RGBA_GREEN] = b[j].rgbGreen;
792								bits[FI_RGBA_RED] = b[j].rgbRed;
793								if (!ignore_alpha) {
794									bits[FI_RGBA_ALPHA] = b[j].rgbReserved;
795								}
796								result++;
797								j = count;
798								break;
799							}
800							a = dstcolors;
801							b = srccolors;
802						}
803					}
804				}
805			}
806			return result;
807		}
808		default: {
809			return 0;
810		}
811	}
812}
813
814/** @brief Swaps two specified colors on a 1-, 4- or 8-bit palletized
815 or a 16-, 24- or 32-bit high color image.
816
817 This function swaps the two specified colors <i>color_a</i> and <i>color_b</i>
818 on a palletized or high color image. For high color images, the actual image
819 data will be modified whereas, for palletized images only the palette will be
820 changed.<br>
821
822 <b>Note, that this behaviour is different from what FreeImage_SwapPaletteIndices()
823 does, which modifies the actual image data on palletized images.</b><br>
824
825 This is just a thin wrapper for FreeImage_ApplyColorMapping() and resolves to:<br>
826 <i>return FreeImage_ApplyColorMapping(dib, color_a, color_b, 1, ignore_alpha, TRUE);</i>
827
828 @param dib Input/output image to be processed.
829 @param color_a On of the two colors to be swapped.
830 @param color_b The other of the two colors to be swapped.
831 @param ignore_alpha If TRUE, 32-bit images and colors are treated as 24-bit. 
832 @return Returns the total number of pixels changed. 
833 */
834unsigned DLL_CALLCONV
835FreeImage_SwapColors(FIBITMAP *dib, RGBQUAD *color_a, RGBQUAD *color_b, BOOL ignore_alpha) {
836	return FreeImage_ApplyColorMapping(dib, color_a, color_b, 1, ignore_alpha, TRUE);
837}
838
839/** @brief Applies palette index mapping for one or several indices on a 1-, 4- 
840 or 8-bit palletized image.
841
842 This function maps up to <i>count</i> palette indices specified in
843 <i>srcindices</i> to these specified in <i>dstindices</i>. Thereby, index 
844 <i>srcindices[N]</i>, if present in the image, will be replaced by index
845 <i>dstindices[N]</i>. If parameter <i>swap</i> is TRUE, additionally all indices
846 specified in <i>dstindices</i> are also mapped to these specified in 
847 <i>srcindices</i>.<br>
848
849 The function returns the number of pixels changed or zero, if no pixels were
850 changed. 
851
852 Both arrays <i>srcindices</i> and <i>dstindices</i> are assumed not to hold less
853 than <i>count</i> indices.<br>
854
855 <b>Note, that this behaviour is different from what FreeImage_ApplyColorMapping()
856 does, which modifies the actual image data on palletized images.</b>
857
858 @param dib Input/output image to be processed.
859 @param srcindices Array of palette indices to be used as the mapping source.
860 @param dstindices Array of palette indices to be used as the mapping destination.
861 @param count The number of palette indices to be mapped. This is the size of both
862 <i>srcindices</i> and <i>dstindices</i>.  
863 @param swap If TRUE, source and destination palette indices are swapped, that is,
864 each destination index is also mapped to the corresponding source index.  
865 @return Returns the total number of pixels changed. 
866 */
867unsigned DLL_CALLCONV
868FreeImage_ApplyPaletteIndexMapping(FIBITMAP *dib, BYTE *srcindices,	BYTE *dstindices, unsigned count, BOOL swap) {
869	unsigned result = 0;
870
871	if (!FreeImage_HasPixels(dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP)) {
872		return 0;
873	}
874
875	// validate parameters
876	if ((!srcindices) || (!dstindices)|| (count < 1)) {
877		return 0;
878	}
879
880	unsigned height = FreeImage_GetHeight(dib);
881	unsigned width = FreeImage_GetLine(dib);
882	BYTE *a, *b;
883
884	int bpp = FreeImage_GetBPP(dib);
885	switch (bpp) {
886		case 1: {
887
888			return result;
889		}
890		case 4: {
891			int skip_last = (FreeImage_GetWidth(dib) & 0x01);
892			unsigned max_x = width - 1;
893			for (unsigned y = 0; y < height; y++) {
894				BYTE *bits = FreeImage_GetScanLine(dib, y);
895				for (unsigned x = 0; x < width; x++) {
896					int start = ((skip_last) && (x == max_x)) ? 1 : 0;
897					for (int cn = start; cn < 2; cn++) {
898						for (unsigned j = 0; j < count; j++) {
899							a = srcindices;
900							b = dstindices;
901							for (int i = ((swap) ? 0 : 1); i < 2; i++) {
902								if (GET_NIBBLE(cn, bits[x]) == (a[j] & 0x0F)) {
903									SET_NIBBLE(cn, bits[x], b[j]);
904									result++;
905									j = count;
906									break;
907								}
908								a = dstindices;
909								b = srcindices;
910							}
911						}
912					}
913				}
914			}
915			return result;
916		}
917		case 8: {
918			for (unsigned y = 0; y < height; y++) {
919				BYTE *bits = FreeImage_GetScanLine(dib, y);
920				for (unsigned x = 0; x < width; x++) {
921					for (unsigned j = 0; j < count; j++) {
922						a = srcindices;
923						b = dstindices;
924						for (int i = ((swap) ? 0 : 1); i < 2; i++) {
925							if (bits[x] == a[j]) {
926								bits[x] = b[j];
927								result++;
928								j = count;
929								break;
930							}
931							a = dstindices;
932							b = srcindices;
933						}
934					}
935				}
936			}
937			return result;
938		}
939		default: {
940			return 0;
941		}
942	}
943}
944
945/** @brief Swaps two specified palette indices on a 1-, 4- or 8-bit palletized
946 image.
947
948 This function swaps the two specified palette indices <i>index_a</i> and
949 <i>index_b</i> on a palletized image. Therefore, not the palette, but the
950 actual image data will be modified.<br>
951
952 <b>Note, that this behaviour is different from what FreeImage_SwapColors() does
953 on palletized images, which only swaps the colors in the palette.</b><br>
954
955 This is just a thin wrapper for FreeImage_ApplyColorMapping() and resolves to:<br>
956 <i>return FreeImage_ApplyPaletteIndexMapping(dib, index_a, index_b, 1, TRUE);</i>
957
958 @param dib Input/output image to be processed.
959 @param index_a On of the two palette indices to be swapped.
960 @param index_b The other of the two palette indices to be swapped.
961 @return Returns the total number of pixels changed. 
962 */
963unsigned DLL_CALLCONV 
964FreeImage_SwapPaletteIndices(FIBITMAP *dib, BYTE *index_a, BYTE *index_b) {
965	return FreeImage_ApplyPaletteIndexMapping(dib, index_a, index_b, 1, TRUE);
966}
967