diff options
Diffstat (limited to 'converter/pbm/xbmtopbm.c')
-rw-r--r-- | converter/pbm/xbmtopbm.c | 568 |
1 files changed, 352 insertions, 216 deletions
diff --git a/converter/pbm/xbmtopbm.c b/converter/pbm/xbmtopbm.c index 7779a9b5..9505ba67 100644 --- a/converter/pbm/xbmtopbm.c +++ b/converter/pbm/xbmtopbm.c @@ -1,4 +1,4 @@ -/* xbmtopbm.c - read an X bitmap file and produce a portable bitmap +/* xbmtopbm.c - read an X bitmap file and produce a PBM image ** ** Copyright (C) 1988 by Jef Poskanzer. ** @@ -10,246 +10,382 @@ ** implied warranty. */ + +#include <assert.h> #include <string.h> +#include "pm_c_util.h" +#include "mallocvar.h" #include "nstring.h" #include "pbm.h" +#include "bitreverse.h" -#define TRUE 1 -#define FALSE 0 -static void ReadBitmapFile ARGS(( FILE* stream, int* widthP, int* heightP, char** dataP )); -int -main( argc, argv ) - int argc; - char* argv[]; - { - FILE* ifp; - bit* bitrow; - register bit* bP; - int rows, cols, row, col, charcount; - char* data; - char mask; - - pbm_init( &argc, argv ); - - if ( argc > 2 ) - pm_usage( "[bitmapfile]" ); - - if ( argc == 2 ) - ifp = pm_openr( argv[1] ); - else - ifp = stdin; - - ReadBitmapFile( ifp, &cols, &rows, &data ); - - pm_close( ifp ); - - pbm_writepbminit( stdout, cols, rows, 0 ); - bitrow = pbm_allocrow( cols ); - - for ( row = 0; row < rows; ++row ) - { - charcount = 0; - mask = 1; - for ( col = 0, bP = bitrow; col < cols; ++col, ++bP ) - { - if ( charcount >= 8 ) - { - ++data; - charcount = 0; - mask = 1; - } - *bP = ( *data & mask ) ? PBM_BLACK : PBM_WHITE; - ++charcount; - mask = mask << 1; - } - ++data; - pbm_writepbmrow( stdout, bitrow, cols, 0 ); - } +#define MAX_LINE 500 + +static unsigned int hexTable[256]; + /* Hexadecimal ASCII translation table. Constant */ + +static void +initHexTable(void) { + + unsigned int i; + + for (i = 0; i < 256; ++i) + hexTable[i] = 256; + + hexTable['0'] = 0; + hexTable['1'] = 1; + hexTable['2'] = 2; + hexTable['3'] = 3; + hexTable['4'] = 4; + hexTable['5'] = 5; + hexTable['6'] = 6; + hexTable['7'] = 7; + hexTable['8'] = 8; + hexTable['9'] = 9; + hexTable['A'] = 10; + hexTable['B'] = 11; + hexTable['C'] = 12; + hexTable['D'] = 13; + hexTable['E'] = 14; + hexTable['F'] = 15; + hexTable['a'] = 10; + hexTable['b'] = 11; + hexTable['c'] = 12; + hexTable['d'] = 13; + hexTable['e'] = 14; + hexTable['f'] = 15; +} - pm_close( stdout ); - exit( 0 ); - } -#define MAX_LINE 500 static void -ReadBitmapFile( stream, widthP, heightP, dataP ) - FILE* stream; - int* widthP; - int* heightP; - char** dataP; -{ - char line[MAX_LINE], name_and_type[MAX_LINE]; - char* ptr; - char* t; - int version10, raster_length, v; - register int bytes, bytes_per_line, padding; - register int c1, c2, value1, value2; - int hex_table[256]; - int 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) - */ - int 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 ( fgets( line, MAX_LINE, stream ) == NULL ) - eof = TRUE; - else { - if ( strlen( line ) == MAX_LINE - 1 ) - pm_error( "line too long" ); - - if ( sscanf( line, "#define %s %d", name_and_type, &v ) == 2 ) { - if ( ( t = strrchr( name_and_type, '_' ) ) == NULL ) - t = name_and_type; +parseWidthHeightLine(const char * const line, + bool * const gotWidthP, + unsigned int * const widthP, + bool * const gotHeightP, + unsigned int * const heightP) { + + int rc; + char nameAndType[MAX_LINE]; + unsigned int value; + + rc = sscanf(line, "#define %s %u", nameAndType, &value); + if (rc == 2) { + const char * underscorePos = strrchr(nameAndType, '_'); + const char * type; + if (underscorePos) + type = underscorePos + 1; else - ++t; - if ( STREQ( "width", t ) ) - *widthP = v; - else if ( STREQ( "height", t ) ) - *heightP = v; - continue; - } + type = nameAndType; + if (streq(type, "width")) { + *gotWidthP = TRUE; + *widthP = value; + } else if (streq(type, "height")) { + *gotHeightP = TRUE; + *heightP = value; + } + } +} + + + +static void +parseDeclaration(const char * const line, + bool * const isDeclarationP, + bool * const version10P) { +/*---------------------------------------------------------------------------- + Parse the XBM file line 'line' as the first line of the data structure + declaration, i.e. the one that looks like this: + + static unsigned char myImage = { + + Return as *isDeclarationP whether the line actually is such a line, + and if so, return as nameAndType what the variable name ('myImage' + in the example) is and as *version10P whether it's of the type used + by X10 as opposed to X11. +-----------------------------------------------------------------------------*/ + char nameAndType[MAX_LINE]; + int rc; - if ( sscanf( line, "static short %s = {", name_and_type ) == 1 ) { - version10 = TRUE; - found_declaration = TRUE; - } - else if ( sscanf( line, "static char %s = {", name_and_type ) == 1 ) { - version10 = FALSE; - found_declaration = TRUE; - } - else if (sscanf(line, - "static unsigned char %s = {", name_and_type ) == 1 ) { - version10 = FALSE; - found_declaration = TRUE; - } + rc = sscanf(line, "static short %s = {", nameAndType); + if (rc == 1) { + *version10P = TRUE; + *isDeclarationP = TRUE; + } else { + int rc; + rc = sscanf(line, "static char %s = {", nameAndType); + if (rc == 1) { + *version10P = FALSE; + *isDeclarationP = TRUE; + } else { + int rc; + rc = sscanf(line, "static unsigned char %s = {", nameAndType); + if (rc == 1) { + *version10P = FALSE; + *isDeclarationP = TRUE; + } else + *isDeclarationP = FALSE; + } } - } - - if (!found_declaration) - pm_error("Unable to find a line in the file containing the start " - "of C array declaration (\"static char\" or whatever)"); - - if ( *widthP == -1 ) - pm_error( "invalid width" ); - if ( *heightP == -1 ) - pm_error( "invalid height" ); - - padding = 0; - if ( ((*widthP % 16) >= 1) && ((*widthP % 16) <= 8) && version10 ) - padding = 1; - - bytes_per_line = (*widthP+7)/8 + padding; +} + + + +static void +getXbmHeader(FILE * const ifP, + unsigned int * const widthP, + unsigned int * const heightP, + bool * const version10P) { + + bool foundDeclaration; + /* 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 gotWidth, gotHeight; + /* We found the line in the bitmap file that gives the width + or height, respectively, of the image (and have set + *widthP or *heightP to the value in it). + */ + + bool eof; + /* We've encountered end of file while searching file */ + + gotWidth = FALSE; + gotHeight = FALSE; + foundDeclaration = FALSE; /* Haven't found it yet; haven't even looked*/ + eof = FALSE; /* Haven't encountered end of file yet */ + + while (!foundDeclaration && !eof) { + char * rc; + char line[MAX_LINE]; + + rc = fgets(line, MAX_LINE, ifP); + if (rc == NULL) + eof = TRUE; + else { + if (strlen(line) == MAX_LINE - 1) + pm_error("A line in the input file is %u characters long. " + "%u is the maximum we can handle", + strlen(line), MAX_LINE-1); + + parseWidthHeightLine(line, &gotWidth, widthP, &gotHeight, heightP); + + parseDeclaration(line, &foundDeclaration, version10P); + } + } + + if (!foundDeclaration) + pm_error("Unable to find a line in the file containing the start " + "of C array declaration (\"static char\" or whatever)"); + + if (!gotWidth) + pm_error("Unable to find the #define statement that gives the " + "width of the image, before the data structure " + "declaration."); + if (!gotHeight) + pm_error("Unable to find the #define statement that gives the " + "height of the image, before the data structure " + "declaration."); +} + + + +static void +getHexByte(FILE * const ifP, + unsigned int * const valueP) { + + int c1, c2; + unsigned int value; + + c1 = getc(ifP); + c2 = getc(ifP); + if (c1 == EOF || c2 == EOF) + pm_error("EOF / read error"); + + assert(c1 >= 0); assert(c1 < 256); + assert(c2 >= 0); assert(c2 < 256); - raster_length = bytes_per_line * *heightP; - *dataP = (char*) malloc( raster_length ); - if ( *dataP == (char*) 0 ) - pm_error( "out of 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 ( version10 ) - for ( bytes = 0, ptr = *dataP; bytes < raster_length; bytes += 2 ) { - while ( ( c1 = getc( stream ) ) != 'x' ) - if ( c1 == EOF ) - pm_error( "EOF / read error" ); - c1 = getc( stream ); - c2 = getc( stream ); - if ( c1 == EOF || c2 == EOF ) - pm_error( "EOF / read error" ); - value1 = ( hex_table[c1] << 4 ) + hex_table[c2]; - if ( value1 >= 256 ) - pm_error( "syntax error" ); - c1 = getc( stream ); - c2 = getc( stream ); - if ( c1 == EOF || c2 == EOF ) - pm_error( "EOF / read error" ); - value2 = ( hex_table[c1] << 4 ) + hex_table[c2]; - if ( value2 >= 256 ) - pm_error( "syntax error" ); - *ptr++ = value2; - if ( ( ! padding ) || ( ( bytes + 2 ) % bytes_per_line ) ) - *ptr++ = value1; + value = (hexTable[c1] << 4) + hexTable[c2]; + if (value >= 256) + pm_error("Invalid XBM input. What should be a two digit " + "hexadecimal cipher is instead '%c%c'", c1, c2); + + *valueP = value; +} + + + +static void +readX10Raster(FILE * const ifP, + unsigned int const rasterLength, + unsigned char * const data, + unsigned int const bytesPerLine, + bool const mustPad) { + + unsigned int bytesDone; + unsigned char * p; + + for (bytesDone = 0, p = &data[0]; + bytesDone < rasterLength; + bytesDone += 2) { + + unsigned int value1; + unsigned int value2; + + while (getc(ifP) != 'x') {} /* Read up through the 'x' in 0x1234 */ + + getHexByte(ifP, &value1); /* Read first two hex digits */ + getHexByte(ifP, &value2); /* Read last two hex digits */ + + *p++ = value2; + + if (!mustPad || ((bytesDone + 2) % bytesPerLine)) + *p++ = value1; } - else - for ( bytes = 0, ptr = *dataP; bytes < raster_length; ++bytes ) { - /* - ** Skip until digit is found. - */ - for ( ; ; ) - { - c1 = getc( stream ); - if ( c1 == EOF ) - pm_error( "EOF / read error" ); - value1 = hex_table[c1]; - if ( value1 != 256 ) - break; - } - /* - ** Loop on digits. - */ - for ( ; ; ) { - c2 = getc( stream ); - if ( c2 == EOF ) - pm_error( "EOF / read error" ); - value2 = hex_table[c2]; - if ( value2 != 256 ) { - value1 = (value1 << 4) | value2; - if ( value1 >= 256 ) - pm_error( "syntax error" ); +} + + + +static void +readX11Raster(FILE * const ifP, + unsigned int const rasterLength, + unsigned char * data) { + + unsigned int i; + + for (i = 0; i < rasterLength; ++i) { + unsigned int value; + int c; + + /* Read up through the 'x' in 0x12 */ + while ((c = getc(ifP))) { + if (c == EOF) + pm_error("EOF where 0x expected"); + else if (toupper(c) == 'X') + break; } - else if ( c2 == 'x' || c2 == 'X' ) - if ( value1 == 0 ) - continue; - else pm_error( "syntax error" ); - else break; - } - *ptr++ = value1; + + getHexByte(ifP, &value); /* Read the two hex digits */ + + assert(value < 256); + + data[i] = value; } } -/* CHANGE HISTORY: - 99.09.08 bryanh Recognize "static unsigned char" declaration. +static void +readBitmapFile(FILE * const ifP, + unsigned int * const widthP, + unsigned int * const heightP, + unsigned char ** const dataP) { + + bool version10; + unsigned int rasterLength; + unsigned int width, height; + unsigned char * data; + unsigned int bytesPerLine; + bool mustPad; + getXbmHeader(ifP, &width, &height, &version10); + *widthP = width; + *heightP = height; + mustPad = (width % 16 >= 1 && width % 16 <= 8 && version10); + + bytesPerLine = (width + 7) / 8 + (mustPad ? 1 : 0); + + rasterLength = bytesPerLine * height; + + MALLOCARRAY(data, rasterLength); + if (data == NULL) + pm_error("Unable to allocate memory for the %u-byte raster", + rasterLength); + + if (version10) + readX10Raster(ifP, rasterLength, data, bytesPerLine, mustPad); + else + readX11Raster(ifP, rasterLength, data); + + *dataP = data; +} + + + +int +main(int argc, + char * argv[]) { + + FILE * ifP; + bit * bitrow; + unsigned int rows, cols; + unsigned int row; + unsigned char * data; + const char * inputFileName; + unsigned char * p; + /* Cursor in raster data data[] */ + + initHexTable(); + + pbm_init(&argc, argv); + + if (argc-1 > 1) + pm_error("The only possible argument is the input file name. " + "You specified %u arguments", argc-1); + + if (argc-1 > 0) + inputFileName = argv[1]; + else + inputFileName = "-"; + + ifP = pm_openr(inputFileName); + + readBitmapFile(ifP, &cols, &rows, &data); + + pm_close(ifP); + + pbm_writepbminit(stdout, cols, rows, 0); + bitrow = pbm_allocrow_packed(cols); + + p = &data[0]; /* Start at beginning of raster */ + + for (row = 0; row < rows; ++row) { + unsigned int const bytesPerRow = pbm_packed_bytes(cols); + unsigned int i; + + for (i = 0; i < bytesPerRow; ++i) + bitrow[i] = bitreverse[*p++]; + + if (cols % 8 > 0) { + bitrow[bytesPerRow-1] >>= 8 - cols % 8; + bitrow[bytesPerRow-1] <<= 8 - cols % 8; + } + + pbm_writepbmrow_packed(stdout, bitrow, cols, 0); + } + + pbm_freerow(bitrow); + free(data); + pm_close(stdout); + + return 0; +} + +/* CHANGE HISTORY: + + 99.09.08 bryanh Recognize "static unsigned char" declaration. + + 06.10 (afu) + Changed bitrow from plain to raw, write function from pbm_writepbmrow() + to pbm_writepbmrow_packed(). + Retired bitwise transformation functions. */ + |