static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { FIBITMAP *dib = NULL; LibRaw RawProcessor; BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS; try { // wrap the input datastream LibRaw_freeimage_datastream datastream(io, handle); // set decoding parameters // the following parameters affect data reading // -------------------------------------------- // (-s [0..N-1]) Select one raw image from input file RawProcessor.imgdata.params.shot_select = 0; // (-w) Use camera white balance, if possible (otherwise, fallback to auto_wb) RawProcessor.imgdata.params.use_camera_wb = 1; // (-h) outputs the image in 50% size RawProcessor.imgdata.params.half_size = ((flags & RAW_HALFSIZE) == RAW_HALFSIZE) ? 1 : 0; // open the datastream if(RawProcessor.open_datastream(&datastream) != LIBRAW_SUCCESS) { throw "LibRaw : failed to open input stream (unknown format)"; } if(header_only) { // header only mode dib = FreeImage_AllocateHeaderT(header_only, FIT_RGB16, RawProcessor.imgdata.sizes.width, RawProcessor.imgdata.sizes.height); } else if((flags & RAW_PREVIEW) == RAW_PREVIEW) { // try to get the embedded JPEG dib = libraw_LoadEmbeddedPreview(RawProcessor, 0); if(!dib) { // no JPEG preview: try to load as 8-bit/sample (i.e. RGB 24-bit) dib = libraw_LoadRawData(RawProcessor, 8); } } else if((flags & RAW_DISPLAY) == RAW_DISPLAY) { // load raw data as 8-bit/sample (i.e. RGB 24-bit) dib = libraw_LoadRawData(RawProcessor, 8); } else { // default: load raw data as linear 16-bit/sample (i.e. RGB 48-bit) dib = libraw_LoadRawData(RawProcessor, 16); } // save ICC profile if present if(dib && (NULL != RawProcessor.imgdata.color.profile)) { FreeImage_CreateICCProfile(dib, RawProcessor.imgdata.color.profile, RawProcessor.imgdata.color.profile_length); } // try to get JPEG embedded Exif metadata if(dib && !((flags & RAW_PREVIEW) == RAW_PREVIEW)) { FIBITMAP *metadata_dib = libraw_LoadEmbeddedPreview(RawProcessor, FIF_LOAD_NOPIXELS); if(metadata_dib) { FreeImage_CloneMetadata(dib, metadata_dib); FreeImage_Unload(metadata_dib); } } // clean-up internal memory allocations RawProcessor.recycle(); return dib; } catch(const char *text) { if(dib) { FreeImage_Unload(dib); } RawProcessor.recycle(); FreeImage_OutputMessageProc(s_format_id, text); } return NULL; }
FIBITMAP * DLL_CALLCONV FreeImage_ConvertToRGB16(FIBITMAP *dib) { FIBITMAP *src = NULL; FIBITMAP *dst = NULL; if(!FreeImage_HasPixels(dib)) return NULL; const FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(dib); // check for allowed conversions switch(src_type) { case FIT_BITMAP: { // convert to 24-bit if needed if((FreeImage_GetBPP(dib) == 24) || (FreeImage_GetBPP(dib) == 32)) { src = dib; } else { src = FreeImage_ConvertTo24Bits(dib); if(!src) return NULL; } break; } case FIT_UINT16: // allow conversion from unsigned 16-bit src = dib; break; case FIT_RGB16: // RGB16 type : clone the src return FreeImage_Clone(dib); break; case FIT_RGBA16: // allow conversion from 64-bit RGBA (ignore the alpha channel) src = dib; break; default: return NULL; } // allocate dst image const unsigned width = FreeImage_GetWidth(src); const unsigned height = FreeImage_GetHeight(src); dst = FreeImage_AllocateT(FIT_RGB16, width, height); if(!dst) { if(src != dib) { FreeImage_Unload(src); } return NULL; } // copy metadata from src to dst FreeImage_CloneMetadata(dst, src); // convert from src type to RGB16 switch(src_type) { case FIT_BITMAP: { // Calculate the number of bytes per pixel (1 for 8-bit, 3 for 24-bit or 4 for 32-bit) const unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src); for(unsigned y = 0; y < height; y++) { const BYTE *src_bits = (BYTE*)FreeImage_GetScanLine(src, y); FIRGB16 *dst_bits = (FIRGB16*)FreeImage_GetScanLine(dst, y); for(unsigned x = 0; x < width; x++) { dst_bits[x].red = src_bits[FI_RGBA_RED] << 8; dst_bits[x].green = src_bits[FI_RGBA_GREEN] << 8; dst_bits[x].blue = src_bits[FI_RGBA_BLUE] << 8; src_bits += bytespp; } } } break; case FIT_UINT16: { for(unsigned y = 0; y < height; y++) { const WORD *src_bits = (WORD*)FreeImage_GetScanLine(src, y); FIRGB16 *dst_bits = (FIRGB16*)FreeImage_GetScanLine(dst, y); for(unsigned x = 0; x < width; x++) { // convert by copying greyscale channel to each R, G, B channels dst_bits[x].red = src_bits[x]; dst_bits[x].green = src_bits[x]; dst_bits[x].blue = src_bits[x]; } } } break; case FIT_RGBA16: { for(unsigned y = 0; y < height; y++) { const FIRGBA16 *src_bits = (FIRGBA16*)FreeImage_GetScanLine(src, y); FIRGB16 *dst_bits = (FIRGB16*)FreeImage_GetScanLine(dst, y); for(unsigned x = 0; x < width; x++) { // convert and skip alpha channel dst_bits[x].red = src_bits[x].red; dst_bits[x].green = src_bits[x].green; dst_bits[x].blue = src_bits[x].blue; } } } break; default: break; } if(src != dib) { FreeImage_Unload(src); } return dst; }
/** @brief Composite a foreground image against a background color or a background image. The equation for computing a composited sample value is:<br> output = alpha * foreground + (1-alpha) * background<br> where alpha and the input and output sample values are expressed as fractions in the range 0 to 1. For colour images, the computation is done separately for R, G, and B samples. @param fg Foreground image @param useFileBkg If TRUE and a file background is present, use it as the background color @param appBkColor If not equal to NULL, and useFileBkg is FALSE, use this color as the background color @param bg If not equal to NULL and useFileBkg is FALSE and appBkColor is NULL, use this as the background image @return Returns the composite image if successful, returns NULL otherwise @see FreeImage_IsTransparent, FreeImage_HasBackgroundColor */ FIBITMAP * DLL_CALLCONV FreeImage_Composite(FIBITMAP *fg, BOOL useFileBkg, RGBQUAD *appBkColor, FIBITMAP *bg) { if(!FreeImage_HasPixels(fg)) return NULL; int width = FreeImage_GetWidth(fg); int height = FreeImage_GetHeight(fg); int bpp = FreeImage_GetBPP(fg); if((bpp != 8) && (bpp != 32)) return NULL; if(bg) { int bg_width = FreeImage_GetWidth(bg); int bg_height = FreeImage_GetHeight(bg); int bg_bpp = FreeImage_GetBPP(bg); if((bg_width != width) || (bg_height != height) || (bg_bpp != 24)) return NULL; } int bytespp = (bpp == 8) ? 1 : 4; int x, y, c; BYTE alpha = 0, not_alpha; BYTE index; RGBQUAD fgc; // foreground color RGBQUAD bkc; // background color memset(&fgc, 0, sizeof(RGBQUAD)); memset(&bkc, 0, sizeof(RGBQUAD)); // allocate the composite image FIBITMAP *composite = FreeImage_Allocate(width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); if(!composite) return NULL; // get the palette RGBQUAD *pal = FreeImage_GetPalette(fg); // retrieve the alpha table from the foreground image BOOL bIsTransparent = FreeImage_IsTransparent(fg); BYTE *trns = FreeImage_GetTransparencyTable(fg); // retrieve the background color from the foreground image BOOL bHasBkColor = FALSE; if(useFileBkg && FreeImage_HasBackgroundColor(fg)) { FreeImage_GetBackgroundColor(fg, &bkc); bHasBkColor = TRUE; } else { // no file background color // use application background color ? if(appBkColor) { memcpy(&bkc, appBkColor, sizeof(RGBQUAD)); bHasBkColor = TRUE; } // use background image ? else if(bg) { bHasBkColor = FALSE; } } for(y = 0; y < height; y++) { // foreground BYTE *fg_bits = FreeImage_GetScanLine(fg, y); // background BYTE *bg_bits = FreeImage_GetScanLine(bg, y); // composite image BYTE *cp_bits = FreeImage_GetScanLine(composite, y); for(x = 0; x < width; x++) { // foreground color + alpha if(bpp == 8) { // get the foreground color index = fg_bits[0]; memcpy(&fgc, &pal[index], sizeof(RGBQUAD)); // get the alpha if(bIsTransparent) { alpha = trns[index]; } else { alpha = 255; } } else if(bpp == 32) { // get the foreground color fgc.rgbBlue = fg_bits[FI_RGBA_BLUE]; fgc.rgbGreen = fg_bits[FI_RGBA_GREEN]; fgc.rgbRed = fg_bits[FI_RGBA_RED]; // get the alpha alpha = fg_bits[FI_RGBA_ALPHA]; } // background color if(!bHasBkColor) { if(bg) { // get the background color from the background image bkc.rgbBlue = bg_bits[FI_RGBA_BLUE]; bkc.rgbGreen = bg_bits[FI_RGBA_GREEN]; bkc.rgbRed = bg_bits[FI_RGBA_RED]; } else { // use a checkerboard pattern c = (((y & 0x8) == 0) ^ ((x & 0x8) == 0)) * 192; c = c ? c : 255; bkc.rgbBlue = (BYTE)c; bkc.rgbGreen = (BYTE)c; bkc.rgbRed = (BYTE)c; } } // composition if(alpha == 0) { // output = background cp_bits[FI_RGBA_BLUE] = bkc.rgbBlue; cp_bits[FI_RGBA_GREEN] = bkc.rgbGreen; cp_bits[FI_RGBA_RED] = bkc.rgbRed; } else if(alpha == 255) { // output = foreground cp_bits[FI_RGBA_BLUE] = fgc.rgbBlue; cp_bits[FI_RGBA_GREEN] = fgc.rgbGreen; cp_bits[FI_RGBA_RED] = fgc.rgbRed; } else { // output = alpha * foreground + (1-alpha) * background not_alpha = (BYTE)~alpha; cp_bits[FI_RGBA_BLUE] = (BYTE)((alpha * (WORD)fgc.rgbBlue + not_alpha * (WORD)bkc.rgbBlue) >> 8); cp_bits[FI_RGBA_GREEN] = (BYTE)((alpha * (WORD)fgc.rgbGreen + not_alpha * (WORD)bkc.rgbGreen) >> 8); cp_bits[FI_RGBA_RED] = (BYTE)((alpha * (WORD)fgc.rgbRed + not_alpha * (WORD)bkc.rgbRed) >> 8); } fg_bits += bytespp; bg_bits += 3; cp_bits += 3; } } // copy metadata from src to dst FreeImage_CloneMetadata(composite, fg); return composite; }