diff options
Diffstat (limited to 'plugins/AdvaImg/src/FreeImage/PluginHDR.cpp')
-rw-r--r-- | plugins/AdvaImg/src/FreeImage/PluginHDR.cpp | 719 |
1 files changed, 719 insertions, 0 deletions
diff --git a/plugins/AdvaImg/src/FreeImage/PluginHDR.cpp b/plugins/AdvaImg/src/FreeImage/PluginHDR.cpp new file mode 100644 index 0000000000..a0334e1143 --- /dev/null +++ b/plugins/AdvaImg/src/FreeImage/PluginHDR.cpp @@ -0,0 +1,719 @@ +// ========================================================== +// HDR Loader and writer +// +// Design and implementation by +// - Hervé Drolon (drolon@infonie.fr) +// +// 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" + +// ========================================================== +// Plugin Interface +// ========================================================== + +static int s_format_id; + +// ========================================================== +// RGBE library +// ========================================================== + +// ---------------------------------------------------------- + +// maximum size of a line in the header +#define HDR_MAXLINE 256 + +// flags indicating which fields in an rgbeHeaderInfo are valid +#define RGBE_VALID_PROGRAMTYPE 0x01 +#define RGBE_VALID_COMMENT 0x02 +#define RGBE_VALID_GAMMA 0x04 +#define RGBE_VALID_EXPOSURE 0x08 + +// offsets to red, green, and blue components in a data (float) pixel +#define RGBE_DATA_RED 0 +#define RGBE_DATA_GREEN 1 +#define RGBE_DATA_BLUE 2 + +// ---------------------------------------------------------- +#ifdef _WIN32 +#pragma pack(push, 1) +#else +#pragma pack(1) +#endif + +typedef struct tagHeaderInfo { + int valid; // indicate which fields are valid + char programtype[16]; // listed at beginning of file to identify it after "#?". defaults to "RGBE" + char comment[HDR_MAXLINE]; // comment beginning with "# " + float gamma; // image has already been gamma corrected with given gamma. defaults to 1.0 (no correction) + float exposure; // a value of 1.0 in an image corresponds to <exposure> watts/steradian/m^2. defaults to 1.0 +} rgbeHeaderInfo; + +#ifdef _WIN32 +#pragma pack(pop) +#else +#pragma pack() +#endif + +typedef enum { + rgbe_read_error, + rgbe_write_error, + rgbe_format_error, + rgbe_memory_error, +} rgbe_error_code; + +// ---------------------------------------------------------- +// Prototypes +// ---------------------------------------------------------- + +static BOOL rgbe_Error(rgbe_error_code error_code, const char *msg); +static BOOL rgbe_GetLine(FreeImageIO *io, fi_handle handle, char *buffer, int length); +static inline void rgbe_FloatToRGBE(BYTE rgbe[4], FIRGBF *rgbf); +static inline void rgbe_RGBEToFloat(FIRGBF *rgbf, BYTE rgbe[4]); +static BOOL rgbe_ReadHeader(FreeImageIO *io, fi_handle handle, unsigned *width, unsigned *height, rgbeHeaderInfo *header_info); +static BOOL rgbe_WriteHeader(FreeImageIO *io, fi_handle handle, unsigned width, unsigned height, rgbeHeaderInfo *info); +static BOOL rgbe_ReadPixels(FreeImageIO *io, fi_handle handle, FIRGBF *data, unsigned numpixels); +static BOOL rgbe_WritePixels(FreeImageIO *io, fi_handle handle, FIRGBF *data, unsigned numpixels); +static BOOL rgbe_ReadPixels_RLE(FreeImageIO *io, fi_handle handle, FIRGBF *data, int scanline_width, unsigned num_scanlines); +static BOOL rgbe_WriteBytes_RLE(FreeImageIO *io, fi_handle handle, BYTE *data, int numbytes); +static BOOL rgbe_WritePixels_RLE(FreeImageIO *io, fi_handle handle, FIRGBF *data, unsigned scanline_width, unsigned num_scanlines); +static BOOL rgbe_ReadMetadata(FIBITMAP *dib, rgbeHeaderInfo *header_info); +static BOOL rgbe_WriteMetadata(FIBITMAP *dib, rgbeHeaderInfo *header_info); + +// ---------------------------------------------------------- + +/** +Default error routine. change this to change error handling +*/ +static BOOL +rgbe_Error(rgbe_error_code error_code, const char *msg) { + switch (error_code) { + case rgbe_read_error: + FreeImage_OutputMessageProc(s_format_id, "RGBE read error"); + break; + case rgbe_write_error: + FreeImage_OutputMessageProc(s_format_id, "RGBE write error"); + break; + case rgbe_format_error: + FreeImage_OutputMessageProc(s_format_id, "RGBE bad file format: %s\n", msg); + break; + default: + case rgbe_memory_error: + FreeImage_OutputMessageProc(s_format_id, "RGBE error: %s\n",msg); + } + + return FALSE; +} + +/** +Get a line from a ASCII io stream +*/ +static BOOL +rgbe_GetLine(FreeImageIO *io, fi_handle handle, char *buffer, int length) { + int i; + memset(buffer, 0, length); + for(i = 0; i < length; i++) { + if (!io->read_proc(&buffer[i], 1, 1, handle)) + return FALSE; + if(buffer[i] == 0x0A) + break; + } + + return (i < length) ? TRUE : FALSE; +} + +/** +Standard conversion from float pixels to rgbe pixels. +Note: you can remove the "inline"s if your compiler complains about it +*/ +static inline void +rgbe_FloatToRGBE(BYTE rgbe[4], FIRGBF *rgbf) { + float v; + int e; + + v = rgbf->red; + if (rgbf->green > v) v = rgbf->green; + if (rgbf->blue > v) v = rgbf->blue; + if (v < 1e-32) { + rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; + } + else { + v = (float)(frexp(v, &e) * 256.0 / v); + rgbe[0] = (BYTE) (rgbf->red * v); + rgbe[1] = (BYTE) (rgbf->green * v); + rgbe[2] = (BYTE) (rgbf->blue * v); + rgbe[3] = (BYTE) (e + 128); + } +} + +/** +Standard conversion from rgbe to float pixels. +Note: Ward uses ldexp(col+0.5,exp-(128+8)). +However we wanted pixels in the range [0,1] to map back into the range [0,1]. +*/ +static inline void +rgbe_RGBEToFloat(FIRGBF *rgbf, BYTE rgbe[4]) { + if (rgbe[3]) { // nonzero pixel + float f = (float)(ldexp(1.0, rgbe[3] - (int)(128+8))); + rgbf->red = rgbe[0] * f; + rgbf->green = rgbe[1] * f; + rgbf->blue = rgbe[2] * f; + + } + else { + rgbf->red = rgbf->green = rgbf->blue = 0; + } +} + +/** +Minimal header reading. Modify if you want to parse more information +*/ +static BOOL +rgbe_ReadHeader(FreeImageIO *io, fi_handle handle, unsigned *width, unsigned *height, rgbeHeaderInfo *header_info) { + char buf[HDR_MAXLINE]; + float tempf; + int i; + BOOL bFormatFound = FALSE; + BOOL bHeaderFound = FALSE; + + header_info->valid = 0; + header_info->programtype[0] = 0; + header_info->gamma = 1.0; + header_info->exposure = 1.0; + + // get the first line + if (!rgbe_GetLine(io, handle, buf, HDR_MAXLINE)) + return rgbe_Error(rgbe_read_error, NULL); + + // check the signature + + if ((buf[0] != '#')||(buf[1] != '?')) { + // if you don't want to require the magic token then comment the next line + return rgbe_Error(rgbe_format_error,"bad initial token"); + } + else { + header_info->valid |= RGBE_VALID_PROGRAMTYPE; + for(i = 0; i < sizeof(header_info->programtype) - 1; i++) { + if ((buf[i+2] == 0) || isspace(buf[i+2])) + break; + header_info->programtype[i] = buf[i+2]; + } + header_info->programtype[i] = 0; + } + + for (;;) { + // get next line + if (!rgbe_GetLine(io, handle, buf, HDR_MAXLINE)) + return rgbe_Error(rgbe_read_error, NULL); + + if ((buf[0] == 0) || (buf[0] == '\n')) { + // end of header so break out of loop + bHeaderFound = TRUE; + break; + } + else if(strcmp(buf,"FORMAT=32-bit_rle_rgbe\n") == 0) { + bFormatFound = TRUE; + } + else if(sscanf(buf, "GAMMA=%g", &tempf) == 1) { + header_info->gamma = tempf; + header_info->valid |= RGBE_VALID_GAMMA; + } + else if(sscanf(buf,"EXPOSURE=%g",&tempf) == 1) { + header_info->exposure = tempf; + header_info->valid |= RGBE_VALID_EXPOSURE; + } + else if ((buf[0] == '#') && (buf[1] == 0x20)) { + header_info->valid |= RGBE_VALID_COMMENT; + strcpy(header_info->comment, buf); + } + } + if (!bHeaderFound || !bFormatFound) { + return rgbe_Error(rgbe_format_error, "invalid header"); + } + + // get next line + if (!rgbe_GetLine(io, handle, buf, HDR_MAXLINE)) + return rgbe_Error(rgbe_read_error, NULL); + + // get the image width & height + if(sscanf(buf,"-Y %d +X %d", height, width) < 2) { + if(sscanf(buf,"+X %d +Y %d", height, width) < 2) { + return rgbe_Error(rgbe_format_error, "missing image size specifier"); + } + } + + return TRUE; +} + +/** + default minimal header. modify if you want more information in header +*/ +static BOOL +rgbe_WriteHeader(FreeImageIO *io, fi_handle handle, unsigned width, unsigned height, rgbeHeaderInfo *info) { + char buffer[HDR_MAXLINE]; + + const char *programtype = "RADIANCE"; + + if(info && (info->valid & RGBE_VALID_PROGRAMTYPE)) { + programtype = info->programtype; + } + // The #? is to identify file type, the programtype is optional + sprintf(buffer, "#?%s\n", programtype); + if(io->write_proc(buffer, 1, (unsigned int)strlen(buffer), handle) < 1) + return rgbe_Error(rgbe_write_error, NULL); + sprintf(buffer, "%s\n", info->comment); + if(io->write_proc(buffer, 1, (unsigned int)strlen(buffer), handle) < 1) + return rgbe_Error(rgbe_write_error, NULL); + sprintf(buffer, "FORMAT=32-bit_rle_rgbe\n"); + if(io->write_proc(buffer, 1, (unsigned int)strlen(buffer), handle) < 1) + return rgbe_Error(rgbe_write_error, NULL); + if(info && (info->valid & RGBE_VALID_GAMMA)) { + sprintf(buffer, "GAMMA=%g\n", info->gamma); + if(io->write_proc(buffer, 1, (unsigned int)strlen(buffer), handle) < 1) + return rgbe_Error(rgbe_write_error, NULL); + } + if(info && (info->valid & RGBE_VALID_EXPOSURE)) { + sprintf(buffer,"EXPOSURE=%g\n", info->exposure); + if(io->write_proc(buffer, 1, (unsigned int)strlen(buffer), handle) < 1) + return rgbe_Error(rgbe_write_error, NULL); + } + sprintf(buffer, "\n-Y %d +X %d\n", height, width); + if(io->write_proc(buffer, 1, (unsigned int)strlen(buffer), handle) < 1) + return rgbe_Error(rgbe_write_error, NULL); + + return TRUE; +} + +static BOOL +rgbe_ReadMetadata(FIBITMAP *dib, rgbeHeaderInfo *header_info) { + return TRUE; +} +static BOOL +rgbe_WriteMetadata(FIBITMAP *dib, rgbeHeaderInfo *header_info) { + header_info->gamma = 1; + header_info->valid |= RGBE_VALID_GAMMA; + header_info->exposure = 0; + header_info->valid |= RGBE_VALID_EXPOSURE; + + return TRUE; +} + +/** +Simple read routine. Will not correctly handle run length encoding +*/ +static BOOL +rgbe_ReadPixels(FreeImageIO *io, fi_handle handle, FIRGBF *data, unsigned numpixels) { + BYTE rgbe[4]; + + for(unsigned x = 0; x < numpixels; x++) { + if(io->read_proc(rgbe, 1, sizeof(rgbe), handle) < 1) { + return rgbe_Error(rgbe_read_error, NULL); + } + rgbe_RGBEToFloat(&data[x], rgbe); + } + + return TRUE; +} + +/** + Simple write routine that does not use run length encoding. + These routines can be made faster by allocating a larger buffer and + fread-ing and fwrite-ing the data in larger chunks. +*/ +static BOOL +rgbe_WritePixels(FreeImageIO *io, fi_handle handle, FIRGBF *data, unsigned numpixels) { + BYTE rgbe[4]; + + for(unsigned x = 0; x < numpixels; x++) { + rgbe_FloatToRGBE(rgbe, &data[x]); + if(io->write_proc(rgbe, sizeof(rgbe), 1, handle) < 1) + return rgbe_Error(rgbe_write_error, NULL); + } + + return TRUE; +} + +static BOOL +rgbe_ReadPixels_RLE(FreeImageIO *io, fi_handle handle, FIRGBF *data, int scanline_width, unsigned num_scanlines) { + BYTE rgbe[4], *scanline_buffer, *ptr, *ptr_end; + int i, count; + BYTE buf[2]; + + if ((scanline_width < 8)||(scanline_width > 0x7fff)) { + // run length encoding is not allowed so read flat + return rgbe_ReadPixels(io, handle, data, scanline_width * num_scanlines); + } + scanline_buffer = NULL; + // read in each successive scanline + while(num_scanlines > 0) { + if(io->read_proc(rgbe, 1, sizeof(rgbe), handle) < 1) { + free(scanline_buffer); + return rgbe_Error(rgbe_read_error,NULL); + } + if ((rgbe[0] != 2) || (rgbe[1] != 2) || (rgbe[2] & 0x80)) { + // this file is not run length encoded + rgbe_RGBEToFloat(data, rgbe); + data ++; + free(scanline_buffer); + return rgbe_ReadPixels(io, handle, data, scanline_width * num_scanlines - 1); + } + if ((((int)rgbe[2]) << 8 | rgbe[3]) != scanline_width) { + free(scanline_buffer); + return rgbe_Error(rgbe_format_error,"wrong scanline width"); + } + if(scanline_buffer == NULL) { + scanline_buffer = (BYTE*)malloc(sizeof(BYTE) * 4 * scanline_width); + if(scanline_buffer == NULL) { + return rgbe_Error(rgbe_memory_error, "unable to allocate buffer space"); + } + } + + ptr = &scanline_buffer[0]; + // read each of the four channels for the scanline into the buffer + for(i = 0; i < 4; i++) { + ptr_end = &scanline_buffer[(i+1)*scanline_width]; + while(ptr < ptr_end) { + if(io->read_proc(buf, 1, 2 * sizeof(BYTE), handle) < 1) { + free(scanline_buffer); + return rgbe_Error(rgbe_read_error, NULL); + } + if(buf[0] > 128) { + // a run of the same value + count = buf[0] - 128; + if ((count == 0) || (count > ptr_end - ptr)) { + free(scanline_buffer); + return rgbe_Error(rgbe_format_error, "bad scanline data"); + } + while(count-- > 0) + *ptr++ = buf[1]; + } + else { + // a non-run + count = buf[0]; + if ((count == 0) || (count > ptr_end - ptr)) { + free(scanline_buffer); + return rgbe_Error(rgbe_format_error, "bad scanline data"); + } + *ptr++ = buf[1]; + if (--count > 0) { + if(io->read_proc(ptr, 1, sizeof(BYTE) * count, handle) < 1) { + free(scanline_buffer); + return rgbe_Error(rgbe_read_error, NULL); + } + ptr += count; + } + } + } + } + // now convert data from buffer into floats + for(i = 0; i < scanline_width; i++) { + rgbe[0] = scanline_buffer[i]; + rgbe[1] = scanline_buffer[i+scanline_width]; + rgbe[2] = scanline_buffer[i+2*scanline_width]; + rgbe[3] = scanline_buffer[i+3*scanline_width]; + rgbe_RGBEToFloat(data, rgbe); + data ++; + } + + num_scanlines--; + } + + free(scanline_buffer); + + return TRUE; +} + +/** + The code below is only needed for the run-length encoded files. + Run length encoding adds considerable complexity but does + save some space. For each scanline, each channel (r,g,b,e) is + encoded separately for better compression. + @return Returns TRUE if successful, returns FALSE otherwise +*/ +static BOOL +rgbe_WriteBytes_RLE(FreeImageIO *io, fi_handle handle, BYTE *data, int numbytes) { + static const int MINRUNLENGTH = 4; + int cur, beg_run, run_count, old_run_count, nonrun_count; + BYTE buf[2]; + + cur = 0; + while(cur < numbytes) { + beg_run = cur; + // find next run of length at least 4 if one exists + run_count = old_run_count = 0; + while((run_count < MINRUNLENGTH) && (beg_run < numbytes)) { + beg_run += run_count; + old_run_count = run_count; + run_count = 1; + while((data[beg_run] == data[beg_run + run_count]) && (beg_run + run_count < numbytes) && (run_count < 127)) + run_count++; + } + // if data before next big run is a short run then write it as such + if ((old_run_count > 1)&&(old_run_count == beg_run - cur)) { + buf[0] = (BYTE)(128 + old_run_count); // write short run + buf[1] = data[cur]; + if(io->write_proc(buf, 2 * sizeof(BYTE), 1, handle) < 1) + return rgbe_Error(rgbe_write_error, NULL); + cur = beg_run; + } + // write out bytes until we reach the start of the next run + while(cur < beg_run) { + nonrun_count = beg_run - cur; + if (nonrun_count > 128) + nonrun_count = 128; + buf[0] = (BYTE)nonrun_count; + if(io->write_proc(buf, sizeof(buf[0]), 1, handle) < 1) + return rgbe_Error(rgbe_write_error,NULL); + if(io->write_proc(&data[cur], sizeof(data[0]) * nonrun_count, 1, handle) < 1) + return rgbe_Error(rgbe_write_error,NULL); + cur += nonrun_count; + } + // write out next run if one was found + if (run_count >= MINRUNLENGTH) { + buf[0] = (BYTE)(128 + run_count); + buf[1] = data[beg_run]; + if(io->write_proc(buf, sizeof(buf[0]) * 2, 1, handle) < 1) + return rgbe_Error(rgbe_write_error,NULL); + cur += run_count; + } + } + + return TRUE; +} + +static BOOL +rgbe_WritePixels_RLE(FreeImageIO *io, fi_handle handle, FIRGBF *data, unsigned scanline_width, unsigned num_scanlines) { + BYTE rgbe[4]; + BYTE *buffer; + + if ((scanline_width < 8)||(scanline_width > 0x7fff)) { + // run length encoding is not allowed so write flat + return rgbe_WritePixels(io, handle, data, scanline_width * num_scanlines); + } + buffer = (BYTE*)malloc(sizeof(BYTE) * 4 * scanline_width); + if (buffer == NULL) { + // no buffer space so write flat + return rgbe_WritePixels(io, handle, data, scanline_width * num_scanlines); + } + while(num_scanlines-- > 0) { + rgbe[0] = (BYTE)2; + rgbe[1] = (BYTE)2; + rgbe[2] = (BYTE)(scanline_width >> 8); + rgbe[3] = (BYTE)(scanline_width & 0xFF); + if(io->write_proc(rgbe, sizeof(rgbe), 1, handle) < 1) { + free(buffer); + return rgbe_Error(rgbe_write_error, NULL); + } + for(unsigned x = 0; x < scanline_width; x++) { + rgbe_FloatToRGBE(rgbe, data); + buffer[x] = rgbe[0]; + buffer[x+scanline_width] = rgbe[1]; + buffer[x+2*scanline_width] = rgbe[2]; + buffer[x+3*scanline_width] = rgbe[3]; + data ++; + } + // write out each of the four channels separately run length encoded + // first red, then green, then blue, then exponent + for(int i = 0; i < 4; i++) { + BOOL bOK = rgbe_WriteBytes_RLE(io, handle, &buffer[i*scanline_width], scanline_width); + if (!bOK) { + free(buffer); + return bOK; + } + } + } + free(buffer); + + return TRUE; +} + + +// ---------------------------------------------------------- + + + +// ========================================================== +// Plugin Implementation +// ========================================================== + +static const char * DLL_CALLCONV +Format() { + return "HDR"; +} + +static const char * DLL_CALLCONV +Description() { + return "High Dynamic Range Image"; +} + +static const char * DLL_CALLCONV +Extension() { + return "hdr"; +} + +static const char * DLL_CALLCONV +RegExpr() { + return NULL; +} + +static const char * DLL_CALLCONV +MimeType() { + return "image/vnd.radiance"; +} + +static BOOL DLL_CALLCONV +Validate(FreeImageIO *io, fi_handle handle) { + BYTE hdr_signature[] = { '#', '?' }; + BYTE signature[] = { 0, 0 }; + + io->read_proc(signature, 1, 2, handle); + + return (memcmp(hdr_signature, signature, 2) == 0); +} + +static BOOL DLL_CALLCONV +SupportsExportDepth(int depth) { + return FALSE; +} + +static BOOL DLL_CALLCONV +SupportsExportType(FREE_IMAGE_TYPE type) { + return (type == FIT_RGBF) ? TRUE : FALSE; +} + +static BOOL DLL_CALLCONV +SupportsNoPixels() { + return TRUE; +} + +// -------------------------------------------------------------------------- + +static FIBITMAP * DLL_CALLCONV +Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { + FIBITMAP *dib = NULL; + + if (!handle) { + return NULL; + } + + BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS; + + try { + + rgbeHeaderInfo header_info; + unsigned width, height; + + // Read the header + if(rgbe_ReadHeader(io, handle, &width, &height, &header_info) == FALSE) { + return NULL; + } + + // allocate a RGBF image + dib = FreeImage_AllocateHeaderT(header_only, FIT_RGBF, width, height); + if (!dib) { + throw FI_MSG_ERROR_MEMORY; + } + + // set the metadata as comments + rgbe_ReadMetadata(dib, &header_info); + + if(header_only) { + // header only mode + return dib; + } + + // read the image pixels and fill the dib + + for(unsigned y = 0; y < height; y++) { + FIRGBF *scanline = (FIRGBF*)FreeImage_GetScanLine(dib, height - 1 - y); + if (!rgbe_ReadPixels_RLE(io, handle, scanline, width, 1)) { + FreeImage_Unload(dib); + return NULL; + } + } + + } + catch(const char *text) { + if(dib != NULL) { + FreeImage_Unload(dib); + } + FreeImage_OutputMessageProc(s_format_id, text); + } + + return dib; +} + +static BOOL DLL_CALLCONV +Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) { + if (!dib) return FALSE; + + if(FreeImage_GetImageType(dib) != FIT_RGBF) { + return FALSE; + } + + unsigned width = FreeImage_GetWidth(dib); + unsigned height = FreeImage_GetHeight(dib); + + // write the header + + rgbeHeaderInfo header_info; + memset(&header_info, 0, sizeof(rgbeHeaderInfo)); + // fill the header with correct gamma and exposure + rgbe_WriteMetadata(dib, &header_info); + // fill a comment + sprintf(header_info.comment, "# Made with FreeImage %s", FreeImage_GetVersion()); + if (!rgbe_WriteHeader(io, handle, width, height, &header_info)) { + return FALSE; + } + + // write each scanline + + for(unsigned y = 0; y < height; y++) { + FIRGBF *scanline = (FIRGBF*)FreeImage_GetScanLine(dib, height - 1 - y); + if (!rgbe_WritePixels_RLE(io, handle, scanline, width, 1)) { + return FALSE; + } + } + + return TRUE; +} + +// ========================================================== +// Init +// ========================================================== + +void DLL_CALLCONV +InitHDR(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; +} |