Coverage Report

Created: 2023-12-08 06:53

/src/freeimage-svn/FreeImage/trunk/Source/FreeImageToolkit/Channels.cpp
Line
Count
Source (jump to first uncovered line)
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 
32
0
FreeImage_GetChannel(FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel) {
33
34
0
  if(!FreeImage_HasPixels(src)) return NULL;
35
36
0
  FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(src);
37
0
  unsigned bpp = FreeImage_GetBPP(src);
38
39
  // 24- or 32-bit 
40
0
  if(image_type == FIT_BITMAP && ((bpp == 24) || (bpp == 32))) {
41
0
    int c;
42
43
    // select the channel to extract
44
0
    switch(channel) {
45
0
      case FICC_BLUE:
46
0
        c = FI_RGBA_BLUE;
47
0
        break;
48
0
      case FICC_GREEN:
49
0
        c = FI_RGBA_GREEN;
50
0
        break;
51
0
      case FICC_RED: 
52
0
        c = FI_RGBA_RED;
53
0
        break;
54
0
      case FICC_ALPHA:
55
0
        if(bpp != 32) return NULL;
56
0
        c = FI_RGBA_ALPHA;
57
0
        break;
58
0
      default:
59
0
        return NULL;
60
0
    }
61
62
    // allocate a 8-bit dib
63
0
    unsigned width  = FreeImage_GetWidth(src);
64
0
    unsigned height = FreeImage_GetHeight(src);
65
0
    FIBITMAP *dst = FreeImage_Allocate(width, height, 8) ;
66
0
    if(!dst) return NULL;
67
    // build a greyscale palette
68
0
    RGBQUAD *pal = FreeImage_GetPalette(dst);
69
0
    for(int i = 0; i < 256; i++) {
70
0
      pal[i].rgbBlue = pal[i].rgbGreen = pal[i].rgbRed = (BYTE)i;
71
0
    }
72
73
    // perform extraction
74
75
0
    int bytespp = bpp / 8;  // bytes / pixel
76
77
0
    for(unsigned y = 0; y < height; y++) {
78
0
      BYTE *src_bits = FreeImage_GetScanLine(src, y);
79
0
      BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
80
0
      for(unsigned x = 0; x < width; x++) {
81
0
        dst_bits[x] = src_bits[c];
82
0
        src_bits += bytespp;
83
0
      }
84
0
    }
85
86
    // copy metadata from src to dst
87
0
    FreeImage_CloneMetadata(dst, src);
88
    
89
0
    return dst;
90
0
  }
91
92
  // 48-bit RGB or 64-bit RGBA images
93
0
  if((image_type == FIT_RGB16) ||  (image_type == FIT_RGBA16)) {
94
0
    int c;
95
96
    // select the channel to extract (always RGB[A])
97
0
    switch(channel) {
98
0
      case FICC_BLUE:
99
0
        c = 2;
100
0
        break;
101
0
      case FICC_GREEN:
102
0
        c = 1;
103
0
        break;
104
0
      case FICC_RED: 
105
0
        c = 0;
106
0
        break;
107
0
      case FICC_ALPHA:
108
0
        if(bpp != 64) return NULL;
109
0
        c = 3;
110
0
        break;
111
0
      default:
112
0
        return NULL;
113
0
    }
114
115
    // allocate a greyscale dib
116
0
    unsigned width  = FreeImage_GetWidth(src);
117
0
    unsigned height = FreeImage_GetHeight(src);
118
0
    FIBITMAP *dst = FreeImage_AllocateT(FIT_UINT16, width, height) ;
119
0
    if(!dst) return NULL;
120
121
    // perform extraction
122
123
0
    int bytespp = bpp / 16; // words / pixel
124
125
0
    for(unsigned y = 0; y < height; y++) {
126
0
      unsigned short *src_bits = (unsigned short*)FreeImage_GetScanLine(src, y);
127
0
      unsigned short *dst_bits = (unsigned short*)FreeImage_GetScanLine(dst, y);
128
0
      for(unsigned x = 0; x < width; x++) {
129
0
        dst_bits[x] = src_bits[c];
130
0
        src_bits += bytespp;
131
0
      }
132
0
    }
133
134
    // copy metadata from src to dst
135
0
    FreeImage_CloneMetadata(dst, src);
136
    
137
0
    return dst;
138
0
  }
139
140
  // 96-bit RGBF or 128-bit RGBAF images
141
0
  if((image_type == FIT_RGBF) ||  (image_type == FIT_RGBAF)) {
142
0
    int c;
143
144
    // select the channel to extract (always RGB[A])
145
0
    switch(channel) {
146
0
      case FICC_BLUE:
147
0
        c = 2;
148
0
        break;
149
0
      case FICC_GREEN:
150
0
        c = 1;
151
0
        break;
152
0
      case FICC_RED: 
153
0
        c = 0;
154
0
        break;
155
0
      case FICC_ALPHA:
156
0
        if(bpp != 128) return NULL;
157
0
        c = 3;
158
0
        break;
159
0
      default:
160
0
        return NULL;
161
0
    }
162
163
    // allocate a greyscale dib
164
0
    unsigned width  = FreeImage_GetWidth(src);
165
0
    unsigned height = FreeImage_GetHeight(src);
166
0
    FIBITMAP *dst = FreeImage_AllocateT(FIT_FLOAT, width, height) ;
167
0
    if(!dst) return NULL;
168
169
    // perform extraction
170
171
0
    int bytespp = bpp / 32; // floats / pixel
172
173
0
    for(unsigned y = 0; y < height; y++) {
174
0
      float *src_bits = (float*)FreeImage_GetScanLine(src, y);
175
0
      float *dst_bits = (float*)FreeImage_GetScanLine(dst, y);
176
0
      for(unsigned x = 0; x < width; x++) {
177
0
        dst_bits[x] = src_bits[c];
178
0
        src_bits += bytespp;
179
0
      }
180
0
    }
181
182
    // copy metadata from src to dst
183
0
    FreeImage_CloneMetadata(dst, src);
184
    
185
0
    return dst;
186
0
  }
187
188
0
  return NULL;
189
0
}
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 
199
0
FreeImage_SetChannel(FIBITMAP *dst, FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel) {
200
0
  int c;
201
202
0
  if(!FreeImage_HasPixels(src) || !FreeImage_HasPixels(dst)) return FALSE;
203
  
204
  // src and dst images should have the same width and height
205
0
  unsigned src_width  = FreeImage_GetWidth(src);
206
0
  unsigned src_height = FreeImage_GetHeight(src);
207
0
  unsigned dst_width  = FreeImage_GetWidth(dst);
208
0
  unsigned dst_height = FreeImage_GetHeight(dst);
209
0
  if((src_width != dst_width) || (src_height != dst_height))
210
0
    return FALSE;
211
212
  // src image should be grayscale, dst image should be RGB or RGBA
213
0
  FREE_IMAGE_COLOR_TYPE src_type = FreeImage_GetColorType(src);
214
0
  FREE_IMAGE_COLOR_TYPE dst_type = FreeImage_GetColorType(dst);
215
0
  if((dst_type != FIC_RGB) && (dst_type != FIC_RGBALPHA) || (src_type != FIC_MINISBLACK)) {
216
0
    return FALSE;
217
0
  }
218
219
0
  FREE_IMAGE_TYPE src_image_type = FreeImage_GetImageType(src);
220
0
  FREE_IMAGE_TYPE dst_image_type = FreeImage_GetImageType(dst);
221
222
0
  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
0
    unsigned src_bpp = FreeImage_GetBPP(src);
226
0
    unsigned dst_bpp = FreeImage_GetBPP(dst);
227
0
    if((src_bpp != 8) || (dst_bpp != 24) && (dst_bpp != 32))
228
0
      return FALSE;
229
230
231
    // select the channel to modify
232
0
    switch(channel) {
233
0
      case FICC_BLUE:
234
0
        c = FI_RGBA_BLUE;
235
0
        break;
236
0
      case FICC_GREEN:
237
0
        c = FI_RGBA_GREEN;
238
0
        break;
239
0
      case FICC_RED: 
240
0
        c = FI_RGBA_RED;
241
0
        break;
242
0
      case FICC_ALPHA:
243
0
        if(dst_bpp != 32) return FALSE;
244
0
        c = FI_RGBA_ALPHA;
245
0
        break;
246
0
      default:
247
0
        return FALSE;
248
0
    }
249
250
    // perform insertion
251
252
0
    int bytespp = dst_bpp / 8;  // bytes / pixel
253
254
0
    for(unsigned y = 0; y < dst_height; y++) {
255
0
      BYTE *src_bits = FreeImage_GetScanLine(src, y);
256
0
      BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
257
0
      for(unsigned x = 0; x < dst_width; x++) {
258
0
        dst_bits[c] = src_bits[x];
259
0
        dst_bits += bytespp;
260
0
      }
261
0
    }
262
263
0
    return TRUE;
264
0
  }
