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