/** * parameter constructor of an fipImage object * * @param type the type of the image of the fipImage to create * @param ulWidth the width of the image (in points) of the fipImage * to create * @param ulHeight the height of the image (in points) of the fipImage * to create * @param uiBitsPerPixel the number of bits per pixel for the color of * the fipImage to create */ fipImage::fipImage( FREE_IMAGE_TYPE type, const unsigned long ulWidth, const unsigned long ulHeight, const unsigned int uiBitsPerPixel ){ if ( ! bFreeImageInitialised ){ FreeImage_Initialise(); bFreeImageInitialised = true; } ulImageInstances++; pImageData = FreeImage_AllocateT( type, ulWidth, ulHeight, uiBitsPerPixel ); }
static void TestFreeImageIcs_SaveIcsTest(CuTest* tc) { ICS *ics = NULL, *new_ics; int err; FIBITMAP* fib; char *out_file = "C:\\test.ics"; fib = FreeImage_AllocateT(FIT_FLOAT, 800, 600, 32, 0, 0, 0); FreeImageIcs_SaveImage (fib, out_file, 1); }
static FIBITMAP* ConvertComplexImageToAbsoluteValued(FIBITMAP *src, bool squared) { FIBITMAP *dst = NULL; unsigned x, y; unsigned width = FreeImage_GetWidth(src); unsigned height = FreeImage_GetHeight(src); // Allocate a double bit dib dst = FreeImage_AllocateT(FIT_DOUBLE, width, height, 32, 0, 0, 0); if(!dst) return NULL; FICOMPLEX *src_bits, *src_bit; double *dst_bits; if(squared) { 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++) { src_bit = src_bits + x; *(dst_bits + x) = (double) ((src_bit->r * src_bit->r) + (src_bit->i * src_bit->i)); } } } else { 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++) { src_bit = src_bits + x; *(dst_bits + x) = sqrt((double) ((src_bit->r * src_bit->r) + (src_bit->i * src_bit->i))); } } } return dst; }
/** Compute the gradient magnitude of an input image H using central differences, and returns the average gradient. @param H Input image @param avgGrad [out] Average gradient @param k Level number @return Returns the gradient magnitude if successful, returns NULL otherwise @see GradientPyramid */ static FIBITMAP* GradientLevel(FIBITMAP *H, float *avgGrad, int k) { FIBITMAP *G = NULL; try { const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(H); if(image_type != FIT_FLOAT) throw(1); const unsigned width = FreeImage_GetWidth(H); const unsigned height = FreeImage_GetHeight(H); G = FreeImage_AllocateT(image_type, width, height); if(!G) throw(1); const unsigned pitch = FreeImage_GetPitch(H) / sizeof(float); const float divider = (float)(1 << (k + 1)); float average = 0; float *src_pixel = (float*)FreeImage_GetBits(H); float *dst_pixel = (float*)FreeImage_GetBits(G); for(unsigned y = 0; y < height; y++) { const unsigned n = (y == 0 ? 0 : y-1); const unsigned s = (y+1 == height ? y : y+1); for(unsigned x = 0; x < width; x++) { const unsigned w = (x == 0 ? 0 : x-1); const unsigned e = (x+1 == width ? x : x+1); // central difference const float gx = (src_pixel[y*pitch+e] - src_pixel[y*pitch+w]) / divider; // [Hk(x+1, y) - Hk(x-1, y)] / 2**(k+1) const float gy = (src_pixel[s*pitch+x] - src_pixel[n*pitch+x]) / divider; // [Hk(x, y+1) - Hk(x, y-1)] / 2**(k+1) // gradient dst_pixel[x] = sqrt(gx*gx + gy*gy); // average gradient average += dst_pixel[x]; } // next line dst_pixel += pitch; } *avgGrad = average / (width * height); return G; } catch(int) { if(G) FreeImage_Unload(G); return NULL; } }
static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { FIBITMAP *dib = NULL; if(handle) { try { rgbeHeaderInfo header_info; unsigned width, height; // Read the header if(rgbe_ReadHeader(io, handle, &width, &height, &header_info) == FALSE) return NULL; // allocate a RGBF image dib = FreeImage_AllocateT(FIT_RGBF, width, height); if(!dib) { throw "Memory allocation failed"; } // read the image pixels and fill the dib for(unsigned y = 0; y < height; y++) { FIRGBF *scanline = (FIRGBF*)FreeImage_GetScanLine(dib, height - 1 - y); if(!rgbe_ReadPixels_RLE(io, handle, scanline, width, 1)) { FreeImage_Unload(dib); return NULL; } } // set the metadata as comments rgbe_ReadMetadata(dib, &header_info); } catch(const char *text) { if(dib != NULL) { FreeImage_Unload(dib); } FreeImage_OutputMessageProc(s_format_id, text); } } return dib; }
void rtgu::image_io::create_image(gil::borrowed_image<PixelType>& image, int width, int height) { typedef detail::pixel_descriptor_t<PixelType> pixel_descriptor; FIBITMAP* fi_image = FreeImage_AllocateT( static_cast<FREE_IMAGE_TYPE>(pixel_descriptor::image_type), width, height, pixel_descriptor::bit_count); if (fi_image == NULL) { throw std::bad_alloc(); } boost::shared_ptr<void> fi_image_holder( fi_image, FreeImage_Unload ); unsigned const pitch = FreeImage_GetPitch( fi_image ); BYTE* const pixels_memory = FreeImage_GetBits( fi_image ); PixelType* pixels = reinterpret_cast<PixelType*>( pixels_memory ); image.reconstruct( width, height, pixels, pitch, true, fi_image_holder ); }
void resize(int w, int h, int bpp) { if(NULL != mImage) { // already allocated image? int oldw = FreeImage_GetWidth(mImage); int oldh = FreeImage_GetHeight(mImage); int oldbpp = FreeImage_GetBPP(mImage); // re-allocate only if dimensions have changed if(oldw != w || oldh != h || oldbpp != bpp) { destroy(); resize(w,h,bpp); } } else { /* FreeImage_AllocateT(FREE_IMAGE_TYPE type, int width, int height, int bpp); bpp Bit depth of the new Bitmap. Supported pixel depth: 1-, 4-, 8-, 16-, 24-, 32-bit per pixel for standard bitmap */ //printf("FreeImage_AllocateT(%d, %d, %d)\n", w,h,bpp); mImage = FreeImage_AllocateT(FIT_BITMAP, w, h, bpp); } }
/** Poisson solver based on a multigrid algorithm. This routine solves a Poisson equation, remap result pixels to [0..1] and returns the solution. NB: The input image is first stored inside a square image whose size is (2^j + 1)x(2^j + 1) for some integer j, where j is such that 2^j is the nearest larger dimension corresponding to MAX(image width, image height). @param Laplacian Laplacian image @param ncycle Number of cycles in the multigrid algorithm (usually 2 or 3) @return Returns the solved PDE equations if successful, returns NULL otherwise */ FIBITMAP* DLL_CALLCONV FreeImage_MultigridPoissonSolver(FIBITMAP *Laplacian, int ncycle) { if(!FreeImage_HasPixels(Laplacian)) return NULL; int width = FreeImage_GetWidth(Laplacian); int height = FreeImage_GetHeight(Laplacian); // get nearest larger dimension length that is acceptable by the algorithm int n = MAX(width, height); int size = 0; while((n >>= 1) > 0) size++; if((1 << size) < MAX(width, height)) { size++; } // size must be of the form 2^j + 1 for some integer j size = 1 + (1 << size); // allocate a temporary square image I FIBITMAP *I = FreeImage_AllocateT(FIT_FLOAT, size, size); if(!I) return NULL; // copy Laplacian into I and shift pixels to create a boundary FreeImage_Paste(I, Laplacian, 1, 1, 255); // solve the PDE equation fmg_mglin(I, size, ncycle); // shift pixels back FIBITMAP *U = FreeImage_Copy(I, 1, 1, width + 1, height + 1); FreeImage_Unload(I); // remap pixels to [0..1] NormalizeY(U, 0, 1); // copy metadata from src to dst FreeImage_CloneMetadata(U, Laplacian); // return the integrated image return U; }
static void TestFIA_GradientBlendPasteTest8(CuTest* tc) { FIBITMAP *src1 = FIA_LoadFIBFromFile(TEST_DATA_DIR "slide12bit1.png"); FIBITMAP *src2 = FIA_LoadFIBFromFile(TEST_DATA_DIR "slide12bit2.png"); FREE_IMAGE_TYPE type = FreeImage_GetImageType(src1); int bpp = FreeImage_GetBPP(src1); int width = FreeImage_GetWidth(src1); int height = FreeImage_GetHeight(src1); FIBITMAP *background = FreeImage_AllocateT(type, width * 2, height, bpp, 0, 0, 0); FIA_PasteFromTopLeft(background, src1, 0, 0); FIA_GradientBlendMosaicPaste (background, src2, 922, 0); FIA_SaveFIBToFile(background, TEST_DATA_OUTPUT_DIR "/GradientBlending/gradient_blended8.png", BIT16); FreeImage_Unload(background); FreeImage_Unload(src1); FreeImage_Unload(src2); }
static void splitRGBAtoBitBlt(FIBITMAP * &image, FIBITMAP *&mask) { unsigned int img_w = FreeImage_GetWidth(image); unsigned int img_h = FreeImage_GetHeight(image); mask = FreeImage_AllocateT(FIT_BITMAP, img_w, img_h, FreeImage_GetBPP(image), FreeImage_GetRedMask(image), FreeImage_GetGreenMask(image), FreeImage_GetBlueMask(image)); RGBQUAD Fpix; RGBQUAD Npix = {0x0, 0x0, 0x0, 0xFF}; for(unsigned int y = 0; (y < img_h); y++) { for(unsigned int x = 0; (x < img_w); x++) { FreeImage_GetPixelColor(image, x, y, &Fpix); uint8_t grey = (255 - Fpix.rgbReserved); Npix.rgbRed = grey; Npix.rgbGreen= grey; Npix.rgbBlue = grey; Npix.rgbReserved = 255; Fpix.rgbRed = subtractAlpha(Fpix.rgbRed, grey); Fpix.rgbGreen= subtractAlpha(Fpix.rgbGreen, grey); Fpix.rgbBlue = subtractAlpha(Fpix.rgbBlue, grey); Fpix.rgbReserved = 255; FreeImage_SetPixelColor(image, x, y, &Fpix); FreeImage_SetPixelColor(mask, x, y, &Npix); } } }
FIBITMAP* finalize(bool showProgress = true) { if (chunks.empty()) { return NULL; } if (showProgress) { printf("Adding all accepted chunks to the final image\n"); } std::list<FIBITMAP*>::iterator it = chunks.begin(); unsigned int width = FreeImage_GetWidth(*it); unsigned int chunkHeight = FreeImage_GetHeight(*it); unsigned int height = chunkHeight * chunks.size() ; unsigned int currentHeight = height - chunkHeight; FREE_IMAGE_TYPE type = FreeImage_GetImageType(*it); int bpp = FreeImage_GetBPP(*it); FIBITMAP *finalImage = FreeImage_AllocateT(type, width, height, bpp); for (; it != chunks.end(); it++) { for(unsigned int y = 0 ; y < chunkHeight ; y++) { FIRGBAF *srcbits = (FIRGBAF *) FreeImage_GetScanLine(*it, y); FIRGBAF *dstbits = (FIRGBAF *) FreeImage_GetScanLine(finalImage, y + currentHeight); for(unsigned int x = 0 ; x < width ; x++) { dstbits[x].red = srcbits[x].red; dstbits[x].blue = srcbits[x].blue; dstbits[x].green = srcbits[x].green; dstbits[x].alpha = srcbits[x].alpha; } } currentHeight -= chunkHeight; } return finalImage; }
FIBITMAP* psdParser::ProcessBuffer(BYTE * iprData) { assert(NULL != iprData); FIBITMAP *Bitmap = NULL; int nHeight = _headerInfo._Height; int nWidth = _headerInfo._Width; unsigned bytes = _headerInfo._BitsPerPixel / 8; int nChannels = _headerInfo._Channels; switch (_headerInfo._ColourMode) { case PSD_BITMAP: // Bitmap { // monochrome 1-bit FIBITMAP *dib = FreeImage_Allocate(nWidth, nHeight, 1); if (NULL != dib) { // fill the palette RGBQUAD *pal = FreeImage_GetPalette(dib); if(pal) { for (int i = 0; i < 2; i++) { BYTE val = i ? 0x0 : 0xFF; pal[i].rgbRed = val; pal[i].rgbGreen = val; pal[i].rgbBlue = val; } } // copy buffer BYTE *src_bits = (BYTE*)iprData; BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1); unsigned src_pitch = (nWidth + 7) / 8; unsigned dst_pitch = FreeImage_GetPitch(dib); for(int y = 0; y < nHeight; y++) { memcpy(dst_bits, src_bits, src_pitch); src_bits += src_pitch; dst_bits -= dst_pitch; } } Bitmap = dib; } break; case PSD_GRAYSCALE: // Grayscale case PSD_DUOTONE: // Duotone case PSD_RGB: // RGB { // 16-bit / channel // -------------------------------------------------------------- if (16 == _headerInfo._BitsPerPixel) { if (1 == nChannels) { // L 16-bit FIBITMAP *dib = FreeImage_AllocateT(FIT_UINT16, nWidth, nHeight); if (NULL != dib) { // just copy buffer BYTE *src_bits = (BYTE*)iprData; BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1); unsigned src_pitch = nChannels * nWidth * bytes; unsigned dst_pitch = FreeImage_GetPitch(dib); for(int y = 0; y < nHeight; y++) { memcpy(dst_bits, src_bits, src_pitch); src_bits += src_pitch; dst_bits -= dst_pitch; } Bitmap = dib; } } else if (2 == nChannels) { // LA 16-bit : convert to RGBA 16-bit FIBITMAP *dib = FreeImage_AllocateT(FIT_RGBA16, nWidth, nHeight); if (NULL != dib) { unsigned short *src_bits = (unsigned short*)iprData; FIRGBA16 *dst_bits = (FIRGBA16*)FreeImage_GetScanLine(dib, nHeight-1); unsigned pitch = FreeImage_GetPitch(dib) / sizeof(FIRGBA16); for(int y = 0; y < nHeight; y++) { for(int x = 0; x < nWidth; x++) { dst_bits[x].red = src_bits[0]; dst_bits[x].green = src_bits[0]; dst_bits[x].blue = src_bits[0]; dst_bits[x].alpha = src_bits[1]; src_bits += nChannels; } dst_bits -= pitch; } Bitmap = dib; } } else if (3 == nChannels) { // RGB 16-bit FIBITMAP *dib = FreeImage_AllocateT(FIT_RGB16, nWidth, nHeight); if (NULL != dib) { // just copy buffer BYTE *src_bits = (BYTE*)iprData; BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1); unsigned src_pitch = nChannels * nWidth * bytes; unsigned dst_pitch = FreeImage_GetPitch(dib); for(int y = 0; y < nHeight; y++) { memcpy(dst_bits, src_bits, src_pitch); src_bits += src_pitch; dst_bits -= dst_pitch; } Bitmap = dib; } } else if (4 == nChannels) { // RGBA 16-bit FIBITMAP *dib = FreeImage_AllocateT(FIT_RGBA16, nWidth, nHeight); if (NULL != dib) { // just copy buffer BYTE *src_bits = (BYTE*)iprData; BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1); unsigned src_pitch = nChannels * nWidth * bytes; unsigned dst_pitch = FreeImage_GetPitch(dib); for(int y = 0; y < nHeight; y++) { memcpy(dst_bits, src_bits, src_pitch); src_bits += src_pitch; dst_bits -= dst_pitch; } Bitmap = dib; } } } // 8-bit / channel // -------------------------------------------------------------- else if (8 == _headerInfo._BitsPerPixel) { if (1 == nChannels) { // L 8-bit FIBITMAP *dib = FreeImage_Allocate(nWidth, nHeight, 8); if (NULL != dib) { // build a greyscale palette RGBQUAD *pal = FreeImage_GetPalette(dib); for (int i = 0; i < 256; i++) { pal[i].rgbRed = (BYTE)i; pal[i].rgbGreen = (BYTE)i; pal[i].rgbBlue = (BYTE)i; } // just copy buffer BYTE *src_bits = (BYTE*)iprData; BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1); unsigned src_pitch = nChannels * nWidth * bytes; unsigned dst_pitch = FreeImage_GetPitch(dib); for(int y = 0; y < nHeight; y++) { memcpy(dst_bits, src_bits, src_pitch); src_bits += src_pitch; dst_bits -= dst_pitch; } Bitmap = dib; } } else if (2 == nChannels) { // LA 8-bit : convert to RGBA 32-bit FIBITMAP *dib = FreeImage_Allocate(nWidth, nHeight, 32); if (NULL != dib) { BYTE *src_bits = (BYTE*)iprData; BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1); unsigned src_pitch = nChannels * nWidth * bytes; unsigned dst_pitch = FreeImage_GetPitch(dib); for(int y = 0; y < nHeight; y++) { BYTE *p_src = src_bits; BYTE *p_dst = dst_bits; for(int x = 0; x < nWidth; x++) { p_dst[FI_RGBA_RED] = p_src[0]; p_dst[FI_RGBA_GREEN] = p_src[0]; p_dst[FI_RGBA_BLUE] = p_src[0]; p_dst[FI_RGBA_ALPHA] = p_src[1]; p_src += nChannels; p_dst += 4; } src_bits += src_pitch; dst_bits -= dst_pitch; } Bitmap = dib; } } else if (3 == nChannels) { // RGB 8-bit FIBITMAP *dib = FreeImage_Allocate(nWidth, nHeight, 24); if (NULL != dib) { // just copy buffer BYTE *src_bits = (BYTE*)iprData; BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1); unsigned src_pitch = nChannels * nWidth * bytes; unsigned dst_pitch = FreeImage_GetPitch(dib); for(int y = 0; y < nHeight; y++) { BYTE *p_src = src_bits; BYTE *p_dst = dst_bits; for(int x = 0; x < nWidth; x++) { p_dst[FI_RGBA_RED] = p_src[0]; p_dst[FI_RGBA_GREEN] = p_src[1]; p_dst[FI_RGBA_BLUE] = p_src[2]; p_src += nChannels; p_dst += nChannels; } src_bits += src_pitch; dst_bits -= dst_pitch; } Bitmap = dib; } } else if (4 == nChannels) { // RGBA 8-bit FIBITMAP *dib = FreeImage_Allocate(nWidth, nHeight, 32); if (NULL != dib) { // just copy buffer BYTE *src_bits = (BYTE*)iprData; BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1); unsigned src_pitch = nChannels * nWidth * bytes; unsigned dst_pitch = FreeImage_GetPitch(dib); for(int y = 0; y < nHeight; y++) { BYTE *p_src = src_bits; BYTE *p_dst = dst_bits; for(int x = 0; x < nWidth; x++) { p_dst[FI_RGBA_RED] = p_src[0]; p_dst[FI_RGBA_GREEN] = p_src[1]; p_dst[FI_RGBA_BLUE] = p_src[2]; p_dst[FI_RGBA_ALPHA] = p_src[3]; p_src += nChannels; p_dst += nChannels; } src_bits += src_pitch; dst_bits -= dst_pitch; } Bitmap = dib; } } else { assert(false);// do nothing } } // 32-bit / channel => undocumented HDR // -------------------------------------------------------------- else if (32 == _headerInfo._BitsPerPixel) { if (3 == nChannels) { // RGBF 32-bit FIBITMAP *dib = FreeImage_AllocateT(FIT_RGBF, nWidth, nHeight); if (NULL != dib) { // just copy buffer BYTE *src_bits = (BYTE*)iprData; BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1); unsigned src_pitch = nChannels * nWidth * bytes; unsigned dst_pitch = FreeImage_GetPitch(dib); for(int y = 0; y < nHeight; y++) { memcpy(dst_bits, src_bits, src_pitch); src_bits += src_pitch; dst_bits -= dst_pitch; } Bitmap = dib; } } } } break; case PSD_INDEXED: // Indexed { // iprData holds the indices of loop through the palette assert(0 != _colourModeData._plColourData); assert(768 == _colourModeData._Length); assert(0 < _ColourCount); // grey or palettised 8 bits FIBITMAP *dib = FreeImage_Allocate(nWidth, nHeight, 8); if (NULL != dib) { // get the palette if (_colourModeData.FillPalette(dib)) { // copy buffer BYTE *src_bits = (BYTE*)iprData; BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1); unsigned src_pitch = nChannels * nWidth * bytes; unsigned dst_pitch = FreeImage_GetPitch(dib); for(int y = 0; y < nHeight; y++) { memcpy(dst_bits, src_bits, src_pitch); src_bits += src_pitch; dst_bits -= dst_pitch; } } } Bitmap = dib; } break; case PSD_CMYK: // CMYK { float C, M, Y, K; float s = 1.f / pow( 2.0f, _headerInfo._BitsPerPixel); if (16 == _headerInfo._BitsPerPixel) { // CMYK 16-bit : convert to RGB 16-bit FIBITMAP *dib = FreeImage_AllocateT(FIT_RGB16, nWidth, nHeight); if (NULL != dib) { BYTE *src_bits = (BYTE*)iprData; BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1); unsigned src_pitch = nChannels * nWidth * bytes; unsigned dst_pitch = FreeImage_GetPitch(dib); for(int y = 0; y < nHeight; y++) { unsigned short *src_line = (unsigned short*)src_bits; FIRGB16 *dst_line = (FIRGB16*)dst_bits; for(int x = 0; x < nWidth; x++) { C = (1.f - (float)psdGetValue((BYTE*)&src_line[0], bytes ) * s ); M = (1.f - (float)psdGetValue((BYTE*)&src_line[1], bytes ) * s ); Y = (1.f - (float)psdGetValue((BYTE*)&src_line[2], bytes ) * s ); K = (1.f - (float)psdGetValue((BYTE*)&src_line[3], bytes ) * s ); CMYKToRGB16(C, M, Y, K, &dst_line[x]); src_line += nChannels; } src_bits += src_pitch; dst_bits -= dst_pitch; } Bitmap = dib; } } else { // CMYK 8-bit : convert to RGB 8-bit FIBITMAP *dib = FreeImage_Allocate(nWidth, nHeight, 24); if (NULL != dib) { BYTE *src_bits = (BYTE*)iprData; BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1); unsigned src_pitch = nChannels * nWidth * bytes; unsigned dst_pitch = FreeImage_GetPitch(dib); for(int y = 0; y < nHeight; y++) { BYTE *src_line = (BYTE*)src_bits; RGBTRIPLE *dst_line = (RGBTRIPLE*)dst_bits; for(int x = 0; x < nWidth; x++) { C = (1.f - (float)psdGetValue((BYTE*)&src_line[0], bytes ) * s ); M = (1.f - (float)psdGetValue((BYTE*)&src_line[1], bytes ) * s ); Y = (1.f - (float)psdGetValue((BYTE*)&src_line[2], bytes ) * s ); K = (1.f - (float)psdGetValue((BYTE*)&src_line[3], bytes ) * s ); CMYKToRGB8(C, M, Y, K, &dst_line[x]); src_line += nChannels; } src_bits += src_pitch; dst_bits -= dst_pitch; } Bitmap = dib; } } } break; case PSD_MULTICHANNEL: // Multichannel { // assume format is in either CMY or CMYK assert(3 <= nChannels); float C, M, Y, K; float s = 1.f / pow( 2.0f, _headerInfo._BitsPerPixel); if (16 == _headerInfo._BitsPerPixel) { // CMY(K) 16-bit : convert to RGB 16-bit FIBITMAP *dib = FreeImage_AllocateT(FIT_RGB16, nWidth, nHeight); if (NULL != dib) { BYTE *src_bits = (BYTE*)iprData; BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1); unsigned src_pitch = nChannels * nWidth * bytes; unsigned dst_pitch = FreeImage_GetPitch(dib); for(int y = 0; y < nHeight; y++) { unsigned short *src_line = (unsigned short*)src_bits; FIRGB16 *dst_line = (FIRGB16*)dst_bits; for(int x = 0; x < nWidth; x++) { C = (1.f - (float)psdGetValue((BYTE*)&src_line[0], bytes ) * s ); M = (1.f - (float)psdGetValue((BYTE*)&src_line[1], bytes ) * s ); Y = (1.f - (float)psdGetValue((BYTE*)&src_line[2], bytes ) * s ); K = (4 <= nChannels) ? (1.f - (float)psdGetValue((BYTE*)&src_line[nChannels], bytes )*s ) : 0; CMYKToRGB16(C, M, Y, K, &dst_line[x]); src_line += nChannels; } src_bits += src_pitch; dst_bits -= dst_pitch; } Bitmap = dib; } } else { // CMY(K) 8-bit : convert to RGB 8-bit FIBITMAP *dib = FreeImage_Allocate(nWidth, nHeight, 24); if (NULL != dib) { BYTE *src_bits = (BYTE*)iprData; BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1); unsigned src_pitch = nChannels * nWidth * bytes; unsigned dst_pitch = FreeImage_GetPitch(dib); for(int y = 0; y < nHeight; y++) { BYTE *src_line = (BYTE*)src_bits; RGBTRIPLE *dst_line = (RGBTRIPLE*)dst_bits; for(int x = 0; x < nWidth; x++) { C = (1.f - (float)psdGetValue((BYTE*)&src_line[0], bytes ) * s ); M = (1.f - (float)psdGetValue((BYTE*)&src_line[1], bytes ) * s ); Y = (1.f - (float)psdGetValue((BYTE*)&src_line[2], bytes ) * s ); K = (4 <= nChannels) ? (1.f - (float)psdGetValue((BYTE*)&src_line[nChannels], bytes )*s ) : 0; CMYKToRGB8(C, M, Y, K, &dst_line[x]); src_line += nChannels; } src_bits += src_pitch; dst_bits -= dst_pitch; } Bitmap = dib; } } } break; case PSD_LAB: // Lab { const unsigned dMaxColours = 1 << _headerInfo._BitsPerPixel; const float sL = 100.F / dMaxColours; const float sa = 256.F / dMaxColours; const float sb = 256.F / dMaxColours; float L, a, b; if (16 == _headerInfo._BitsPerPixel) { // CIE Lab 16-bit : convert to RGB 16-bit FIBITMAP *dib = FreeImage_AllocateT(FIT_RGB16, nWidth, nHeight); if (NULL != dib) { BYTE *src_bits = (BYTE*)iprData; BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1); unsigned src_pitch = nChannels * nWidth * bytes; unsigned dst_pitch = FreeImage_GetPitch(dib); for(int y = 0; y < nHeight; y++) { unsigned short *src_line = (unsigned short*)src_bits; FIRGB16 *dst_line = (FIRGB16*)dst_bits; for(int x = 0; x < nWidth; x++) { L = (float)psdGetValue((BYTE*)&src_line[0], bytes ) * sL; a = (float)psdGetValue((BYTE*)&src_line[1], bytes ) * sa - 128.F; b = (float)psdGetValue((BYTE*)&src_line[2], bytes ) * sb - 128.F; CIELabToRGB16(L, a, b, &dst_line[x]); src_line += nChannels; } src_bits += src_pitch; dst_bits -= dst_pitch; } Bitmap = dib; } } else { // CIE Lab 8-bit : convert to RGB 8-bit FIBITMAP *dib = FreeImage_Allocate(nWidth, nHeight, 24); if (NULL != dib) { BYTE *src_bits = (BYTE*)iprData; BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1); unsigned src_pitch = nChannels * nWidth * bytes; unsigned dst_pitch = FreeImage_GetPitch(dib); for(int y = 0; y < nHeight; y++) { BYTE *src_line = (BYTE*)src_bits; RGBTRIPLE *dst_line = (RGBTRIPLE*)dst_bits; for(int x = 0; x < nWidth; x++) { L = (float)psdGetValue((BYTE*)&src_line[0], bytes ) * sL; a = (float)psdGetValue((BYTE*)&src_line[1], bytes ) * sa - 128.F; b = (float)psdGetValue((BYTE*)&src_line[2], bytes ) * sb - 128.F; CIELabToRGB8(L, a, b, &dst_line[x]); src_line += nChannels; } src_bits += src_pitch; dst_bits -= dst_pitch; } Bitmap = dib; } } } break; default: break; } return Bitmap; }
GXBOOL RenderTargetImpl::SaveToMemory(clstd::MemBuffer* pBuffer, GXLPCSTR pImageFormat) { GXSIZE sDimension; GXBOOL bval = TRUE; GXFormat format = m_pColorTexture->GetFormat(); m_pColorTexture->GetDimension(&sDimension); Texture* pReadBackTexture = NULL; GetColorTexture(&pReadBackTexture, GXResUsage::Read); Texture::MAPPED mapped; if(pReadBackTexture->Map(&mapped, GXResMap::Read)) { GXUINT bpp = GetBytesOfGraphicsFormat(format); GXLPVOID pSourceBits = mapped.pBits; GXINT nSourcePitch = mapped.Pitch; clstd::Image temp_image; FREE_IMAGE_TYPE fit = FIT_BITMAP; switch(format) { case Format_R8G8B8A8: temp_image.Set(sDimension.cx, sDimension.cy, "RGBA", 8, pSourceBits, nSourcePitch); break; case Format_B8G8R8X8: temp_image.Set(sDimension.cx, sDimension.cy, "BGRX", 8, pSourceBits, nSourcePitch); break; case Format_B8G8R8: temp_image.Set(sDimension.cx, sDimension.cy, "BGRX", 8, pSourceBits, nSourcePitch); break; case Format_R8: temp_image.Set(sDimension.cx, sDimension.cy, "R", 8, pSourceBits, nSourcePitch); break; case Format_R8G8: temp_image.Set(sDimension.cx, sDimension.cy, "RG", 8, pSourceBits, nSourcePitch); break; case Format_R32G32B32A32_Float: fit = FIT_RGBAF; break; case Format_R32: fit = FIT_FLOAT; break; } if(temp_image.GetDataSize() > 0) { temp_image.SetFormat("BGRA"); pSourceBits = temp_image.GetLine(0); nSourcePitch = temp_image.GetPitch(); bpp = temp_image.GetChannels(); } FIBITMAP* fibmp = (fit == FIT_BITMAP) ? FreeImage_Allocate(sDimension.cx, sDimension.cy, bpp * 8) : FreeImage_AllocateT(fit, sDimension.cx, sDimension.cy, bpp * 8); BYTE* pDest = FreeImage_GetBits(fibmp); GXINT nDestPitch = FreeImage_GetPitch(fibmp); pDest += nDestPitch * (sDimension.cy - 1); for(int y = 0; y < sDimension.cy; y++) { memcpy(pDest, pSourceBits, clMin(nDestPitch, nSourcePitch)); pDest -= nDestPitch; pSourceBits = reinterpret_cast<GXLPVOID>(reinterpret_cast<size_t>(pSourceBits) + nSourcePitch); } pReadBackTexture->Unmap(); FREE_IMAGE_FORMAT fi_format = FIF_UNKNOWN; clStringA strFormat = pImageFormat; strFormat.MakeUpper(); if(strFormat == "PNG") { fi_format = FIF_PNG; } else if(strFormat == "JPEG" || strFormat == "JPG") { fi_format = FIF_JPEG; } else if(strFormat == "TIF" || strFormat == "TIFF") { fi_format = FIF_TIFF; } else if(strFormat == "TGA") { fi_format = FIF_TARGA; } else if(strFormat == "BMP") { fi_format = FIF_BMP; } else if(strFormat == "EXR") { fi_format = FIF_EXR; } if(fi_format != FIF_UNKNOWN) { FIMEMORY* fimemory = FreeImage_OpenMemory(); if(FreeImage_SaveToMemory(fi_format, fibmp, fimemory)) { BYTE *pData; DWORD size_in_bytes; if(FreeImage_AcquireMemory(fimemory, &pData, &size_in_bytes)) { pBuffer->Resize(0, FALSE); pBuffer->Append(pData, size_in_bytes); } else { bval = FALSE; } } else { bval = FALSE; } FreeImage_CloseMemory(fimemory); } else { bval = FALSE; } FreeImage_Unload(fibmp); } SAFE_RELEASE(pReadBackTexture); return bval; }
FIBITMAP * DLL_CALLCONV FreeImage_ConvertToRGBF(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: { // allow conversion from 24- and 32-bit const FREE_IMAGE_COLOR_TYPE color_type = FreeImage_GetColorType(dib); if((color_type != FIC_RGB) && (color_type != FIC_RGBALPHA)) { src = FreeImage_ConvertTo24Bits(dib); if(!src) return NULL; } else { src = dib; } break; } case FIT_UINT16: // allow conversion from 16-bit src = dib; break; case FIT_RGB16: // allow conversion from 48-bit RGB src = dib; break; case FIT_RGBA16: // allow conversion from 64-bit RGBA (ignore the alpha channel) src = dib; break; case FIT_FLOAT: // allow conversion from 32-bit float src = dib; break; case FIT_RGBAF: // allow conversion from 128-bit RGBAF src = dib; break; case FIT_RGBF: // RGBF type : clone the src return FreeImage_Clone(dib); break; default: return NULL; } // allocate dst image const unsigned width = FreeImage_GetWidth(src); const unsigned height = FreeImage_GetHeight(src); dst = FreeImage_AllocateT(FIT_RGBF, 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 RGBF const unsigned src_pitch = FreeImage_GetPitch(src); const unsigned dst_pitch = FreeImage_GetPitch(dst); switch(src_type) { case FIT_BITMAP: { // calculate the number of bytes per pixel (3 for 24-bit or 4 for 32-bit) const unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src); const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src); BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst); for(unsigned y = 0; y < height; y++) { const BYTE *src_pixel = (BYTE*)src_bits; FIRGBF *dst_pixel = (FIRGBF*)dst_bits; for(unsigned x = 0; x < width; x++) { // convert and scale to the range [0..1] dst_pixel->red = (float)(src_pixel[FI_RGBA_RED]) / 255.0F; dst_pixel->green = (float)(src_pixel[FI_RGBA_GREEN]) / 255.0F; dst_pixel->blue = (float)(src_pixel[FI_RGBA_BLUE]) / 255.0F; src_pixel += bytespp; dst_pixel ++; } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_UINT16: { const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src); BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst); for(unsigned y = 0; y < height; y++) { const WORD *src_pixel = (WORD*)src_bits; FIRGBF *dst_pixel = (FIRGBF*)dst_bits; for(unsigned x = 0; x < width; x++) { // convert and scale to the range [0..1] const float dst_value = (float)src_pixel[x] / 65535.0F; dst_pixel[x].red = dst_value; dst_pixel[x].green = dst_value; dst_pixel[x].blue = dst_value; } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_RGB16: { const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src); BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst); for(unsigned y = 0; y < height; y++) { const FIRGB16 *src_pixel = (FIRGB16*) src_bits; FIRGBF *dst_pixel = (FIRGBF*) dst_bits; for(unsigned x = 0; x < width; x++) { // convert and scale to the range [0..1] dst_pixel[x].red = (float)(src_pixel[x].red) / 65535.0F; dst_pixel[x].green = (float)(src_pixel[x].green) / 65535.0F; dst_pixel[x].blue = (float)(src_pixel[x].blue) / 65535.0F; } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_RGBA16: { const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src); BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst); for(unsigned y = 0; y < height; y++) { const FIRGBA16 *src_pixel = (FIRGBA16*) src_bits; FIRGBF *dst_pixel = (FIRGBF*) dst_bits; for(unsigned x = 0; x < width; x++) { // convert and scale to the range [0..1] dst_pixel[x].red = (float)(src_pixel[x].red) / 65535.0F; dst_pixel[x].green = (float)(src_pixel[x].green) / 65535.0F; dst_pixel[x].blue = (float)(src_pixel[x].blue) / 65535.0F; } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_FLOAT: { const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src); BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst); for(unsigned y = 0; y < height; y++) { const float *src_pixel = (float*) src_bits; FIRGBF *dst_pixel = (FIRGBF*) dst_bits; for(unsigned x = 0; x < width; x++) { // convert by copying greyscale channel to each R, G, B channels // assume float values are in [0..1] const float value = CLAMP(src_pixel[x], 0.0F, 1.0F); dst_pixel[x].red = value; dst_pixel[x].green = value; dst_pixel[x].blue = value; } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_RGBAF: { const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src); BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst); for(unsigned y = 0; y < height; y++) { const FIRGBAF *src_pixel = (FIRGBAF*) src_bits; FIRGBF *dst_pixel = (FIRGBF*) dst_bits; for(unsigned x = 0; x < width; x++) { // convert and skip alpha channel dst_pixel[x].red = CLAMP(src_pixel[x].red, 0.0F, 1.0F); dst_pixel[x].green = CLAMP(src_pixel[x].green, 0.0F, 1.0F); dst_pixel[x].blue = CLAMP(src_pixel[x].blue, 0.0F, 1.0F); } src_bits += src_pitch; dst_bits += dst_pitch; } } break; } if(src != dib) { FreeImage_Unload(src); } return dst; }
virtual bool save(const std::string& filename, const Array& lat) { // check existing image type FREE_IMAGE_FORMAT type = FreeImage_GetFIFFromFilename(filename.c_str()); if(type == FIF_UNKNOWN) { AL_WARN("image format not recognized: %s", filename.c_str()); return false; } if(!FreeImage_FIFSupportsWriting(type)) { AL_WARN("image format not supported: %s", filename.c_str()); return false; } destroy(); const AlloArrayHeader& header = lat.header; int w = header.dim[0]; int h = (header.dimcount > 1) ? header.dim[1] : 1; Image::Format format = Image::getFormat(header.components); switch(format) { case Image::RGB: { switch(header.type) { case AlloUInt8Ty: { int bpp = header.stride[0]; mImage = FreeImage_AllocateT(FIT_BITMAP, w, h, bpp*8); char *bp = (char *)(lat.data.ptr); int rowstride = header.stride[1]; for(unsigned j = 0; j < header.dim[1]; ++j) { // copy Array row to image buffer /*memcpy( FreeImage_GetScanLine(mImage, j), bp + j*rowstride, w*3 );*/ RGBTRIPLE *pix = (RGBTRIPLE *)FreeImage_GetScanLine(mImage, j); Image::RGBPix<uint8_t> *o_pix = (Image::RGBPix<uint8_t> *)(bp + j*rowstride); for(unsigned i=0; i < header.dim[0]; ++i) { pix->rgbtRed = o_pix->r; pix->rgbtGreen = o_pix->g; pix->rgbtBlue = o_pix->b; ++pix; ++o_pix; } } } break; default: AL_WARN("input matrix type not supported"); break; } } break; case Image::RGBA: { switch(header.type) { case AlloUInt8Ty: { int bpp = header.stride[0]; mImage = FreeImage_AllocateT(FIT_BITMAP, w, h, bpp*8); char *bp = (char *)(lat.data.ptr); int rowstride = header.stride[1]; for(unsigned j = 0; j < header.dim[1]; ++j) { // copy Array row to image buffer /*memcpy( FreeImage_GetScanLine(mImage, j), bp + j*rowstride, w*4 );*/ RGBQUAD *pix = (RGBQUAD *)FreeImage_GetScanLine(mImage, j); Image::RGBAPix<uint8_t> *o_pix = (Image::RGBAPix<uint8_t> *)(bp + j*rowstride); for(unsigned i=0; i < header.dim[0]; ++i) { pix->rgbRed = o_pix->r; pix->rgbGreen = o_pix->g; pix->rgbBlue = o_pix->b; pix->rgbReserved = o_pix->a; ++pix; ++o_pix; } } } break; default: AL_WARN("input matrix type not supported"); return false; } } break; default: { AL_WARN("input matrix format not supported"); return false; } } if (mImage == NULL) { AL_WARN("image could not be understood"); return false; } return FreeImage_Save(type, mImage, filename.c_str(), 0); }
FIBITMAP * DLL_CALLCONV FreeImage_Clone(FIBITMAP *dib) { if(!dib) return NULL; unsigned width = FreeImage_GetWidth(dib); unsigned height = FreeImage_GetHeight(dib); unsigned bpp = FreeImage_GetBPP(dib); // allocate a new dib FIBITMAP *new_dib = FreeImage_AllocateT(FreeImage_GetImageType(dib), width, height, bpp, FreeImage_GetRedMask(dib), FreeImage_GetGreenMask(dib), FreeImage_GetBlueMask(dib)); if (new_dib) { // save ICC profile links FIICCPROFILE *src_iccProfile = FreeImage_GetICCProfile(dib); FIICCPROFILE *dst_iccProfile = FreeImage_GetICCProfile(new_dib); // save metadata links METADATAMAP *src_metadata = ((FREEIMAGEHEADER *)dib->data)->metadata; METADATAMAP *dst_metadata = ((FREEIMAGEHEADER *)new_dib->data)->metadata; // calculate the size of a FreeImage image // align the palette and the pixels on a FIBITMAP_ALIGNMENT bytes alignment boundary // palette is aligned on a 16 bytes boundary // pixels are aligned on a 16 bytes boundary unsigned dib_size = FreeImage_GetImageSize(width, height, bpp); // copy the bitmap + internal pointers (remember to restore new_dib internal pointers later) memcpy(new_dib->data, dib->data, dib_size); // reset ICC profile link for new_dib memset(dst_iccProfile, 0, sizeof(FIICCPROFILE)); // restore metadata link for new_dib ((FREEIMAGEHEADER *)new_dib->data)->metadata = dst_metadata; // copy possible ICC profile FreeImage_CreateICCProfile(new_dib, src_iccProfile->data, src_iccProfile->size); dst_iccProfile->flags = src_iccProfile->flags; // copy metadata models for(METADATAMAP::iterator i = (*src_metadata).begin(); i != (*src_metadata).end(); i++) { int model = (*i).first; TAGMAP *src_tagmap = (*i).second; if(src_tagmap) { // create a metadata model TAGMAP *dst_tagmap = new TAGMAP(); // fill the model for(TAGMAP::iterator j = src_tagmap->begin(); j != src_tagmap->end(); j++) { std::string dst_key = (*j).first; FITAG *dst_tag = FreeImage_CloneTag( (*j).second ); // assign key and tag value (*dst_tagmap)[dst_key] = dst_tag; } // assign model and tagmap (*dst_metadata)[model] = dst_tagmap; } } return new_dib; } return NULL; }
FIBITMAP * DLL_CALLCONV FreeImage_Allocate(int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) { return FreeImage_AllocateT(FIT_BITMAP, width, height, bpp, red_mask, green_mask, blue_mask); }
//--------------------------------------------------------------------- FIBITMAP* FreeImageCodec::encode(MemoryDataStreamPtr& input, CodecDataPtr& pData) const { // Set error handler FreeImage_SetOutputMessage(FreeImageSaveErrorHandler); FIBITMAP* ret = 0; ImageData* pImgData = static_cast< ImageData * >( pData.getPointer() ); PixelBox src(pImgData->width, pImgData->height, pImgData->depth, pImgData->format, input->getPtr()); // The required format, which will adjust to the format // actually supported by FreeImage. PixelFormat requiredFormat = pImgData->format; // determine the settings FREE_IMAGE_TYPE imageType; PixelFormat determiningFormat = pImgData->format; switch(determiningFormat) { case PF_R5G6B5: case PF_B5G6R5: case PF_R8G8B8: case PF_B8G8R8: case PF_A8R8G8B8: case PF_X8R8G8B8: case PF_A8B8G8R8: case PF_X8B8G8R8: case PF_B8G8R8A8: case PF_R8G8B8A8: case PF_A4L4: case PF_BYTE_LA: case PF_R3G3B2: case PF_A4R4G4B4: case PF_A1R5G5B5: case PF_A2R10G10B10: case PF_A2B10G10R10: // I'd like to be able to use r/g/b masks to get FreeImage to load the data // in it's existing format, but that doesn't work, FreeImage needs to have // data in RGB[A] (big endian) and BGR[A] (little endian), always. if (PixelUtil::hasAlpha(determiningFormat)) { #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB requiredFormat = PF_BYTE_RGBA; #else requiredFormat = PF_BYTE_BGRA; #endif } else { #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB requiredFormat = PF_BYTE_RGB; #else requiredFormat = PF_BYTE_BGR; #endif } // fall through case PF_L8: case PF_A8: imageType = FIT_BITMAP; break; case PF_L16: imageType = FIT_UINT16; break; case PF_SHORT_GR: requiredFormat = PF_SHORT_RGB; // fall through case PF_SHORT_RGB: imageType = FIT_RGB16; break; case PF_SHORT_RGBA: imageType = FIT_RGBA16; break; case PF_FLOAT16_R: requiredFormat = PF_FLOAT32_R; // fall through case PF_FLOAT32_R: imageType = FIT_FLOAT; break; case PF_FLOAT16_GR: case PF_FLOAT16_RGB: case PF_FLOAT32_GR: requiredFormat = PF_FLOAT32_RGB; // fall through case PF_FLOAT32_RGB: imageType = FIT_RGBF; break; case PF_FLOAT16_RGBA: requiredFormat = PF_FLOAT32_RGBA; // fall through case PF_FLOAT32_RGBA: imageType = FIT_RGBAF; break; default: OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Invalid image format", "FreeImageCodec::encode"); }; // Check support for this image type & bit depth if (!FreeImage_FIFSupportsExportType((FREE_IMAGE_FORMAT)mFreeImageType, imageType) || !FreeImage_FIFSupportsExportBPP((FREE_IMAGE_FORMAT)mFreeImageType, (int)PixelUtil::getNumElemBits(requiredFormat))) { // Ok, need to allocate a fallback // Only deal with RGBA -> RGB for now switch (requiredFormat) { case PF_BYTE_RGBA: requiredFormat = PF_BYTE_RGB; break; case PF_BYTE_BGRA: requiredFormat = PF_BYTE_BGR; break; default: break; }; } bool conversionRequired = false; unsigned char* srcData = input->getPtr(); // Check BPP unsigned bpp = static_cast<unsigned>(PixelUtil::getNumElemBits(requiredFormat)); if (!FreeImage_FIFSupportsExportBPP((FREE_IMAGE_FORMAT)mFreeImageType, (int)bpp)) { if (bpp == 32 && PixelUtil::hasAlpha(pImgData->format) && FreeImage_FIFSupportsExportBPP((FREE_IMAGE_FORMAT)mFreeImageType, 24)) { // drop to 24 bit (lose alpha) #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB requiredFormat = PF_BYTE_RGB; #else requiredFormat = PF_BYTE_BGR; #endif bpp = 24; } else if (bpp == 128 && PixelUtil::hasAlpha(pImgData->format) && FreeImage_FIFSupportsExportBPP((FREE_IMAGE_FORMAT)mFreeImageType, 96)) { // drop to 96-bit floating point requiredFormat = PF_FLOAT32_RGB; } } PixelBox convBox(pImgData->width, pImgData->height, 1, requiredFormat); if (requiredFormat != pImgData->format) { conversionRequired = true; // Allocate memory convBox.data = OGRE_ALLOC_T(uchar, convBox.getConsecutiveSize(), MEMCATEGORY_GENERAL); // perform conversion and reassign source PixelBox src(pImgData->width, pImgData->height, 1, pImgData->format, input->getPtr()); PixelUtil::bulkPixelConversion(src, convBox); srcData = static_cast<unsigned char*>(convBox.data); } ret = FreeImage_AllocateT( imageType, static_cast<int>(pImgData->width), static_cast<int>(pImgData->height), bpp); if (!ret) { if (conversionRequired) OGRE_FREE(convBox.data, MEMCATEGORY_GENERAL); OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "FreeImage_AllocateT failed - possibly out of memory. ", __FUNCTION__); } if (requiredFormat == PF_L8 || requiredFormat == PF_A8) { // Must explicitly tell FreeImage that this is greyscale by setting // a "grey" palette (otherwise it will save as a normal RGB // palettized image). FIBITMAP *tmp = FreeImage_ConvertToGreyscale(ret); FreeImage_Unload(ret); ret = tmp; } size_t dstPitch = FreeImage_GetPitch(ret); size_t srcPitch = pImgData->width * PixelUtil::getNumElemBytes(requiredFormat); // Copy data, invert scanlines and respect FreeImage pitch uchar* pSrc; uchar* pDst = FreeImage_GetBits(ret); for (size_t y = 0; y < pImgData->height; ++y) { pSrc = srcData + (pImgData->height - y - 1) * srcPitch; memcpy(pDst, pSrc, srcPitch); pDst += dstPitch; } if (conversionRequired) { // delete temporary conversion area OGRE_FREE(convBox.data, MEMCATEGORY_GENERAL); } return ret; }
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; }
FIBITMAP* CResizeEngine::scale(FIBITMAP *src, unsigned dst_width, unsigned dst_height) { DWORD src_width = FreeImage_GetWidth(src); DWORD src_height = FreeImage_GetHeight(src); unsigned redMask = FreeImage_GetRedMask(src); unsigned greenMask = FreeImage_GetGreenMask(src); unsigned blueMask = FreeImage_GetBlueMask(src); unsigned bpp = FreeImage_GetBPP(src); FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(src); // allocate the dst image FIBITMAP *dst = FreeImage_AllocateT(image_type, dst_width, dst_height, bpp, redMask, greenMask, blueMask); if(!dst) return NULL; if(bpp == 8) { if(FreeImage_GetColorType(src) == FIC_MINISWHITE) { // build an inverted greyscale palette RGBQUAD *dst_pal = FreeImage_GetPalette(dst); for(int i = 0; i < 256; i++) { dst_pal[i].rgbRed = dst_pal[i].rgbGreen = dst_pal[i].rgbBlue = (BYTE)(255 - i); } } else { // build a greyscale palette RGBQUAD *dst_pal = FreeImage_GetPalette(dst); for(int i = 0; i < 256; i++) { dst_pal[i].rgbRed = dst_pal[i].rgbGreen = dst_pal[i].rgbBlue = (BYTE)i; } } } // decide which filtering order (xy or yx) is faster for this mapping by // counting convolution multiplies if(dst_width*src_height <= dst_height*src_width) { // xy filtering // ------------- // allocate a temporary image FIBITMAP *tmp = FreeImage_AllocateT(image_type, dst_width, src_height, bpp, redMask, greenMask, blueMask); if(!tmp) { FreeImage_Unload(dst); return NULL; } // scale source image horizontally into temporary image horizontalFilter(src, src_width, src_height, tmp, dst_width, src_height); // scale temporary image vertically into result image verticalFilter(tmp, dst_width, src_height, dst, dst_width, dst_height); // free temporary image FreeImage_Unload(tmp); } else { // yx filtering // ------------- // allocate a temporary image FIBITMAP *tmp = FreeImage_AllocateT(image_type, src_width, dst_height, bpp, redMask, greenMask, blueMask); if(!tmp) { FreeImage_Unload(dst); return NULL; } // scale source image vertically into temporary image verticalFilter(src, src_width, src_height, tmp, src_width, dst_height); // scale temporary image horizontally into result image horizontalFilter(tmp, src_width, dst_height, dst, dst_width, dst_height); // free temporary image FreeImage_Unload(tmp); } return dst; }
FIBITMAP * DLL_CALLCONV FreeImage_ConvertToFloat(FIBITMAP *dib) { FIBITMAP *src = NULL; FIBITMAP *dst = NULL; if(!FreeImage_HasPixels(dib)) return NULL; FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(dib); // check for allowed conversions switch(src_type) { case FIT_BITMAP: { // allow conversion from 8-bit if((FreeImage_GetBPP(dib) == 8) && (FreeImage_GetColorType(dib) == FIC_MINISBLACK)) { src = dib; } else { src = FreeImage_ConvertToGreyscale(dib); if(!src) return NULL; } break; } case FIT_UINT16: case FIT_RGB16: case FIT_RGBA16: case FIT_RGBF: case FIT_RGBAF: src = dib; break; case FIT_FLOAT: // float type : clone the src return FreeImage_Clone(dib); default: return NULL; } // allocate dst image const unsigned width = FreeImage_GetWidth(src); const unsigned height = FreeImage_GetHeight(src); dst = FreeImage_AllocateT(FIT_FLOAT, 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 float const unsigned src_pitch = FreeImage_GetPitch(src); const unsigned dst_pitch = FreeImage_GetPitch(dst); const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src); BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst); switch(src_type) { case FIT_BITMAP: { for(unsigned y = 0; y < height; y++) { const BYTE *src_pixel = (BYTE*)src_bits; float *dst_pixel = (float*)dst_bits; for(unsigned x = 0; x < width; x++) { // convert and scale to the range [0..1] dst_pixel[x] = (float)(src_pixel[x]) / 255; } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_UINT16: { for(unsigned y = 0; y < height; y++) { const WORD *src_pixel = (WORD*)src_bits; float *dst_pixel = (float*)dst_bits; for(unsigned x = 0; x < width; x++) { // convert and scale to the range [0..1] dst_pixel[x] = (float)(src_pixel[x]) / 65535; } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_RGB16: { for(unsigned y = 0; y < height; y++) { const FIRGB16 *src_pixel = (FIRGB16*)src_bits; float *dst_pixel = (float*)dst_bits; for(unsigned x = 0; x < width; x++) { // convert and scale to the range [0..1] dst_pixel[x] = LUMA_REC709(src_pixel[x].red, src_pixel[x].green, src_pixel[x].blue) / 65535.0F; } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_RGBA16: { for(unsigned y = 0; y < height; y++) { const FIRGBA16 *src_pixel = (FIRGBA16*)src_bits; float *dst_pixel = (float*)dst_bits; for(unsigned x = 0; x < width; x++) { // convert and scale to the range [0..1] dst_pixel[x] = LUMA_REC709(src_pixel[x].red, src_pixel[x].green, src_pixel[x].blue) / 65535.0F; } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_RGBF: { for(unsigned y = 0; y < height; y++) { const FIRGBF *src_pixel = (FIRGBF*)src_bits; float *dst_pixel = (float*)dst_bits; for(unsigned x = 0; x < width; x++) { // convert (assume pixel values are in the range [0..1]) dst_pixel[x] = LUMA_REC709(src_pixel[x].red, src_pixel[x].green, src_pixel[x].blue); } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_RGBAF: { for(unsigned y = 0; y < height; y++) { const FIRGBAF *src_pixel = (FIRGBAF*)src_bits; float *dst_pixel = (float*)dst_bits; for(unsigned x = 0; x < width; x++) { // convert (assume pixel values are in the range [0..1]) dst_pixel[x] = LUMA_REC709(src_pixel[x].red, src_pixel[x].green, src_pixel[x].blue); } src_bits += src_pitch; dst_bits += dst_pitch; } } break; } if(src != dib) { FreeImage_Unload(src); } return dst; }
/** Performs a 5 by 5 gaussian filtering using two 1D convolutions, followed by a subsampling by 2. @param dib Input image @return Returns a blurred image of size SIZE(dib)/2 @see GaussianPyramid */ static FIBITMAP* GaussianLevel5x5(FIBITMAP *dib) { FIBITMAP *h_dib = NULL, *v_dib = NULL, *dst = NULL; float *src_pixel, *dst_pixel; try { const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); if(image_type != FIT_FLOAT) throw(1); const unsigned width = FreeImage_GetWidth(dib); const unsigned height = FreeImage_GetHeight(dib); h_dib = FreeImage_AllocateT(image_type, width, height); v_dib = FreeImage_AllocateT(image_type, width, height); if(!h_dib || !v_dib) throw(1); const unsigned pitch = FreeImage_GetPitch(dib) / sizeof(float); // horizontal convolution dib -> h_dib src_pixel = (float*)FreeImage_GetBits(dib); dst_pixel = (float*)FreeImage_GetBits(h_dib); for(unsigned y = 0; y < height; y++) { // work on line y for(unsigned x = 2; x < width - 2; x++) { dst_pixel[x] = src_pixel[x-2] + src_pixel[x+2] + 4 * (src_pixel[x-1] + src_pixel[x+1]) + 6 * src_pixel[x]; dst_pixel[x] /= 16; } // boundary mirroring dst_pixel[0] = (2 * src_pixel[2] + 8 * src_pixel[1] + 6 * src_pixel[0]) / 16; dst_pixel[1] = (src_pixel[3] + 4 * (src_pixel[0] + src_pixel[2]) + 7 * src_pixel[1]) / 16; dst_pixel[width-2] = (src_pixel[width-4] + 5 * src_pixel[width-1] + 4 * src_pixel[width-3] + 6 * src_pixel[width-2]) / 16; dst_pixel[width-1] = (src_pixel[width-3] + 5 * src_pixel[width-2] + 10 * src_pixel[width-1]) / 16; // next line src_pixel += pitch; dst_pixel += pitch; } // vertical convolution h_dib -> v_dib src_pixel = (float*)FreeImage_GetBits(h_dib); dst_pixel = (float*)FreeImage_GetBits(v_dib); for(unsigned x = 0; x < width; x++) { // work on column x for(unsigned y = 2; y < height - 2; y++) { const unsigned index = y*pitch + x; dst_pixel[index] = src_pixel[index-2*pitch] + src_pixel[index+2*pitch] + 4 * (src_pixel[index-pitch] + src_pixel[index+pitch]) + 6 * src_pixel[index]; dst_pixel[index] /= 16; } // boundary mirroring dst_pixel[x] = (2 * src_pixel[x+2*pitch] + 8 * src_pixel[x+pitch] + 6 * src_pixel[x]) / 16; dst_pixel[x+pitch] = (src_pixel[x+3*pitch] + 4 * (src_pixel[x] + src_pixel[x+2*pitch]) + 7 * src_pixel[x+pitch]) / 16; dst_pixel[(height-2)*pitch+x] = (src_pixel[(height-4)*pitch+x] + 5 * src_pixel[(height-1)*pitch+x] + 4 * src_pixel[(height-3)*pitch+x] + 6 * src_pixel[(height-2)*pitch+x]) / 16; dst_pixel[(height-1)*pitch+x] = (src_pixel[(height-3)*pitch+x] + 5 * src_pixel[(height-2)*pitch+x] + 10 * src_pixel[(height-1)*pitch+x]) / 16; } FreeImage_Unload(h_dib); h_dib = NULL; // perform downsampling dst = FreeImage_Rescale(v_dib, width/2, height/2, FILTER_BILINEAR); FreeImage_Unload(v_dib); return dst; } catch(int) { if(h_dib) FreeImage_Unload(h_dib); if(v_dib) FreeImage_Unload(v_dib); if(dst) FreeImage_Unload(dst); return NULL; } }
/** Compute the gradient attenuation function PHI(x, y) @param gradients Gradient pyramid (nlevels levels) @param avgGrad Average gradient on each level (array of size nlevels) @param nlevels Number of levels @param alpha Parameter alpha in the paper @param beta Parameter beta in the paper @return Returns the attenuation matrix Phi if successful, returns NULL otherwise */ static FIBITMAP* PhiMatrix(FIBITMAP **gradients, float *avgGrad, int nlevels, float alpha, float beta) { float *src_pixel, *dst_pixel; FIBITMAP **phi = NULL; try { phi = (FIBITMAP**)malloc(nlevels * sizeof(FIBITMAP*)); if(!phi) throw(1); memset(phi, 0, nlevels * sizeof(FIBITMAP*)); for(int k = nlevels-1; k >= 0; k--) { // compute phi(k) FIBITMAP *Gk = gradients[k]; const unsigned width = FreeImage_GetWidth(Gk); const unsigned height = FreeImage_GetHeight(Gk); const unsigned pitch = FreeImage_GetPitch(Gk) / sizeof(float); // parameter alpha is 0.1 times the average gradient magnitude // also, note the factor of 2**k in the denominator; // that is there to correct for the fact that an average gradient avgGrad(H) over 2**k pixels // in the original image will appear as a gradient grad(Hk) = 2**k*avgGrad(H) over a single pixel in Hk. float ALPHA = alpha * avgGrad[k] * (float)((int)1 << k); if(ALPHA == 0) ALPHA = EPSILON; phi[k] = FreeImage_AllocateT(FIT_FLOAT, width, height); if(!phi[k]) throw(1); src_pixel = (float*)FreeImage_GetBits(Gk); dst_pixel = (float*)FreeImage_GetBits(phi[k]); for(unsigned y = 0; y < height; y++) { for(unsigned x = 0; x < width; x++) { // compute (alpha / grad) * (grad / alpha) ** beta const float v = src_pixel[x] / ALPHA; const float value = (float)pow((float)v, (float)(beta-1)); dst_pixel[x] = (value > 1) ? 1 : value; } // next line src_pixel += pitch; dst_pixel += pitch; } if(k < nlevels-1) { // compute PHI(k) = L( PHI(k+1) ) * phi(k) FIBITMAP *L = FreeImage_Rescale(phi[k+1], width, height, FILTER_BILINEAR); if(!L) throw(1); src_pixel = (float*)FreeImage_GetBits(L); dst_pixel = (float*)FreeImage_GetBits(phi[k]); for(unsigned y = 0; y < height; y++) { for(unsigned x = 0; x < width; x++) { dst_pixel[x] *= src_pixel[x]; } // next line src_pixel += pitch; dst_pixel += pitch; } FreeImage_Unload(L); // PHI(k+1) is no longer needed FreeImage_Unload(phi[k+1]); phi[k+1] = NULL; } // next level } // get the final result and return FIBITMAP *dst = phi[0]; free(phi); return dst; } catch(int) { if(phi) { for(int k = nlevels-1; k >= 0; k--) { if(phi[k]) FreeImage_Unload(phi[k]); } free(phi); } return NULL; } }
/** Load the Bayer matrix (unprocessed raw data) as a FIT_UINT16 image. Note that some formats don't have a Bayer matrix (e.g. Foveon, Canon sRAW, demosaiced DNG files). @param RawProcessor Libraw handle @return Returns the loaded dib if successfull, returns NULL otherwise */ static FIBITMAP * libraw_LoadUnprocessedData(LibRaw *RawProcessor) { FIBITMAP *dib = NULL; try { // unpack data if(RawProcessor->unpack() != LIBRAW_SUCCESS) { throw "LibRaw : failed to unpack data"; } // check for a supported Bayer format if(!(RawProcessor->imgdata.idata.filters || RawProcessor->imgdata.idata.colors == 1)) { throw "LibRaw : only Bayer-pattern RAW files are supported"; } // allocate output dib const unsigned width = RawProcessor->imgdata.sizes.raw_width; const unsigned height = RawProcessor->imgdata.sizes.raw_height; const size_t line_size = width * sizeof(WORD); const WORD *src_bits = (WORD*)RawProcessor->imgdata.rawdata.raw_image; if(src_bits) { dib = FreeImage_AllocateT(FIT_UINT16, width, height); } if(!dib) { throw FI_MSG_ERROR_DIB_MEMORY; } // retrieve the raw image for(unsigned y = 0; y < height; y++) { WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dib, height - 1 - y); memcpy(dst_bits, src_bits, line_size); src_bits += width; } // store metadata needed for post-processing { char value[512]; const libraw_image_sizes_t *sizes = &RawProcessor->imgdata.sizes; // image output width & height { sprintf(value, "%d", sizes->iwidth); FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.Output.Width", value); sprintf(value, "%d", sizes->iheight); FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.Output.Height", value); } // image output frame { const unsigned f_left = sizes->left_margin; const unsigned f_top = sizes->top_margin; const unsigned f_width = sizes->width; const unsigned f_height = sizes->height; sprintf(value, "%d", f_left); FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.Frame.Left", value); sprintf(value, "%d", f_top); FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.Frame.Top", value); sprintf(value, "%d", f_width); FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.Frame.Width", value); sprintf(value, "%d", f_height); FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.Frame.Height", value); } // Bayer pattern // Mask describing the order of color pixels in the matrix. // This field describe 16 pixels (8 rows with two pixels in each, from left to right and from top to bottom). if(RawProcessor->imgdata.idata.filters) { // description of colors numbered from 0 to 3 (RGBG,RGBE,GMCY, or GBTG) char *cdesc = RawProcessor->imgdata.idata.cdesc; if(!cdesc[3]) { cdesc[3] = 'G'; } char *pattern = &value[0]; for(int i = 0; i < 16; i++) { pattern[i] = cdesc[ RawProcessor->fcol(i >> 1, i & 1) ]; } pattern[16] = 0; FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.BayerPattern", value); } } return dib; } catch(const char *text) {
FIBITMAP * DLL_CALLCONV FreeImage_ConvertToUINT16(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 greyscale if needed if((FreeImage_GetBPP(dib) == 8) && (FreeImage_GetColorType(dib) == FIC_MINISBLACK)) { src = dib; } else { src = FreeImage_ConvertToGreyscale(dib); if(!src) return NULL; } break; } case FIT_UINT16: // UINT16 type : clone the src return FreeImage_Clone(dib); break; case FIT_RGB16: // allow conversion from 48-bit RGB src = 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_UINT16, width, height); if(!dst) return NULL; // copy metadata from src to dst FreeImage_CloneMetadata(dst, src); // convert from src type to UINT16 switch(src_type) { case FIT_BITMAP: { for(unsigned y = 0; y < height; y++) { const BYTE *src_bits = (BYTE*)FreeImage_GetScanLine(src, y); WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y); for(unsigned x = 0; x < width; x++) { dst_bits[x] = src_bits[x] << 8; } } } break; case FIT_RGB16: { for(unsigned y = 0; y < height; y++) { const FIRGB16 *src_bits = (FIRGB16*)FreeImage_GetScanLine(src, y); WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y); for(unsigned x = 0; x < width; x++) { // convert to grey dst_bits[x] = (WORD)LUMA_REC709(src_bits[x].red, src_bits[x].green, src_bits[x].blue); } } } break; case FIT_RGBA16: { for(unsigned y = 0; y < height; y++) { const FIRGBA16 *src_bits = (FIRGBA16*)FreeImage_GetScanLine(src, y); WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y); for(unsigned x = 0; x < width; x++) { // convert to grey dst_bits[x] = (WORD)LUMA_REC709(src_bits[x].red, src_bits[x].green, src_bits[x].blue); } } } break; default: break; } if(src != dib) { FreeImage_Unload(src); } return dst; }
template<class Tsrc> FIBITMAP* FFT2D<Tsrc>::FFT(FIBITMAP *src) { int height, width; int i=0, x, y; int dims[2]; int ndims = 2; size_t bufsize; Tsrc *bits; FICOMPLEX *outbits; FIBITMAP *dst = NULL; kiss_fftnd_cfg st; kiss_fft_cpx* fftbuf; kiss_fft_cpx* fftoutbuf; kiss_fft_cpx* tmp_fftoutbuf; // Dims needs to be {rows, cols}, if you have contiguous rows. dims[0] = height = FreeImage_GetHeight(src); dims[1] = width = FreeImage_GetWidth(src); bufsize = width * height * sizeof(kiss_fft_cpx); fftbuf = (kiss_fft_cpx*) malloc(bufsize); tmp_fftoutbuf = fftoutbuf = (kiss_fft_cpx*) malloc(bufsize); CheckMemory(fftbuf); CheckMemory(fftoutbuf); memset(fftbuf,0,bufsize); memset(tmp_fftoutbuf,0,bufsize); st = kiss_fftnd_alloc (dims, ndims, 0, 0, 0); for(y = height - 1; y >= 0; y--) { bits = (Tsrc *) FreeImage_GetScanLine(src, y); for(x=0; x < width; x++) { fftbuf[i].r = (float) bits[x]; fftbuf[i].i = 0.0; i++; } } kiss_fftnd(st, fftbuf, tmp_fftoutbuf); if ( (dst = FreeImage_AllocateT(FIT_COMPLEX, width, height, 32, 0, 0, 0)) == NULL ) goto Error; for(y = height - 1; y >= 0; y--) { outbits = (FICOMPLEX *) FreeImage_GetScanLine(dst, y); for(x=0; x < width; x++) { (outbits + x)->r = (double)((tmp_fftoutbuf + x)->r); (outbits + x)->i = (double)((tmp_fftoutbuf + x)->i); } tmp_fftoutbuf += width; } Error: free(fftbuf); free(fftoutbuf); free(st); return dst; }
/** Compute gradients in x and y directions, attenuate them with the attenuation matrix, then compute the divergence div G from the attenuated gradient. @param H Normalized luminance @param PHI Attenuation matrix @return Returns the divergence matrix if successful, returns NULL otherwise */ static FIBITMAP* Divergence(FIBITMAP *H, FIBITMAP *PHI) { FIBITMAP *Gx = NULL, *Gy = NULL, *divG = NULL; float *phi, *h, *gx, *gy, *divg; try { const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(H); if(image_type != FIT_FLOAT) throw(1); const unsigned width = FreeImage_GetWidth(H); const unsigned height = FreeImage_GetHeight(H); Gx = FreeImage_AllocateT(image_type, width, height); if(!Gx) throw(1); Gy = FreeImage_AllocateT(image_type, width, height); if(!Gy) throw(1); const unsigned pitch = FreeImage_GetPitch(H) / sizeof(float); // perform gradient attenuation phi = (float*)FreeImage_GetBits(PHI); h = (float*)FreeImage_GetBits(H); gx = (float*)FreeImage_GetBits(Gx); gy = (float*)FreeImage_GetBits(Gy); for(unsigned y = 0; y < height; y++) { const unsigned s = (y+1 == height ? y : y+1); for(unsigned x = 0; x < width; x++) { const unsigned e = (x+1 == width ? x : x+1); // forward difference const unsigned index = y*pitch + x; const float phi_xy = phi[index]; const float h_xy = h[index]; gx[x] = (h[y*pitch+e] - h_xy) * phi_xy; // [H(x+1, y) - H(x, y)] * PHI(x, y) gy[x] = (h[s*pitch+x] - h_xy) * phi_xy; // [H(x, y+1) - H(x, y)] * PHI(x, y) } // next line gx += pitch; gy += pitch; } // calculate the divergence divG = FreeImage_AllocateT(image_type, width, height); if(!divG) throw(1); gx = (float*)FreeImage_GetBits(Gx); gy = (float*)FreeImage_GetBits(Gy); divg = (float*)FreeImage_GetBits(divG); for(unsigned y0 = 0; y0 < height; y0++) { for(unsigned x = 0; x < width; x++) { // backward difference approximation // divG = Gx(x, y) - Gx(x-1, y) + Gy(x, y) - Gy(x, y-1) const unsigned index = y0*pitch + x; divg[index] = gx[index] + gy[index]; if(x > 0) divg[index] -= gx[index-1]; if(y0 > 0) divg[index] -= gy[index-pitch]; } } // no longer needed ... FreeImage_Unload(Gx); FreeImage_Unload(Gy); // return the divergence return divG; } catch(int) { if(Gx) FreeImage_Unload(Gx); if(Gy) FreeImage_Unload(Gy); if(divG) FreeImage_Unload(divG); return NULL; } }
static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { char line_buffer[PFM_MAXLINE]; char id_one = 0, id_two = 0; FIBITMAP *dib = NULL; float *lineBuffer = NULL; if (!handle) return NULL; try { FREE_IMAGE_TYPE image_type = FIT_UNKNOWN; // Read the first two bytes of the file to determine the file format // "PF" = color image // "Pf" = greyscale image io->read_proc(&id_one, 1, 1, handle); io->read_proc(&id_two, 1, 1, handle); if(id_one == 'P') { if(id_two == 'F') { image_type = FIT_RGBF; } else if(id_two == 'f') { image_type = FIT_FLOAT; } } if(image_type == FIT_UNKNOWN) { // signature error throw FI_MSG_ERROR_MAGIC_NUMBER; } // Read the header information: width, height and the scale value unsigned width = (unsigned) pfm_get_int(io, handle); unsigned height = (unsigned) pfm_get_int(io, handle); float scalefactor = 1; BOOL bResult = pfm_get_line(io, handle, line_buffer, PFM_MAXLINE); if(bResult) { bResult = (sscanf(line_buffer, "%f", &scalefactor) == 1) ? TRUE : FALSE; } if(!bResult) { throw "Read error: invalid PFM header"; } // Create a new DIB dib = FreeImage_AllocateT(image_type, width, height); if (dib == NULL) { throw FI_MSG_ERROR_DIB_MEMORY; } // Read the image... if(image_type == FIT_RGBF) { const unsigned lineWidth = 3 * width; lineBuffer = (float*)malloc(lineWidth * sizeof(float)); if(!lineBuffer) { throw FI_MSG_ERROR_MEMORY; } for (unsigned y = 0; y < height; y++) { FIRGBF *bits = (FIRGBF*)FreeImage_GetScanLine(dib, height - 1 - y); if(io->read_proc(lineBuffer, sizeof(float), lineWidth, handle) != lineWidth) { throw "Read error"; } float *channel = lineBuffer; if(scalefactor > 0) { // MSB for (unsigned x = 0; x < width; x++) { REVERSEBYTES(channel++, &bits[x].red); REVERSEBYTES(channel++, &bits[x].green); REVERSEBYTES(channel++, &bits[x].blue); } } else { // LSB for (unsigned x = 0; x < width; x++) { bits[x].red = *channel++; bits[x].green = *channel++; bits[x].blue = *channel++; } } } free(lineBuffer); lineBuffer = NULL; } else if(image_type == FIT_FLOAT) { const unsigned lineWidth = width; lineBuffer = (float*)malloc(lineWidth * sizeof(float)); if(!lineBuffer) { throw FI_MSG_ERROR_MEMORY; } for (unsigned y = 0; y < height; y++) { float *bits = (float*)FreeImage_GetScanLine(dib, height - 1 - y); if(io->read_proc(lineBuffer, sizeof(float), lineWidth, handle) != lineWidth) { throw "Read error"; } float *channel = lineBuffer; if(scalefactor > 0) { // MSB - File is Big endian for (unsigned x = 0; x < width; x++) { REVERSEBYTES(channel++, &bits[x]); } } else { // LSB - File is Little Endian for (unsigned x = 0; x < width; x++) { bits[x] = *channel++; } } } free(lineBuffer); lineBuffer = NULL; } return dib; } catch (const char *text) { if(lineBuffer) free(lineBuffer); if(dib) FreeImage_Unload(dib); if(NULL != text) { FreeImage_OutputMessageProc(s_format_id, text); } return NULL; } }
template<class Tsrc> FIBITMAP* CONVERT_TO_BYTE<Tsrc>::convert(FIBITMAP *src, BOOL scale_linear) { FIBITMAP *dst = NULL; unsigned x, y; unsigned width = FreeImage_GetWidth(src); unsigned height = FreeImage_GetHeight(src); // allocate a 8-bit dib dst = FreeImage_AllocateT(FIT_BITMAP, width, height, 8, 0, 0, 0); if(!dst) return NULL; // build a greyscale palette RGBQUAD *pal = FreeImage_GetPalette(dst); for(int i = 0; i < 256; i++) { pal[i].rgbRed = (BYTE)i; pal[i].rgbGreen = (BYTE)i; pal[i].rgbBlue = (BYTE)i; } // convert the src image to dst // (FIBITMAP are stored upside down) if(scale_linear) { Tsrc max, min; double scale; // find the min and max value of the image Tsrc l_min, l_max; min = 255, max = 0; for(y = 0; y < height; y++) { Tsrc *bits = reinterpret_cast<Tsrc*>(FreeImage_GetScanLine(src, y)); MAXMIN(bits, width, l_max, l_min); if(l_max > max) max = l_max; if(l_min < min) min = l_min; } if(max == min) { max = 255; min = 0; } // compute the scaling factor scale = 255 / (double)(max - min); // scale to 8-bit for(y = 0; y < height; y++) { Tsrc *src_bits = reinterpret_cast<Tsrc*>(FreeImage_GetScanLine(src, y)); BYTE *dst_bits = FreeImage_GetScanLine(dst, y); for(x = 0; x < width; x++) { dst_bits[x] = (BYTE)( scale * (src_bits[x] - min) + 0.5); } } } else { for(y = 0; y < height; y++) { Tsrc *src_bits = reinterpret_cast<Tsrc*>(FreeImage_GetScanLine(src, y)); BYTE *dst_bits = FreeImage_GetScanLine(dst, y); for(x = 0; x < width; x++) { // rounding int q = int(src_bits[x] + 0.5); dst_bits[x] = (BYTE) MIN(255, MAX(0, q)); } } } return dst; }
/** Full Multigrid Algorithm for solution of linear elliptic equation, here the model problem (19.0.6). On input u[0..n-1][0..n-1] contains the right-hand side ñ, while on output it returns the solution. The dimension n must be of the form 2^j + 1 for some integer j. (j is actually the number of grid levels used in the solution, called ng below.) ncycle is the number of V-cycles to be used at each level. */ static BOOL fmg_mglin(FIBITMAP *U, int n, int ncycle) { int j, jcycle, jj, jpost, jpre, nf, ngrid; FIBITMAP **IRHO = NULL; FIBITMAP **IU = NULL; FIBITMAP **IRHS = NULL; FIBITMAP **IRES = NULL; int ng = 0; // number of allocated grids // -------------------------------------------------------------------------- #define _CREATE_ARRAY_GRID_(array, array_size) \ array = (FIBITMAP**)malloc(array_size * sizeof(FIBITMAP*));\ if(!array) throw(1);\ memset(array, 0, array_size * sizeof(FIBITMAP*)) #define _FREE_ARRAY_GRID_(array, array_size) \ if(NULL != array) {\ for(int k = 0; k < array_size; k++) {\ if(NULL != array[k]) {\ FreeImage_Unload(array[k]); array[k] = NULL;\ }\ }\ free(array);\ } // -------------------------------------------------------------------------- try { int nn = n; // check grid size and grid levels while (nn >>= 1) ng++; if (n != 1 + (1L << ng)) { FreeImage_OutputMessageProc(FIF_UNKNOWN, "Multigrid algorithm: n = %d, while n-1 must be a power of 2.", n); throw(1); } if (ng > NGMAX) { FreeImage_OutputMessageProc(FIF_UNKNOWN, "Multigrid algorithm: ng = %d while NGMAX = %d, increase NGMAX.", ng, NGMAX); throw(1); } // allocate grid arrays { _CREATE_ARRAY_GRID_(IRHO, ng); _CREATE_ARRAY_GRID_(IU, ng); _CREATE_ARRAY_GRID_(IRHS, ng); _CREATE_ARRAY_GRID_(IRES, ng); } nn = n/2 + 1; ngrid = ng - 2; // allocate storage for r.h.s. on grid (ng - 2) ... IRHO[ngrid] = FreeImage_AllocateT(FIT_FLOAT, nn, nn); if(!IRHO[ngrid]) throw(1); // ... and fill it by restricting from the fine grid fmg_restrict(IRHO[ngrid], U, nn); // similarly allocate storage and fill r.h.s. on all coarse grids. while (nn > 3) { nn = nn/2 + 1; ngrid--; IRHO[ngrid] = FreeImage_AllocateT(FIT_FLOAT, nn, nn); if(!IRHO[ngrid]) throw(1); fmg_restrict(IRHO[ngrid], IRHO[ngrid+1], nn); } nn = 3; IU[0] = FreeImage_AllocateT(FIT_FLOAT, nn, nn); if(!IU[0]) throw(1); IRHS[0] = FreeImage_AllocateT(FIT_FLOAT, nn, nn); if(!IRHS[0]) throw(1); // initial solution on coarsest grid fmg_solve(IU[0], IRHO[0]); // irho[0] no longer needed ... FreeImage_Unload(IRHO[0]); IRHO[0] = NULL; ngrid = ng; // nested iteration loop for (j = 1; j < ngrid; j++) { nn = 2*nn - 1; IU[j] = FreeImage_AllocateT(FIT_FLOAT, nn, nn); if(!IU[j]) throw(1); IRHS[j] = FreeImage_AllocateT(FIT_FLOAT, nn, nn); if(!IRHS[j]) throw(1); IRES[j] = FreeImage_AllocateT(FIT_FLOAT, nn, nn); if(!IRES[j]) throw(1); fmg_prolongate(IU[j], IU[j-1], nn); // interpolate from coarse grid to next finer grid // set up r.h.s. fmg_copyArray(IRHS[j], j != (ngrid - 1) ? IRHO[j] : U); // V-cycle loop for (jcycle = 0; jcycle < ncycle; jcycle++) { nf = nn; // downward stoke of the V for (jj = j; jj >= 1; jj--) { // pre-smoothing for (jpre = 0; jpre < NPRE; jpre++) { fmg_relaxation(IU[jj], IRHS[jj], nf); } fmg_residual(IRES[jj], IU[jj], IRHS[jj], nf); nf = nf/2 + 1; // restriction of the residual is the next r.h.s. fmg_restrict(IRHS[jj-1], IRES[jj], nf); // zero for initial guess in next relaxation fmg_fillArrayWithZeros(IU[jj-1]); } // bottom of V: solve on coarsest grid fmg_solve(IU[0], IRHS[0]); nf = 3; // upward stroke of V. for (jj = 1; jj <= j; jj++) { nf = 2*nf - 1; // use res for temporary storage inside addint fmg_addint(IU[jj], IU[jj-1], IRES[jj], nf); // post-smoothing for (jpost = 0; jpost < NPOST; jpost++) { fmg_relaxation(IU[jj], IRHS[jj], nf); } } } } // return solution in U fmg_copyArray(U, IU[ngrid-1]); // delete allocated arrays _FREE_ARRAY_GRID_(IRES, ng); _FREE_ARRAY_GRID_(IRHS, ng); _FREE_ARRAY_GRID_(IU, ng); _FREE_ARRAY_GRID_(IRHO, ng); return TRUE; } catch(int) { // delete allocated arrays _FREE_ARRAY_GRID_(IRES, ng); _FREE_ARRAY_GRID_(IRHS, ng); _FREE_ARRAY_GRID_(IU, ng); _FREE_ARRAY_GRID_(IRHO, ng); return FALSE; } }