Exemplo n.º 1
0
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
	bool bUseRgbaInterface = false;
	FIBITMAP *dib = NULL;	

	if(!handle) {
		return NULL;
	}

	try {
		BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;

		// save the stream starting point
		const long stream_start = io->tell_proc(handle);

		// wrap the FreeImage IO stream
		C_IStream istream(io, handle);

		// open the file
		Imf::InputFile file(istream);

		// get file info			
		const Imath::Box2i &dataWindow = file.header().dataWindow();
		int width  = dataWindow.max.x - dataWindow.min.x + 1;
		int height = dataWindow.max.y - dataWindow.min.y + 1;

		//const Imf::Compression &compression = file.header().compression();

		const Imf::ChannelList &channels = file.header().channels();

		// check the number of components and check for a coherent format

		std::string exr_color_model;
		Imf::PixelType pixel_type = Imf::HALF;
		FREE_IMAGE_TYPE image_type = FIT_UNKNOWN;
		int components = 0;
		bool bMixedComponents = false;

		for (Imf::ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
			components++;
			if(components == 1) {
				exr_color_model += i.name();
				pixel_type = i.channel().type;
			} else {
				exr_color_model += "/";
				exr_color_model += i.name();
				if (i.channel().type != pixel_type) {
					bMixedComponents = true;
				}
			}
		}

		if(bMixedComponents) {
			bool bHandled = false;
			// we may have a RGBZ or RGBAZ image ... 
			if(components > 4) {
				if(channels.findChannel("R") && channels.findChannel("G") && channels.findChannel("B") && channels.findChannel("A")) {
					std::string msg = "Warning: converting color model " + exr_color_model + " to RGBA color model";
					FreeImage_OutputMessageProc(s_format_id, msg.c_str());
					bHandled = true;
				}
			}
			else if(components > 3) {
				if(channels.findChannel("R") && channels.findChannel("G") && channels.findChannel("B")) {
					std::string msg = "Warning: converting color model " + exr_color_model + " to RGB color model";
					FreeImage_OutputMessageProc(s_format_id, msg.c_str());
					bHandled = true;
				}
			}
			if(!bHandled) {
				THROW (Iex::InputExc, "Unable to handle mixed component types (color model = " << exr_color_model << ")");
			} 
		}

		switch(pixel_type) {
			case Imf::UINT:
				THROW (Iex::InputExc, "Unsupported format: UINT");
				break;
			case Imf::HALF:
			case Imf::FLOAT:
			default:
				break;
		}

		// check for supported image color models
		// --------------------------------------------------------------

		if((components == 1) || (components == 2)) {				
			// if the image is gray-alpha (YA), ignore the alpha channel
			if((components == 1) && channels.findChannel("Y")) {
				image_type = FIT_FLOAT;
				components = 1;
			} else {
				std::string msg = "Warning: loading color model " + exr_color_model + " as Y color model";
				FreeImage_OutputMessageProc(s_format_id, msg.c_str());
				image_type = FIT_FLOAT;
				// ignore the other channel
				components = 1;
			}
		} else if(components == 3) {
			if(channels.findChannel("R") && channels.findChannel("G") && channels.findChannel("B")) {
				image_type = FIT_RGBF;
			}
			else if(channels.findChannel("BY") && channels.findChannel("RY") && channels.findChannel("Y")) {
				image_type = FIT_RGBF;
				bUseRgbaInterface = true;
			}
		} else if(components >= 4) {
			if(channels.findChannel("R") && channels.findChannel("G") && channels.findChannel("B")) {
				if(channels.findChannel("A")) {
					if(components > 4) {
						std::string msg = "Warning: converting color model " + exr_color_model + " to RGBA color model";
						FreeImage_OutputMessageProc(s_format_id, msg.c_str());
					}
					image_type = FIT_RGBAF;
					// ignore other layers if there is more than one alpha layer
					components = 4;
				} else {
					std::string msg = "Warning: converting color model " + exr_color_model + " to RGB color model";
					FreeImage_OutputMessageProc(s_format_id, msg.c_str());

					image_type = FIT_RGBF;
					// ignore other channels
					components = 3;					
				}
			}
		}

		if(image_type == FIT_UNKNOWN) {
			THROW (Iex::InputExc, "Unsupported color model: " << exr_color_model);
		}

		// allocate a new dib
		dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, 0);
		if(!dib) THROW (Iex::NullExc, FI_MSG_ERROR_MEMORY);

		// try to load the preview image
		// --------------------------------------------------------------

		if(file.header().hasPreviewImage()) {
			const Imf::PreviewImage& preview = file.header().previewImage();
			const unsigned thWidth = preview.width();
			const unsigned thHeight = preview.height();
			
			FIBITMAP* thumbnail = FreeImage_Allocate(thWidth, thHeight, 32);
			if(thumbnail) {
				const Imf::PreviewRgba *src_line = preview.pixels();
				BYTE *dst_line = FreeImage_GetScanLine(thumbnail, thHeight - 1);
				const unsigned dstPitch = FreeImage_GetPitch(thumbnail);
				
				for (unsigned y = 0; y < thHeight; ++y) {
					const Imf::PreviewRgba *src_pixel = src_line;
					RGBQUAD* dst_pixel = (RGBQUAD*)dst_line;
					
					for(unsigned x = 0; x < thWidth; ++x) {
						dst_pixel->rgbRed = src_pixel->r;
						dst_pixel->rgbGreen = src_pixel->g;
						dst_pixel->rgbBlue = src_pixel->b;
						dst_pixel->rgbReserved = src_pixel->a;				
						src_pixel++;
						dst_pixel++;
					}
					src_line += thWidth;
					dst_line -= dstPitch;
				}
				FreeImage_SetThumbnail(dib, thumbnail);
				FreeImage_Unload(thumbnail);
			}
		}

		if(header_only) {
			// header only mode
			return dib;
		}

		// load pixels
		// --------------------------------------------------------------

		const BYTE *bits = FreeImage_GetBits(dib);			// pointer to our pixel buffer
		const size_t bytespp = sizeof(float) * components;	// size of our pixel in bytes
		const unsigned pitch = FreeImage_GetPitch(dib);		// size of our yStride in bytes

		Imf::PixelType pixelType = Imf::FLOAT;	// load as float data type;
		
		if(bUseRgbaInterface) {
			// use the RGBA interface (used when loading RY BY Y images )

			const int chunk_size = 16;

			BYTE *scanline = (BYTE*)bits;

			// re-open using the RGBA interface
			io->seek_proc(handle, stream_start, SEEK_SET);
			Imf::RgbaInputFile rgbaFile(istream);

			// read the file in chunks
			Imath::Box2i dw = dataWindow;
			Imf::Array2D<Imf::Rgba> chunk(chunk_size, width);
			while (dw.min.y <= dw.max.y) {
				// read a chunk
				rgbaFile.setFrameBuffer (&chunk[0][0] - dw.min.x - dw.min.y * width, 1, width);
				rgbaFile.readPixels (dw.min.y, MIN(dw.min.y + chunk_size - 1, dw.max.y));
				// fill the dib
				const int y_max = ((dw.max.y - dw.min.y) <= chunk_size) ? (dw.max.y - dw.min.y) : chunk_size;
				for(int y = 0; y < y_max; y++) {
					FIRGBF *pixel = (FIRGBF*)scanline;
					const Imf::Rgba *half_rgba = chunk[y];
					for(int x = 0; x < width; x++) {
						// convert from half to float
						pixel[x].red = half_rgba[x].r;
						pixel[x].green = half_rgba[x].g;
						pixel[x].blue = half_rgba[x].b;
					}
					// next line
					scanline += pitch;
				}
				// next chunk
				dw.min.y += chunk_size;
			}

		} else {
			// use the low level interface

			// build a frame buffer (i.e. what we want on output)
			Imf::FrameBuffer frameBuffer;

			// allow dataWindow with minimal bounds different form zero
			size_t offset = - dataWindow.min.x * bytespp - dataWindow.min.y * pitch;

			if(components == 1) {
				frameBuffer.insert ("Y",	// name
					Imf::Slice (pixelType,	// type
					(char*)(bits + offset), // base
					bytespp,				// xStride
					pitch,					// yStride
					1, 1,					// x/y sampling
					0.0));					// fillValue
			} else if((components == 3) || (components == 4)) {
				const char *channel_name[4] = { "R", "G", "B", "A" };

				for(int c = 0; c < components; c++) {
					frameBuffer.insert (
						channel_name[c],					// name
						Imf::Slice (pixelType,				// type
						(char*)(bits + c * sizeof(float) + offset), // base
						bytespp,							// xStride
						pitch,								// yStride
						1, 1,								// x/y sampling
						0.0));								// fillValue
				}
			}

			// read the file
			file.setFrameBuffer(frameBuffer);
			file.readPixels(dataWindow.min.y, dataWindow.max.y);
		}

		// lastly, flip dib lines
		FreeImage_FlipVertical(dib);

	}
	catch(Iex::BaseExc & e) {
		if(dib != NULL) {
			FreeImage_Unload(dib);
		}
		FreeImage_OutputMessageProc(s_format_id, e.what());
		return NULL;
	}

	return dib;
}
Exemplo n.º 2
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;
	}

	BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;

	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_AllocateHeaderT(header_only, image_type, width, height);
		if (dib == NULL) {
			throw FI_MSG_ERROR_DIB_MEMORY;
		}

		if(header_only) {
			// header only mode
			return dib;
		}

		// 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;
	}

}
Exemplo n.º 3
0
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;
	png_uint_32 width, height;
	int color_type;
	int bit_depth;
	int pixel_depth = 0;	// pixel_depth = bit_depth * channels

	FIBITMAP *dib = NULL;
	png_bytepp row_pointers = NULL;

    fi_ioStructure fio;
    fio.s_handle = handle;
	fio.s_io = io;
    
	if (handle) {
		BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;

		try {		
			// check to see if the file is in fact a PNG file

			BYTE png_check[PNG_BYTES_TO_CHECK];

			io->read_proc(png_check, PNG_BYTES_TO_CHECK, 1, handle);

			if (png_sig_cmp(png_check, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0) {
				return NULL;	// Bad signature
			}
			
			// create the chunk manage structure

			png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, error_handler, warning_handler);

			if (!png_ptr) {
				return NULL;			
			}

			// create the info structure

		    info_ptr = png_create_info_struct(png_ptr);

			if (!info_ptr) {
				png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
				return NULL;
			}

			// init the IO

			png_set_read_fn(png_ptr, &fio, _ReadProc);

            if (setjmp(png_jmpbuf(png_ptr))) {
				png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
				return NULL;
			}

			// because we have already read the signature...

			png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);

			// read the IHDR chunk

			png_read_info(png_ptr, info_ptr);
			png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL);

			// configure the decoder

			FREE_IMAGE_TYPE image_type = FIT_BITMAP;

			if(!ConfigureDecoder(png_ptr, info_ptr, flags, &image_type)) {
				throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
			}

			// update image info

			color_type = png_get_color_type(png_ptr, info_ptr);
			bit_depth = png_get_bit_depth(png_ptr, info_ptr);
			pixel_depth = bit_depth * png_get_channels(png_ptr, info_ptr);

			// create a dib and write the bitmap header
			// set up the dib palette, if needed

			switch (color_type) {
				case PNG_COLOR_TYPE_RGB:
				case PNG_COLOR_TYPE_RGB_ALPHA:
					dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
					break;

				case PNG_COLOR_TYPE_PALETTE:
					dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
					if(dib) {
						png_colorp png_palette = NULL;
						int palette_entries = 0;

						png_get_PLTE(png_ptr,info_ptr, &png_palette, &palette_entries);

						palette_entries = MIN((unsigned)palette_entries, FreeImage_GetColorsUsed(dib));

						// store the palette

						RGBQUAD *palette = FreeImage_GetPalette(dib);
						for(int i = 0; i < palette_entries; i++) {
							palette[i].rgbRed   = png_palette[i].red;
							palette[i].rgbGreen = png_palette[i].green;
							palette[i].rgbBlue  = png_palette[i].blue;
						}
					}
					break;

				case PNG_COLOR_TYPE_GRAY:
					dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);

					if(dib && (pixel_depth <= 8)) {
						RGBQUAD *palette = FreeImage_GetPalette(dib);
						const int palette_entries = 1 << pixel_depth;

						for(int i = 0; i < palette_entries; i++) {
							palette[i].rgbRed   =
							palette[i].rgbGreen =
							palette[i].rgbBlue  = (BYTE)((i * 255) / (palette_entries - 1));
						}
					}
					break;

				default:
					throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
			}

			if(!dib) {
				throw FI_MSG_ERROR_DIB_MEMORY;
			}

			// store the transparency table

			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
				// array of alpha (transparency) entries for palette
				png_bytep trans_alpha = NULL;
				// number of transparent entries
				int num_trans = 0;						
				// graylevel or color sample values of the single transparent color for non-paletted images
				png_color_16p trans_color = NULL;

				png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color);

				if((color_type == PNG_COLOR_TYPE_GRAY) && trans_color) {
					// single transparent color
					if (trans_color->gray < 256) { 
						BYTE table[256]; 
						memset(table, 0xFF, 256); 
						table[trans_color->gray] = 0; 
						FreeImage_SetTransparencyTable(dib, table, 256); 
					}
					// check for a full transparency table, too
					else if ((trans_alpha) && (pixel_depth <= 8)) {
						FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans);
					}

				} else if((color_type == PNG_COLOR_TYPE_PALETTE) && trans_alpha) {
					// transparency table
					FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans);
				}
			}

			// store the background color (only supported for FIT_BITMAP types)

			if ((image_type == FIT_BITMAP) && png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) {
				// Get the background color to draw transparent and alpha images over.
				// Note that even if the PNG file supplies a background, you are not required to
				// use it - you should use the (solid) application background if it has one.

				png_color_16p image_background = NULL;
				RGBQUAD rgbBkColor;

				if (png_get_bKGD(png_ptr, info_ptr, &image_background)) {
					rgbBkColor.rgbRed      = (BYTE)image_background->red;
					rgbBkColor.rgbGreen    = (BYTE)image_background->green;
					rgbBkColor.rgbBlue     = (BYTE)image_background->blue;
					rgbBkColor.rgbReserved = 0;

					FreeImage_SetBackgroundColor(dib, &rgbBkColor);
				}
			}

			// get physical resolution

			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) {
				png_uint_32 res_x, res_y;
				
				// we'll overload this var and use 0 to mean no phys data,
				// since if it's not in meters we can't use it anyway

				int res_unit_type = PNG_RESOLUTION_UNKNOWN;

				png_get_pHYs(png_ptr,info_ptr, &res_x, &res_y, &res_unit_type);

				if (res_unit_type == PNG_RESOLUTION_METER) {
					FreeImage_SetDotsPerMeterX(dib, res_x);
					FreeImage_SetDotsPerMeterY(dib, res_y);
				}
			}

			// get possible ICC profile

			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP)) {
				png_charp profile_name = NULL;
				png_bytep profile_data = NULL;
				png_uint_32 profile_length = 0;
				int  compression_type;

				png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &profile_length);

				// copy ICC profile data (must be done after FreeImage_AllocateHeader)

				FreeImage_CreateICCProfile(dib, profile_data, profile_length);
			}

			// --- header only mode => clean-up and return

			if (header_only) {
				// get possible metadata (it can be located both before and after the image data)
				ReadMetadata(png_ptr, info_ptr, dib);
				if (png_ptr) {
					// clean up after the read, and free any memory allocated - REQUIRED
					png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
				}
				return dib;
			}

			// set the individual row_pointers to point at the correct offsets

			row_pointers = (png_bytepp)malloc(height * sizeof(png_bytep));

			if (!row_pointers) {
				png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
				FreeImage_Unload(dib);
				return NULL;
			}

			// read in the bitmap bits via the pointer table
			// allow loading of PNG with minor errors (such as images with several IDAT chunks)

			for (png_uint_32 k = 0; k < height; k++) {
				row_pointers[height - 1 - k] = FreeImage_GetScanLine(dib, k);
			}

			png_set_benign_errors(png_ptr, 1);
			png_read_image(png_ptr, row_pointers);

			// check if the bitmap contains transparency, if so enable it in the header

			if (FreeImage_GetBPP(dib) == 32) {
				if (FreeImage_GetColorType(dib) == FIC_RGBALPHA) {
					FreeImage_SetTransparent(dib, TRUE);
				} else {
					FreeImage_SetTransparent(dib, FALSE);
				}
			}
				
			// cleanup

			if (row_pointers) {
				free(row_pointers);
				row_pointers = NULL;
			}

			// read the rest of the file, getting any additional chunks in info_ptr

			png_read_end(png_ptr, info_ptr);

			// get possible metadata (it can be located both before and after the image data)

			ReadMetadata(png_ptr, info_ptr, dib);

			if (png_ptr) {
				// clean up after the read, and free any memory allocated - REQUIRED
				png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
			}

			return dib;

		} catch (const char *text) {
			if (png_ptr) {
				png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
			}
			if (row_pointers) {
				free(row_pointers);
			}
			if (dib) {
				FreeImage_Unload(dib);
			}
			FreeImage_OutputMessageProc(s_format_id, text);
			
			return NULL;
		}
	}			

	return NULL;
}
Exemplo n.º 4
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);
	
	// check for pixel availability ...
	BOOL header_only = FreeImage_HasPixels(dib) ? FALSE : TRUE;

	// allocate a new dib
	FIBITMAP *new_dib = FreeImage_AllocateHeaderT(header_only, 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

		size_t dib_size = FreeImage_GetImageSizeHeader(header_only, 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;

		// reset thumbnail link for new_dib
		((FREEIMAGEHEADER *)new_dib->data)->thumbnail = NULL;

		// 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(std::nothrow) TAGMAP();

				if(dst_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;
				}
			}
		}

		// copy the thumbnail
		FreeImage_SetThumbnail(new_dib, FreeImage_GetThumbnail(dib));

		return new_dib;
	}

	return NULL;
}
Exemplo n.º 5
0
FIBITMAP* psdParser::ReadImageData(FreeImageIO *io, fi_handle handle) {
	if(handle == NULL) 
		return NULL;
	
	bool header_only = (_fi_flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
	
	assert(sizeof(WORD) == 2);
	WORD nCompression = 0;
	io->read_proc(&nCompression, sizeof(nCompression), 1, handle);
	
#ifndef FREEIMAGE_BIGENDIAN
	SwapShort(&nCompression);
#endif
	
	if((nCompression != PSDP_COMPRESSION_NONE && nCompression != PSDP_COMPRESSION_RLE))	{
		FreeImage_OutputMessageProc(_fi_format_id, "Unsupported compression %d", nCompression);
		return NULL;
	}
	
	const unsigned nWidth = _headerInfo._Width;
	const unsigned nHeight = _headerInfo._Height;
	const unsigned nChannels = _headerInfo._Channels;
	const unsigned depth = _headerInfo._BitsPerChannel;
	const unsigned bytes = (depth == 1) ? 1 : depth / 8;
		
	// channel(plane) line (BYTE aligned)
	const unsigned lineSize = (_headerInfo._BitsPerChannel == 1) ? (nWidth + 7) / 8 : nWidth * bytes;
	
	if(nCompression == PSDP_COMPRESSION_RLE && depth > 16) {
		FreeImage_OutputMessageProc(_fi_format_id, "Unsupported RLE with depth %d", depth);
		return NULL;
	}
	
	// build output buffer
	
	FIBITMAP* bitmap = NULL;
	unsigned dstCh = 0;
	
	short mode = _headerInfo._ColourMode;
	
	if(mode == PSDP_MULTICHANNEL && nChannels < 3) {
		// CM 
		mode = PSDP_GRAYSCALE; // C as gray, M as extra channel
	}
		
	bool needPalette = false;
	switch (mode) {
		case PSDP_BITMAP:
		case PSDP_DUOTONE:	
		case PSDP_INDEXED:
		case PSDP_GRAYSCALE:
			dstCh = 1;
			switch(depth) {
				case 16:
				bitmap = FreeImage_AllocateHeaderT(header_only, FIT_UINT16, nWidth, nHeight, depth*dstCh);
				break;
				case 32:
				bitmap = FreeImage_AllocateHeaderT(header_only, FIT_FLOAT, nWidth, nHeight, depth*dstCh);
				break;
				default: // 1-, 8-
				needPalette = true;
				bitmap = FreeImage_AllocateHeader(header_only, nWidth, nHeight, depth*dstCh);
				break;
			}
			break;
		case PSDP_RGB:	
		case PSDP_LAB:		
		case PSDP_CMYK	:
		case PSDP_MULTICHANNEL	:
			// force PSDP_MULTICHANNEL CMY as CMYK
			dstCh = (mode == PSDP_MULTICHANNEL && !header_only) ? 4 : MIN<unsigned>(nChannels, 4);
			assert(dstCh >= 3);
			switch(depth) {
				case 16:
				bitmap = FreeImage_AllocateHeaderT(header_only, dstCh < 4 ? FIT_RGB16 : FIT_RGBA16, nWidth, nHeight, depth*dstCh);
				break;
				case 32:
				bitmap = FreeImage_AllocateHeaderT(header_only, dstCh < 4 ? FIT_RGBF : FIT_RGBAF, nWidth, nHeight, depth*dstCh);
				break;
				default:
				bitmap = FreeImage_AllocateHeader(header_only, nWidth, nHeight, depth*dstCh);
				break;
			}
			break;
		default:
			assert(false);
			break;
	}
	if(!bitmap) {
		throw FI_MSG_ERROR_DIB_MEMORY;
	}
		
	// @todo Add some metadata model
		
	if(header_only) {
		return bitmap;
	}
	
	// Load pixels data

	const unsigned dstChannels = dstCh;
	
	const unsigned dstBpp =  (depth == 1) ? 1 : FreeImage_GetBPP(bitmap)/8;
	const unsigned dstLineSize = FreeImage_GetPitch(bitmap);	
	BYTE* const dst_first_line = FreeImage_GetScanLine(bitmap, nHeight - 1);//<*** flipped
	
	BYTE* line_start = new BYTE[lineSize]; //< fileline cache

	switch ( nCompression ) {
		case PSDP_COMPRESSION_NONE: // raw data	
		{			
			for(unsigned c = 0; c < nChannels; c++) {
				if(c >= dstChannels) {
					// @todo write extra channels
					break; 
				}
					
				const unsigned channelOffset = c * bytes;
				
				BYTE* dst_line_start = dst_first_line;
				for(unsigned h = 0; h < nHeight; ++h, dst_line_start -= dstLineSize) {//<*** flipped

					io->read_proc(line_start, lineSize, 1, handle);
					
					for (BYTE *line = line_start, *dst_line = dst_line_start; line < line_start + lineSize; 
						line += bytes, dst_line += dstBpp) {
#ifdef FREEIMAGE_BIGENDIAN
							memcpy(dst_line + channelOffset, line, bytes);
#else
						// reverse copy bytes
						for (unsigned b = 0; b < bytes; ++b) {
							dst_line[channelOffset + b] = line[(bytes-1) - b];
						}
#endif // FREEIMAGE_BIGENDIAN
					}
				} //< h
			}//< ch
			
			SAFE_DELETE_ARRAY(line_start);
					
		}
		break;
		
		case PSDP_COMPRESSION_RLE: // RLE compression	
		{			
									
			// The RLE-compressed data is preceeded by a 2-byte line size for each row in the data,
			// store an array of these

			// later use this array as WORD rleLineSizeList[nChannels][nHeight];
			WORD *rleLineSizeList = new (std::nothrow) WORD[nChannels*nHeight];

			if(!rleLineSizeList) {
				FreeImage_Unload(bitmap);
				SAFE_DELETE_ARRAY(line_start);
				throw std::bad_alloc();
			}	
			
			io->read_proc(rleLineSizeList, 2, nChannels * nHeight, handle);
			
			WORD largestRLELine = 0;
			for(unsigned ch = 0; ch < nChannels; ++ch) {
				for(unsigned h = 0; h < nHeight; ++h) {
					const unsigned index = ch * nHeight + h;

#ifndef FREEIMAGE_BIGENDIAN 
					SwapShort(&rleLineSizeList[index]);
#endif
					if(largestRLELine < rleLineSizeList[index]) {
						largestRLELine = rleLineSizeList[index];
					}
				}
			}

			BYTE* rle_line_start = new (std::nothrow) BYTE[largestRLELine];
			if(!rle_line_start) {
				FreeImage_Unload(bitmap);
				SAFE_DELETE_ARRAY(line_start);
				SAFE_DELETE_ARRAY(rleLineSizeList);
				throw std::bad_alloc();
			}
			
			// Read the RLE data (assume 8-bit)
			
			const BYTE* const line_end = line_start + lineSize;

			for (unsigned ch = 0; ch < nChannels; ch++) {
				const unsigned channelOffset = ch * bytes;
				
				BYTE* dst_line_start = dst_first_line;
				for(unsigned h = 0; h < nHeight; ++h, dst_line_start -= dstLineSize) {//<*** flipped
					const unsigned index = ch * nHeight + h;
					
					// - read and uncompress line -
					
					const WORD rleLineSize = rleLineSizeList[index];
					
					io->read_proc(rle_line_start, rleLineSize, 1, handle);
					
					for (BYTE* rle_line = rle_line_start, *line = line_start; 
						rle_line < rle_line_start + rleLineSize, line < line_end;) {

						int len = *rle_line++;
						
						// NOTE len is signed byte in PackBits RLE
						
						if ( len < 128 ) { //<- MSB is not set
							// uncompressed packet
							
							// (len + 1) bytes of data are copied
							
							++len;
							
							// assert we don't write beyound eol
							memcpy(line, rle_line, line + len > line_end ? line_end - line : len);
							line += len;
							rle_line += len;
						}
						else if ( len > 128 ) { //< MSB is set
						
							// RLE compressed packet
							
							// One byte of data is repeated (–len + 1) times
							
							len ^= 0xFF; // same as (-len + 1) & 0xFF 
							len += 2;    //

							// assert we don't write beyound eol
							memset(line, *rle_line++, line + len > line_end ? line_end - line : len);							
							line += len;

						}
						else if ( 128 == len ) {
							// Do nothing
						}
					}//< rle_line
					
					// - write line to destination -
					
					if(ch >= dstChannels) {
						// @todo write to extra channels
						break; 
					}
						
					// byte by byte copy a single channel to pixel
					for (BYTE *line = line_start, *dst_line = dst_line_start; line < line_start + lineSize; 
						line += bytes, dst_line += dstBpp) {

#ifdef FREEIMAGE_BIGENDIAN
							memcpy(dst_line + channelOffset, line, bytes);
#else
							// reverse copy bytes
							for (unsigned b = 0; b < bytes; ++b) {
								dst_line[channelOffset + b] = line[(bytes-1) - b];							
							}
#endif // FREEIMAGE_BIGENDIAN
					}	
				}//< h
			}//< ch
			
			SAFE_DELETE_ARRAY(line_start);
			SAFE_DELETE_ARRAY(rleLineSizeList);
			SAFE_DELETE_ARRAY(rle_line_start);
		}
		break;
		
		case 2: // ZIP without prediction, no specification
			break;
			
		case 3: // ZIP with prediction, no specification
			break;
			
		default: // Unknown format
			break;
		
	}
	
	// --- Further process the bitmap ---
	
	if((mode == PSDP_CMYK || mode == PSDP_MULTICHANNEL)) {	
		// CMYK values are "inverted", invert them back		

		if(mode == PSDP_MULTICHANNEL) {
			invertColor(bitmap);
		} else {
			FreeImage_Invert(bitmap);
		}

		if((_fi_flags & PSD_CMYK) == PSD_CMYK) {
			// keep as CMYK

			if(mode == PSDP_MULTICHANNEL) {
				//### we force CMY to be CMYK, but CMY has no ICC. 
				// Create empty profile and add the flag.
				FreeImage_CreateICCProfile(bitmap, NULL, 0);
				FreeImage_GetICCProfile(bitmap)->flags |= FIICC_COLOR_IS_CMYK;
			}
		}
		else { 
			// convert to RGB
			
			ConvertCMYKtoRGBA(bitmap);
			
			// The ICC Profile is no longer valid
			_iccProfile.clear();
			
			// remove the pending A if not present in source 
			if(nChannels == 4 || nChannels == 3 ) {
				FIBITMAP* t = RemoveAlphaChannel(bitmap);
				if(t) {
					FreeImage_Unload(bitmap);
					bitmap = t;
				} // else: silently fail
			}
		}
	}
	else if ( mode == PSDP_LAB && !((_fi_flags & PSD_LAB) == PSD_LAB)) {
		ConvertLABtoRGB(bitmap);
	}
	else {
		if (needPalette) {
			assert(FreeImage_GetPalette(bitmap));
			
			if(mode == PSDP_BITMAP) {
				CREATE_GREYSCALE_PALETTE_REVERSE(FreeImage_GetPalette(bitmap), 2);
			}
			else if(mode == PSDP_INDEXED) {
				if(!_colourModeData._plColourData || _colourModeData._Length != 768 || _ColourCount < 0) {
					FreeImage_OutputMessageProc(_fi_format_id, "Indexed image has no palette. Using the default grayscale one.");
				} else {
					_colourModeData.FillPalette(bitmap);
				}
			}
			// GRAYSCALE, DUOTONE - use default grayscale palette
		}
		
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
		if(FreeImage_GetImageType(bitmap) == FIT_BITMAP) {
			SwapRedBlue32(bitmap);
		}
#endif
	}
	
	return bitmap;
} 
Exemplo n.º 6
0
FIBITMAP * DLL_CALLCONV
FreeImage_Allocate(int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) {
	return FreeImage_AllocateHeaderT(FALSE, FIT_BITMAP, width, height, bpp, red_mask, green_mask, blue_mask);
}
Exemplo n.º 7
0
FIBITMAP * DLL_CALLCONV
FreeImage_AllocateT(FREE_IMAGE_TYPE type, int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) {
	return FreeImage_AllocateHeaderT(FALSE, type, width, height, bpp, red_mask, green_mask, blue_mask);
}
Exemplo n.º 8
0
FIBITMAP * DLL_CALLCONV
FreeImage_Clone(FIBITMAP *dib) {
	if(!dib) {
		return NULL;
	}

	FREE_IMAGE_TYPE type = FreeImage_GetImageType(dib);
	unsigned width	= FreeImage_GetWidth(dib);
	unsigned height	= FreeImage_GetHeight(dib);
	unsigned bpp	= FreeImage_GetBPP(dib);

	const BYTE *ext_bits = ((FREEIMAGEHEADER *)dib->data)->external_bits;
	
	// check for pixel availability ...
	BOOL header_only = FreeImage_HasPixels(dib) ? FALSE : TRUE;

	// check whether this image has masks defined ...
	BOOL need_masks = (bpp == 16 && type == FIT_BITMAP) ? TRUE : FALSE;

	// allocate a new dib
	FIBITMAP *new_dib = FreeImage_AllocateHeaderT(header_only, type, 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 the src 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
		
		// when using a user provided pixel buffer, force a 'header only' calculation		

		size_t dib_size = FreeImage_GetInternalImageSize(header_only || ext_bits, width, height, bpp, need_masks);

		// 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;

		// reset thumbnail link for new_dib
		((FREEIMAGEHEADER *)new_dib->data)->thumbnail = NULL;

		// 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(std::nothrow) TAGMAP();

				if(dst_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;
				}
			}
		}

		// copy the thumbnail
		FreeImage_SetThumbnail(new_dib, FreeImage_GetThumbnail(dib));

		// copy user provided pixel buffer (if any)
		if(ext_bits) {
			const unsigned pitch = FreeImage_GetPitch(dib);
			const unsigned linesize = FreeImage_GetLine(dib);
			for(unsigned y = 0; y < height; y++) {
				memcpy(FreeImage_GetScanLine(new_dib, y), ext_bits, linesize);
				ext_bits += pitch;
			}
		}

		return new_dib;
	}

	return NULL;
}
Exemplo n.º 9
0
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
    png_structp png_ptr = NULL;
    png_infop info_ptr;
    png_uint_32 width, height;
    png_colorp png_palette = NULL;
    int color_type, palette_entries = 0;
    int bit_depth, pixel_depth;		// pixel_depth = bit_depth * channels

    FIBITMAP *dib = NULL;
    RGBQUAD *palette = NULL;		// pointer to dib palette
    png_bytepp  row_pointers = NULL;
    int i;

    fi_ioStructure fio;
    fio.s_handle = handle;
    fio.s_io = io;

    if (handle) {
        BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;

        try {
            // check to see if the file is in fact a PNG file

            BYTE png_check[PNG_BYTES_TO_CHECK];

            io->read_proc(png_check, PNG_BYTES_TO_CHECK, 1, handle);

            if (png_sig_cmp(png_check, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0) {
                return NULL;	// Bad signature
            }

            // create the chunk manage structure

            png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, error_handler, warning_handler);

            if (!png_ptr) {
                return NULL;
            }

            // create the info structure

            info_ptr = png_create_info_struct(png_ptr);

            if (!info_ptr) {
                png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
                return NULL;
            }

            // init the IO

            png_set_read_fn(png_ptr, &fio, _ReadProc);

            if (setjmp(png_jmpbuf(png_ptr))) {
                png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
                return NULL;
            }

            // because we have already read the signature...

            png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);

            // read the IHDR chunk

            png_read_info(png_ptr, info_ptr);
            png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL);

            pixel_depth = png_get_bit_depth(png_ptr, info_ptr) * png_get_channels(png_ptr, info_ptr);

            // get image data type (assume standard image type)

            FREE_IMAGE_TYPE image_type = FIT_BITMAP;
            if (bit_depth == 16) {
                if ((pixel_depth == 16) && (color_type == PNG_COLOR_TYPE_GRAY)) {
                    image_type = FIT_UINT16;
                }
                else if ((pixel_depth == 48) && (color_type == PNG_COLOR_TYPE_RGB)) {
                    image_type = FIT_RGB16;
                }
                else if ((pixel_depth == 64) && (color_type == PNG_COLOR_TYPE_RGB_ALPHA)) {
                    image_type = FIT_RGBA16;
                } else {
                    // tell libpng to strip 16 bit/color files down to 8 bits/color
                    png_set_strip_16(png_ptr);
                    bit_depth = 8;
                }
            }

