diff options
author | Kirill Volinsky <mataes2007@gmail.com> | 2012-12-22 16:38:58 +0000 |
---|---|---|
committer | Kirill Volinsky <mataes2007@gmail.com> | 2012-12-22 16:38:58 +0000 |
commit | 87d155ba9f4e699293adc65954c89f20fc65b36d (patch) | |
tree | d79d69145cc6ef4e97d2ad2912b4d645c7b27158 /plugins/AdvaImg/src/FreeImage/PluginEXR.cpp | |
parent | a8bd33017b1959588d60c9a8a5ae3a744cb75e4d (diff) |
AdvaImg plugin folder renaming
git-svn-id: http://svn.miranda-ng.org/main/trunk@2801 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/AdvaImg/src/FreeImage/PluginEXR.cpp')
-rw-r--r-- | plugins/AdvaImg/src/FreeImage/PluginEXR.cpp | 764 |
1 files changed, 764 insertions, 0 deletions
diff --git a/plugins/AdvaImg/src/FreeImage/PluginEXR.cpp b/plugins/AdvaImg/src/FreeImage/PluginEXR.cpp new file mode 100644 index 0000000000..b9963a11b2 --- /dev/null +++ b/plugins/AdvaImg/src/FreeImage/PluginEXR.cpp @@ -0,0 +1,764 @@ +// ========================================================== +// EXR Loader and writer +// +// Design and implementation by +// - Hervé Drolon (drolon@infonie.fr) +// - Mihail Naydenov (mnaydenov@users.sourceforge.net) +// +// This file is part of FreeImage 3 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include "FreeImage.h" +#include "Utilities.h" +#include "../OpenEXR/IlmImf/ImfIO.h" +#include "../OpenEXR/Iex/Iex.h" +#include "../OpenEXR/IlmImf/ImfOutputFile.h" +#include "../OpenEXR/IlmImf/ImfInputFile.h" +#include "../OpenEXR/IlmImf/ImfRgbaFile.h" +#include "../OpenEXR/IlmImf/ImfChannelList.h" +#include "../OpenEXR/IlmImf/ImfRgba.h" +#include "../OpenEXR/IlmImf/ImfArray.h" +#include "../OpenEXR/IlmImf/ImfPreviewImage.h" +#include "../OpenEXR/Half/half.h" + + +// ========================================================== +// Plugin Interface +// ========================================================== + +static int s_format_id; + +// ---------------------------------------------------------- + +/** +FreeImage input stream wrapper +*/ +class C_IStream: public Imf::IStream { +public: + C_IStream (FreeImageIO *io, fi_handle handle): + IStream(""), _io (io), _handle(handle) {} + + virtual bool read (char c[/*n*/], int n); + virtual Imf::Int64 tellg (); + virtual void seekg (Imf::Int64 pos); + virtual void clear () {}; + +private: + FreeImageIO *_io; + fi_handle _handle; +}; + + +/** +FreeImage output stream wrapper +*/ +class C_OStream: public Imf::OStream { +public: + C_OStream (FreeImageIO *io, fi_handle handle): + OStream(""), _io (io), _handle(handle) {} + + virtual void write (const char c[/*n*/], int n); + virtual Imf::Int64 tellp (); + virtual void seekp (Imf::Int64 pos); + +private: + FreeImageIO *_io; + fi_handle _handle; +}; + + +bool +C_IStream::read (char c[/*n*/], int n) { + return ((unsigned)n != _io->read_proc(c, 1, n, _handle)); +} + +Imf::Int64 +C_IStream::tellg () { + return _io->tell_proc(_handle); +} + +void +C_IStream::seekg (Imf::Int64 pos) { + _io->seek_proc(_handle, (unsigned)pos, SEEK_SET); +} + +void +C_OStream::write (const char c[/*n*/], int n) { + if ((unsigned)n != _io->write_proc((void*)&c[0], 1, n, _handle)) { + Iex::throwErrnoExc(); + } +} + +Imf::Int64 +C_OStream::tellp () { + return _io->tell_proc(_handle); +} + +void +C_OStream::seekp (Imf::Int64 pos) { + _io->seek_proc(_handle, (unsigned)pos, SEEK_SET); +} + +// ---------------------------------------------------------- + + +// ========================================================== +// 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 << ")"); + } + } + + 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; +} + +/** +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; + } + + header.setPreviewImage(preview); + } + + return TRUE; +} + +/** +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; + } + } + 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; + + 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; +} |