Alien-FreeImage

 view release on metacpan or  search on metacpan

src/Source/FreeImage/PluginEXR.cpp  view on Meta::CPAN

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

/**
Set the preview image using the dib embedded thumbnail
*/
static BOOL
SetPreviewImage(FIBITMAP *dib, Imf::Header& header) {
	if(!FreeImage_GetThumbnail(dib)) {
		return FALSE;
	}
	FIBITMAP* thumbnail = FreeImage_GetThumbnail(dib);

	if((FreeImage_GetImageType(thumbnail) != FIT_BITMAP) || (FreeImage_GetBPP(thumbnail) != 32)) {
		// invalid thumbnail - ignore it
		FreeImage_OutputMessageProc(s_format_id, FI_MSG_WARNING_INVALID_THUMBNAIL);
	} else {
		const unsigned thWidth = FreeImage_GetWidth(thumbnail);
		const unsigned thHeight = FreeImage_GetHeight(thumbnail);
		
		Imf::PreviewImage preview(thWidth, thHeight);

		// copy thumbnail to 32-bit RGBA preview image
		
		const BYTE* src_line = FreeImage_GetScanLine(thumbnail, thHeight - 1);
		Imf::PreviewRgba* dst_line = preview.pixels();
		const unsigned srcPitch = FreeImage_GetPitch(thumbnail);
		
		for (unsigned y = 0; y < thHeight; y++) {
			const RGBQUAD* src_pixel = (RGBQUAD*)src_line;
			Imf::PreviewRgba* dst_pixel = dst_line;
			
			for(unsigned x = 0; x < thWidth; x++) {
				dst_pixel->r = src_pixel->rgbRed;
				dst_pixel->g = src_pixel->rgbGreen;
				dst_pixel->b = src_pixel->rgbBlue;
				dst_pixel->a = src_pixel->rgbReserved;
				
				src_pixel++;
				dst_pixel++;
			}
			
			src_line -= srcPitch;
			dst_line += thWidth;
		}

src/Source/FreeImage/PluginEXR.cpp  view on Meta::CPAN

			// default value
			compress = Imf::PIZ_COMPRESSION;
		}

		// create the header
		int width  = FreeImage_GetWidth(dib);
		int height = FreeImage_GetHeight(dib);
		int dx = 0, dy = 0;

		Imath::Box2i dataWindow (Imath::V2i (0, 0), Imath::V2i (width - 1, height - 1));
		Imath::Box2i displayWindow (Imath::V2i (-dx, -dy), Imath::V2i (width - dx - 1, height - dy - 1));

		Imf::Header header = Imf::Header(displayWindow, dataWindow, 1, 
			Imath::V2f(0,0), 1, 
			Imf::INCREASING_Y, compress);        		

		// handle thumbnail
		SetPreviewImage(dib, header);
		
		// check for EXR_LC compression
		if((flags & EXR_LC) == EXR_LC) {
			return SaveAsEXR_LC(ostream, dib, header, width, height);
		}

		// output pixel type
		Imf::PixelType pixelType;
		if((flags & EXR_FLOAT) == EXR_FLOAT) {
			pixelType = Imf::FLOAT;	// save as float data type
		} else {
			// default value
			pixelType = Imf::HALF;	// save as half data type
		}

		// check the data type and number of channels
		int components = 0;
		FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
		switch(image_type) {
			case FIT_FLOAT:
				components = 1;
				// insert luminance channel
				header.channels().insert ("Y", Imf::Channel(pixelType));
				break;
			case FIT_RGBF:
				components = 3;
				for(int c = 0; c < components; c++) {
					// insert R, G and B channels
					header.channels().insert (channel_name[c], Imf::Channel(pixelType));
				}
				break;
			case FIT_RGBAF:
				components = 4;
				for(int c = 0; c < components; c++) {
					// insert R, G, B and A channels
					header.channels().insert (channel_name[c], Imf::Channel(pixelType));
				}
				break;
			default:
				THROW (Iex::ArgExc, "Cannot save: invalid data type.\nConvert the image to float before saving as OpenEXR.");
		}

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

		BYTE *bits = NULL;	// pointer to our pixel buffer
		size_t bytespp = 0;	// size of our pixel in bytes
		size_t bytespc = 0;	// size of our pixel component in bytes
		unsigned pitch = 0;	// size of our yStride in bytes


		if(pixelType == Imf::HALF) {
			// convert from float to half
			halfData = new(std::nothrow) half[width * height * components];
			if(!halfData) {
				THROW (Iex::NullExc, FI_MSG_ERROR_MEMORY);
			}

			for(int y = 0; y < height; y++) {
				float *src_bits = (float*)FreeImage_GetScanLine(dib, height - 1 - y);
				half *dst_bits = halfData + y * width * components;
				for(int x = 0; x < width; x++) {
					for(int c = 0; c < components; c++) {
						dst_bits[c] = src_bits[c];
					}
					src_bits += components;
					dst_bits += components;
				}
			}
			bits = (BYTE*)halfData;
			bytespc = sizeof(half);
			bytespp = sizeof(half) * components;
			pitch = sizeof(half) * width * components;
		} else if(pixelType == Imf::FLOAT) {
			// invert dib scanlines
			bIsFlipped = FreeImage_FlipVertical(dib);
		
			bits = FreeImage_GetBits(dib);
			bytespc = sizeof(float);
			bytespp = sizeof(float) * components;
			pitch = FreeImage_GetPitch(dib);
		}

		if(image_type == FIT_FLOAT) {
			frameBuffer.insert ("Y",	// name
				Imf::Slice (pixelType,	// type
				(char*)(bits),			// base
				bytespp,				// xStride
				pitch));				// yStride
		} else if((image_type == FIT_RGBF) || (image_type == FIT_RGBAF)) {			
			for(int c = 0; c < components; c++) {
				char *channel_base = (char*)(bits) + c*bytespc;
				frameBuffer.insert (channel_name[c],// name
					Imf::Slice (pixelType,			// type
					channel_base,					// base
					bytespp,	// xStride
					pitch));	// yStride
			}
		}

		// write the data
		Imf::OutputFile file (ostream, header);
		file.setFrameBuffer (frameBuffer);
		file.writePixels (height);

		if(halfData != NULL) {
			delete[] halfData;
		}
		if(bIsFlipped) {
			// invert dib scanlines
			FreeImage_FlipVertical(dib);
		}

		return TRUE;

	} catch(Iex::BaseExc & e) {
		if(halfData != NULL) {
			delete[] halfData;
		}
		if(bIsFlipped) {
			// invert dib scanlines
			FreeImage_FlipVertical(dib);
		}

		FreeImage_OutputMessageProc(s_format_id, e.what());

		return FALSE;
	}	
}

// ==========================================================
//   Init
// ==========================================================

void DLL_CALLCONV
InitEXR(Plugin *plugin, int format_id) {
	s_format_id = format_id;

	// initialize the OpenEXR library
	// note that this OpenEXR function produce so called "false memory leaks"
	// see http://lists.nongnu.org/archive/html/openexr-devel/2013-11/msg00000.html
	Imf::staticInitialize();

	plugin->format_proc = Format;
	plugin->description_proc = Description;
	plugin->extension_proc = Extension;
	plugin->regexpr_proc = RegExpr;
	plugin->open_proc = NULL;
	plugin->close_proc = NULL;
	plugin->pagecount_proc = NULL;
	plugin->pagecapability_proc = NULL;
	plugin->load_proc = Load;
	plugin->save_proc = Save;
	plugin->validate_proc = Validate;
	plugin->mime_proc = MimeType;
	plugin->supports_export_bpp_proc = SupportsExportDepth;
	plugin->supports_export_type_proc = SupportsExportType;
	plugin->supports_icc_profiles_proc = NULL;
	plugin->supports_no_pixels_proc = SupportsNoPixels;
}



( run in 0.723 second using v1.01-cache-2.11-cpan-df04353d9ac )