|
Packit |
78deda |
/* xbmtopbm.c - read an X bitmap file and produce a PBM image
|
|
Packit |
78deda |
**
|
|
Packit |
78deda |
** Copyright (C) 1988 by Jef Poskanzer.
|
|
Packit |
78deda |
**
|
|
Packit |
78deda |
** Permission to use, copy, modify, and distribute this software and its
|
|
Packit |
78deda |
** documentation for any purpose and without fee is hereby granted, provided
|
|
Packit |
78deda |
** that the above copyright notice appear in all copies and that both that
|
|
Packit |
78deda |
** copyright notice and this permission notice appear in supporting
|
|
Packit |
78deda |
** documentation. This software is provided "as is" without express or
|
|
Packit |
78deda |
** implied warranty.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#include <assert.h>
|
|
Packit |
78deda |
#include <string.h>
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#include "pm_c_util.h"
|
|
Packit |
78deda |
#include "mallocvar.h"
|
|
Packit |
78deda |
#include "nstring.h"
|
|
Packit |
78deda |
#include "pbm.h"
|
|
Packit |
78deda |
#include "bitreverse.h"
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#define MAX_LINE 500
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static unsigned int hexTable[256];
|
|
Packit |
78deda |
/* Hexadecimal ASCII translation table. Constant */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
initHexTable(void) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int i;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (i = 0; i < 256; ++i)
|
|
Packit |
78deda |
hexTable[i] = 256;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
hexTable['0'] = 0;
|
|
Packit |
78deda |
hexTable['1'] = 1;
|
|
Packit |
78deda |
hexTable['2'] = 2;
|
|
Packit |
78deda |
hexTable['3'] = 3;
|
|
Packit |
78deda |
hexTable['4'] = 4;
|
|
Packit |
78deda |
hexTable['5'] = 5;
|
|
Packit |
78deda |
hexTable['6'] = 6;
|
|
Packit |
78deda |
hexTable['7'] = 7;
|
|
Packit |
78deda |
hexTable['8'] = 8;
|
|
Packit |
78deda |
hexTable['9'] = 9;
|
|
Packit |
78deda |
hexTable['A'] = 10;
|
|
Packit |
78deda |
hexTable['B'] = 11;
|
|
Packit |
78deda |
hexTable['C'] = 12;
|
|
Packit |
78deda |
hexTable['D'] = 13;
|
|
Packit |
78deda |
hexTable['E'] = 14;
|
|
Packit |
78deda |
hexTable['F'] = 15;
|
|
Packit |
78deda |
hexTable['a'] = 10;
|
|
Packit |
78deda |
hexTable['b'] = 11;
|
|
Packit |
78deda |
hexTable['c'] = 12;
|
|
Packit |
78deda |
hexTable['d'] = 13;
|
|
Packit |
78deda |
hexTable['e'] = 14;
|
|
Packit |
78deda |
hexTable['f'] = 15;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
parseWidthHeightLine(const char * const line,
|
|
Packit |
78deda |
bool * const gotWidthP,
|
|
Packit |
78deda |
unsigned int * const widthP,
|
|
Packit |
78deda |
bool * const gotHeightP,
|
|
Packit |
78deda |
unsigned int * const heightP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
int rc;
|
|
Packit |
78deda |
char nameAndType[MAX_LINE];
|
|
Packit |
78deda |
unsigned int value;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
rc = sscanf(line, "#define %s %u", nameAndType, &value);
|
|
Packit |
78deda |
if (rc == 2) {
|
|
Packit |
78deda |
const char * underscorePos = strrchr(nameAndType, '_');
|
|
Packit |
78deda |
const char * type;
|
|
Packit |
78deda |
if (underscorePos)
|
|
Packit |
78deda |
type = underscorePos + 1;
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
type = nameAndType;
|
|
Packit |
78deda |
if (streq(type, "width")) {
|
|
Packit |
78deda |
*gotWidthP = TRUE;
|
|
Packit |
78deda |
*widthP = value;
|
|
Packit |
78deda |
} else if (streq(type, "height")) {
|
|
Packit |
78deda |
*gotHeightP = TRUE;
|
|
Packit |
78deda |
*heightP = value;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
parseDeclaration(const char * const line,
|
|
Packit |
78deda |
bool * const isDeclarationP,
|
|
Packit |
78deda |
bool * const version10P) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Parse the XBM file line 'line' as the first line of the data structure
|
|
Packit |
78deda |
declaration, i.e. the one that looks like this:
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static unsigned char myImage = {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
Return as *isDeclarationP whether the line actually is such a line,
|
|
Packit |
78deda |
and if so, return as nameAndType what the variable name ('myImage'
|
|
Packit |
78deda |
in the example) is and as *version10P whether it's of the type used
|
|
Packit |
78deda |
by X10 as opposed to X11.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
char nameAndType[MAX_LINE];
|
|
Packit |
78deda |
int rc;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
rc = sscanf(line, "static short %s = {", nameAndType);
|
|
Packit |
78deda |
if (rc == 1) {
|
|
Packit |
78deda |
*version10P = TRUE;
|
|
Packit |
78deda |
*isDeclarationP = TRUE;
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
int rc;
|
|
Packit |
78deda |
rc = sscanf(line, "static char %s = {", nameAndType);
|
|
Packit |
78deda |
if (rc == 1) {
|
|
Packit |
78deda |
*version10P = FALSE;
|
|
Packit |
78deda |
*isDeclarationP = TRUE;
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
int rc;
|
|
Packit |
78deda |
rc = sscanf(line, "static unsigned char %s = {", nameAndType);
|
|
Packit |
78deda |
if (rc == 1) {
|
|
Packit |
78deda |
*version10P = FALSE;
|
|
Packit |
78deda |
*isDeclarationP = TRUE;
|
|
Packit |
78deda |
} else
|
|
Packit |
78deda |
*isDeclarationP = FALSE;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
getXbmHeader(FILE * const ifP,
|
|
Packit |
78deda |
unsigned int * const widthP,
|
|
Packit |
78deda |
unsigned int * const heightP,
|
|
Packit |
78deda |
bool * const version10P) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
bool foundDeclaration;
|
|
Packit |
78deda |
/* In scanning through the bitmap file, we have found the first
|
|
Packit |
78deda |
line of the C declaration of the array (the "static char ..."
|
|
Packit |
78deda |
or whatever line)
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
bool gotWidth, gotHeight;
|
|
Packit |
78deda |
/* We found the line in the bitmap file that gives the width
|
|
Packit |
78deda |
or height, respectively, of the image (and have set
|
|
Packit |
78deda |
*widthP or *heightP to the value in it).
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
bool eof;
|
|
Packit |
78deda |
/* We've encountered end of file while searching file */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
gotWidth = FALSE;
|
|
Packit |
78deda |
gotHeight = FALSE;
|
|
Packit |
78deda |
foundDeclaration = FALSE; /* Haven't found it yet; haven't even looked*/
|
|
Packit |
78deda |
eof = FALSE; /* Haven't encountered end of file yet */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
while (!foundDeclaration && !eof) {
|
|
Packit |
78deda |
char * rc;
|
|
Packit |
78deda |
char line[MAX_LINE];
|
|
Packit |
78deda |
|
|
Packit |
78deda |
rc = fgets(line, MAX_LINE, ifP);
|
|
Packit |
78deda |
if (rc == NULL)
|
|
Packit |
78deda |
eof = TRUE;
|
|
Packit |
78deda |
else {
|
|
Packit |
78deda |
if (strlen(line) == MAX_LINE - 1)
|
|
Packit |
78deda |
pm_error("A line in the input file is %u characters long. "
|
|
Packit |
78deda |
"%u is the maximum we can handle",
|
|
Packit |
78deda |
(unsigned)strlen(line), MAX_LINE-1);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
parseWidthHeightLine(line, &gotWidth, widthP, &gotHeight, heightP);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
parseDeclaration(line, &foundDeclaration, version10P);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (!foundDeclaration)
|
|
Packit |
78deda |
pm_error("Unable to find a line in the file containing the start "
|
|
Packit |
78deda |
"of C array declaration (\"static char\" or whatever)");
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (!gotWidth)
|
|
Packit |
78deda |
pm_error("Unable to find the #define statement that gives the "
|
|
Packit |
78deda |
"width of the image, before the data structure "
|
|
Packit |
78deda |
"declaration.");
|
|
Packit |
78deda |
if (!gotHeight)
|
|
Packit |
78deda |
pm_error("Unable to find the #define statement that gives the "
|
|
Packit |
78deda |
"height of the image, before the data structure "
|
|
Packit |
78deda |
"declaration.");
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
getHexByte(FILE * const ifP,
|
|
Packit |
78deda |
unsigned int * const valueP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
int c1, c2;
|
|
Packit |
78deda |
unsigned int value;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
c1 = getc(ifP);
|
|
Packit |
78deda |
c2 = getc(ifP);
|
|
Packit |
78deda |
if (c1 == EOF || c2 == EOF)
|
|
Packit |
78deda |
pm_error("EOF / read error");
|
|
Packit |
78deda |
|
|
Packit |
78deda |
assert(c1 >= 0); assert(c1 < 256);
|
|
Packit |
78deda |
assert(c2 >= 0); assert(c2 < 256);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
value = (hexTable[c1] << 4) + hexTable[c2];
|
|
Packit |
78deda |
if (value >= 256)
|
|
Packit |
78deda |
pm_error("Invalid XBM input. What should be a two digit "
|
|
Packit |
78deda |
"hexadecimal cipher is instead '%c%c'", c1, c2);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
*valueP = value;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
readX10Raster(FILE * const ifP,
|
|
Packit |
78deda |
unsigned int const rasterLength,
|
|
Packit |
78deda |
unsigned char * const data,
|
|
Packit |
78deda |
unsigned int const bytesPerLine,
|
|
Packit |
78deda |
bool const mustPad) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int bytesDone;
|
|
Packit |
78deda |
unsigned char * p;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (bytesDone = 0, p = &data[0];
|
|
Packit |
78deda |
bytesDone < rasterLength;
|
|
Packit |
78deda |
bytesDone += 2) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int value1;
|
|
Packit |
78deda |
unsigned int value2;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
while (getc(ifP) != 'x') {} /* Read up through the 'x' in 0x1234 */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
getHexByte(ifP, &value1); /* Read first two hex digits */
|
|
Packit |
78deda |
getHexByte(ifP, &value2); /* Read last two hex digits */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
*p++ = value2;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (!mustPad || ((bytesDone + 2) % bytesPerLine))
|
|
Packit |
78deda |
*p++ = value1;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
readX11Raster(FILE * const ifP,
|
|
Packit |
78deda |
unsigned int const rasterLength,
|
|
Packit |
78deda |
unsigned char * data) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int i;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (i = 0; i < rasterLength; ++i) {
|
|
Packit |
78deda |
unsigned int value;
|
|
Packit |
78deda |
int c;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Read up through the 'x' in 0x12 */
|
|
Packit |
78deda |
while ((c = getc(ifP))) {
|
|
Packit |
78deda |
if (c == EOF)
|
|
Packit |
78deda |
pm_error("EOF where 0x expected");
|
|
Packit |
78deda |
else if (toupper(c) == 'X')
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
getHexByte(ifP, &value); /* Read the two hex digits */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
assert(value < 256);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
data[i] = value;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
readBitmapFile(FILE * const ifP,
|
|
Packit |
78deda |
unsigned int * const widthP,
|
|
Packit |
78deda |
unsigned int * const heightP,
|
|
Packit |
78deda |
unsigned char ** const dataP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
bool version10;
|
|
Packit |
78deda |
unsigned int rasterLength;
|
|
Packit |
78deda |
unsigned int width, height;
|
|
Packit |
78deda |
unsigned char * data;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int bytesPerLine;
|
|
Packit |
78deda |
bool mustPad;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
getXbmHeader(ifP, &width, &height, &version10);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
*widthP = width;
|
|
Packit |
78deda |
*heightP = height;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
mustPad = (width % 16 >= 1 && width % 16 <= 8 && version10);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
bytesPerLine = (width + 7) / 8 + (mustPad ? 1 : 0);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
rasterLength = bytesPerLine * height;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
MALLOCARRAY(data, rasterLength);
|
|
Packit |
78deda |
if (data == NULL)
|
|
Packit |
78deda |
pm_error("Unable to allocate memory for the %u-byte raster",
|
|
Packit |
78deda |
rasterLength);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (version10)
|
|
Packit |
78deda |
readX10Raster(ifP, rasterLength, data, bytesPerLine, mustPad);
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
readX11Raster(ifP, rasterLength, data);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
*dataP = data;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
int
|
|
Packit |
78deda |
main(int argc,
|
|
Packit |
78deda |
char * argv[]) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
FILE * ifP;
|
|
Packit |
78deda |
bit * bitrow;
|
|
Packit |
78deda |
unsigned int rows, cols;
|
|
Packit |
78deda |
unsigned int row;
|
|
Packit |
78deda |
unsigned char * data;
|
|
Packit |
78deda |
const char * inputFileName;
|
|
Packit |
78deda |
unsigned char * p;
|
|
Packit |
78deda |
/* Cursor in raster data data[] */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
initHexTable();
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pbm_init(&argc, argv);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (argc-1 > 1)
|
|
Packit |
78deda |
pm_error("The only possible argument is the input file name. "
|
|
Packit |
78deda |
"You specified %u arguments", argc-1);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (argc-1 > 0)
|
|
Packit |
78deda |
inputFileName = argv[1];
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
inputFileName = "-";
|
|
Packit |
78deda |
|
|
Packit |
78deda |
ifP = pm_openr(inputFileName);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
readBitmapFile(ifP, &cols, &rows, &data);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_close(ifP);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pbm_writepbminit(stdout, cols, rows, 0);
|
|
Packit |
78deda |
bitrow = pbm_allocrow_packed(cols);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
p = &data[0]; /* Start at beginning of raster */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (row = 0; row < rows; ++row) {
|
|
Packit |
78deda |
unsigned int const bytesPerRow = pbm_packed_bytes(cols);
|
|
Packit |
78deda |
unsigned int i;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (i = 0; i < bytesPerRow; ++i)
|
|
Packit |
78deda |
bitrow[i] = bitreverse[*p++];
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pbm_cleanrowend_packed(bitrow, cols);
|
|
Packit |
78deda |
pbm_writepbmrow_packed(stdout, bitrow, cols, 0);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pbm_freerow(bitrow);
|
|
Packit |
78deda |
free(data);
|
|
Packit |
78deda |
pm_close(stdout);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return 0;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* CHANGE HISTORY:
|
|
Packit |
78deda |
|
|
Packit |
78deda |
99.09.08 bryanh Recognize "static unsigned char" declaration.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
06.10 (afu)
|
|
Packit |
78deda |
Changed bitrow from plain to raw, write function from pbm_writepbmrow()
|
|
Packit |
78deda |
to pbm_writepbmrow_packed().
|
|
Packit |
78deda |
Retired bitwise transformation functions.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
|