265
266
0
  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
0
    unsigned src_bpp = FreeImage_GetBPP(src);
270
0
    unsigned dst_bpp = FreeImage_GetBPP(dst);
271
0
    if((src_bpp != 16) || (dst_bpp != 48) && (dst_bpp != 64))
272
0
      return FALSE;
273
274
275
    // select the channel to modify (always RGB[A])
276
0
    switch(channel) {
277
0
      case FICC_BLUE:
278
0
        c = 2;
279
0
        break;
280
0
      case FICC_GREEN:
281
0
        c = 1;
282
0
        break;
283
0
      case FICC_RED: 
284
0
        c = 0;
285
0
        break;
286
0
      case FICC_ALPHA:
287
0
        if(dst_bpp != 64) return FALSE;
288
0
        c = 3;
289
0
        break;
290
0
      default:
291
0
        return FALSE;
292
0
    }
293
294
    // perform insertion
295
296
0
    int bytespp = dst_bpp / 16; // words / pixel
297
298
0
    for(unsigned y = 0; y < dst_height; y++) {
299
0
      unsigned short *src_bits = (unsigned short*)FreeImage_GetScanLine(src, y);
300
0
      unsigned short *dst_bits = (unsigned short*)FreeImage_GetScanLine(dst, y);
301
0
      for(unsigned x = 0; x < dst_width; x++) {
302
0
        dst_bits[c] = src_bits[x];
303
0
        dst_bits += bytespp;
304
0
      }
305
0
    }
