1 // ==========================================================
2 // Channel processing support
3 //
4 // Design and implementation by
5 // - Herv� Drolon (drolon@infonie.fr)
6 //
7 // This file is part of FreeImage 3
8 //
9 // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
10 // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
11 // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
12 // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
13 // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
14 // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
15 // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
16 // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
17 // THIS DISCLAIMER.
18 //
19 // Use at your own risk!
20 // ==========================================================
21
22 #include "FreeImage.h"
23 #include "Utilities.h"
24
25
26 /** @brief Retrieves the red, green, blue or alpha channel of a BGR[A] image.
27 @param src Input image to be processed.
28 @param channel Color channel to extract
29 @return Returns the extracted channel if successful, returns NULL otherwise.
30 */
31 FIBITMAP * DLL_CALLCONV
FreeImage_GetChannel(FIBITMAP * src,FREE_IMAGE_COLOR_CHANNEL channel)32 FreeImage_GetChannel(FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel) {
33
34 if(!FreeImage_HasPixels(src)) return NULL;
35
36 FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(src);
37 unsigned bpp = FreeImage_GetBPP(src);
38
39 // 24- or 32-bit
40 if(image_type == FIT_BITMAP && ((bpp == 24) || (bpp == 32))) {
41 int c;
42
43 // select the channel to extract
44 switch(channel) {
45 case FICC_BLUE:
46 c = FI_RGBA_BLUE;
47 break;
48 case FICC_GREEN:
49 c = FI_RGBA_GREEN;
50 break;
51 case FICC_RED:
52 c = FI_RGBA_RED;
53 break;
54 case FICC_ALPHA:
55 if(bpp != 32) return NULL;
56 c = FI_RGBA_ALPHA;
57 break;
58 default:
59 return NULL;
60 }
61
62 // allocate a 8-bit dib
63 unsigned width = FreeImage_GetWidth(src);
64 unsigned height = FreeImage_GetHeight(src);
65 FIBITMAP *dst = FreeImage_Allocate(width, height, 8) ;
66 if(!dst) return NULL;
67 // build a greyscale palette
68 RGBQUAD *pal = FreeImage_GetPalette(dst);
69 for(int i = 0; i < 256; i++) {
70 pal[i].rgbBlue = pal[i].rgbGreen = pal[i].rgbRed = (BYTE)i;
71 }
72
73 // perform extraction
74
75 int bytespp = bpp / 8; // bytes / pixel
76
77 for(unsigned y = 0; y < height; y++) {
78 BYTE *src_bits = FreeImage_GetScanLine(src, y);
79 BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
80 for(unsigned x = 0; x < width; x++) {
81 dst_bits[x] = src_bits[c];
82 src_bits += bytespp;
83 }
84 }
85
86 // copy metadata from src to dst
87 FreeImage_CloneMetadata(dst, src);
88
89 return dst;
90 }
91
92 // 48-bit RGB or 64-bit RGBA images
93 if((image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) {
94 int c;
95
96 // select the channel to extract (always RGB[A])
97 switch(channel) {
98 case FICC_BLUE:
99 c = 2;
100 break;
101 case FICC_GREEN:
102 c = 1;
103 break;
104 case FICC_RED:
105 c = 0;
106 break;
107 case FICC_ALPHA:
108 if(bpp != 64) return NULL;
109 c = 3;
110 break;
111 default:
112 return NULL;
113 }
114
115 // allocate a greyscale dib
116 unsigned width = FreeImage_GetWidth(src);
117 unsigned height = FreeImage_GetHeight(src);
118 FIBITMAP *dst = FreeImage_AllocateT(FIT_UINT16, width, height) ;
119 if(!dst) return NULL;
120
121 // perform extraction
122
123 int bytespp = bpp / 16; // words / pixel
124
125 for(unsigned y = 0; y < height; y++) {
126 unsigned short *src_bits = (unsigned short*)FreeImage_GetScanLine(src, y);
127 unsigned short *dst_bits = (unsigned short*)FreeImage_GetScanLine(dst, y);
128 for(unsigned x = 0; x < width; x++) {
129 dst_bits[x] = src_bits[c];
130 src_bits += bytespp;
131 }
132 }
133
134 // copy metadata from src to dst
135 FreeImage_CloneMetadata(dst, src);
136
137 return dst;
138 }
139
140 // 96-bit RGBF or 128-bit RGBAF images
141 if((image_type == FIT_RGBF) || (image_type == FIT_RGBAF)) {
142 int c;
143
144 // select the channel to extract (always RGB[A])
145 switch(channel) {
146 case FICC_BLUE:
147 c = 2;
148 break;
149 case FICC_GREEN:
150 c = 1;
151 break;
152 case FICC_RED:
153 c = 0;
154 break;
155 case FICC_ALPHA:
156 if(bpp != 128) return NULL;
157 c = 3;
158 break;
159 default:
160 return NULL;
161 }
162
163 // allocate a greyscale dib
164 unsigned width = FreeImage_GetWidth(src);
165 unsigned height = FreeImage_GetHeight(src);
166 FIBITMAP *dst = FreeImage_AllocateT(FIT_FLOAT, width, height) ;
167 if(!dst) return NULL;
168
169 // perform extraction
170
171 int bytespp = bpp / 32; // floats / pixel
172
173 for(unsigned y = 0; y < height; y++) {
174 float *src_bits = (float*)FreeImage_GetScanLine(src, y);
175 float *dst_bits = (float*)FreeImage_GetScanLine(dst, y);
176 for(unsigned x = 0; x < width; x++) {
177 dst_bits[x] = src_bits[c];
178 src_bits += bytespp;
179 }
180 }
181
182 // copy metadata from src to dst
183 FreeImage_CloneMetadata(dst, src);
184
185 return dst;
186 }
187
188 return NULL;
189 }
190
191 /** @brief Insert a greyscale dib into a RGB[A] image.
192 Both src and dst must have the same width and height.
193 @param dst Image to modify (RGB or RGBA)
194 @param src Input greyscale image to insert
195 @param channel Color channel to modify
196 @return Returns TRUE if successful, FALSE otherwise.
197 */
198 BOOL DLL_CALLCONV
FreeImage_SetChannel(FIBITMAP * dst,FIBITMAP * src,FREE_IMAGE_COLOR_CHANNEL channel)199 FreeImage_SetChannel(FIBITMAP *dst, FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel) {
200 int c;
201
202 if(!FreeImage_HasPixels(src) || !FreeImage_HasPixels(dst)) return FALSE;
203
204 // src and dst images should have the same width and height
205 unsigned src_width = FreeImage_GetWidth(src);
206 unsigned src_height = FreeImage_GetHeight(src);
207 unsigned dst_width = FreeImage_GetWidth(dst);
208 unsigned dst_height = FreeImage_GetHeight(dst);
209 if((src_width != dst_width) || (src_height != dst_height))
210 return FALSE;
211
212 // src image should be grayscale, dst image should be RGB or RGBA
213 FREE_IMAGE_COLOR_TYPE src_type = FreeImage_GetColorType(src);
214 FREE_IMAGE_COLOR_TYPE dst_type = FreeImage_GetColorType(dst);
215 if((dst_type != FIC_RGB) && (dst_type != FIC_RGBALPHA) || (src_type != FIC_MINISBLACK)) {
216 return FALSE;
217 }
218
219 FREE_IMAGE_TYPE src_image_type = FreeImage_GetImageType(src);
220 FREE_IMAGE_TYPE dst_image_type = FreeImage_GetImageType(dst);
221
222 if((dst_image_type == FIT_BITMAP) && (src_image_type == FIT_BITMAP)) {
223
224 // src image should be grayscale, dst image should be 24- or 32-bit
225 unsigned src_bpp = FreeImage_GetBPP(src);
226 unsigned dst_bpp = FreeImage_GetBPP(dst);
227 if((src_bpp != 8) || (dst_bpp != 24) && (dst_bpp != 32))
228 return FALSE;
229
230
231 // select the channel to modify
232 switch(channel) {
233 case FICC_BLUE:
234 c = FI_RGBA_BLUE;
235 break;
236 case FICC_GREEN:
237 c = FI_RGBA_GREEN;
238 break;
239 case FICC_RED:
240 c = FI_RGBA_RED;
241 break;
242 case FICC_ALPHA:
243 if(dst_bpp != 32) return FALSE;
244 c = FI_RGBA_ALPHA;
245 break;
246 default:
247 return FALSE;
248 }
249
250 // perform insertion
251
252 int bytespp = dst_bpp / 8; // bytes / pixel
253
254 for(unsigned y = 0; y < dst_height; y++) {
255 BYTE *src_bits = FreeImage_GetScanLine(src, y);
256 BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
257 for(unsigned x = 0; x < dst_width; x++) {
258 dst_bits[c] = src_bits[x];
259 dst_bits += bytespp;
260 }
261 }
262
263 return TRUE;
264 }
265
266 if(((dst_image_type == FIT_RGB16) || (dst_image_type == FIT_RGBA16)) && (src_image_type == FIT_UINT16)) {
267
268 // src image should be grayscale, dst image should be 48- or 64-bit
269 unsigned src_bpp = FreeImage_GetBPP(src);
270 unsigned dst_bpp = FreeImage_GetBPP(dst);
271 if((src_bpp != 16) || (dst_bpp != 48) && (dst_bpp != 64))
272 return FALSE;
273
274
275 // select the channel to modify (always RGB[A])
276 switch(channel) {
277 case FICC_BLUE:
278 c = 2;
279 break;
280 case FICC_GREEN:
281 c = 1;
282 break;
283 case FICC_RED:
284 c = 0;
285 break;
286 case FICC_ALPHA:
287 if(dst_bpp != 64) return FALSE;
288 c = 3;
289 break;
290 default:
291 return FALSE;
292 }
293
294 // perform insertion
295
296 int bytespp = dst_bpp / 16; // words / pixel
297
298 for(unsigned y = 0; y < dst_height; y++) {
299 unsigned short *src_bits = (unsigned short*)FreeImage_GetScanLine(src, y);
300 unsigned short *dst_bits = (unsigned short*)FreeImage_GetScanLine(dst, y);
301 for(unsigned x = 0; x < dst_width; x++) {
302 dst_bits[c] = src_bits[x];
303 dst_bits += bytespp;
304 }
305 }
306
307 return TRUE;
308 }
309
310 if(((dst_image_type == FIT_RGBF) || (dst_image_type == FIT_RGBAF)) && (src_image_type == FIT_FLOAT)) {
311
312 // src image should be grayscale, dst image should be 96- or 128-bit
313 unsigned src_bpp = FreeImage_GetBPP(src);
314 unsigned dst_bpp = FreeImage_GetBPP(dst);
315 if((src_bpp != 32) || (dst_bpp != 96) && (dst_bpp != 128))
316 return FALSE;
317
318
319 // select the channel to modify (always RGB[A])
320 switch(channel) {
321 case FICC_BLUE:
322 c = 2;
323 break;
324 case FICC_GREEN:
325 c = 1;
326 break;
327 case FICC_RED:
328 c = 0;
329 break;
330 case FICC_ALPHA:
331 if(dst_bpp != 128) return FALSE;
332 c = 3;
333 break;
334 default:
335 return FALSE;
336 }
337
338 // perform insertion
339
340 int bytespp = dst_bpp / 32; // floats / pixel
341
342 for(unsigned y = 0; y < dst_height; y++) {
343 float *src_bits = (float*)FreeImage_GetScanLine(src, y);
344 float *dst_bits = (float*)FreeImage_GetScanLine(dst, y);
345 for(unsigned x = 0; x < dst_width; x++) {
346 dst_bits[c] = src_bits[x];
347 dst_bits += bytespp;
348 }
349 }
350
351 return TRUE;
352 }
353
354 return FALSE;
355 }
356
357 /** @brief Retrieves the real part, imaginary part, magnitude or phase of a complex image.
358 @param src Input image to be processed.
359 @param channel Channel to extract
360 @return Returns the extracted channel if successful, returns NULL otherwise.
361 */
362 FIBITMAP * DLL_CALLCONV
FreeImage_GetComplexChannel(FIBITMAP * src,FREE_IMAGE_COLOR_CHANNEL channel)363 FreeImage_GetComplexChannel(FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel) {
364 unsigned x, y;
365 double mag, phase;
366 FICOMPLEX *src_bits = NULL;
367 double *dst_bits = NULL;
368 FIBITMAP *dst = NULL;
369
370 if(!FreeImage_HasPixels(src)) return NULL;
371
372 if(FreeImage_GetImageType(src) == FIT_COMPLEX) {
373 // allocate a dib of type FIT_DOUBLE
374 unsigned width = FreeImage_GetWidth(src);
375 unsigned height = FreeImage_GetHeight(src);
376 dst = FreeImage_AllocateT(FIT_DOUBLE, width, height) ;
377 if(!dst) return NULL;
378
379 // perform extraction
380
381 switch(channel) {
382 case FICC_REAL: // real part
383 for(y = 0; y < height; y++) {
384 src_bits = (FICOMPLEX *)FreeImage_GetScanLine(src, y);
385 dst_bits = (double *)FreeImage_GetScanLine(dst, y);
386 for(x = 0; x < width; x++) {
387 dst_bits[x] = src_bits[x].r;
388 }
389 }
390 break;
391
392 case FICC_IMAG: // imaginary part
393 for(y = 0; y < height; y++) {
394 src_bits = (FICOMPLEX *)FreeImage_GetScanLine(src, y);
395 dst_bits = (double *)FreeImage_GetScanLine(dst, y);
396 for(x = 0; x < width; x++) {
397 dst_bits[x] = src_bits[x].i;
398 }
399 }
400 break;
401
402 case FICC_MAG: // magnitude
403 for(y = 0; y < height; y++) {
404 src_bits = (FICOMPLEX *)FreeImage_GetScanLine(src, y);
405 dst_bits = (double *)FreeImage_GetScanLine(dst, y);
406 for(x = 0; x < width; x++) {
407 mag = src_bits[x].r * src_bits[x].r + src_bits[x].i * src_bits[x].i;
408 dst_bits[x] = sqrt(mag);
409 }
410 }
411 break;
412
413 case FICC_PHASE: // phase
414 for(y = 0; y < height; y++) {
415 src_bits = (FICOMPLEX *)FreeImage_GetScanLine(src, y);
416 dst_bits = (double *)FreeImage_GetScanLine(dst, y);
417 for(x = 0; x < width; x++) {
418 if((src_bits[x].r == 0) && (src_bits[x].i == 0)) {
419 phase = 0;
420 } else {
421 phase = atan2(src_bits[x].i, src_bits[x].r);
422 }
423 dst_bits[x] = phase;
424 }
425 }
426 break;
427 }
428 }
429
430 // copy metadata from src to dst
431 FreeImage_CloneMetadata(dst, src);
432
433 return dst;
434 }
435
436 /** @brief Set the real or imaginary part of a complex image.
437 Both src and dst must have the same width and height.
438 @param dst Image to modify (image of type FIT_COMPLEX)
439 @param src Input image of type FIT_DOUBLE
440 @param channel Channel to modify
441 @return Returns TRUE if successful, FALSE otherwise.
442 */
443 BOOL DLL_CALLCONV
FreeImage_SetComplexChannel(FIBITMAP * dst,FIBITMAP * src,FREE_IMAGE_COLOR_CHANNEL channel)444 FreeImage_SetComplexChannel(FIBITMAP *dst, FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel) {
445 unsigned x, y;
446 double *src_bits = NULL;
447 FICOMPLEX *dst_bits = NULL;
448
449 if(!FreeImage_HasPixels(src) || !FreeImage_HasPixels(dst)) return FALSE;
450
451 // src image should be of type FIT_DOUBLE, dst image should be of type FIT_COMPLEX
452 const FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(src);
453 const FREE_IMAGE_TYPE dst_type = FreeImage_GetImageType(dst);
454 if((src_type != FIT_DOUBLE) || (dst_type != FIT_COMPLEX))
455 return FALSE;
456
457 // src and dst images should have the same width and height
458 unsigned src_width = FreeImage_GetWidth(src);
459 unsigned src_height = FreeImage_GetHeight(src);
460 unsigned dst_width = FreeImage_GetWidth(dst);
461 unsigned dst_height = FreeImage_GetHeight(dst);
462 if((src_width != dst_width) || (src_height != dst_height))
463 return FALSE;
464
465 // select the channel to modify
466 switch(channel) {
467 case FICC_REAL: // real part
468 for(y = 0; y < dst_height; y++) {
469 src_bits = (double *)FreeImage_GetScanLine(src, y);
470 dst_bits = (FICOMPLEX *)FreeImage_GetScanLine(dst, y);
471 for(x = 0; x < dst_width; x++) {
472 dst_bits[x].r = src_bits[x];
473 }
474 }
475 break;
476 case FICC_IMAG: // imaginary part
477 for(y = 0; y < dst_height; y++) {
478 src_bits = (double *)FreeImage_GetScanLine(src, y);
479 dst_bits = (FICOMPLEX *)FreeImage_GetScanLine(dst, y);
480 for(x = 0; x < dst_width; x++) {
481 dst_bits[x].i = src_bits[x];
482 }
483 }
484 break;
485 }
486
487 return TRUE;
488 }
489