Alien-FreeImage
view release on metacpan or search on metacpan
src/Source/FreeImage/PluginEXR.cpp view on Meta::CPAN
// ==========================================================
// Plugin Implementation
// ==========================================================
static const char * DLL_CALLCONV
Format() {
return "EXR";
}
static const char * DLL_CALLCONV
Description() {
return "ILM OpenEXR";
}
static const char * DLL_CALLCONV
Extension() {
return "exr";
}
static const char * DLL_CALLCONV
RegExpr() {
return NULL;
}
static const char * DLL_CALLCONV
MimeType() {
return "image/x-exr";
}
static BOOL DLL_CALLCONV
Validate(FreeImageIO *io, fi_handle handle) {
BYTE exr_signature[] = { 0x76, 0x2F, 0x31, 0x01 };
BYTE signature[] = { 0, 0, 0, 0 };
io->read_proc(signature, 1, 4, handle);
return (memcmp(exr_signature, signature, 4) == 0);
}
static BOOL DLL_CALLCONV
SupportsExportDepth(int depth) {
return FALSE;
}
static BOOL DLL_CALLCONV
SupportsExportType(FREE_IMAGE_TYPE type) {
return (
(type == FIT_FLOAT) ||
(type == FIT_RGBF) ||
(type == FIT_RGBAF)
);
}
static BOOL DLL_CALLCONV
SupportsNoPixels() {
return TRUE;
}
// --------------------------------------------------------------------------
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 << ")");
src/Source/FreeImage/PluginEXR.cpp view on Meta::CPAN
Save using EXR_LC compression (works only with RGB[A]F images)
*/
static BOOL
SaveAsEXR_LC(C_OStream& ostream, FIBITMAP *dib, Imf::Header& header, int width, int height) {
int x, y;
Imf::RgbaChannels rgbaChannels;
try {
FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
// convert from float to half
Imf::Array2D<Imf::Rgba> pixels(height, width);
switch(image_type) {
case FIT_RGBF:
rgbaChannels = Imf::WRITE_YC;
for(y = 0; y < height; y++) {
FIRGBF *src_bits = (FIRGBF*)FreeImage_GetScanLine(dib, height - 1 - y);
for(x = 0; x < width; x++) {
Imf::Rgba &dst_bits = pixels[y][x];
dst_bits.r = src_bits[x].red;
dst_bits.g = src_bits[x].green;
dst_bits.b = src_bits[x].blue;
}
}
break;
case FIT_RGBAF:
rgbaChannels = Imf::WRITE_YCA;
for(y = 0; y < height; y++) {
FIRGBAF *src_bits = (FIRGBAF*)FreeImage_GetScanLine(dib, height - 1 - y);
for(x = 0; x < width; x++) {
Imf::Rgba &dst_bits = pixels[y][x];
dst_bits.r = src_bits[x].red;
dst_bits.g = src_bits[x].green;
dst_bits.b = src_bits[x].blue;
dst_bits.a = src_bits[x].alpha;
}
}
break;
default:
THROW (Iex::IoExc, "Bad image type");
break;
}
// write the data
Imf::RgbaOutputFile file(ostream, header, rgbaChannels);
file.setFrameBuffer (&pixels[0][0], 1, width);
file.writePixels (height);
return TRUE;
} catch(Iex::BaseExc & e) {
FreeImage_OutputMessageProc(s_format_id, e.what());
return FALSE;
}
}
static BOOL DLL_CALLCONV
Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
const char *channel_name[4] = { "R", "G", "B", "A" };
BOOL bIsFlipped = FALSE;
half *halfData = NULL;
if(!dib || !handle) return FALSE;
try {
// check for EXR_LC compression and verify that the format is RGB
if((flags & EXR_LC) == EXR_LC) {
FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
if(((image_type != FIT_RGBF) && (image_type != FIT_RGBAF)) || ((flags & EXR_FLOAT) == EXR_FLOAT)) {
THROW (Iex::IoExc, "EXR_LC compression is only available with RGB[A]F images");
}
if((FreeImage_GetWidth(dib) % 2) || (FreeImage_GetHeight(dib) % 2)) {
THROW (Iex::IoExc, "EXR_LC compression only works when the width and height are a multiple of 2");
}
}
// wrap the FreeImage IO stream
C_OStream ostream(io, handle);
// compression
Imf::Compression compress;
if((flags & EXR_NONE) == EXR_NONE) {
// no compression
compress = Imf::NO_COMPRESSION;
} else if((flags & EXR_ZIP) == EXR_ZIP) {
// zlib compression, in blocks of 16 scan lines
compress = Imf::ZIP_COMPRESSION;
} else if((flags & EXR_PIZ) == EXR_PIZ) {
// piz-based wavelet compression
compress = Imf::PIZ_COMPRESSION;
} else if((flags & EXR_PXR24) == EXR_PXR24) {
// lossy 24-bit float compression
compress = Imf::PXR24_COMPRESSION;
} else if((flags & EXR_B44) == EXR_B44) {
// lossy 44% float compression
compress = Imf::B44_COMPRESSION;
} else {
// 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;
}
}
( run in 0.619 second using v1.01-cache-2.11-cpan-63c85eba8c4 )