diff options
Diffstat (limited to 'plugins/FreeImage/Source/FreeImage/PluginPFM.cpp')
| -rw-r--r-- | plugins/FreeImage/Source/FreeImage/PluginPFM.cpp | 402 | 
1 files changed, 402 insertions, 0 deletions
diff --git a/plugins/FreeImage/Source/FreeImage/PluginPFM.cpp b/plugins/FreeImage/Source/FreeImage/PluginPFM.cpp new file mode 100644 index 0000000000..c74f1c7ca9 --- /dev/null +++ b/plugins/FreeImage/Source/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/freeimage-pfm";
 +}
 +
 +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;
 +}
  | 
