Exemple #1
0
/**
 * 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;
}
Exemple #4
0
/**
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;
	}
Exemple #12
0
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;
	}
Exemple #19
0
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;
}
Exemple #20
0
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;
} 
Exemple #21
0
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;
}
Exemple #22
0
/**
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;
	}
}
Exemple #23
0
/**
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;
	}
}
Exemple #24
0
/**
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;
}
Exemple #27
0
/**
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;
	}
}
Exemple #28
0
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;
	}

}
Exemple #29
0
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;
	}
}