| // ========================================================== |
| // Channel processing support |
| // |
| // Design and implementation by |
| // - Hervé Drolon (drolon@infonie.fr) |
| // |
| // This file is part of FreeImage 3 |
| // |
| // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY |
| // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES |
| // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE |
| // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED |
| // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT |
| // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY |
| // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL |
| // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER |
| // THIS DISCLAIMER. |
| // |
| // Use at your own risk! |
| // ========================================================== |
| |
| #include "FreeImage.h" |
| #include "Utilities.h" |
| |
| |
| /** @brief Retrieves the red, green, blue or alpha channel of a BGR[A] image. |
| @param src Input image to be processed. |
| @param channel Color channel to extract |
| @return Returns the extracted channel if successful, returns NULL otherwise. |
| */ |
| FIBITMAP * DLL_CALLCONV |
| FreeImage_GetChannel(FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel) { |
| |
| if(!FreeImage_HasPixels(src)) return NULL; |
| |
| FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(src); |
| unsigned bpp = FreeImage_GetBPP(src); |
| |
| // 24- or 32-bit |
| if(image_type == FIT_BITMAP && ((bpp == 24) || (bpp == 32))) { |
| int c; |
| |
| // select the channel to extract |
| switch(channel) { |
| case FICC_BLUE: |
| c = FI_RGBA_BLUE; |
| break; |
| case FICC_GREEN: |
| c = FI_RGBA_GREEN; |
| break; |
| case FICC_RED: |
| c = FI_RGBA_RED; |
| break; |
| case FICC_ALPHA: |
| if(bpp != 32) return NULL; |
| c = FI_RGBA_ALPHA; |
| break; |
| default: |
| return NULL; |
| } |
| |
| // allocate a 8-bit dib |
| unsigned width = FreeImage_GetWidth(src); |
| unsigned height = FreeImage_GetHeight(src); |
| FIBITMAP *dst = FreeImage_Allocate(width, height, 8) ; |
| if(!dst) return NULL; |
| // build a greyscale palette |
| RGBQUAD *pal = FreeImage_GetPalette(dst); |
| for(int i = 0; i < 256; i++) { |
| pal[i].rgbBlue = pal[i].rgbGreen = pal[i].rgbRed = (BYTE)i; |
| } |
| |
| // perform extraction |
| |
| int bytespp = bpp / 8; // bytes / pixel |
| |
| for(unsigned y = 0; y < height; y++) { |
| BYTE *src_bits = FreeImage_GetScanLine(src, y); |
| BYTE *dst_bits = FreeImage_GetScanLine(dst, y); |
| for(unsigned x = 0; x < width; x++) { |
| dst_bits[x] = src_bits[c]; |
| src_bits += bytespp; |
| } |
| } |
| |
| // copy metadata from src to dst |
| FreeImage_CloneMetadata(dst, src); |
| |
| return dst; |
| } |
| |
| // 48-bit RGB or 64-bit RGBA images |
| if((image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) { |
| int c; |
| |
| // select the channel to extract (always RGB[A]) |
| switch(channel) { |
| case FICC_BLUE: |
| c = 2; |
| break; |
| case FICC_GREEN: |
| c = 1; |
| break; |
| case FICC_RED: |
| c = 0; |
| break; |
| case FICC_ALPHA: |
| if(bpp != 64) return NULL; |
| c = 3; |
| break; |
| default: |
| return NULL; |
| } |
| |
| // allocate a greyscale dib |
| unsigned width = FreeImage_GetWidth(src); |
| unsigned height = FreeImage_GetHeight(src); |
| FIBITMAP *dst = FreeImage_AllocateT(FIT_UINT16, width, height) ; |
| if(!dst) return NULL; |
| |
| // perform extraction |
| |
| int bytespp = bpp / 16; // words / pixel |
| |
| for(unsigned y = 0; y < height; y++) { |
| unsigned short *src_bits = (unsigned short*)FreeImage_GetScanLine(src, y); |
| unsigned short *dst_bits = (unsigned short*)FreeImage_GetScanLine(dst, y); |
| for(unsigned x = 0; x < width; x++) { |
| dst_bits[x] = src_bits[c]; |
| src_bits += bytespp; |
| } |
| } |
| |
| // copy metadata from src to dst |
| FreeImage_CloneMetadata(dst, src); |
| |
| return dst; |
| } |
| |
| // 96-bit RGBF or 128-bit RGBAF images |
| if((image_type == FIT_RGBF) || (image_type == FIT_RGBAF)) { |
| int c; |
| |
| // select the channel to extract (always RGB[A]) |
| switch(channel) { |
| case FICC_BLUE: |
| c = 2; |
| break; |
| case FICC_GREEN: |
| c = 1; |
| break; |
| case FICC_RED: |
| c = 0; |
| break; |
| case FICC_ALPHA: |
| if(bpp != 128) return NULL; |
| c = 3; |
| break; |
| default: |
| return NULL; |
| } |
| |
| // allocate a greyscale dib |
| unsigned width = FreeImage_GetWidth(src); |
| unsigned height = FreeImage_GetHeight(src); |
| FIBITMAP *dst = FreeImage_AllocateT(FIT_FLOAT, width, height) ; |
| if(!dst) return NULL; |
| |
| // perform extraction |
| |
| int bytespp = bpp / 32; // floats / pixel |
| |
| for(unsigned y = 0; y < height; y++) { |
| float *src_bits = (float*)FreeImage_GetScanLine(src, y); |
| float *dst_bits = (float*)FreeImage_GetScanLine(dst, y); |
| for(unsigned x = 0; x < width; x++) { |
| dst_bits[x] = src_bits[c]; |
| src_bits += bytespp; |
| } |
| } |
| |
| // copy metadata from src to dst |
| FreeImage_CloneMetadata(dst, src); |
| |
| return dst; |
| } |
| |
| return NULL; |
| } |
| |
| /** @brief Insert a greyscale dib into a RGB[A] image. |
| Both src and dst must have the same width and height. |
| @param dst Image to modify (RGB or RGBA) |
| @param src Input greyscale image to insert |
| @param channel Color channel to modify |
| @return Returns TRUE if successful, FALSE otherwise. |
| */ |
| BOOL DLL_CALLCONV |
| FreeImage_SetChannel(FIBITMAP *dst, FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel) { |
| int c; |
| |
| if(!FreeImage_HasPixels(src) || !FreeImage_HasPixels(dst)) return FALSE; |
| |
| // src and dst images should have the same width and height |
| unsigned src_width = FreeImage_GetWidth(src); |
| unsigned src_height = FreeImage_GetHeight(src); |
| unsigned dst_width = FreeImage_GetWidth(dst); |
| unsigned dst_height = FreeImage_GetHeight(dst); |
| if((src_width != dst_width) || (src_height != dst_height)) |
| return FALSE; |
| |
| // src image should be grayscale, dst image should be RGB or RGBA |
| FREE_IMAGE_COLOR_TYPE src_type = FreeImage_GetColorType(src); |
| FREE_IMAGE_COLOR_TYPE dst_type = FreeImage_GetColorType(dst); |
| if((dst_type != FIC_RGB) && (dst_type != FIC_RGBALPHA) || (src_type != FIC_MINISBLACK)) { |
| return FALSE; |
| } |
| |
| FREE_IMAGE_TYPE src_image_type = FreeImage_GetImageType(src); |
| FREE_IMAGE_TYPE dst_image_type = FreeImage_GetImageType(dst); |
| |
| if((dst_image_type == FIT_BITMAP) && (src_image_type == FIT_BITMAP)) { |
| |
| // src image should be grayscale, dst image should be 24- or 32-bit |
| unsigned src_bpp = FreeImage_GetBPP(src); |
| unsigned dst_bpp = FreeImage_GetBPP(dst); |
| if((src_bpp != 8) || (dst_bpp != 24) && (dst_bpp != 32)) |
| return FALSE; |
| |
| |
| // select the channel to modify |
| switch(channel) { |
| case FICC_BLUE: |
| c = FI_RGBA_BLUE; |
| break; |
| case FICC_GREEN: |
| c = FI_RGBA_GREEN; |
| break; |
| case FICC_RED: |
| c = FI_RGBA_RED; |
| break; |
| case FICC_ALPHA: |
| if(dst_bpp != 32) return FALSE; |
| c = FI_RGBA_ALPHA; |
| break; |
| default: |
| return FALSE; |
| } |
| |
| // perform insertion |
| |
| int bytespp = dst_bpp / 8; // bytes / pixel |
| |
| for(unsigned y = 0; y < dst_height; y++) { |
| BYTE *src_bits = FreeImage_GetScanLine(src, y); |
| BYTE *dst_bits = FreeImage_GetScanLine(dst, y); |
| for(unsigned x = 0; x < dst_width; x++) { |
| dst_bits[c] = src_bits[x]; |
| dst_bits += bytespp; |
| } |
| } |
| |
| return TRUE; |
| } |
| |
| if(((dst_image_type == FIT_RGB16) || (dst_image_type == FIT_RGBA16)) && (src_image_type == FIT_UINT16)) { |
| |
| // src image should be grayscale, dst image should be 48- or 64-bit |
| unsigned src_bpp = FreeImage_GetBPP(src); |
| unsigned dst_bpp = FreeImage_GetBPP(dst); |
| if((src_bpp != 16) || (dst_bpp != 48) && (dst_bpp != 64)) |
| return FALSE; |
| |
| |
| // select the channel to modify (always RGB[A]) |
| switch(channel) { |
| case FICC_BLUE: |
| c = 2; |
| break; |
| case FICC_GREEN: |
| c = 1; |
| break; |
| case FICC_RED: |
| c = 0; |
| break; |
| case FICC_ALPHA: |
| if(dst_bpp != 64) return FALSE; |
| c = 3; |
| break; |
| default: |
| return FALSE; |
| } |
| |
| // perform insertion |
| |
| int bytespp = dst_bpp / 16; // words / pixel |
| |
| for(unsigned y = 0; y < dst_height; y++) { |
| unsigned short *src_bits = (unsigned short*)FreeImage_GetScanLine(src, y); |
| unsigned short *dst_bits = (unsigned short*)FreeImage_GetScanLine(dst, y); |
| for(unsigned x = 0; x < dst_width; x++) { |
| dst_bits[c] = src_bits[x]; |
| dst_bits += bytespp; |
| } |
| } |
| |
| return TRUE; |
| } |
| |
| if(((dst_image_type == FIT_RGBF) || (dst_image_type == FIT_RGBAF)) && (src_image_type == FIT_FLOAT)) { |
| |
| // src image should be grayscale, dst image should be 96- or 128-bit |
| unsigned src_bpp = FreeImage_GetBPP(src); |
| unsigned dst_bpp = FreeImage_GetBPP(dst); |
| if((src_bpp != 32) || (dst_bpp != 96) && (dst_bpp != 128)) |
| return FALSE; |
| |
| |
| // select the channel to modify (always RGB[A]) |
| switch(channel) { |
| case FICC_BLUE: |
| c = 2; |
| break; |
| case FICC_GREEN: |
| c = 1; |
| break; |
| case FICC_RED: |
| c = 0; |
| break; |
| case FICC_ALPHA: |
| if(dst_bpp != 128) return FALSE; |
| c = 3; |
| break; |
| default: |
| return FALSE; |
| } |
| |
| // perform insertion |
| |
| int bytespp = dst_bpp / 32; // floats / pixel |
| |
| for(unsigned y = 0; y < dst_height; y++) { |
| float *src_bits = (float*)FreeImage_GetScanLine(src, y); |
| float *dst_bits = (float*)FreeImage_GetScanLine(dst, y); |
| for(unsigned x = 0; x < dst_width; x++) { |
| dst_bits[c] = src_bits[x]; |
| dst_bits += bytespp; |
| } |
| } |
| |
| return TRUE; |
| } |
| |
| return FALSE; |
| } |
| |
| /** @brief Retrieves the real part, imaginary part, magnitude or phase of a complex image. |
| @param src Input image to be processed. |
| @param channel Channel to extract |
| @return Returns the extracted channel if successful, returns NULL otherwise. |
| */ |
| FIBITMAP * DLL_CALLCONV |
| FreeImage_GetComplexChannel(FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel) { |
| unsigned x, y; |
| double mag, phase; |
| FICOMPLEX *src_bits = NULL; |
| double *dst_bits = NULL; |
| FIBITMAP *dst = NULL; |
| |
| if(!FreeImage_HasPixels(src)) return NULL; |
| |
| if(FreeImage_GetImageType(src) == FIT_COMPLEX) { |
| // allocate a dib of type FIT_DOUBLE |
| unsigned width = FreeImage_GetWidth(src); |
| unsigned height = FreeImage_GetHeight(src); |
| dst = FreeImage_AllocateT(FIT_DOUBLE, width, height) ; |
| if(!dst) return NULL; |
| |
| // perform extraction |
| |
| switch(channel) { |
| case FICC_REAL: // real part |
| for(y = 0; y < height; y++) { |
| src_bits = (FICOMPLEX *)FreeImage_GetScanLine(src, y); |
| dst_bits = (double *)FreeImage_GetScanLine(dst, y); |
| for(x = 0; x < width; x++) { |
| dst_bits[x] = src_bits[x].r; |
| } |
| } |
| break; |
| |
| case FICC_IMAG: // imaginary part |
| for(y = 0; y < height; y++) { |
| src_bits = (FICOMPLEX *)FreeImage_GetScanLine(src, y); |
| dst_bits = (double *)FreeImage_GetScanLine(dst, y); |
| for(x = 0; x < width; x++) { |
| dst_bits[x] = src_bits[x].i; |
| } |
| } |
| break; |
| |
| case FICC_MAG: // magnitude |
| for(y = 0; y < height; y++) { |
| src_bits = (FICOMPLEX *)FreeImage_GetScanLine(src, y); |
| dst_bits = (double *)FreeImage_GetScanLine(dst, y); |
| for(x = 0; x < width; x++) { |
| mag = src_bits[x].r * src_bits[x].r + src_bits[x].i * src_bits[x].i; |
| dst_bits[x] = sqrt(mag); |
| } |
| } |
| break; |
| |
| case FICC_PHASE: // phase |
| for(y = 0; y < height; y++) { |
| src_bits = (FICOMPLEX *)FreeImage_GetScanLine(src, y); |
| dst_bits = (double *)FreeImage_GetScanLine(dst, y); |
| for(x = 0; x < width; x++) { |
| if((src_bits[x].r == 0) && (src_bits[x].i == 0)) { |
| phase = 0; |
| } else { |
| phase = atan2(src_bits[x].i, src_bits[x].r); |
| } |
| dst_bits[x] = phase; |
| } |
| } |
| break; |
| } |
| } |
| |
| // copy metadata from src to dst |
| FreeImage_CloneMetadata(dst, src); |
| |
| return dst; |
| } |
| |
| /** @brief Set the real or imaginary part of a complex image. |
| Both src and dst must have the same width and height. |
| @param dst Image to modify (image of type FIT_COMPLEX) |
| @param src Input image of type FIT_DOUBLE |
| @param channel Channel to modify |
| @return Returns TRUE if successful, FALSE otherwise. |
| */ |
| BOOL DLL_CALLCONV |
| FreeImage_SetComplexChannel(FIBITMAP *dst, FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel) { |
| unsigned x, y; |
| double *src_bits = NULL; |
| FICOMPLEX *dst_bits = NULL; |
| |
| if(!FreeImage_HasPixels(src) || !FreeImage_HasPixels(dst)) return FALSE; |
| |
| // src image should be of type FIT_DOUBLE, dst image should be of type FIT_COMPLEX |
| const FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(src); |
| const FREE_IMAGE_TYPE dst_type = FreeImage_GetImageType(dst); |
| if((src_type != FIT_DOUBLE) || (dst_type != FIT_COMPLEX)) |
| return FALSE; |
| |
| // src and dst images should have the same width and height |
| unsigned src_width = FreeImage_GetWidth(src); |
| unsigned src_height = FreeImage_GetHeight(src); |
| unsigned dst_width = FreeImage_GetWidth(dst); |
| unsigned dst_height = FreeImage_GetHeight(dst); |
| if((src_width != dst_width) || (src_height != dst_height)) |
| return FALSE; |
| |
| // select the channel to modify |
| switch(channel) { |
| case FICC_REAL: // real part |
| for(y = 0; y < dst_height; y++) { |
| src_bits = (double *)FreeImage_GetScanLine(src, y); |
| dst_bits = (FICOMPLEX *)FreeImage_GetScanLine(dst, y); |
| for(x = 0; x < dst_width; x++) { |
| dst_bits[x].r = src_bits[x]; |
| } |
| } |
| break; |
| case FICC_IMAG: // imaginary part |
| for(y = 0; y < dst_height; y++) { |
| src_bits = (double *)FreeImage_GetScanLine(src, y); |
| dst_bits = (FICOMPLEX *)FreeImage_GetScanLine(dst, y); |
| for(x = 0; x < dst_width; x++) { |
| dst_bits[x].i = src_bits[x]; |
| } |
| } |
| break; |
| } |
| |
| return TRUE; |
| } |