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 */
46 BOOL DLL_CALLCONV
FreeImage_Invert(FIBITMAP * src)47 FreeImage_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
134 according to the values of a lookup table (LUT).
135 
136 The transformation is done as follows.<br>
137 Image 8-bit : if the image has a color palette, the LUT is applied to this palette,
138 otherwise, it is applied to the grey values.<br>
139 Image 24-bit & 32-bit : if channel == FICC_RGB, the same LUT is applied to each color
140 plane (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 */
147 BOOL DLL_CALLCONV
FreeImage_AdjustCurve(FIBITMAP * src,BYTE * LUT,FREE_IMAGE_COLOR_CHANNEL channel)148 FreeImage_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,
267 less than one darkens it, and greater than one lightens it.
268 @return Returns TRUE if successful, FALSE otherwise.
269 */
270 BOOL DLL_CALLCONV
FreeImage_AdjustGamma(FIBITMAP * src,double gamma)271 FreeImage_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>
296 A value 0 means no change, less than 0 will make the image darker
297 and greater than 0 will make the image brighter.
298 @return Returns TRUE if successful, FALSE otherwise.
299 */
300 BOOL DLL_CALLCONV
FreeImage_AdjustBrightness(FIBITMAP * src,double percentage)301 FreeImage_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>
322 A value 0 means no change, less than 0 will decrease the contrast
323 and greater than 0 will increase the contrast of the image.
324 @return Returns TRUE if successful, FALSE otherwise.
325 */
326 BOOL DLL_CALLCONV
FreeImage_AdjustContrast(FIBITMAP * src,double percentage)327 FreeImage_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 
346 For 24-bit and 32-bit images, histogram can be computed from red, green, blue and
347 black channels. For 8-bit images, histogram is computed from the black channel. Other
348 bit 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 */
354 BOOL DLL_CALLCONV
FreeImage_GetHistogram(FIBITMAP * src,DWORD * histo,FREE_IMAGE_COLOR_CHANNEL channel)355 FreeImage_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  */
502 int DLL_CALLCONV
FreeImage_GetAdjustColorsLookupTable(BYTE * LUT,double brightness,double contrast,double gamma,BOOL invert)503 FreeImage_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  */
613 BOOL DLL_CALLCONV
FreeImage_AdjustColors(FIBITMAP * dib,double brightness,double contrast,double gamma,BOOL invert)614 FreeImage_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  */
666 unsigned DLL_CALLCONV
FreeImage_ApplyColorMapping(FIBITMAP * dib,RGBQUAD * srccolors,RGBQUAD * dstcolors,unsigned count,BOOL ignore_alpha,BOOL swap)667 FreeImage_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  */
834 unsigned DLL_CALLCONV
FreeImage_SwapColors(FIBITMAP * dib,RGBQUAD * color_a,RGBQUAD * color_b,BOOL ignore_alpha)835 FreeImage_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  */
867 unsigned DLL_CALLCONV
FreeImage_ApplyPaletteIndexMapping(FIBITMAP * dib,BYTE * srcindices,BYTE * dstindices,unsigned count,BOOL swap)868 FreeImage_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  */
963 unsigned DLL_CALLCONV
FreeImage_SwapPaletteIndices(FIBITMAP * dib,BYTE * index_a,BYTE * index_b)964 FreeImage_SwapPaletteIndices(FIBITMAP *dib, BYTE *index_a, BYTE *index_b) {
965 	return FreeImage_ApplyPaletteIndexMapping(dib, index_a, index_b, 1, TRUE);
966 }
967 
968