306
307
0
    return TRUE;
308
0
  }
309
  
310
0
  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
0
    unsigned src_bpp = FreeImage_GetBPP(src);
314
0
    unsigned dst_bpp = FreeImage_GetBPP(dst);
315
0
    if((src_bpp != 32) || (dst_bpp != 96) && (dst_bpp != 128))
316
0
      return FALSE;
317
318
319
    // select the channel to modify (always RGB[A])
320
0
    switch(channel) {
321
0
      case FICC_BLUE:
322
0
        c = 2;
323
0
        break;
324
0
      case FICC_GREEN:
325
0
        c = 1;
326
0
        break;
327
0
      case FICC_RED: 
328
0
        c = 0;
329
0
        break;
330
0
      case FICC_ALPHA:
331
0
        if(dst_bpp != 128) return FALSE;
332
0
        c = 3;
333
0
        break;
334
0
      default:
335
0
        return FALSE;
336
0
    }
337
338
    // perform insertion
339
340
0
    int bytespp = dst_bpp / 32; // floats / pixel
341
342
0
    for(unsigned y = 0; y < dst_height; y++) {
343
0
      float *src_bits = (float*)FreeImage_GetScanLine(src, y);
344
0
      float *dst_bits = (float*)FreeImage_GetScanLine(dst, y);
345
0
      for(unsigned x = 0; x < dst_width; x++) {
346
0
        dst_bits[c] = src_bits[x];
347
0
        dst_bits += bytespp;
348
0
      }
349
0
    }
350
351
0
    return TRUE;
352
0
  }
353
354
0
  return FALSE;
