summaryrefslogtreecommitdiff
path: root/Source/FreeImage/PluginXBM.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/FreeImage/PluginXBM.cpp')
-rw-r--r--Source/FreeImage/PluginXBM.cpp399
1 files changed, 399 insertions, 0 deletions
diff --git a/Source/FreeImage/PluginXBM.cpp b/Source/FreeImage/PluginXBM.cpp
new file mode 100644
index 0000000..0aac48c
--- /dev/null
+++ b/Source/FreeImage/PluginXBM.cpp
@@ -0,0 +1,399 @@
+// ==========================================================
+// XBM Loader
+//
+// Design and implementation by
+// - Hervé Drolon <drolon@infonie.fr>
+// part of the code adapted from the netPBM package (xbmtopbm.c)
+//
+// 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
+// ==========================================================
+
+#define MAX_LINE 512
+
+static const char *ERR_XBM_SYNTAX = "Syntax error";
+static const char *ERR_XBM_LINE = "Line too long";
+static const char *ERR_XBM_DECL = "Unable to find a line in the file containing the start of C array declaration (\"static char\" or whatever)";
+static const char *ERR_XBM_EOFREAD = "EOF / read error";
+static const char *ERR_XBM_WIDTH = "Invalid width";
+static const char *ERR_XBM_HEIGHT = "Invalid height";
+static const char *ERR_XBM_MEMORY = "Out of memory";
+
+/**
+Get a string from a stream.
+Read the string from the current stream to the first newline character.
+The result stored in str is appended with a null character.
+@param str Storage location for data
+@param n Maximum number of characters to read
+@param io Pointer to the FreeImageIO structure
+@param handle Handle to the stream
+@return Returns str. NULL is returned to indicate an error or an end-of-file condition.
+*/
+static char*
+readLine(char *str, int n, FreeImageIO *io, fi_handle handle) {
+ char c;
+ int count, i = 0;
+ do {
+ count = io->read_proc(&c, 1, 1, handle);
+ str[i++] = c;
+ } while((c != '\n') && (i < n));
+ if(count <= 0)
+ return NULL;
+ str[i] = '\0';
+ return str;
+}
+
+/**
+Get a char from the stream
+@param io Pointer to the FreeImageIO structure
+@param handle Handle to the stream
+@return Returns the next character in the stream
+*/
+static int
+readChar(FreeImageIO *io, fi_handle handle) {
+ BYTE c;
+ io->read_proc(&c, 1, 1, handle);
+ return c;
+}
+
+/**
+Read an XBM file into a buffer
+@param io Pointer to the FreeImageIO structure
+@param handle Handle to the stream
+@param widthP (return value) Pointer to the bitmap width
+@param heightP (return value) Pointer to the bitmap height
+@param dataP (return value) Pointer to the bitmap buffer
+@return Returns NULL if OK, returns an error message otherwise
+*/
+static const char*
+readXBMFile(FreeImageIO *io, fi_handle handle, int *widthP, int *heightP, char **dataP) {
+ char line[MAX_LINE], name_and_type[MAX_LINE];
+ char* ptr;
+ char* t;
+ int version = 0;
+ int raster_length, v;
+ int bytes, bytes_per_line, padding;
+ int c1, c2, value1, value2;
+ int hex_table[256];
+ BOOL found_declaration;
+ /* in scanning through the bitmap file, we have found the first
+ line of the C declaration of the array (the "static char ..."
+ or whatever line)
+ */
+ BOOL eof; // we've encountered end of file while searching file
+
+ *widthP = *heightP = -1;
+
+ found_declaration = FALSE; // haven't found it yet; haven't even looked
+ eof = FALSE; // haven't encountered end of file yet
+
+ while(!found_declaration && !eof) {
+
+ if( readLine(line, MAX_LINE, io, handle) == NULL) {
+ eof = TRUE;
+ }
+ else {
+ if( strlen( line ) == MAX_LINE - 1 )
+ return( ERR_XBM_LINE );
+ if( sscanf(line, "#define %s %d", name_and_type, &v) == 2 ) {
+ if( ( t = strrchr( name_and_type, '_' ) ) == NULL )
+ t = name_and_type;
+ else
+ t++;
+ if ( ! strcmp( "width", t ) )
+ *widthP = v;
+ else if ( ! strcmp( "height", t ) )
+ *heightP = v;
+ continue;
+ }
+
+ if( sscanf( line, "static short %s = {", name_and_type ) == 1 ) {
+ version = 10;
+ found_declaration = TRUE;
+ }
+ else if( sscanf( line, "static char %s = {", name_and_type ) == 1 ) {
+ version = 11;
+ found_declaration = TRUE;
+ }
+ else if(sscanf(line, "static unsigned char %s = {", name_and_type ) == 1 ) {
+ version = 11;
+ found_declaration = TRUE;
+ }
+ }
+ }
+
+ if(!found_declaration)
+ return( ERR_XBM_DECL );
+
+ if(*widthP == -1 )
+ return( ERR_XBM_WIDTH );
+ if( *heightP == -1 )
+ return( ERR_XBM_HEIGHT );
+
+ padding = 0;
+ if ( ((*widthP % 16) >= 1) && ((*widthP % 16) <= 8) && (version == 10) )
+ padding = 1;
+
+ bytes_per_line = (*widthP + 7) / 8 + padding;
+
+ raster_length = bytes_per_line * *heightP;
+ *dataP = (char*) malloc( raster_length );
+ if ( *dataP == (char*) 0 )
+ return( ERR_XBM_MEMORY );
+
+ // initialize hex_table
+ for ( c1 = 0; c1 < 256; c1++ ) {
+ hex_table[c1] = 256;
+ }
+ hex_table['0'] = 0;
+ hex_table['1'] = 1;
+ hex_table['2'] = 2;
+ hex_table['3'] = 3;
+ hex_table['4'] = 4;
+ hex_table['5'] = 5;
+ hex_table['6'] = 6;
+ hex_table['7'] = 7;
+ hex_table['8'] = 8;
+ hex_table['9'] = 9;
+ hex_table['A'] = 10;
+ hex_table['B'] = 11;
+ hex_table['C'] = 12;
+ hex_table['D'] = 13;
+ hex_table['E'] = 14;
+ hex_table['F'] = 15;
+ hex_table['a'] = 10;
+ hex_table['b'] = 11;
+ hex_table['c'] = 12;
+ hex_table['d'] = 13;
+ hex_table['e'] = 14;
+ hex_table['f'] = 15;
+
+ if(version == 10) {
+ for( bytes = 0, ptr = *dataP; bytes < raster_length; bytes += 2 ) {
+ while( ( c1 = readChar(io, handle) ) != 'x' ) {
+ if ( c1 == EOF )
+ return( ERR_XBM_EOFREAD );
+ }
+
+ c1 = readChar(io, handle);
+ c2 = readChar(io, handle);
+ if( c1 == EOF || c2 == EOF )
+ return( ERR_XBM_EOFREAD );
+ value1 = ( hex_table[c1] << 4 ) + hex_table[c2];
+ if ( value1 >= 256 )
+ return( ERR_XBM_SYNTAX );
+ c1 = readChar(io, handle);
+ c2 = readChar(io, handle);
+ if( c1 == EOF || c2 == EOF )
+ return( ERR_XBM_EOFREAD );
+ value2 = ( hex_table[c1] << 4 ) + hex_table[c2];
+ if ( value2 >= 256 )
+ return( ERR_XBM_SYNTAX );
+ *ptr++ = (char)value2;
+ if ( ( ! padding ) || ( ( bytes + 2 ) % bytes_per_line ) )
+ *ptr++ = (char)value1;
+ }
+ }
+ else {
+ for(bytes = 0, ptr = *dataP; bytes < raster_length; bytes++ ) {
+ /*
+ ** skip until digit is found
+ */
+ for( ; ; ) {
+ c1 = readChar(io, handle);
+ if ( c1 == EOF )
+ return( ERR_XBM_EOFREAD );
+ value1 = hex_table[c1];
+ if ( value1 != 256 )
+ break;
+ }
+ /*
+ ** loop on digits
+ */
+ for( ; ; ) {
+ c2 = readChar(io, handle);
+ if ( c2 == EOF )
+ return( ERR_XBM_EOFREAD );
+ value2 = hex_table[c2];
+ if ( value2 != 256 ) {
+ value1 = (value1 << 4) | value2;
+ if ( value1 >= 256 )
+ return( ERR_XBM_SYNTAX );
+ }
+ else if ( c2 == 'x' || c2 == 'X' ) {
+ if ( value1 == 0 )
+ continue;
+ else return( ERR_XBM_SYNTAX );
+ }
+ else break;
+ }
+ *ptr++ = (char)value1;
+ }
+ }
+
+ return NULL;
+}
+
+// ==========================================================
+// Plugin Interface
+// ==========================================================
+
+static int s_format_id;
+
+// ==========================================================
+// Plugin Implementation
+// ==========================================================
+
+static const char * DLL_CALLCONV
+Format() {
+ return "XBM";
+}
+
+static const char * DLL_CALLCONV
+Description() {
+ return "X11 Bitmap Format";
+}
+
+static const char * DLL_CALLCONV
+Extension() {
+ return "xbm";
+}
+
+static const char * DLL_CALLCONV
+RegExpr() {
+ return NULL;
+}
+
+static const char * DLL_CALLCONV
+MimeType() {
+ return "image/x-xbitmap";
+}
+
+static BOOL DLL_CALLCONV
+Validate(FreeImageIO *io, fi_handle handle) {
+ char magic[8];
+ if(readLine(magic, 7, io, handle)) {
+ if(strcmp(magic, "#define") == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static BOOL DLL_CALLCONV
+SupportsExportDepth(int depth) {
+ return FALSE;
+}
+
+static BOOL DLL_CALLCONV
+SupportsExportType(FREE_IMAGE_TYPE type) {
+ return FALSE;
+}
+
+// ----------------------------------------------------------
+
+static FIBITMAP * DLL_CALLCONV
+Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
+ char *buffer = NULL;
+ int width, height;
+ FIBITMAP *dib = NULL;
+
+ try {
+
+ // load the bitmap data
+ const char* error = readXBMFile(io, handle, &width, &height, &buffer);
+ // Microsoft doesn't implement throw between functions :(
+ if(error) throw (char*)error;
+
+
+ // allocate a new dib
+ dib = FreeImage_Allocate(width, height, 1);
+ if(!dib) throw (char*)ERR_XBM_MEMORY;
+
+ // write the palette data
+ RGBQUAD *pal = FreeImage_GetPalette(dib);
+ pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0;
+ pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255;
+
+ // copy the bitmap
+ BYTE *bP = (BYTE*)buffer;
+ for(int y = 0; y < height; y++) {
+ BYTE count = 0;
+ BYTE mask = 1;
+ BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y);
+
+ for(int x = 0; x < width; x++) {
+ if(count >= 8) {
+ bP++;
+ count = 0;
+ mask = 1;
+ }
+ if(*bP & mask) {
+ // Set bit(x, y) to 0
+ bits[x >> 3] &= (0xFF7F >> (x & 0x7));
+ } else {
+ // Set bit(x, y) to 1
+ bits[x >> 3] |= (0x80 >> (x & 0x7));
+ }
+ count++;
+ mask <<= 1;
+ }
+ bP++;
+ }
+
+ free(buffer);
+ return dib;
+
+ } catch(const char *text) {
+ if(buffer) free(buffer);
+ if(dib) FreeImage_Unload(dib);
+ FreeImage_OutputMessageProc(s_format_id, text);
+ return NULL;
+ }
+}
+
+
+// ==========================================================
+// Init
+// ==========================================================
+
+void DLL_CALLCONV
+InitXBM(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 = NULL;
+ 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;
+}
+