summaryrefslogtreecommitdiff
path: root/plugins/AdvaImg/src/FreeImage/PluginPFM.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/AdvaImg/src/FreeImage/PluginPFM.cpp')
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginPFM.cpp402
1 files changed, 402 insertions, 0 deletions
diff --git a/plugins/AdvaImg/src/FreeImage/PluginPFM.cpp b/plugins/AdvaImg/src/FreeImage/PluginPFM.cpp
new file mode 100644
index 0000000000..8ccbd48ba5
--- /dev/null
+++ b/plugins/AdvaImg/src/FreeImage/PluginPFM.cpp
@@ -0,0 +1,402 @@
+// ==========================================================
+// PFM 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"
+
+// ==========================================================
+// Internal functions
+// ==========================================================
+
+/** maximum size of a line in the header */
+#define PFM_MAXLINE 256
+
+/** Big endian / Little endian float conversion */
+#define REVERSEBYTES(source, dest) \
+{ \
+ char *j = (char *) source; \
+ char *dj = (char *) dest; \
+ dj[0] = j[3]; \
+ dj[1] = j[2]; \
+ dj[2] = j[1]; \
+ dj[3] = j[0]; \
+}
+
+/**
+Get a line from a ASCII io stream
+*/
+static BOOL
+pfm_get_line(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;
+}
+
+/**
+Get an integer value from the actual position pointed by handle
+*/
+static int
+pfm_get_int(FreeImageIO *io, fi_handle handle) {
+ char c = 0;
+ BOOL firstchar;
+
+ // skip forward to start of next number
+
+ if (!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING;
+
+ while (1) {
+ // eat comments
+
+ if (c == '#') {
+ // if we're at a comment, read to end of line
+
+ firstchar = TRUE;
+
+ while (1) {
+ if (!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING;
+
+ if (firstchar && c == ' ') {
+ // loop off 1 sp after #
+
+ firstchar = FALSE;
+ } else if (c == '\n') {
+ break;
+ }
+ }
+ }
+
+ if (c >= '0' && c <='9') {
+ // we've found what we were looking for
+
+ break;
+ }
+
+ if (!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING;
+ }
+
+ // we're at the start of a number, continue until we hit a non-number
+
+ int i = 0;
+
+ while (1) {
+ i = (i * 10) + (c - '0');
+
+ if (!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING;
+
+ if (c < '0' || c > '9')
+ break;
+ }
+
+ return i;
+}
+
+// ==========================================================
+// Plugin Interface
+// ==========================================================
+
+static int s_format_id;
+
+// ==========================================================
+// Plugin Implementation
+// ==========================================================
+
+static const char * DLL_CALLCONV
+Format() {
+ return "PFM";
+}
+
+static const char * DLL_CALLCONV
+Description() {
+ return "Portable floatmap";
+}
+
+static const char * DLL_CALLCONV
+Extension() {
+ return "pfm";
+}
+
+static const char * DLL_CALLCONV
+RegExpr() {
+ return NULL;
+}
+
+static const char * DLL_CALLCONV
+MimeType() {
+ return "image/x-portable-floatmap";
+}
+
+static BOOL DLL_CALLCONV
+Validate(FreeImageIO *io, fi_handle handle) {
+ BYTE pfm_id1[] = { 0x50, 0x46 };
+ BYTE pfm_id2[] = { 0x50, 0x66 };
+ BYTE signature[2] = { 0, 0 };
+
+ io->read_proc(signature, 1, sizeof(pfm_id1), handle);
+
+ if (memcmp(pfm_id1, signature, sizeof(pfm_id1)) == 0)
+ return TRUE;
+
+ if (memcmp(pfm_id2, signature, sizeof(pfm_id2)) == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+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)
+ );
+}
+
+static BOOL DLL_CALLCONV
+SupportsNoPixels() {
+ return TRUE;
+}
+
+// ----------------------------------------------------------
+
+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;
+ }
+
+}
+
+static BOOL DLL_CALLCONV
+Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
+ if (!dib || !handle) return FALSE;
+
+ FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
+ if ((image_type != FIT_RGBF) && (image_type != FIT_FLOAT)) {
+ return FALSE;
+ }
+
+ unsigned width = FreeImage_GetWidth(dib);
+ unsigned height = FreeImage_GetHeight(dib);
+ unsigned lineWidth = FreeImage_GetLine(dib);
+
+ // save image as Little Endian
+ const float scalefactor = -1.0F;
+
+ char buffer[PFM_MAXLINE]; // temporary buffer whose size should be enough for what we need
+
+ // Find the appropriate magic number for this file type
+
+ char magic = 0;
+
+ switch(image_type) {
+ case FIT_RGBF:
+ magic = 'F'; // RGBF
+ break;
+ case FIT_FLOAT:
+ magic = 'f'; // float greyscale
+ break;
+ default:
+ return FALSE;
+ }
+
+ // Write the header info
+
+ sprintf(buffer, "P%c\n%d %d\n%f\n", magic, width, height, scalefactor);
+ io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle);
+
+ // Write the image data
+ for (unsigned y = 0; y < height; y++) {
+ BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y);
+ io->write_proc(bits, 1, lineWidth, handle);
+ }
+
+ return TRUE;
+}
+
+// ==========================================================
+// Init
+// ==========================================================
+
+void DLL_CALLCONV
+InitPFM(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;
+}