355
0
}
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 
363
0
FreeImage_GetComplexChannel(FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel) {
364
0
  unsigned x, y;
365
0
  double mag, phase;
366
0
  FICOMPLEX *src_bits = NULL;
367
0
  double *dst_bits = NULL;
368
0
  FIBITMAP *dst = NULL;
369
370
0
  if(!FreeImage_HasPixels(src)) return NULL;
371
372
0
  if(FreeImage_GetImageType(src) == FIT_COMPLEX) {
373
    // allocate a dib of type FIT_DOUBLE
374
0
    unsigned width  = FreeImage_GetWidth(src);
375
0
    unsigned height = FreeImage_GetHeight(src);
376
0
    dst = FreeImage_AllocateT(FIT_DOUBLE, width, height) ;
377
0
    if(!dst) return NULL;
378
379
    // perform extraction
380
381
0
    switch(channel) {
382
0
      case FICC_REAL: // real part
383
0
        for(y = 0; y < height; y++) {
384
0
          src_bits = (FICOMPLEX *)FreeImage_GetScanLine(src, y);
385
0
          dst_bits = (double *)FreeImage_GetScanLine(dst, y);
386
0
          for(x = 0; x < width; x++) {
387
0
            dst_bits[x] = src_bits[x].r;
388
0
          }
389
0
        }
390
0
        break;
391
392
0
      case FICC_IMAG: // imaginary part
393
0
        for(y = 0; y < height; y++) {
394
0
          src_bits = (FICOMPLEX *)FreeImage_GetScanLine(src, y);
395
0
          dst_bits = (double *)FreeImage_GetScanLine(dst, y);
396
0
          for(x = 0; x < width; x++) {
397
0
            dst_bits[x] = src_bits[x].i;
398
0
          }
399
0
        }
400
0
        break;
401
402
0
      case FICC_MAG: // magnitude
403
0
        for(y = 0; y < height; y++) {
404
0
          src_bits = (FICOMPLEX *)FreeImage_GetScanLine(src, y);
405
0
          dst_bits = (double *)FreeImage_GetScanLine(dst, y);
406
0
          for(x = 0; x < width; x++) {
407
0
            mag = src_bits[x].r * src_bits[x].r + src_bits[x].i * src_bits[x].i;
408
0
            dst_bits[x] = sqrt(mag);
409
0
          }
410
0
        }
411
0
        break;
412
413
0
      case FICC_PHASE: // phase
414
0
        for(y = 0; y < height; y++) {
415
0
          src_bits = (FICOMPLEX *)FreeImage_GetScanLine(src, y);
416
0
          dst_bits = (double *)FreeImage_GetScanLine(dst, y);
417
0
          for(x = 0; x < width; x++) {
418
0
            if((src_bits[x].r == 0) && (src_bits[x].i == 0)) {
419
0
              phase = 0;
420
0
            } else {
421
0
              phase = atan2(src_bits[x].i, src_bits[x].r);
422
0
            }
423
0
            dst_bits[x] = phase;
424
0
          }
425
0
        }
426
0
        break;
427
0
    }
428
0
  }
429
430
  // copy metadata from src to dst
431
0
  FreeImage_CloneMetadata(dst, src);
432
  
433
0
  return dst;
434
0
}
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 
444
0
FreeImage_SetComplexChannel(FIBITMAP *dst, FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel) {
445
0
  unsigned x, y;
446
0
  double *src_bits = NULL;
447
0
  FICOMPLEX *dst_bits = NULL;
448
449
0
  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
0
  const FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(src);
453
0
  const FREE_IMAGE_TYPE dst_type = FreeImage_GetImageType(dst);
454
0
  if((src_type != FIT_DOUBLE) || (dst_type != FIT_COMPLEX))
455
0
    return FALSE;
456
457
  // src and dst images should have the same width and height
458
0
  unsigned src_width  = FreeImage_GetWidth(src);
459
0
  unsigned src_height = FreeImage_GetHeight(src);
460
0
  unsigned dst_width  = FreeImage_GetWidth(dst);
461
0
  unsigned dst_height = FreeImage_GetHeight(dst);
462
0
  if((src_width != dst_width) || (src_height != dst_height))
463
0
    return FALSE;
464
465
  // select the channel to modify
466
0
  switch(channel) {
467
0
    case FICC_REAL: // real part
468
0
      for(y = 0; y < dst_height; y++) {
469
0
        src_bits = (double *)FreeImage_GetScanLine(src, y);
470
0
        dst_bits = (FICOMPLEX *)FreeImage_GetScanLine(dst, y);
471
0
        for(x = 0; x < dst_width; x++) {
472
0
          dst_bits[x].r = src_bits[x];
473
0
        }
474
0
      }
475
0
      break;
476
0
    case FICC_IMAG: // imaginary part
477
0
      for(y = 0; y < dst_height; y++) {
478
0
        src_bits = (double *)FreeImage_GetScanLine(src, y);
479
0
        dst_bits = (FICOMPLEX *)FreeImage_GetScanLine(dst, y);
480
0
        for(x = 0; x < dst_width; x++) {
481
0
          dst_bits[x].i = src_bits[x];
482
0
        }
483
0
      }
484
0
      break;
485
0
  }
486
487
0
  return TRUE;
488
0
}