#ifndef FREEIMAGE_BIGENDIAN
            if((image_type == FIT_UINT16) || (image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) {
                // turn on 16 bit byte swapping
                png_set_swap(png_ptr);
            }
#endif

            // set some additional flags

            switch(color_type) {
            case PNG_COLOR_TYPE_RGB:
            case PNG_COLOR_TYPE_RGB_ALPHA:
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
                // flip the RGB pixels to BGR (or RGBA to BGRA)

                if(image_type == FIT_BITMAP) {
                    png_set_bgr(png_ptr);
                }
#endif
                break;

            case PNG_COLOR_TYPE_PALETTE:
                // expand palette images to the full 8 bits from 2 bits/pixel

                if (pixel_depth == 2) {
                    png_set_packing(png_ptr);
                    pixel_depth = 8;
                }

                break;

            case PNG_COLOR_TYPE_GRAY:
                // expand grayscale images to the full 8 bits from 2 bits/pixel
                // but *do not* expand fully transparent palette entries to a full alpha channel

                if (pixel_depth == 2) {
                    png_set_expand_gray_1_2_4_to_8(png_ptr);
                    pixel_depth = 8;
                }

                break;

            case PNG_COLOR_TYPE_GRAY_ALPHA:
                // expand 8-bit greyscale + 8-bit alpha to 32-bit

                png_set_gray_to_rgb(png_ptr);
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
                // flip the RGBA pixels to BGRA

                png_set_bgr(png_ptr);
#endif
                pixel_depth = 32;

                break;

            default:
                throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
            }

            // unlike the example in the libpng documentation, we have *no* idea where
            // this file may have come from--so if it doesn't have a file gamma, don't
            // do any correction ("do no harm")

            if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) {
                double gamma = 0;
                double screen_gamma = 2.2;

                if (png_get_gAMA(png_ptr, info_ptr, &gamma) && ( flags & PNG_IGNOREGAMMA ) != PNG_IGNOREGAMMA) {
                    png_set_gamma(png_ptr, screen_gamma, gamma);
                }
            }

            // all transformations have been registered; now update info_ptr data

            png_read_update_info(png_ptr, info_ptr);

            // color type may have changed, due to our transformations

            color_type = png_get_color_type(png_ptr,info_ptr);

            // create a DIB and write the bitmap header
            // set up the DIB palette, if needed

            switch (color_type) {
            case PNG_COLOR_TYPE_RGB:
                png_set_invert_alpha(png_ptr);

                if(image_type == FIT_BITMAP) {
                    dib = FreeImage_AllocateHeader(header_only, width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
                } else {
                    dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth);
                }
                break;

            case PNG_COLOR_TYPE_RGB_ALPHA:
                if(image_type == FIT_BITMAP) {
                    dib = FreeImage_AllocateHeader(header_only, width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
                } else {
                    dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth);
                }
                break;

            case PNG_COLOR_TYPE_PALETTE:
                dib = FreeImage_AllocateHeader(header_only, width, height, pixel_depth);

                png_get_PLTE(png_ptr,info_ptr, &png_palette, &palette_entries);

                palette_entries = MIN((unsigned)palette_entries, FreeImage_GetColorsUsed(dib));
                palette = FreeImage_GetPalette(dib);

                // store the palette

                for (i = 0; i < palette_entries; i++) {
                    palette[i].rgbRed   = png_palette[i].red;
                    palette[i].rgbGreen = png_palette[i].green;
                    palette[i].rgbBlue  = png_palette[i].blue;
                }
                break;

            case PNG_COLOR_TYPE_GRAY:
                dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth);

                if(pixel_depth <= 8) {
                    palette = FreeImage_GetPalette(dib);
                    palette_entries = 1 << pixel_depth;

                    for (i = 0; i < palette_entries; i++) {
                        palette[i].rgbRed   =
                            palette[i].rgbGreen =
                                palette[i].rgbBlue  = (BYTE)((i * 255) / (palette_entries - 1));
                    }
                }
                break;

            default:
                throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
            }

            // store the transparency table

            if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
                // array of alpha (transparency) entries for palette
                png_bytep trans_alpha = NULL;
                // number of transparent entries
                int num_trans = 0;
                // graylevel or color sample values of the single transparent color for non-paletted images
                png_color_16p trans_color = NULL;

                png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color);

                if((color_type == PNG_COLOR_TYPE_GRAY) && trans_color) {
                    // single transparent color
                    if (trans_color->gray < palette_entries) {
                        BYTE table[256];
                        memset(table, 0xFF, palette_entries);
                        table[trans_color->gray] = 0;
                        FreeImage_SetTransparencyTable(dib, table, palette_entries);
                    }
                } else if((color_type == PNG_COLOR_TYPE_PALETTE) && trans_alpha) {
                    // transparency table
                    FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans);
                }
            }

            // store the background color

            if (png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) {
                // Get the background color to draw transparent and alpha images over.
                // Note that even if the PNG file supplies a background, you are not required to
                // use it - you should use the (solid) application background if it has one.

                png_color_16p image_background = NULL;
                RGBQUAD rgbBkColor;

                if (png_get_bKGD(png_ptr, info_ptr, &image_background)) {
                    rgbBkColor.rgbRed      = (BYTE)image_background->red;
                    rgbBkColor.rgbGreen    = (BYTE)image_background->green;
                    rgbBkColor.rgbBlue     = (BYTE)image_background->blue;
                    rgbBkColor.rgbReserved = 0;

                    FreeImage_SetBackgroundColor(dib, &rgbBkColor);
                }
            }

            // get physical resolution

            if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) {
                png_uint_32 res_x, res_y;

                // we'll overload this var and use 0 to mean no phys data,
                // since if it's not in meters we can't use it anyway

                int res_unit_type = PNG_RESOLUTION_UNKNOWN;

                png_get_pHYs(png_ptr,info_ptr, &res_x, &res_y, &res_unit_type);

                if (res_unit_type == PNG_RESOLUTION_METER) {
                    FreeImage_SetDotsPerMeterX(dib, res_x);
                    FreeImage_SetDotsPerMeterY(dib, res_y);
                }
            }

            // get possible ICC profile

            if (png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP)) {
                png_charp profile_name = NULL;
                png_bytep profile_data = NULL;
                png_uint_32 profile_length = 0;
                int  compression_type;

                png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &profile_length);

                // copy ICC profile data (must be done after FreeImage_AllocateHeader)

                FreeImage_CreateICCProfile(dib, profile_data, profile_length);
            }

            // --- header only mode => clean-up and return

            if (header_only) {
                // get possible metadata (it can be located both before and after the image data)
                ReadMetadata(png_ptr, info_ptr, dib);
                if (png_ptr) {
                    // clean up after the read, and free any memory allocated - REQUIRED
                    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
                }
                return dib;
            }

            // set the individual row_pointers to point at the correct offsets

            row_pointers = (png_bytepp)malloc(height * sizeof(png_bytep));

            if (!row_pointers) {
                png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
                FreeImage_Unload(dib);
                return NULL;
            }

            // read in the bitmap bits via the pointer table
            // allow loading of PNG with minor errors (such as images with several IDAT chunks)

            for (png_uint_32 k = 0; k < height; k++) {
                row_pointers[height - 1 - k] = FreeImage_GetScanLine(dib, k);
            }

            png_set_benign_errors(png_ptr, 1);
            png_read_image(png_ptr, row_pointers);

            // check if the bitmap contains transparency, if so enable it in the header

            if (FreeImage_GetBPP(dib) == 32) {
                if (FreeImage_GetColorType(dib) == FIC_RGBALPHA) {
                    FreeImage_SetTransparent(dib, TRUE);
                } else {
                    FreeImage_SetTransparent(dib, FALSE);
                }
            }

            // cleanup

            if (row_pointers) {
                free(row_pointers);
                row_pointers = NULL;
            }

            // read the rest of the file, getting any additional chunks in info_ptr

            png_read_end(png_ptr, info_ptr);

            // get possible metadata (it can be located both before and after the image data)

            ReadMetadata(png_ptr, info_ptr, dib);

            if (png_ptr) {
                // clean up after the read, and free any memory allocated - REQUIRED
                png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
            }

            return dib;
        } catch (const char *text) {
            if (png_ptr) {
                png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
            }
            if (row_pointers) {
                free(row_pointers);
            }
            if (dib) {
                FreeImage_Unload(dib);
            }
            FreeImage_OutputMessageProc(s_format_id, text);

            return NULL;
        }
    }

    return NULL;
}
Exemplo n.º 10
0
/**
Convert a OpenJPEG image to a FIBITMAP
@param format_id Plugin ID
@param image OpenJPEG image
@param header_only If TRUE, allocate a 'header only' FIBITMAP, otherwise allocate a full FIBITMAP
@return Returns the converted image if successful, returns NULL otherwise
*/
FIBITMAP* J2KImageToFIBITMAP(int format_id, const opj_image_t *image, BOOL header_only) {
	FIBITMAP *dib = NULL;

	try {
		// compute image width and height

		//int w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx);
		int wr = image->comps[0].w;
		int wrr = int_ceildivpow2(image->comps[0].w, image->comps[0].factor);
		
		//int h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy);
		//int hr = image->comps[0].h;
		int hrr = int_ceildivpow2(image->comps[0].h, image->comps[0].factor);

		// check the number of components

		int numcomps = image->numcomps;

		BOOL bIsValid = TRUE;
		for(int c = 0; c < numcomps - 1; c++) {
			if(	(image->comps[c].dx == image->comps[c+1].dx) && 
				(image->comps[c].dy == image->comps[c+1].dy) &&
				(image->comps[c].prec == image->comps[c+1].prec) ) {
				continue;
			} else {
				bIsValid = FALSE;
				break;
			}
		}
		bIsValid &= ((numcomps == 1) || (numcomps == 3) || (numcomps == 4));
		if(!bIsValid) {
			if(numcomps) {
				FreeImage_OutputMessageProc(format_id, "Warning: image contains %d greyscale components. Only the first will be loaded.\n", numcomps);
				numcomps = 1;
			} else {
				// unknown type
				throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
			}
		}

		// create a new DIB

		if(image->comps[0].prec <= 8) {
			switch(numcomps) {
				case 1:
					dib = FreeImage_AllocateHeader(header_only, wrr, hrr, 8);
					break;
				case 3:
					dib = FreeImage_AllocateHeader(header_only, wrr, hrr, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
					break;
				case 4:
					dib = FreeImage_AllocateHeader(header_only, wrr, hrr, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
					break;
			}
		} else if(image->comps[0].prec <= 16) {
			switch(numcomps) {
				case 1:
					dib = FreeImage_AllocateHeaderT(header_only, FIT_UINT16, wrr, hrr);
					break;
				case 3:
					dib = FreeImage_AllocateHeaderT(header_only, FIT_RGB16, wrr, hrr);
					break;
				case 4:
					dib = FreeImage_AllocateHeaderT(header_only, FIT_RGBA16, wrr, hrr);
					break;
			}
		} else {
			throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
		}
		if(!dib) {
			throw FI_MSG_ERROR_DIB_MEMORY;
		}

		// "header only" FIBITMAP ?
		if(header_only) {
			return dib;
		}
		
		if(image->comps[0].prec <= 8) {
			if(numcomps == 1) {
				// 8-bit greyscale
				// ----------------------------------------------------------

				// 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;
				}

				// load pixel data

				unsigned pixel_count = 0;

				for(int y = 0; y < hrr; y++) {		
					BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y);

					for(int x = 0; x < wrr; x++) {
						const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;

						int index = image->comps[0].data[pixel_pos];
						index += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);

						bits[x] = (BYTE)index;

						pixel_count++;
					}
				}
			}
			else if(numcomps == 3) {

				// 24-bit RGB
				// ----------------------------------------------------------	
				
				// load pixel data

				unsigned pixel_count = 0;

				for(int y = 0; y < hrr; y++) {		
					BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y);

					for(int x = 0; x < wrr; x++) {
						const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;

						int r = image->comps[0].data[pixel_pos];
						r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
						
						int g = image->comps[1].data[pixel_pos];
						g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
						
						int b = image->comps[2].data[pixel_pos];
						b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);

						bits[FI_RGBA_RED]   = (BYTE)r;
						bits[FI_RGBA_GREEN] = (BYTE)g;
						bits[FI_RGBA_BLUE]  = (BYTE)b;
						bits += 3;

						pixel_count++;
					}
				}
			}
			else if(numcomps == 4) {

				// 32-bit RGBA
				// ----------------------------------------------------------	
				
				// load pixel data

				unsigned pixel_count = 0;

				for(int y = 0; y < hrr; y++) {		
					BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y);

					for(int x = 0; x < wrr; x++) {
						const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;

						int r = image->comps[0].data[pixel_pos];
						r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
						
						int g = image->comps[1].data[pixel_pos];
						g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
						
						int b = image->comps[2].data[pixel_pos];
						b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);

						int a = image->comps[3].data[pixel_pos];
						a += (image->comps[3].sgnd ? 1 << (image->comps[3].prec - 1) : 0);

						bits[FI_RGBA_RED]   = (BYTE)r;
						bits[FI_RGBA_GREEN] = (BYTE)g;
						bits[FI_RGBA_BLUE]  = (BYTE)b;
						bits[FI_RGBA_ALPHA] = (BYTE)a;
						bits += 4;

						pixel_count++;
					}
				}
			}
		}
		else if(image->comps[0].prec <= 16) {
			if(numcomps == 1) {
				// 16-bit greyscale
				// ----------------------------------------------------------

				// load pixel data

				unsigned pixel_count = 0;

				for(int y = 0; y < hrr; y++) {		
					WORD *bits = (WORD*)FreeImage_GetScanLine(dib, hrr - 1 - y);

					for(int x = 0; x < wrr; x++) {
						const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;

						int index = image->comps[0].data[pixel_pos];
						index += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);

						bits[x] = (WORD)index;

						pixel_count++;
					}
				}
			}
			else if(numcomps == 3) {

				// 48-bit RGB
				// ----------------------------------------------------------	
				
				// load pixel data

				unsigned pixel_count = 0;

				for(int y = 0; y < hrr; y++) {		
					FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, hrr - 1 - y);

					for(int x = 0; x < wrr; x++) {
						const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;

						int r = image->comps[0].data[pixel_pos];
						r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
						
						int g = image->comps[1].data[pixel_pos];
						g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
						
						int b = image->comps[2].data[pixel_pos];
						b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);

						bits[x].red   = (WORD)r;
						bits[x].green = (WORD)g;
						bits[x].blue  = (WORD)b;

						pixel_count++;
					}
				}
			}
			else if(numcomps == 4) {

				// 64-bit RGBA
				// ----------------------------------------------------------	
				
				// load pixel data

				unsigned pixel_count = 0;

				for(int y = 0; y < hrr; y++) {		
					FIRGBA16 *bits = (FIRGBA16*)FreeImage_GetScanLine(dib, hrr - 1 - y);

					for(int x = 0; x < wrr; x++) {
						const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;

						int r = image->comps[0].data[pixel_pos];
						r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
						
						int g = image->comps[1].data[pixel_pos];
						g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
						
						int b = image->comps[2].data[pixel_pos];
						b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);

						int a = image->comps[3].data[pixel_pos];
						a += (image->comps[3].sgnd ? 1 << (image->comps[3].prec - 1) : 0);

						bits[x].red   = (WORD)r;
						bits[x].green = (WORD)g;
						bits[x].blue  = (WORD)b;
						bits[x].alpha = (WORD)a;

						pixel_count++;
					}
				}
			}
		}

		return dib;

	} catch(const char *text) {
		if(dib) FreeImage_Unload(dib);
		FreeImage_OutputMessageProc(format_id, text);
		return NULL;
	}

}
Exemplo n.º 11
0
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
	FIBITMAP *dib = NULL;
	LibRaw RawProcessor;

	BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;

	try {
		// wrap the input datastream
		LibRaw_freeimage_datastream datastream(io, handle);

		// set decoding parameters
		// the following parameters affect data reading
		// --------------------------------------------

		// (-s [0..N-1]) Select one raw image from input file
		RawProcessor.imgdata.params.shot_select = 0;
		// (-w) Use camera white balance, if possible (otherwise, fallback to auto_wb)
		RawProcessor.imgdata.params.use_camera_wb = 1;
		// (-h) outputs the image in 50% size
		RawProcessor.imgdata.params.half_size = ((flags & RAW_HALFSIZE) == RAW_HALFSIZE) ? 1 : 0;

		// open the datastream
		if(RawProcessor.open_datastream(&datastream) != LIBRAW_SUCCESS) {
			throw "LibRaw : failed to open input stream (unknown format)";
		}

		if(header_only) {
			// header only mode
			dib = FreeImage_AllocateHeaderT(header_only, FIT_RGB16, RawProcessor.imgdata.sizes.width, RawProcessor.imgdata.sizes.height);
		}
		else if((flags & RAW_PREVIEW) == RAW_PREVIEW) {
			// try to get the embedded JPEG
			dib = libraw_LoadEmbeddedPreview(RawProcessor, 0);
			if(!dib) {
				// no JPEG preview: try to load as 8-bit/sample (i.e. RGB 24-bit)
				dib = libraw_LoadRawData(RawProcessor, 8);
			}
		} 
		else if((flags & RAW_DISPLAY) == RAW_DISPLAY) {
			// load raw data as 8-bit/sample (i.e. RGB 24-bit)
			dib = libraw_LoadRawData(RawProcessor, 8);
		} 
		else {
			// default: load raw data as linear 16-bit/sample (i.e. RGB 48-bit)
			dib = libraw_LoadRawData(RawProcessor, 16);
		}

		// save ICC profile if present
		if(dib && (NULL != RawProcessor.imgdata.color.profile)) {
			FreeImage_CreateICCProfile(dib, RawProcessor.imgdata.color.profile, RawProcessor.imgdata.color.profile_length);
		}

		// try to get JPEG embedded Exif metadata
		if(dib && !((flags & RAW_PREVIEW) == RAW_PREVIEW)) {
			FIBITMAP *metadata_dib = libraw_LoadEmbeddedPreview(RawProcessor, FIF_LOAD_NOPIXELS);
			if(metadata_dib) {
				FreeImage_CloneMetadata(dib, metadata_dib);
				FreeImage_Unload(metadata_dib);
			}
		}

		// clean-up internal memory allocations
		RawProcessor.recycle();

		return dib;

	} catch(const char *text) {
		if(dib) {
			FreeImage_Unload(dib);
		}
		RawProcessor.recycle();
		FreeImage_OutputMessageProc(s_format_id, text);
	}

	return NULL;
}
Exemplo n.º 12
0
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
	PKImageDecode *pDecoder = NULL;	// decoder interface
	ERR error_code = 0;				// error code as returned by the interface
	PKPixelFormatGUID guid_format;	// loaded pixel format (== input file pixel format if no conversion needed)
	
	FREE_IMAGE_TYPE image_type = FIT_UNKNOWN;	// input image type
	unsigned bpp = 0;							// input image bit depth
	FIBITMAP *dib = NULL;
	
	// get the I/O stream wrapper
	WMPStream *pDecodeStream = (WMPStream*)data;

	if(!handle || !pDecodeStream) {
		return NULL;
	}

	BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;

	try {
		int width, height;	// image dimensions (in pixels)

		// create a JXR decoder interface and initialize function pointers with *_WMP functions
		error_code = PKImageDecode_Create_WMP(&pDecoder);
		JXR_CHECK(error_code);

		// attach the stream to the decoder ...
		// ... then read the image container and the metadata
		error_code = pDecoder->Initialize(pDecoder, pDecodeStream);
		JXR_CHECK(error_code);

		// set decoder parameters
		SetDecoderParameters(pDecoder, flags);

		// get dst image format specifications
		unsigned red_mask = 0, green_mask = 0, blue_mask = 0;
		error_code = GetInputPixelFormat(pDecoder, &guid_format, &image_type, &bpp, &red_mask, &green_mask, &blue_mask);
		JXR_CHECK(error_code);

		// get image dimensions
		pDecoder->GetSize(pDecoder, &width, &height);

		// allocate dst image
		{			
			dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, bpp, red_mask, green_mask, blue_mask);
			if(!dib) {
				throw FI_MSG_ERROR_DIB_MEMORY;
			}
			if(FreeImage_GetBPP(dib) == 1) {
				// BD_1 - build a FIC_MINISBLACK palette
				RGBQUAD *pal = FreeImage_GetPalette(dib);
				pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0;
				pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255;
			}
		}

		// get image resolution
		{
			float resX, resY;	// image resolution (in dots per inch)
			// convert from English units, i.e. dots per inch to universal units, i.e. dots per meter
			pDecoder->GetResolution(pDecoder, &resX, &resY);
			FreeImage_SetDotsPerMeterX(dib, (unsigned)(resX / 0.0254F + 0.5F));
			FreeImage_SetDotsPerMeterY(dib, (unsigned)(resY / 0.0254F + 0.5F));
		}

		// get metadata & ICC profile
		error_code = ReadMetadata(pDecoder, dib);
		JXR_CHECK(error_code);

		if(header_only) {
			// header only mode ...
			
			// free the decoder
			pDecoder->Release(&pDecoder);
			assert(pDecoder == NULL);

			return dib;
		}
		
		// copy pixels into the dib, perform pixel conversion if needed
		error_code = CopyPixels(pDecoder, guid_format, dib, width, height);
		JXR_CHECK(error_code);

		// free the decoder
		pDecoder->Release(&pDecoder);
		assert(pDecoder == NULL);

		return dib;

	} catch (const char *message) {
		// unload the dib
		FreeImage_Unload(dib);
		// free the decoder
		pDecoder->Release(&pDecoder);

		if(NULL != message) {
			FreeImage_OutputMessageProc(s_format_id, message);
		}
	}

	return NULL;
}