diff options
Diffstat (limited to 'converter')
-rw-r--r-- | converter/other/fitstopnm.c | 212 | ||||
-rw-r--r-- | converter/other/xwdtopnm.c | 188 | ||||
-rw-r--r-- | converter/pbm/mrftopbm.c | 64 | ||||
-rw-r--r-- | converter/pbm/pbmtog3.c | 30 | ||||
-rw-r--r-- | converter/pbm/pbmtomrf.c | 162 | ||||
-rw-r--r-- | converter/ppm/ilbmtoppm.c | 446 | ||||
-rw-r--r-- | converter/ppm/mitsu.h | 1 | ||||
-rw-r--r-- | converter/ppm/picttoppm.c | 632 | ||||
-rw-r--r-- | converter/ppm/ppmtomitsu.c | 143 | ||||
-rw-r--r-- | converter/ppm/ppmtomitsu.test | 4 | ||||
-rw-r--r-- | converter/ppm/ppmtopict.c | 4 |
11 files changed, 1183 insertions, 703 deletions
diff --git a/converter/other/fitstopnm.c b/converter/other/fitstopnm.c index b41e0960..0d8753e5 100644 --- a/converter/other/fitstopnm.c +++ b/converter/other/fitstopnm.c @@ -39,11 +39,12 @@ #include <string.h> #include <float.h> +#include "pm_config.h" #include "pm_c_util.h" #include "mallocvar.h" +#include "floatcode.h" #include "shhopt.h" #include "pnm.h" -#include "pm_config.h" @@ -156,109 +157,150 @@ struct FITS_Header { }; +/* This code deals properly with integers, no matter what the byte order + or integer size of the host machine. We handle sign extension manually to + prevent problems with signed/unsigned characters. We read floating point + values properly only when the host architecture conforms to IEEE-754. If + you need to tweak this code for other machines, you might want to get a + copy of the FITS documentation from nssdca.gsfc.nasa.gov +*/ + static void -swapbytes(void * const p, - unsigned int const nbytes) { -#if BYTE_ORDER == LITTLE_ENDIAN - unsigned char * const c = p; - unsigned int i; - for (i = 0; i < nbytes/2; ++i) { - unsigned char const orig = c[i]; - c[i] = c[nbytes-(i+1)]; - c[nbytes-(i+1)] = orig; - } -#endif +readFitsChar(FILE * const ifP, + double * const vP) { + + /* 8 bit FITS integers are unsigned */ + + int const ich = getc(ifP); + + if (ich == EOF) + pm_error("EOF / read error"); + else + *vP = ich; } -/* - ** This code will deal properly with integers, no matter what the byte order - ** or integer size of the host machine. Sign extension is handled manually - ** to prevent problems with signed/unsigned characters. Floating point - ** values will only be read properly when the host architecture is IEEE-754 - ** conformant. If you need to tweak this code for other machines, you might - ** want to snag a copy of the FITS documentation from nssdca.gsfc.nasa.gov - */ static void -readVal(FILE * const ifP, - int const bitpix, - double * const vP) { +readFitsShort(FILE * const ifP, + double * const vP) { - switch (bitpix) { - /* 8 bit FITS integers are unsigned */ - case 8: { + int ich; + int ival; + unsigned char c[8]; + + ich = getc(ifP); + + if (ich == EOF) + pm_error("EOF / read error"); + + c[0] = ich; + + ich = getc(ifP); + + if (ich == EOF) + pm_error("EOF / read error"); + + c[1] = ich; + + if (c[0] & 0x80) + ival = ~0xFFFF | c[0] << 8 | c[1]; + else + ival = c[0] << 8 | c[1]; + + *vP = ival; +} + + + +static void +readFitsLong(FILE * const ifP, + double * const vP) { + + unsigned int i; + long int lval; + unsigned char c[4]; + + for (i = 0; i < 4; ++i) { int const ich = getc(ifP); if (ich == EOF) pm_error("EOF / read error"); - *vP = ich; - } break; + c[i] = ich; + } + + if (c[0] & 0x80) + lval = ~0xFFFFFFFF | c[0] << 24 | c[1] << 16 | c[2] << 8 | c[3]; + else + lval = c[0] << 24 | c[1] << 16 | c[2] << 8 | c[3] << 0; + + *vP = lval; +} + + + +static void +readFitsFloat(FILE * const ifP, + double * const vP) { - case 16: { - int ich; - int ival; - unsigned char c[8]; + unsigned int i; + pm_bigendFloat bigend; - ich = getc(ifP); + for (i = 0; i < 4; ++i) { + int const ich = getc(ifP); if (ich == EOF) pm_error("EOF / read error"); - c[0] = ich; - ich = getc(ifP); + bigend.bytes[i] = ich; + } + + *vP = pm_floatFromBigendFloat(bigend); +} + + + +static void +readFitsDouble(FILE * const ifP, + double * const vP) { + + unsigned int i; + pm_bigendDouble bigend; + + for (i = 0; i < 8; ++i) { + int const ich = getc(ifP); if (ich == EOF) pm_error("EOF / read error"); - c[1] = ich; - if (c[0] & 0x80) - ival = ~0xFFFF | c[0] << 8 | c[1]; - else - ival = c[0] << 8 | c[1]; - *vP = ival; - } break; + bigend.bytes[i] = ich; + } + + *vP = pm_doubleFromBigendDouble(bigend); +} + + + +static void +readVal(FILE * const ifP, + int const bitpix, + double * const vP) { + + switch (bitpix) { + case 8: + readFitsChar(ifP, vP); + break; + + case 16: + readFitsShort(ifP, vP); + break; - case 32: { - unsigned int i; - long int lval; - unsigned char c[4]; - - for (i = 0; i < 4; ++i) { - int const ich = getc(ifP); - if (ich == EOF) - pm_error("EOF / read error"); - c[i] = ich; - } - if (c[0] & 0x80) - lval = ~0xFFFFFFFF | c[0] << 24 | c[1] << 16 | c[2] << 8 | c[3]; - else - lval = c[0] << 24 | c[1] << 16 | c[2] << 8 | c[3] << 0; - *vP = lval; - } break; + case 32: + readFitsLong(ifP, vP); + break; - case -32: { - unsigned int i; - unsigned char c[4]; - - for (i = 0; i < 4; ++i) { - int const ich = getc(ifP); - if (ich == EOF) - pm_error("EOF / read error"); - c[i] = ich; - } - swapbytes(c, 4); - *vP = *((float *)c); - } break; + case -32: + readFitsFloat(ifP, vP); + break; - case -64: { - unsigned int i; - unsigned char c[8]; - - for (i = 0; i < 8; ++i) { - int const ich = getc(ifP); - if (ich == EOF) - pm_error("EOF / read error"); - c[i] = ich; - } - swapbytes(c, 8); - *vP = *((double *)c); - } break; + case -64: + readFitsDouble(ifP, vP); + break; default: pm_error("Strange bitpix value %d in readVal()", bitpix); diff --git a/converter/other/xwdtopnm.c b/converter/other/xwdtopnm.c index c919ca70..4bb642e7 100644 --- a/converter/other/xwdtopnm.c +++ b/converter/other/xwdtopnm.c @@ -53,6 +53,7 @@ struct cmdlineInfo { unsigned int verbose; unsigned int debug; unsigned int headerdump; + unsigned int cmapdump; }; @@ -123,6 +124,7 @@ parseCommandLine(int argc, char ** argv, OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); OPTENT3(0, "debug", OPT_FLAG, NULL, &cmdlineP->debug, 0); OPTENT3(0, "headerdump", OPT_FLAG, NULL, &cmdlineP->headerdump, 0); + OPTENT3(0, "cmapdump", OPT_FLAG, NULL, &cmdlineP->cmapdump, 0); opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ @@ -166,9 +168,7 @@ processX10Header(X10WDFileHeader * const h10P, bool grayscale; bool byte_swap; - *maxvalP = 65535; /* Initial assumption */ - - if ( h10P->file_version != X10WD_FILE_VERSION ) { + if (h10P->file_version != X10WD_FILE_VERSION) { byte_swap = TRUE; h10P->header_size = pm_bs_long(h10P->header_size); h10P->file_version = pm_bs_long(h10P->file_version); @@ -186,51 +186,53 @@ processX10Header(X10WDFileHeader * const h10P, } else byte_swap = FALSE; - for ( i = 0; i < h10P->header_size - sizeof(*h10P); ++i ) - if ( getc( file ) == EOF ) - pm_error( "couldn't read rest of X10 XWD file header" ); + for (i = 0; i < h10P->header_size - sizeof(*h10P); ++i) + if (getc(file) == EOF) + pm_error("couldn't read rest of X10 XWD file header"); /* Check whether we can handle this dump. */ - if ( h10P->window_ncolors > 256 ) - pm_error( "can't handle X10 window_ncolors > %d", 256 ); - if ( h10P->pixmap_format != ZFormat && h10P->display_planes != 1 ) - pm_error( - "can't handle X10 pixmap_format %d with planes != 1", - h10P->pixmap_format ); + if (h10P->window_ncolors > 256) + pm_error("can't handle X10 window_ncolors > %d", 256); + if (h10P->pixmap_format != ZFormat && h10P->display_planes != 1) + pm_error("can't handle X10 pixmap_format %d with planes != 1", + h10P->pixmap_format); grayscale = TRUE; /* initial assumption */ - if ( h10P->window_ncolors != 0 ) { + if (h10P->window_ncolors != 0) { /* Read X10 colormap. */ - MALLOCARRAY( x10colors, h10P->window_ncolors ); - if ( x10colors == NULL ) - pm_error( "out of memory" ); - for ( i = 0; i < h10P->window_ncolors; ++i ) { - if ( fread( &x10colors[i], sizeof(X10Color), 1, file ) != 1 ) - pm_error( "couldn't read X10 XWD colormap" ); - if ( byte_swap ) { + MALLOCARRAY(x10colors, h10P->window_ncolors); + if (x10colors == NULL) + pm_error("out of memory"); + for (i = 0; i < h10P->window_ncolors; ++i) { + size_t bytesRead; + bytesRead = fread(&x10colors[i], sizeof(X10Color), 1, file); + if (bytesRead != 1) + pm_error("couldn't read X10 XWD colormap"); + if (byte_swap) { x10colors[i].red = pm_bs_short(x10colors[i].red); x10colors[i].green = pm_bs_short(x10colors[i].green); x10colors[i].blue = pm_bs_short(x10colors[i].blue); } - if ( x10colors[i].red != x10colors[i].green || - x10colors[i].green != x10colors[i].blue ) + if (x10colors[i].red != x10colors[i].green || + x10colors[i].green != x10colors[i].blue) grayscale = FALSE; } } - if ( h10P->display_planes == 1 ) { + if (h10P->display_planes == 1) { *formatP = PBM_TYPE; *visualclassP = StaticGray; *maxvalP = 1; - *colorsP = pnm_allocrow( 2 ); - PNM_ASSIGN1( (*colorsP)[0], 0 ); - PNM_ASSIGN1( (*colorsP)[1], *maxvalP ); + *colorsP = pnm_allocrow(2); + PNM_ASSIGN1((*colorsP)[0], 0); + PNM_ASSIGN1((*colorsP)[1], *maxvalP); *padrightP = (((h10P->pixmap_width + 15) / 16) * 16 - h10P->pixmap_width) * 8; *bits_per_itemP = 16; *bits_per_pixelP = 1; - } else if ( h10P->window_ncolors == 0 ) { + } else if (h10P->window_ncolors == 0) { /* Must be grayscale. */ + unsigned int i; *formatP = PGM_TYPE; *visualclassP = StaticGray; if (h10P->display_planes > sizeof(*maxvalP) * 8 - 1) @@ -242,23 +244,27 @@ processX10Header(X10WDFileHeader * const h10P, pm_error("XWD header says display_planes = %u, which is too " "large for maximum maxval of %u", h10P->display_planes, PNM_OVERALLMAXVAL); - *colorsP = pnm_allocrow( *maxvalP + 1 ); - for ( i = 0; i <= *maxvalP; ++i ) - PNM_ASSIGN1( (*colorsP)[i], i ); + *colorsP = pnm_allocrow(*maxvalP + 1); + for (i = 0; i <= *maxvalP; ++i) + PNM_ASSIGN1((*colorsP)[i], i); *padrightP = (((h10P->pixmap_width + 15) / 16) * 16 - h10P->pixmap_width) * 8; *bits_per_itemP = 16; *bits_per_pixelP = 1; } else { - *colorsP = pnm_allocrow( h10P->window_ncolors ); + *maxvalP = 65535; + + *colorsP = pnm_allocrow(h10P->window_ncolors); *visualclassP = PseudoColor; - if ( grayscale ) { + if (grayscale) { + unsigned int i; *formatP = PGM_TYPE; - for ( i = 0; i < h10P->window_ncolors; ++i ) - PNM_ASSIGN1( (*colorsP)[i], x10colors[i].red ); + for (i = 0; i < h10P->window_ncolors; ++i) + PNM_ASSIGN1((*colorsP)[i], x10colors[i].red); } else { + unsigned int i; *formatP = PPM_TYPE; - for ( i = 0; i < h10P->window_ncolors; ++i ) + for (i = 0; i < h10P->window_ncolors; ++i) PPM_ASSIGN( (*colorsP)[i], x10colors[i].red, x10colors[i].green, x10colors[i].blue); @@ -319,36 +325,46 @@ fixH11ByteOrder(X11WDFileHeader * const h11P, static void -readX11Colormap(FILE * const file, - int const ncolors, - bool const byteSwap, - X11XColor** const x11colorsP) { +dumpX11Cmap(unsigned int const nColors, + const X11XColor * const x11colors) { + + unsigned int i; + for (i = 0; i < nColors; ++i) + pm_message("Color %u r/g/b = %u/%u/%u", i, + x11colors[i].red, x11colors[i].green, + x11colors[i].blue); +} + + + +static void +readX11Colormap(FILE * const file, + unsigned int const nColors, + bool const byteSwap, + bool const cmapDump, + X11XColor** const x11colorsP) { X11XColor * x11colors; int rc; /* Read X11 colormap. */ - MALLOCARRAY(x11colors, ncolors); + MALLOCARRAY(x11colors, nColors); if (x11colors == NULL) pm_error("out of memory"); - rc = fread(x11colors, sizeof(x11colors[0]), ncolors, file); - if (rc != ncolors) + rc = fread(x11colors, sizeof(x11colors[0]), nColors, file); + if (rc != nColors) pm_error("couldn't read X11 XWD colormap"); if (byteSwap) { unsigned int i; - for (i = 0; i < ncolors; ++i) { + for (i = 0; i < nColors; ++i) { x11colors[i].red = pm_bs_short(x11colors[i].red); x11colors[i].green = pm_bs_short(x11colors[i].green); x11colors[i].blue = pm_bs_short(x11colors[i].blue); } } - if (debug) { - unsigned int i; - for (i = 0; i < ncolors && i < 8; ++i) - pm_message("Color %d r/g/b = %d/%d/%d", i, - x11colors[i].red, x11colors[i].green, - x11colors[i].blue); - } + if (cmapDump) + dumpX11Cmap(nColors, x11colors); + *x11colorsP = x11colors; } @@ -490,10 +506,36 @@ computeComponentMasks(X11WDFileHeader * const h11P, } +/* About TrueColor maxval: + + The X11 spec says that in TrueColor, you use the bits in the raster for a + particular color component of a particular pixel to index the server's + colormap for that component, which contains 'bits_per_rgb' significant bits + of intensity information. 'bits_per_rgb' is in the XWD header, and in + practice is normally 8 or 16, usually 8. + + We don't have the server's colormap, so we assume the most ordinary + one, a linear-as-possible distribution over the indices. + + That means the maxval is that implied by 'bits_per_rgb' bits and we get + the proper sample value by scaling the value from the raster to that + maxval. + + We (mostly Julian Bradfield <jcb@inf.ed.ac.uk>) figured this out in Netpbm + 10.46 (March 2009). Between ca. 2000 and 10.46, we instead assumed the + value in the XWD raster to be the exact brightness value, and chose a + maxval that would best allow us to represent that exact value for all + three components (e.g. if the XWD had 5 bits for blue, 5 for red, and + 6 for red, we'd use maxval 31*63=1953). Before that, the maxval was + 31 if bits per pixel was 16 and 255 otherwise. +*/ + + static void processX11Header(X11WDFileHeader * const h11P, - FILE * const file, + FILE * const fileP, + bool const cmapDump, int * const colsP, int * const rowsP, unsigned int * const padrightP, @@ -519,7 +561,7 @@ processX11Header(X11WDFileHeader * const h11P, pm_message("Header is different endianness from this machine."); for (i = 0; i < h11FixedP->header_size - sizeof(*h11FixedP); ++i) - if (getc(file) == EOF) + if (getc(fileP) == EOF) pm_error("couldn't read rest of X11 XWD file header"); /* Check whether we can handle this dump. */ @@ -541,7 +583,8 @@ processX11Header(X11WDFileHeader * const h11P, h11FixedP->bitmap_unit); if (h11FixedP->ncolors > 0) { - readX11Colormap(file, h11FixedP->ncolors, byte_swap, &x11colors); + readX11Colormap(fileP, h11FixedP->ncolors, byte_swap, cmapDump, + &x11colors); grayscale = colormapAllGray(x11colors, h11FixedP->ncolors); } else grayscale = TRUE; @@ -565,11 +608,8 @@ processX11Header(X11WDFileHeader * const h11P, } else if (*visualclassP == TrueColor) { *formatP = PPM_TYPE; - *maxvalP = pm_lcm(pm_bitstomaxval(one_bits(h11FixedP->red_mask)), - pm_bitstomaxval(one_bits(h11FixedP->green_mask)), - pm_bitstomaxval(one_bits(h11FixedP->blue_mask)), - PPM_OVERALLMAXVAL - ); + /* See discussion above about this maxval */ + *maxvalP = pm_bitstomaxval(h11FixedP->bits_per_rgb); } else if (*visualclassP == StaticGray && h11FixedP->bits_per_pixel == 1) { *formatP = PBM_TYPE; *maxvalP = 1; @@ -681,7 +721,8 @@ getinit(FILE * const ifP, struct compMask * const compMaskP, enum byteorder * const byte_orderP, enum byteorder * const bit_orderP, - bool const headerDump) { + bool const headerDump, + bool const cmapDump) { /*---------------------------------------------------------------------------- Read the header from the XWD image in input stream 'ifP'. Leave the stream positioned to the beginning of the raster. @@ -743,7 +784,8 @@ getinit(FILE * const ifP, if (headerDump) dumpX11Header(h11P); - processX11Header(h11P, ifP, colsP, rowsP, padrightP, maxvalP, + processX11Header(h11P, ifP, cmapDump, + colsP, rowsP, padrightP, maxvalP, visualclassP, formatP, colorsP, bits_per_pixelP, bits_per_itemP, compMaskP, byte_orderP, bit_orderP); @@ -1126,6 +1168,28 @@ reportInfo(int const cols, +static void +warn16Bit(xelval const maxval) { +/*---------------------------------------------------------------------------- + This program is often used by users of X, and those users often use + 'xv', which doesn't properly interpret PNM files with 16 bit samples. + Furthermore, the maxval is often much larger than the user assumes + because of PNM's need to use the same maxval for all color components, + while XWD often uses different resolution for each. + + Users get really frustrated when Xv displays something other than the + original mimage, almost always assuming that means Xwdtopnm converted + incorrectly. +-----------------------------------------------------------------------------*/ + + if (pm_maxvaltobits(maxval) > 8) + pm_message("WARNING: Producing maxval %u output. This involves " + "multiple bytes per sample, which some programs, e.g. " + "'xv', can't handle. See manual.", maxval); +} + + + static void convertRowSimpleIndex(pixelReader * const pixelReaderP, int const cols, @@ -1318,7 +1382,9 @@ main(int argc, char *argv[]) { getinit(ifP, &cols, &rows, &padright, &maxval, &visualclass, &format, &colors, &bitsPerPixel, &bitsPerItem, &compMask, &byteOrder, &bitOrder, - cmdline.headerdump); + cmdline.headerdump, cmdline.cmapdump); + + warn16Bit(maxval); if (verbose) reportInfo(cols, rows, padright, maxval, visualclass, diff --git a/converter/pbm/mrftopbm.c b/converter/pbm/mrftopbm.c index b7534115..51281028 100644 --- a/converter/pbm/mrftopbm.c +++ b/converter/pbm/mrftopbm.c @@ -41,34 +41,50 @@ bit_input(FILE * const in) { static void -doSquare(FILE * const in, - unsigned char * const image, - int const ox, - int const oy, - int const w, - int const size) { - - if (size == 1 || bit_input(in)) { +doSquare(FILE * const ifP, + unsigned char * const image, + unsigned int const ulCol, + unsigned int const ulRow, + unsigned int const imageWidth, + unsigned int const size) { +/*---------------------------------------------------------------------------- + Do a square of side 'size', whose upper left corner is at (ulCol, ulRow). + The contents of that square are next in file *ifP, in MRF format. + + Return the pixel values of the square in the corresponding position of + image[], which is a concatenation of rows 'imageWidth' pixels wide, one + byte per pixel. +-----------------------------------------------------------------------------*/ + if (size == 1 || bit_input(ifP)) { /* It's all black or all white. Next bit says which. */ - unsigned int const c = bit_input(in); + unsigned int const c = bit_input(ifP); - unsigned int y; + unsigned int rowOfSquare; - for (y = 0; y < size; ++y) { - unsigned int x; - for (x = 0; x < size; ++x) - image[(oy+y)*w+ox+x] = c; + for (rowOfSquare = 0; rowOfSquare < size; ++rowOfSquare) { + unsigned int colOfSquare; + for (colOfSquare = 0; colOfSquare < size; ++colOfSquare) { + unsigned int rowOfImage = ulRow + rowOfSquare; + unsigned int colOfImage = ulCol + colOfSquare; + + image[rowOfImage * imageWidth + colOfImage] = c; + } } } else { - /* not all one color, so recurse. */ - - int halfsize = size >> 1; - - doSquare(in, image, ox, oy, w, halfsize); - doSquare(in, image, ox+halfsize, oy, w, halfsize); - doSquare(in, image, ox, oy+halfsize, w, halfsize); - doSquare(in, image, ox+halfsize, oy+halfsize, w, halfsize); + /* Square is not all one color, so recurse. Do each of the four + quadrants of this square individually. + */ + unsigned int const quadSize = size/2; + + doSquare(ifP, image, ulCol, ulRow, + imageWidth, quadSize); + doSquare(ifP, image, ulCol + quadSize, ulRow, + imageWidth, quadSize); + doSquare(ifP, image, ulCol, ulRow + quadSize, + imageWidth, quadSize); + doSquare(ifP, image, ulCol + quadSize, ulRow + quadSize, + imageWidth, quadSize); } } @@ -80,7 +96,7 @@ writeOutput(FILE * const ofP, int const rows, const unsigned char * const image) { - /* w64 is units-of-64-bits width, h64 same for height */ + /* w64 is units-of-64-bits width */ unsigned int const w64 = (cols+63)/64; bit * bitrow; @@ -145,7 +161,7 @@ readMrfImage(FILE * const ifP, pm_error("Ridiculously large, unprocessable image: %u cols x %u rows", cols, rows); - image = calloc(w64*h64*64*64,1); + image = calloc(w64*h64*64*64, 1); if (image == NULL) pm_error("Unable to get memory for raster"); diff --git a/converter/pbm/pbmtog3.c b/converter/pbm/pbmtog3.c index 0b536390..3fe7f3fc 100644 --- a/converter/pbm/pbmtog3.c +++ b/converter/pbm/pbmtog3.c @@ -55,7 +55,7 @@ struct bitString { struct outStream { struct bitString buffer; - + bool reverseBits; }; @@ -109,6 +109,8 @@ parseCommandLine(int argc, char ** const argv, optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + free(option_def); + if (argc-1 == 0) cmdlineP->inputFileName = "-"; else if (argc-1 != 1) @@ -142,7 +144,7 @@ makeBs(wordint const bits, return retval; } - + static __inline__ void putbits(struct bitString const newBits) { @@ -153,7 +155,7 @@ putbits(struct bitString const newBits) { Flush the buffer to stdout as necessary to make room. 'newBits' must be shorter than a whole word. - + N.B. the definition of struct bitString requires upper bits to be zero. -----------------------------------------------------------------------------*/ unsigned int const spaceLeft = @@ -182,11 +184,11 @@ putbits(struct bitString const newBits) { | (newBits.intBuffer >> nextBufBitCount)); if (out.reverseBits) reversebuffer(outbytes, sizeof(outbytes)); - + rc = fwrite(outbytes, 1, sizeof(outbytes), stdout); if (rc != sizeof(outbytes)) pm_error("Output error. Unable to fwrite() to stdout"); - + out.buffer.intBuffer = newBits.intBuffer & ((1<<nextBufBitCount) - 1); out.buffer.bitCount = nextBufBitCount; } @@ -237,7 +239,7 @@ putcode2(int const clr, if (sizeof(wordint) * 8 > 24) { unsigned int const l1 = ttable[loIndex].length; - + putbits( makeBs(mtable[hiIndex].code << l1 | ttable[loIndex].code, mtable[hiIndex].length + l1) @@ -299,7 +301,7 @@ puteol(void) { puts("EOL"); else { struct bitString const eol = {12, 1}; - + putbits(eol); } } @@ -341,7 +343,7 @@ convertRowToRunLengths(unsigned char * const bitrow, wordint * const bitrowByWord = (wordint *) bitrow; int const wordCount = (cols + bitsPerWord - 1)/bitsPerWord; /* Number of full and partial words in the row */ - + if (cols % bitsPerWord != 0) { /* Clean final word in row. For loop simplicity */ @@ -411,7 +413,7 @@ main(int argc, a word of zero padding on the high (right) end for the convenience of code that accesses this buffer in word-size bites. */ - + int rows; int cols; int readcols; @@ -423,7 +425,7 @@ main(int argc, pbm_init(&argc, argv); parseCommandLine(argc, argv, &cmdline); - + ifP = pm_openr(cmdline.inputFileName); pbm_readpbminit(ifP, &cols, &rows, &format); @@ -447,9 +449,9 @@ main(int argc, unsigned int i; pbm_readpbmrow_packed(ifP, bitrow, cols, format); - + convertRowToRunLengths(bitrow, readcols, milepost, &nRun); - + padToDesiredWidth(milepost, &nRun, readcols, outwidth); for (i = p = 0; i < nRun; p = milepost[i++]) @@ -459,6 +461,8 @@ main(int argc, } free(milepost); + pbm_freerow_packed(bitrow); + { unsigned int i; for( i = 0; i < 6; ++i) @@ -467,7 +471,7 @@ main(int argc, if (out.buffer.bitCount > 0) { /* flush final partial buffer */ unsigned int const bytesToWrite = (out.buffer.bitCount+7)/8; - + unsigned char outbytes[sizeof(wordint)]; size_t rc; wordintToBytes(&outbytes, diff --git a/converter/pbm/pbmtomrf.c b/converter/pbm/pbmtomrf.c index c93c88aa..e7b7fcc9 100644 --- a/converter/pbm/pbmtomrf.c +++ b/converter/pbm/pbmtomrf.c @@ -13,83 +13,139 @@ #include "pm_c_util.h" #include "pbm.h" -static int bitbox; -static int bitsleft; -static FILE *bit_out; + +typedef struct bitOut { + int bitbox; + int bitsleft; + FILE * fileP; +} bitOut; + static void -bit_init(FILE * const out) { - bitbox = 0; - bitsleft = 8; - bit_out = out; +bit_init(struct bitOut * const bitOutP, + FILE * const ofP) { + + bitOutP->bitbox = 0; + bitOutP->bitsleft = 8; + bitOutP->fileP = ofP; } static void -bit_output(int const bit) { - --bitsleft; - bitbox |= (bit << bitsleft); - if (bitsleft == 0) { - fputc(bitbox, bit_out); - bitbox = 0; - bitsleft = 8; +bit_output(struct bitOut * const bitOutP, + int const bit) { + + --bitOutP->bitsleft; + bitOutP->bitbox |= (bit << bitOutP->bitsleft); + if (bitOutP->bitsleft == 0) { + fputc(bitOutP->bitbox, bitOutP->fileP); + bitOutP->bitbox = 0; + bitOutP->bitsleft = 8; } } static void -bit_flush(void) { +bit_flush(struct bitOut * const bitOutP) { /* there are never 0 bits left outside of bit_output, but * if 8 bits are left here there's nothing to flush, so * only do it if bitsleft!=8. */ - if (bitsleft != 8) { - bitsleft = 1; - bit_output(0); /* yes, really. This will always work. */ + if (bitOutP->bitsleft != 8) { + bitOutP->bitsleft = 1; + bit_output(bitOutP, 0); /* yes, really. This will always work. */ } } -static void -doSquare(unsigned char * const image, - int const ox, - int const oy, - int const w, - int const size) { - - unsigned int y; +static void +determineBlackWhiteOrMix(const unsigned char * const image, + unsigned int const ulCol, + unsigned int const ulRow, + unsigned int const imageWidth, + unsigned int const size, + bool * const oneColorP, + int * const colorP) { +/*---------------------------------------------------------------------------- + Determine whether a square within 'image' is all white, all black, + or a mix. +-----------------------------------------------------------------------------*/ + unsigned int rowOfSquare; unsigned int t; - /* check square to see if it's all black or all white. */ + for (rowOfSquare = 0, t = 0; rowOfSquare < size; ++rowOfSquare) { + unsigned int colOfSquare; + for (colOfSquare = 0; colOfSquare < size; ++colOfSquare) { + unsigned int rowOfImage = ulRow + rowOfSquare; + unsigned int colOfImage = ulCol + colOfSquare; - t = 0; - for (y = 0; y < size; ++y) { - unsigned int x; - for (x = 0; x < size; ++x) - t += image[(oy+y)*w + ox + x]; + t += image[rowOfImage * imageWidth + colOfImage]; + } } /* if the total's 0, it's black. if it's size*size, it's white. */ - if (t == 0 || t == size*size) { - if (size != 1) /* (it's implicit when size is 1, of course) */ - bit_output(1); /* all same color */ - bit_output(t?1:0); - return; - } - - /* otherwise, if our square is greater than 1x1, we need to recurse. */ - if(size > 1) { - int halfsize = size >> 1; - - bit_output(0); /* not all same */ - doSquare(image, ox, oy, w, halfsize); - doSquare(image, ox+halfsize, oy, w, halfsize); - doSquare(image, ox, oy+halfsize, w, halfsize); - doSquare(image, ox+halfsize, oy+halfsize, w, halfsize); + if (t == 0) { + *oneColorP = TRUE; + *colorP = 0; + } else if (t == SQR(size)) { + *oneColorP = TRUE; + *colorP = 1; + } else + *oneColorP = FALSE; +} + + + +static void +doSquare(bitOut * const bitOutP, + const unsigned char * const image, + unsigned int const ulCol, + unsigned int const ulRow, + unsigned int const imageWidth, + unsigned int const size) { +/*---------------------------------------------------------------------------- + Do a square of side 'size', whose upper left corner is at (ulCol, ulRow). + This is a square within 'image', which is a concatenation of rows + 'imageWidth' pixels wide, one byte per pixel. + + Write the pixel values out to the bit stream *bitOutP, in MRF format. +-----------------------------------------------------------------------------*/ + if (size == 1) { + /* The fact that it is all one color is implied because the square is + just one pixel; no bit goes in MRF output to state that. + */ + bit_output(bitOutP, image[ulRow * imageWidth + ulCol] ? 1 : 0); + } else { + bool oneColor; + int color; + + determineBlackWhiteOrMix(image, ulCol, ulRow, imageWidth, size, + &oneColor, &color); + + if (oneColor) { + bit_output(bitOutP, 1); /* all same color */ + bit_output(bitOutP, color); + } else { + /* Square is not all the same color, so recurse. Do each + of the four quadrants of this square individually. + */ + unsigned int const quadSize = size/2; + + bit_output(bitOutP, 0); /* not all same color */ + + doSquare(bitOutP, image, ulCol, ulRow, + imageWidth, quadSize); + doSquare(bitOutP, image, ulCol + quadSize, ulRow, + imageWidth, quadSize); + doSquare(bitOutP, image, ulCol, ulRow + quadSize, + imageWidth, quadSize); + doSquare(bitOutP, image, ulCol + quadSize, ulRow + quadSize, + imageWidth, quadSize); + } } } @@ -243,7 +299,7 @@ readPbmImage(FILE * const ifP, pm_error("Ridiculously large, unprocessable image: %u cols x %u rows", cols, rows); - image = calloc(w64*h64*64*64,1); + image = calloc(w64*h64*64*64, 1); if (image == NULL) pm_error("Unable to get memory for raster"); @@ -276,6 +332,8 @@ outputMrf(FILE * const ofP, unsigned int const w64 = (cols + 63) / 64; unsigned int const h64 = (rows + 63) / 64; + bitOut bitOut; + unsigned int row; fprintf(ofP, "MRF1"); @@ -285,14 +343,14 @@ outputMrf(FILE * const ofP, /* now recursively check squares. */ - bit_init(ofP); + bit_init(&bitOut, ofP); for (row = 0; row < h64; ++row) { unsigned int col; for (col = 0; col < w64; ++col) - doSquare(image, col*64, row*64, w64*64, 64); + doSquare(&bitOut, image, col*64, row*64, w64*64, 64); } - bit_flush(); + bit_flush(&bitOut); } diff --git a/converter/ppm/ilbmtoppm.c b/converter/ppm/ilbmtoppm.c index d140d088..0c365834 100644 --- a/converter/ppm/ilbmtoppm.c +++ b/converter/ppm/ilbmtoppm.c @@ -1,4 +1,4 @@ -/* ilbmtoppm.c - read an IFF ILBM file and produce a portable pixmap +/* ilbmtoppm.c - read an IFF ILBM file and produce a PPM ** ** Copyright (C) 1989 by Jef Poskanzer. ** @@ -43,11 +43,10 @@ #include <string.h> #include "pm_c_util.h" -#include "ppm.h" -#include "ilbm.h" #include "mallocvar.h" - -/*#define DEBUG*/ +#include "intcode.h" +#include "ilbm.h" +#include "ppm.h" typedef struct { int reg; /* color register to change */ @@ -765,10 +764,15 @@ multi_free(cmap) ****************************************************************************/ static void -check_cmap(bmhd, cmap) - BitMapHeader *bmhd; - ColorMap *cmap; -{ +prepareCmap(const BitMapHeader * const bmhd, + ColorMap * const cmap) { +/*---------------------------------------------------------------------------- + This is a really ugly subroutine that 1) analyzes a colormap and its + context (returning the analysis in global variables); and 2) modifies that + color map, because it's really one type of data structure as input and + another as output. + +-----------------------------------------------------------------------------*/ pixval colmaxval = 0; int shifted = 1; int i, r, g, b; @@ -987,6 +991,8 @@ std_to_ppm(FILE * const ifp, ColorMap * const cmap, long const viewportmodes); + + static void ham_to_ppm(FILE * const ifp, long const chunksize, @@ -1342,16 +1348,10 @@ dcol_to_ppm(FILE * const ifP, static void -cmap_to_ppm(cmap) - ColorMap *cmap; -{ - ppm_colorrowtomapfile(stdout, cmap->color, cmap->ncolors, MAXCOLVAL); -#if 0 - int i; - ppm_writeppminit(stdout, cmap->ncolors, 1, MAXCOLVAL, 1); - for( i = 0; i < cmap->ncolors; i++ ) - ppm_writeppmrow(stdout, &(cmap->color[i]), 1, MAXCOLVAL, 1); -#endif +cmapToPpm(FILE * const ofP, + ColorMap * const cmapP) { + + ppm_colorrowtomapfile(ofP, cmapP->color, cmapP->ncolors, MAXCOLVAL); } @@ -1656,39 +1656,41 @@ PCHG_DecompHuff(src, dest, tree, origsize) } + static void -PCHG_Decompress(PCHG, CompHdr, compdata, compsize, comptree, data) - PCHGHeader *PCHG; - PCHGCompHeader *CompHdr; - unsigned char *compdata; - unsigned long compsize; - unsigned char *comptree; - unsigned char *data; -{ - short *hufftree; - unsigned long huffsize, i; - unsigned long treesize = CompHdr->CompInfoSize; +PCHG_Decompress(PCHGHeader * const PCHG, + PCHGCompHeader * const CompHdr, + unsigned char * const compdata, + unsigned long const compsize, + unsigned char * const comptree, + unsigned char * const data) { - switch( PCHG->Compression ) { - case PCHG_COMP_HUFFMAN: + switch(PCHG->Compression) { + case PCHG_COMP_HUFFMAN: { + unsigned long const treesize = CompHdr->CompInfoSize; + unsigned long const huffsize = treesize / 2; + const bigend16 * const bigendComptree = (const void *)comptree; -#ifdef DEBUG - pm_message("PCHG Huffman compression"); -#endif - /* turn big-endian 2-byte shorts into native format */ - huffsize = treesize/2; - MALLOCARRAY_NOFAIL(hufftree, huffsize); - for( i = 0; i < huffsize; i++ ) { - hufftree[i] = (short)BIG_WORD(comptree); - comptree += 2; - } + short * hufftree; + unsigned long i; - /* decompress the change structure data */ - PCHG_DecompHuff(compdata, data, &hufftree[huffsize-1], - CompHdr->OriginalDataSize); + /* Convert big-endian 2-byte shorts to C shorts */ - free(hufftree); - break; + MALLOCARRAY(hufftree, huffsize); + + if (!hufftree) + pm_error("Couldn't get memory for %lu-byte Huffman tree", + huffsize); + + for (i = 0; i < huffsize; ++i) + hufftree[i] = pm_uintFromBigend16(bigendComptree[i]); + + /* decompress the change structure data */ + PCHG_DecompHuff(compdata, data, &hufftree[huffsize-1], + CompHdr->OriginalDataSize); + + free(hufftree); + } break; default: pm_error("unknown PCHG compression type %d", PCHG->Compression); } @@ -1797,94 +1799,119 @@ fail2: } + static void -PCHG_ConvertBig(PCHG, cmap, mask, datasize) - PCHGHeader *PCHG; - ColorMap *cmap; - unsigned char *mask; - unsigned long datasize; -{ - unsigned char *data; +PCHG_ConvertBig(PCHGHeader * const PCHG, + ColorMap * const cmap, + unsigned char * const maskStart, + unsigned long const datasize) { + + unsigned char * data; unsigned char thismask; - int bits, row, i, changes, masklen, reg; - unsigned long totalchanges = 0; - int changedlines = PCHG->ChangedLines; + int bits; + unsigned int row; + int changes; + int masklen; + int reg; + unsigned long totalchanges; + int changedlines; + unsigned long dataRemaining; + unsigned char * mask; + + mask = maskStart; /* initial value */ + dataRemaining = datasize; /* initial value */ + changedlines = PCHG->ChangedLines; /* initial value */ + totalchanges = 0; /* initial value */ masklen = 4 * MaskLongWords(PCHG->LineCount); - data = mask + masklen; datasize -= masklen; + data = mask + masklen; dataRemaining -= masklen; - bits = 0; - for( row = PCHG->StartLine; changedlines && row < 0; row++ ) { - if( bits == 0 ) { - if( masklen == 0 ) goto fail2; + for (row = PCHG->StartLine, bits = 0; changedlines && row < 0; ++row) { + if (bits == 0) { + if (masklen == 0) + pm_error("insufficient data in line mask"); thismask = *mask++; --masklen; bits = 8; } - if( thismask & (1<<7) ) { - if( datasize < 2 ) goto fail; - changes = BIG_WORD(data); data += 2; datasize -= 2; + if (thismask & (1<<7)) { + unsigned int i; + + if (dataRemaining < 2) + pm_error("insufficient data in BigLineChanges structures"); + + changes = BIG_WORD(data); data += 2; dataRemaining -= 2; + + for (i = 0; i < changes; ++i) { + if (totalchanges >= PCHG->TotalChanges) + pm_error("insufficient data in BigLineChanges structures"); + + if (dataRemaining < 6) + pm_error("insufficient data in BigLineChanges structures"); - for( i = 0; i < changes; i++ ) { - if( totalchanges >= PCHG->TotalChanges ) goto fail; - if( datasize < 6 ) goto fail; reg = BIG_WORD(data); data += 2; cmap->mp_init[reg - PCHG->MinReg].reg = reg; ++data; /* skip alpha */ cmap->mp_init[reg - PCHG->MinReg].r = *data++; cmap->mp_init[reg - PCHG->MinReg].b = *data++; /* yes, RBG */ cmap->mp_init[reg - PCHG->MinReg].g = *data++; - datasize -= 6; + dataRemaining -= 6; ++totalchanges; } --changedlines; } thismask <<= 1; - bits--; + --bits; } - for( row = PCHG->StartLine; changedlines && row < cmap->mp_rows; row++ ) { - if( bits == 0 ) { - if( masklen == 0 ) goto fail2; + for (row = PCHG->StartLine; changedlines && row < cmap->mp_rows; ++row) { + if (bits == 0) { + if (masklen == 0) + pm_error("insufficient data in line mask"); + thismask = *mask++; --masklen; bits = 8; } - if( thismask & (1<<7) ) { - if( datasize < 2 ) goto fail; - changes = BIG_WORD(data); data += 2; datasize -= 2; + if (thismask & (1<<7)) { + unsigned int i; + + if (dataRemaining < 2) + pm_error("insufficient data in BigLineChanges structures"); + + changes = BIG_WORD(data); data += 2; dataRemaining -= 2; MALLOCARRAY_NOFAIL(cmap->mp_change[row], changes + 1); - for( i = 0; i < changes; i++ ) { - if( totalchanges >= PCHG->TotalChanges ) goto fail; - if( datasize < 6 ) goto fail; + for (i = 0; i < changes; ++i) { + if (totalchanges >= PCHG->TotalChanges) + pm_error("insufficient data in BigLineChanges structures"); + + if (dataRemaining < 6) + pm_error("insufficient data in BigLineChanges structures"); + reg = BIG_WORD(data); data += 2; cmap->mp_change[row][i].reg = reg; ++data; /* skip alpha */ cmap->mp_change[row][i].r = *data++; cmap->mp_change[row][i].b = *data++; /* yes, RBG */ cmap->mp_change[row][i].g = *data++; - datasize -= 6; + dataRemaining -= 6; ++totalchanges; } cmap->mp_change[row][changes].reg = MP_REG_END; --changedlines; } thismask <<= 1; - bits--; + --bits; } - if( totalchanges != PCHG->TotalChanges ) + if (totalchanges != PCHG->TotalChanges) pm_message("warning - got %ld change structures, " "chunk header reports %ld", totalchanges, PCHG->TotalChanges); - return; -fail: - pm_error("insufficient data in BigLineChanges structures"); -fail2: - pm_error("insufficient data in line mask"); } + static void read_pchg(FILE * const ifp, IFF_ID const iffid, @@ -1938,7 +1965,7 @@ read_pchg(FILE * const ifp, read_bytes(ifp, treesize, comptree, iffid, &remainingChunksize); compsize = remainingChunksize; - MALLOCARRAY_NOFAIL(compdata, remainingChunksize); + MALLOCARRAY_NOFAIL(compdata, compsize); read_bytes(ifp, compsize, compdata, iffid, &remainingChunksize); datasize = CompHdr.OriginalDataSize; @@ -2032,7 +2059,7 @@ process_body( FILE * const ifp, pm_error("%s chunk without %s chunk", ID2string(ID_BODY), ID2string(ID_BMHD)); - check_cmap(bmhdP, cmap); + prepareCmap(bmhdP, cmap); pixelrow = ppm_allocrow(bmhdP->w); if( maskfile ) { @@ -2080,21 +2107,21 @@ process_body( FILE * const ifp, static void -process_chunk(FILE * const ifp, - long const formsize, - IFF_ID const ignorelist[], - unsigned int const ignorecount, - int const fakeviewport, - int const viewportmask, - int const isdeepopt, - bool const cmaponly, - bool * const bodyChunkProcessedP, - bool * const endchunkP, - BitMapHeader ** const bmhdP, - ColorMap * const cmap, - DirectColor ** const dcolP, - int * const viewportmodesP, - long * const bytesReadP +processChunk(FILE * const ifP, + long const formsize, + IFF_ID const ignorelist[], + unsigned int const ignorecount, + int const fakeviewport, + int const viewportmask, + int const isdeepopt, + bool const cmaponly, + bool * const bodyChunkProcessedP, + bool * const endchunkP, + BitMapHeader ** const bmhdP, + ColorMap * const cmap, + DirectColor ** const dcolP, + int * const viewportmodesP, + long * const bytesReadP ) { IFF_ID iffid; @@ -2103,129 +2130,168 @@ process_chunk(FILE * const ifp, bytesread = 0; - iffid = get_big_long(ifp, ID_FORM, NULL); - chunksize = get_big_long(ifp, iffid, NULL); + iffid = get_big_long(ifP, ID_FORM, NULL); + chunksize = get_big_long(ifP, iffid, NULL); bytesread += 8; if (debug) - pm_message("reading %s chunk: %ld bytes", - ID2string(iffid), chunksize); + pm_message("reading %s chunk: %ld bytes", ID2string(iffid), chunksize); - if( ignored_iffid(iffid, ignorelist, ignorecount) ) { + if (ignored_iffid(iffid, ignorelist, ignorecount)) { pm_message("ignoring %s chunk", ID2string(iffid)); - skip_chunk(ifp, iffid, chunksize); - } else if( iffid == ID_END ) { + skip_chunk(ifP, iffid, chunksize); + } else if (iffid == ID_END) { /* END chunks are not officially valid in IFF, but suggested as a future expansion for stream-writing, see Amiga RKM Devices, 3rd Ed, page 376 */ - if( chunksize != 0 ) { + if (chunksize != 0 ) { pm_message("warning - non-0 %s chunk", ID2string(iffid)); - skip_chunk(ifp, iffid, chunksize); + skip_chunk(ifP, iffid, chunksize); } - if( formsize != 0xffffffff ) + if (formsize != 0xffffffff) pm_message("warning - %s chunk with FORM size 0x%08lx " "(should be 0x%08x)", ID2string(iffid), formsize, 0xffffffff); *endchunkP = 1; - } else if( *bodyChunkProcessedP ) { + } else if (*bodyChunkProcessedP) { pm_message("%s chunk found after %s chunk - skipping", ID2string(iffid), ID2string(ID_BODY)); - skip_chunk(ifp, iffid, chunksize); + skip_chunk(ifP, iffid, chunksize); } else - switch( iffid ) { + switch (iffid) { case ID_BMHD: - *bmhdP = read_bmhd(ifp, iffid, chunksize); + *bmhdP = read_bmhd(ifP, iffid, chunksize); break; case ID_CMAP: - read_cmap(ifp, iffid, chunksize, cmap); + read_cmap(ifP, iffid, chunksize, cmap); break; case ID_CMYK: - read_cmyk(ifp, iffid, chunksize, cmap); + read_cmyk(ifP, iffid, chunksize, cmap); break; case ID_CLUT: - read_clut(ifp, iffid, chunksize, cmap); + read_clut(ifP, iffid, chunksize, cmap); break; case ID_CAMG: - if( chunksize != CAMGChunkSize ) + if (chunksize != CAMGChunkSize) pm_error("%s chunk size mismatch", ID2string(iffid)); - *viewportmodesP = get_big_long(ifp, ID_CAMG, NULL); + *viewportmodesP = get_big_long(ifP, ID_CAMG, NULL); *viewportmodesP &= viewportmask; /* -isnotham/-isnotehb */ break; case ID_PCHG: - read_pchg(ifp, iffid, chunksize, cmap); + read_pchg(ifP, iffid, chunksize, cmap); break; case ID_CTBL: case ID_SHAM: - read_4bit_mp(ifp, iffid, chunksize, cmap); + read_4bit_mp(ifP, iffid, chunksize, cmap); break; case ID_DCOL: - if( chunksize != DirectColorSize ) + if (chunksize != DirectColorSize) pm_error("%s chunk size mismatch", ID2string(iffid)); MALLOCVAR_NOFAIL(*dcolP); - (*dcolP)->r = get_byte(ifp, iffid, NULL); - (*dcolP)->g = get_byte(ifp, iffid, NULL); - (*dcolP)->b = get_byte(ifp, iffid, NULL); - (void)get_byte(ifp, iffid, NULL); /* skip pad byte */ + (*dcolP)->r = get_byte(ifP, iffid, NULL); + (*dcolP)->g = get_byte(ifP, iffid, NULL); + (*dcolP)->b = get_byte(ifP, iffid, NULL); + get_byte(ifP, iffid, NULL); /* skip pad byte */ break; case ID_BODY: - if( cmaponly || (*bmhdP && (*bmhdP)->nPlanes == 0 )) { - skip_chunk(ifp, ID_BODY, chunksize); - return; - } - - process_body(ifp, chunksize, *bmhdP, cmap, - maskfile, fakeviewport, isdeepopt, *dcolP, - viewportmodesP); - - *bodyChunkProcessedP = TRUE; + if (cmaponly || (*bmhdP && (*bmhdP)->nPlanes == 0)) + skip_chunk(ifP, ID_BODY, chunksize); + else { + process_body(ifP, chunksize, *bmhdP, cmap, + maskfile, fakeviewport, isdeepopt, *dcolP, + viewportmodesP); - break; + *bodyChunkProcessedP = TRUE; + } break; case ID_GRAB: case ID_DEST: case ID_SPRT: case ID_CRNG: case ID_CCRT: case ID_DYCP: case ID_DPPV: case ID_DRNG: case ID_EPSF: case ID_JUNK: case ID_CNAM: case ID_PRVW: case ID_TINY: case ID_DPPS: - skip_chunk(ifp, iffid, chunksize); + skip_chunk(ifP, iffid, chunksize); break; case ID_copy: case ID_AUTH: case ID_NAME: case ID_ANNO: case ID_TEXT: case ID_FVER: - if( verbose ) - display_chunk(ifp, iffid, chunksize); + if (verbose) + display_chunk(ifP, iffid, chunksize); else - skip_chunk(ifp, iffid, chunksize); + skip_chunk(ifP, iffid, chunksize); break; - case ID_DPI: - { + case ID_DPI: { int x, y; - x = get_big_short(ifp, ID_DPI, NULL); - y = get_big_short(ifp, ID_DPI, NULL); - if( verbose ) + x = get_big_short(ifP, ID_DPI, NULL); + y = get_big_short(ifP, ID_DPI, NULL); + if (verbose) pm_message("%s chunk: dpi_x = %d dpi_y = %d", ID2string(ID_DPI), x, y); - } - break; + } break; default: pm_message("unknown chunk type %s - skipping", ID2string(iffid)); - skip_chunk(ifp, iffid, chunksize); + skip_chunk(ifP, iffid, chunksize); break; } bytesread += chunksize; - if( ODD(chunksize) ) { - (void) get_byte(ifp, iffid, NULL); + if (ODD(chunksize)) { + get_byte(ifP, iffid, NULL); bytesread += 1; } *bytesReadP = bytesread; } + +static void +maybeWriteColorMap(FILE * const ofP, + const BitMapHeader * const bmhdP, + ColorMap * const cmapP, + bool const bodyChunkProcessed, + bool const cmaponly) { +/*---------------------------------------------------------------------------- + Write to file *ofP the color map *cmapP as a PPM, if appropriate. + + The logic (not just here -- in the program as a whole) for deciding whether + to write the image or the colormap is quite twisted. If I thought anyone + was actually using this program, I would take the time to straighten it + out. + + What's really sick about this subroutine is that in choosing to write + a color map, it has to know that Caller hasn't already written + the image. Huge modularity violation. +-----------------------------------------------------------------------------*/ + if (cmaponly) { + if (HAS_COLORMAP(cmapP)) { + prepareCmap(bmhdP, cmapP); + cmapToPpm(ofP, cmapP); + } else + pm_error("You specified -cmaponly, but the ILBM " + "has no colormap"); + } else if (bmhdP && bmhdP->nPlanes == 0) { + if (HAS_COLORMAP(cmapP)) { + prepareCmap(bmhdP, cmapP); + cmapToPpm(ofP, cmapP); + } else + pm_error("ILBM has neither a color map nor color planes"); + } else if (!bodyChunkProcessed) { + if (HAS_COLORMAP(cmapP)) { + pm_message("input is a colormap file"); + prepareCmap(bmhdP, cmapP); + cmapToPpm(ofP, cmapP); + } else + pm_error("ILBM has neither %s or %s chunk", + ID2string(ID_BODY), ID2string(ID_CMAP)); + } +} + + + int main(int argc, char *argv[]) { - FILE *ifp; + FILE * ifP; int argn; short cmaponly = 0, isdeepopt = 0; bool endchunk; @@ -2299,25 +2365,25 @@ main(int argc, char *argv[]) { } if( argn < argc ) { - ifp = pm_openr( argv[argn] ); + ifP = pm_openr( argv[argn] ); argn++; } else - ifp = stdin; + ifP = stdin; if( argn != argc ) pm_usage(usage); /* Read in the ILBM file. */ - firstIffid = get_big_long(ifp, ID_FORM, NULL); - if( firstIffid != ID_FORM ) + firstIffid = get_big_long(ifP, ID_FORM, NULL); + if (firstIffid != ID_FORM) pm_error("input is not a FORM type IFF file"); - formsize = get_big_long(ifp, ID_FORM, NULL); - typeid = get_big_long(ifp, ID_FORM, NULL); - if( typeid != ID_ILBM && typeid != ID_RGBN && typeid != ID_RGB8 && - typeid != ID_PBM ) - pm_error( "input is not an ILBM, RGBN, RGB8 or PBM " - "type FORM IFF file" ); + formsize = get_big_long(ifP, ID_FORM, NULL); + typeid = get_big_long(ifP, ID_FORM, NULL); + if (typeid != ID_ILBM && typeid != ID_RGBN && typeid != ID_RGB8 && + typeid != ID_PBM) + pm_error("input is not an ILBM, RGBN, RGB8 or PBM " + "type FORM IFF file"); bytesread = 4; /* FORM and formsize do not count */ cmap = alloc_cmap(); @@ -2325,55 +2391,41 @@ main(int argc, char *argv[]) { /* Main loop, parsing the IFF FORM. */ bodyChunkProcessed = FALSE; endchunk = FALSE; - while( !endchunk && formsize-bytesread >= 8 ) { - long bytes_read_for_chunk; + while (!endchunk && formsize-bytesread >= 8) { + long bytesReadForChunk; - process_chunk(ifp, formsize, ignorelist, ignorecount, - fakeviewport, viewportmask, - isdeepopt, cmaponly, - &bodyChunkProcessed, - &endchunk, &bmhdP, cmap, &dcol, - &viewportmodes, &bytes_read_for_chunk); + processChunk(ifP, formsize, ignorelist, ignorecount, + fakeviewport, viewportmask, + isdeepopt, cmaponly, + &bodyChunkProcessed, + &endchunk, &bmhdP, cmap, &dcol, + &viewportmodes, &bytesReadForChunk); - bytesread += bytes_read_for_chunk; + bytesread += bytesReadForChunk; } - if( maskfile ) { + if (maskfile) { pm_close(maskfile); - if( !wrotemask ) + if (!wrotemask) remove(maskname); pbm_freerow(maskrow); } - if( cmaponly || (bmhdP && bmhdP->nPlanes == 0 )) { - if( HAS_COLORMAP(cmap) ) { - check_cmap(bmhdP, cmap); - cmap_to_ppm(cmap); - } else - pm_error("no colormap"); - } else if( !bodyChunkProcessed ) { - if( HAS_COLORMAP(cmap) ) { - pm_message("input is a colormap file"); - check_cmap(bmhdP, cmap); - cmap_to_ppm(cmap); - } else - pm_error("no %s or %s chunk found", - ID2string(ID_BODY), ID2string(ID_CMAP)); - } + maybeWriteColorMap(stdout, bmhdP, cmap, bodyChunkProcessed, cmaponly); { unsigned int skipped; - for( skipped = 0; fgetc(ifp) != EOF; ++skipped ) - bytesread++; + for (skipped = 0; fgetc(ifP) != EOF; ++skipped) + ++bytesread; - if( skipped > 0 ) + if (skipped > 0) pm_message("skipped %u extraneous byte%s after last chunk", skipped, (skipped == 1 ? "" : "s")); } - pm_close(ifp); + pm_close(ifP); - if( !endchunk && bytesread != formsize ) { + if (!endchunk && bytesread != formsize) { pm_message("warning - file length/FORM size field mismatch " "(%ld != %ld+8)", bytesread+8 /* FORM+size */, formsize); diff --git a/converter/ppm/mitsu.h b/converter/ppm/mitsu.h index 8676a39d..bca4fbdf 100644 --- a/converter/ppm/mitsu.h +++ b/converter/ppm/mitsu.h @@ -1,7 +1,6 @@ #ifndef MITSU_H_INCLUDED #define MITSU_H_INCLUDED -/* static char SCCSid[] = "@(#)mitsu.h\t\t1.3\t(SPZ)\t3/11/92\n"; */ #define MAXLUTCOL 255 #define A4_MAXCOLS 1184 diff --git a/converter/ppm/picttoppm.c b/converter/ppm/picttoppm.c index b7da0c79..9a7d8e7c 100644 --- a/converter/ppm/picttoppm.c +++ b/converter/ppm/picttoppm.c @@ -142,15 +142,6 @@ static int ps_cent_x; static int ps_cent_y; static int ps_cent_set; -typedef void (drawFn)(struct canvas *, int); - -struct opdef { - const char* name; - int len; - drawFn * impl; - const char* description; -}; - struct raster { /*---------------------------------------------------------------------------- An image raster. May be either truecolor or paletted. @@ -265,13 +256,30 @@ struct blit_info { struct raster srcplane; int pixSize; struct Rect dstRect; - struct RGBColor * color_map; + struct RGBColor * colorMap; int mode; struct blit_info * next; }; -static struct blit_info* blit_list = 0; -static struct blit_info** last_bl = &blit_list; +typedef struct { + struct blit_info * firstP; + struct blit_info ** connectorP; + bool unblittableText; + /* The image contains text opcodes, and we don't know how to put that + in a blit list (I really don't even know what a blit _is_), so + the image information here is incomplete. + */ +} blitList; + + +typedef void (drawFn)(struct canvas *, blitList *, int); + +struct opdef { + const char* name; + int len; + drawFn * impl; + const char* description; +}; #define WORD_LEN (-1) @@ -610,6 +618,7 @@ static drawFn ShortComment; static void ShortComment(struct canvas * const canvasP, + blitList * const blitListP, int const version) { picComment(read_word(), 0); @@ -621,6 +630,7 @@ static drawFn LongComment; static void LongComment(struct canvas * const canvasP, + blitList * const blitListP, int const version) { word type; @@ -635,6 +645,7 @@ static drawFn skip_poly_or_region; static void skip_poly_or_region(struct canvas * const canvasP, + blitList * const blitListP, int const version) { stage = "skipping polygon or region"; @@ -765,24 +776,33 @@ load_fontdir(const char * const dirfile) { static void +dumpRect(const char * const label, + struct Rect const rectangle) { + + pm_message("%s (%u,%u) (%u,%u)", + label, + rectangle.left, rectangle.top, + rectangle.right, rectangle.bottom); +} + + + +static void read_rect(struct Rect * const r) { r->top = read_word(); r->left = read_word(); r->bottom = read_word(); r->right = read_word(); -} - + if (r->top > r->bottom || r->right < r->left) + dumpRect("Invalid rectangle", *r); -static void -dumpRect(const char * const label, - struct Rect const rectangle) { - - pm_message("%s (%u,%u) (%u,%u)", - label, - rectangle.left, rectangle.top, - rectangle.right, rectangle.bottom); + if (r->top > r->bottom) + pm_error("Invalid PICT: a rectangle has a top below its bottom"); + if (r->right < r->left) + pm_error("Invalid PICT: a rectangle has a right edge " + "left of its left edge"); } @@ -802,10 +822,10 @@ rectheight(const struct Rect * const r) { static bool -rectsamesize(const struct Rect * const r1, - const struct Rect * const r2) { - return r1->right - r1->left == r2->right - r2->left && - r1->bottom - r1->top == r2->bottom - r2->top ; +rectsamesize(struct Rect const r1, + struct Rect const r2) { + return r1.right - r1.left == r2.right - r2.left && + r1.bottom - r1.top == r2.bottom - r2.top ; } @@ -835,20 +855,45 @@ rectscale(struct Rect * const r, -static struct blit_info* -add_blit_list(void) { +static void + initBlitList(blitList * const blitListP) { - struct blit_info * bi; + blitListP->firstP = NULL; + blitListP->connectorP = &blitListP->firstP; + blitListP->unblittableText = false; +} + + + +static void +addBlitList(blitList * const blitListP, + struct Rect const srcRect, + struct Rect const srcBounds, + struct raster const srcplane, + int const pixSize, + struct Rect const dstRect, + struct RGBColor * const colorMap, + int const mode) { + + struct blit_info * biP; - MALLOCVAR(bi); - if (bi == NULL) + MALLOCVAR(biP); + if (biP == NULL) pm_error("out of memory for blit list"); - - bi->next = 0; - *last_bl = bi; - last_bl = &bi->next; - - return bi; + else { + biP->srcRect = srcRect; + biP->srcBounds = srcBounds; + biP->srcplane = srcplane; + biP->pixSize = pixSize; + biP->dstRect = dstRect; + biP->colorMap = colorMap; + biP->mode = mode; + + biP->next = NULL; + + *blitListP->connectorP = biP; + blitListP->connectorP = &biP->next; + } } @@ -1327,8 +1372,6 @@ doSameSize(transfer_func trf, struct rgbPlanes const dst, unsigned int const dstwid) { /*---------------------------------------------------------------------------- - Generalized (but slow) blit. - Transfer pixels from 'src' to 'dst', applying the transfer function 'trf'. @@ -1501,19 +1544,30 @@ blitIdempotent(unsigned int const pixSize, static void -generalBlit(struct Rect const srcRect, - struct Rect const srcBounds, - struct raster const srcplane, - struct rgbPlanes const planes, - int const pixSize, - struct Rect const dstRect, - struct Rect const dstBounds, - int const dstwid, - struct RGBColor * const color_map, - int const mode, - struct Rect const clipsrc, - struct Rect const clipdst) { - +doBlit(struct Rect const srcRect, + struct Rect const dstRect, + struct Rect const srcBounds, + struct raster const srcplane, + struct Rect const dstBounds, + struct rgbPlanes const canvasPlanes, + int const pixSize, + int const dstwid, + struct RGBColor * const color_map, + int const mode) { +/*---------------------------------------------------------------------------- + Transfer some pixels from 'srcplane' to 'canvasPlanes', applying the + transfer function 'trf'. + + 'srcplane' contains the rectangle 'srcBounds' of the image. + 'canvasPlanes' contains the rectangle 'dstRect' of the image. + + Take the rectangle 'srcRect' of the source image and copy it to the + rectangle 'dstRec' of the destination image. + + Each plane of 'canvasPlanes' is one word per pixel and contains actual + colors, never a palette index. It is an array in row-major order + with 'dstwid' words per row. +-----------------------------------------------------------------------------*/ unsigned char * src; struct rgbPlanes dst; int dstoff; @@ -1523,31 +1577,31 @@ generalBlit(struct Rect const srcRect, transfer_func trf; if (verbose) { - dumpRect("copying from:", clipsrc); - dumpRect("to: ", clipdst); + dumpRect("copying from:", srcRect); + dumpRect("to: ", dstRect); pm_message("a %u x %u area to a %u x %u area", - rectwidth(&clipsrc), rectheight(&clipsrc), - rectwidth(&clipdst), rectheight(&clipdst)); + rectwidth(&srcRect), rectheight(&srcRect), + rectwidth(&dstRect), rectheight(&dstRect)); } { unsigned int const pkpixsize = pixSize == 16 ? 2 : 1; - unsigned int const srcRowNumber = clipsrc.top - srcBounds.top; + unsigned int const srcRowNumber = srcRect.top - srcBounds.top; unsigned int const srcRowOffset = - (clipsrc.left - srcBounds.left) * pkpixsize; + (srcRect.left - srcBounds.left) * pkpixsize; assert(srcRowNumber < srcplane.rowCount); assert(srcRowOffset < srcplane.rowSize); src = srcplane.bytes + srcRowNumber * srcplane.rowSize + srcRowOffset; - xsize = clipsrc.right - clipsrc.left; - ysize = clipsrc.bottom - clipsrc.top; + xsize = rectwidth(&srcRect); + ysize = rectheight(&srcRect); srcadd = srcplane.rowSize - xsize * pkpixsize; } - dstoff = (clipdst.top - dstBounds.top) * dstwid + - (clipdst.left - dstBounds.left); - dst.red = planes.red + dstoff; - dst.grn = planes.grn + dstoff; - dst.blu = planes.blu + dstoff; + dstoff = (dstRect.top - dstBounds.top) * dstwid + + (dstRect.left - dstBounds.left); + dst.red = canvasPlanes.red + dstoff; + dst.grn = canvasPlanes.grn + dstoff; + dst.blu = canvasPlanes.blu + dstoff; /* get rid of Text mask mode bit, if (erroneously) set */ if ((mode & ~64) == 0) @@ -1555,8 +1609,8 @@ generalBlit(struct Rect const srcRect, else trf = transfer(mode & ~64); - if (!rectsamesize(&clipsrc, &clipdst)) - doDiffSize(clipsrc, clipdst, pixSize, xsize, ysize, + if (!rectsamesize(srcRect, dstRect)) + doDiffSize(srcRect, dstRect, pixSize, xsize, ysize, trf, color_map, src, srcplane.rowSize, dst, dstwid); else { if (trf == NULL) @@ -1575,12 +1629,21 @@ blit(struct Rect const srcRect, struct Rect const srcBounds, struct raster const srcplane, struct canvas * const canvasP, + blitList * const blitListP, int const pixSize, struct Rect const dstRect, struct Rect const dstBounds, int const dstwid, struct RGBColor * const color_map, int const mode) { +/*---------------------------------------------------------------------------- + 'srcplane' contains the rectangle 'srcBounds' of the image. + + We transfer rectangle 'srcRect' from that. + + if 'blitListP' is non-null, we don't draw anything on 'canvasP'; instead, + we add to the list *blitlistP a description of what needs to be drawn. +-----------------------------------------------------------------------------*/ /* I can't tell what the result value of this function is supposed to mean, but I found several return statements that did not set it to anything, @@ -1595,9 +1658,7 @@ blit(struct Rect const srcRect, retval = 1; else { /* Almost got it. Clip source rect with source bounds. - clip dest rect with dest bounds. If source and - destination are not the same size, use Pnmscale - to get a nicely sized rectangle. + clip dest rect with dest bounds. */ struct Rect clipsrc; struct Rect clipdst; @@ -1605,22 +1666,16 @@ blit(struct Rect const srcRect, rectinter(srcBounds, srcRect, &clipsrc); rectinter(dstBounds, dstRect, &clipdst); - if (fullres) { - struct blit_info * bi; - bi = add_blit_list(); - bi->srcRect = clipsrc; - bi->srcBounds = srcBounds; - bi->srcplane = srcplane; - bi->pixSize = pixSize; - bi->dstRect = clipdst; - bi->color_map = color_map; - bi->mode = mode; + if (blitListP) { + addBlitList(blitListP, + clipsrc, srcBounds, srcplane, pixSize, + clipdst, color_map, mode); retval = 0; } else { - generalBlit(srcRect, srcBounds, srcplane, canvasP->planes, pixSize, - dstRect, dstBounds, dstwid, color_map, mode, - clipsrc, clipdst); + doBlit(clipsrc, clipdst, + srcBounds, srcplane, dstBounds, canvasP->planes, + pixSize, dstwid, color_map, mode); retval = 1; } @@ -1680,9 +1735,31 @@ compact(word const input) { static void -do_blits(struct canvas * const canvasP) { +reportBlitList(blitList * const blitListP) { + + if (verbose) { + unsigned int count; + struct blit_info * biP; + + for (count = 0, biP = blitListP->firstP; biP; biP = biP->next) + ++count; + + pm_message("# blits: %u", count); + } +} + - struct blit_info* bi; + +static void +doBlitList(struct canvas * const canvasP, + blitList * const blitListP) { +/*---------------------------------------------------------------------------- + Do the list of blits *blitListP, drawing on canvas *canvasP. + + We allocate new plane data structures in *canvasP. We assume it doesn't + have them already. +-----------------------------------------------------------------------------*/ + struct blit_info * bi; int srcwidth, dstwidth, srcheight, dstheight; double scale, scalelow, scalehigh; double xscale = 1.0; @@ -1690,9 +1767,11 @@ do_blits(struct canvas * const canvasP) { double lowxscale, highxscale, lowyscale, highyscale; int xscalecalc = 0, yscalecalc = 0; + reportBlitList(blitListP); + fullres = 0; - for (bi = blit_list; bi; bi = bi->next) { + for (bi = blitListP->firstP; bi; bi = bi->next) { srcwidth = rectwidth(&bi->srcRect); dstwidth = rectwidth(&bi->dstRect); srcheight = rectheight(&bi->srcRect); @@ -1768,11 +1847,12 @@ do_blits(struct canvas * const canvasP) { } if (xscale != 1.0 || yscale != 1.0) { - for (bi = blit_list; bi; bi = bi->next) - rectscale(&bi->dstRect, xscale, yscale); + struct blit_info * biP; + + for (biP = blitListP->firstP; biP; biP = biP->next) + rectscale(&biP->dstRect, xscale, yscale); - pm_message("Scaling output by %f in X and %f in Y", - xscale, yscale); + pm_message("Scaling output by %f in X and %f in Y", xscale, yscale); rectscale(&picFrame, xscale, yscale); } @@ -1783,12 +1863,10 @@ do_blits(struct canvas * const canvasP) { clip_rect = picFrame; - for (bi = blit_list; bi; bi = bi->next) { - blit(bi->srcRect, bi->srcBounds, bi->srcplane, canvasP, - bi->pixSize, - bi->dstRect, picFrame, rowlen, - bi->color_map, - bi->mode); + for (bi = blitListP->firstP; bi; bi = bi->next) { + doBlit(bi->srcRect, bi->dstRect, + bi->srcBounds, bi->srcplane, picFrame, canvasP->planes, + bi->pixSize, rowlen, bi->colorMap, bi->mode); } } @@ -1856,6 +1934,7 @@ static drawFn Clip; static void Clip(struct canvas * const canvasP, + blitList * const blitListP, int const version) { word len; @@ -1878,6 +1957,7 @@ static drawFn OpColor; static void OpColor(struct canvas * const canvasP, + blitList * const blitListP, int const version) { op_color.red = read_word(); @@ -1967,7 +2047,7 @@ read_color_table(void) { color_table[val].blu = read_word(); if (verbose > 1) - pm_message("%d: [%d,%d,%d]", val, + pm_message("Color %3u: [%u,%u,%u]", val, color_table[val].red, color_table[val].grn, color_table[val].blu); @@ -2173,6 +2253,42 @@ unpackUncompressedBits(FILE * const ifP, static void +reportValidateCompressedLineLen(unsigned int const row, + unsigned int const linelen, + unsigned int const rowSize) { +/*---------------------------------------------------------------------------- + 'row' is a row number in the raster. + + 'linelen' is the number of bytes of PICT that the PICT says hold the + compressed version of that row. + + 'rowSize' is the number of bytes we expect the uncompressed line to + be (includes pad pixels on the right). +-----------------------------------------------------------------------------*/ + if (verbose > 1) + pm_message("Row %u: %u-byte compressed line", row, linelen); + + /* When the line length value is garbage, it often causes the program to + try to read beyond EOF. To make that failure easier to diagnose, + we sanity check the line length now. + */ + + /* In the worst case, a pixel is represented by two bytes: a one byte + repeat count of one followed by a one byte pixel value (the byte could + be up to 8 pixels) or a one byte block length of one followed by the + pixel value. So expansion factor two. + */ + + if (linelen > rowSize * 2) + pm_error("Invalid PICT: compressed line of %u bytes for Row %u " + "is too big " + "to represent a %u-byte padded row, even with worse case " + "compression.", linelen, row, rowSize); +} + + + +static void expandRun(unsigned char * const block, unsigned int const blockLimit, unsigned int const bitsPerPixel, @@ -2375,7 +2491,7 @@ interpretCompressedLine(unsigned char * const linebuf, assert(lineCursor <= linelen); - if (verbose > 1) + if (verbose > 2) pm_message("At Byte %u of line, Column %u of row", lineCursor, rasterCursor); @@ -2394,6 +2510,32 @@ interpretCompressedLine(unsigned char * const linebuf, } +/* There is some confusion about when, in PICT, a line length is one byte and + when it is two. An Apple document says it is two bytes when the number of + pixels in the row, padded, is > 250. Ppmtopict generated PICTs that way + until January 2009. Picttoppm assumed something similar until March 2004: + It assumed the line length is two bytes when the number of pixels > 250 _or_ + bits per pixel > 8. But in March 2004, Steve Summit did a bunch of + experiments on existing PICT files and found that they all worked with the + rule "pixels per row > 200 => 2 byte line length" and some did not work + with the original rule. + + So in March 2004, Picttoppm changed to pixels per row > 200. Ppmtopict + didn't catch up until January 2009. + + http://developer.apple.com/documentation/mac/QuickDraw/QuickDraw-460.html#HEADING460-0 + + Of course, neither 200 nor 250 make any logical sense. In the worst case, + you can represent 254 pixels of 8 bpp or less in a 255 byte line. + In the worst case, you can represent 127 16bpp pixels in a 255 byte line. + So with 200 being the cutoff, it's actually impossible to represent some + 16 bpp images with 200 pixels per row. + + We have not been able to find an offical spec for PICT. + + Some day, we may have to make a user option for this. +*/ + static void unpackCompressedBits(FILE * const ifP, @@ -2410,14 +2552,13 @@ unpackCompressedBits(FILE * const ifP, "packing" and I don't know what packing is called. But we don't use that confusing terminology in this program, except when talking to the user. - - *boundsP describes the rectangle. -----------------------------------------------------------------------------*/ unsigned int const llsize = rowBytes > 200 ? 2 : 1; /* Width in bytes of the field at the beginning of a line that tells - how long (in bytes) the line is. + how long (in bytes) the line is. See notes above about this + computation. */ - unsigned int rowOfRect; + unsigned int row; unsigned char * linebuf; unsigned int linebufSize; @@ -2426,9 +2567,9 @@ unpackCompressedBits(FILE * const ifP, if (linebuf == NULL) pm_error("can't allocate memory for line buffer"); - for (rowOfRect = 0; rowOfRect < raster.rowCount; ++rowOfRect) { + for (row = 0; row < raster.rowCount; ++row) { unsigned char * const rowRaster = - &raster.bytes[rowOfRect * raster.rowSize]; + &raster.bytes[row * raster.rowSize]; unsigned int linelen; if (llsize == 2) @@ -2436,8 +2577,7 @@ unpackCompressedBits(FILE * const ifP, else linelen = read_byte(); - if (verbose > 1) - pm_message("Row %u: %u-byte line", rowOfRect, linelen); + reportValidateCompressedLineLen(row, linelen, raster.rowSize); if (linelen > linebufSize) { linebufSize = linelen; @@ -2554,6 +2694,7 @@ static drawFn BkPixPat; static void BkPixPat(struct canvas * const canvasP, + blitList * const blitListP, int const version) { read_pattern(); @@ -2565,6 +2706,7 @@ static drawFn PnPixPat; static void PnPixPat(struct canvas * const canvasP, + blitList * const blitListP, int const version) { read_pattern(); @@ -2576,6 +2718,7 @@ static drawFn FillPixPat; static void FillPixPat(struct canvas * const canvasP, + blitList * const blitListP, int const version) { read_pattern(); @@ -2610,6 +2753,7 @@ static drawFn BkPat; static void BkPat(struct canvas * const canvasP, + blitList * const blitListP, int const version) { read_8x8_pattern(&bkpat); @@ -2621,6 +2765,7 @@ static drawFn PnPat; static void PnPat(struct canvas * const canvasP, + blitList * const blitListP, int const version) { read_8x8_pattern(&pen_pat); @@ -2632,6 +2777,7 @@ static drawFn FillPat; static void FillPat(struct canvas * const canvasP, + blitList * const blitListP, int const version) { read_8x8_pattern(&fillpat); @@ -2643,6 +2789,7 @@ static drawFn PnSize; static void PnSize(struct canvas * const canvasP, + blitList * const blitListP, int const version) { pen_height = read_word(); @@ -2657,6 +2804,7 @@ static drawFn PnSize; static void PnMode(struct canvas * const canvasP, + blitList * const blitListP, int const version) { pen_mode = read_word(); @@ -2685,6 +2833,7 @@ static drawFn RGBFgCol; static void RGBFgCol(struct canvas * const canvasP, + blitList * const blitListP, int const version) { read_rgb(&foreground); @@ -2699,6 +2848,7 @@ static drawFn RGBBkCol; static void RGBBkCol(struct canvas * const canvasP, + blitList * const blitListP, int const version) { read_rgb(&background); @@ -2857,6 +3007,7 @@ static drawFn Line; static void Line(struct canvas * const canvasP, + blitList * const blitListP, int const version) { struct Point p1; @@ -2874,6 +3025,7 @@ static drawFn LineFrom; static void LineFrom(struct canvas * const canvasP, + blitList * const blitListP, int const version) { struct Point p1; @@ -2881,7 +3033,7 @@ LineFrom(struct canvas * const canvasP, if (verbose) pm_message("(%d,%d) to (%d, %d)", current.x, current.y, p1.x, p1.y); - if (!fullres) + if (!blitListP) scan_line(canvasP, current.x, current.y, p1.x, p1.y); current.x = p1.x; @@ -2894,6 +3046,7 @@ static drawFn ShortLine; static void ShortLine(struct canvas * const canvasP, + blitList * const blitListP, int const version) { struct Point p1; @@ -2904,7 +3057,7 @@ ShortLine(struct canvas * const canvasP, current.x += p1.x; current.y += p1.y; - if (!fullres) + if (!blitListP) scan_line(canvasP, p1.x, p1.y, current.x, current.y); } @@ -2914,6 +3067,7 @@ static drawFn ShortLineFrom; static void ShortLineFrom(struct canvas * const canvasP, + blitList * const blitListP, int const version) { struct Point p1; @@ -2923,7 +3077,7 @@ ShortLineFrom(struct canvas * const canvasP, current.x,current.y,p1.x,p1.y); p1.x += current.x; p1.y += current.y; - if (!fullres) + if (!blitListP) scan_line(canvasP, current.x, current.y, p1.x, p1.y); current.x = p1.x; current.y = p1.y; @@ -2937,9 +3091,6 @@ do_paintRect(struct canvas * const canvasP, struct Rect rect; - if (fullres) - return; - if (verbose) dumpRect("painting", prect); @@ -2954,10 +3105,12 @@ static drawFn paintRect; static void paintRect(struct canvas * const canvasP, + blitList * const blitListP, int const version) { read_rect(&cur_rect); - do_paintRect(canvasP, cur_rect); + if (!blitListP) + do_paintRect(canvasP, cur_rect); } @@ -2966,9 +3119,11 @@ static drawFn paintSameRect; static void paintSameRect(struct canvas * const canvasP, + blitList * const blitListP, int const version) { - do_paintRect(canvasP, cur_rect); + if (!blitListP) + do_paintRect(canvasP, cur_rect); } @@ -2976,25 +3131,22 @@ paintSameRect(struct canvas * const canvasP, static void do_frameRect(struct canvas * const canvasP, struct Rect const rect) { - int x, y; - if (fullres) - return; - if (verbose) dumpRect("framing", rect); - if (pen_width == 0 || pen_height == 0) - return; - - for (x = rect.left; x <= rect.right - pen_width; x += pen_width) { - draw_pen(canvasP, x, rect.top); - draw_pen(canvasP, x, rect.bottom - pen_height); - } + if (pen_width > 0 && pen_height > 0) { + unsigned int x, y; - for (y = rect.top; y <= rect.bottom - pen_height ; y += pen_height) { - draw_pen(canvasP, rect.left, y); - draw_pen(canvasP, rect.right - pen_width, y); + for (x = rect.left; x <= rect.right - pen_width; x += pen_width) { + draw_pen(canvasP, x, rect.top); + draw_pen(canvasP, x, rect.bottom - pen_height); + } + + for (y = rect.top; y <= rect.bottom - pen_height ; y += pen_height) { + draw_pen(canvasP, rect.left, y); + draw_pen(canvasP, rect.right - pen_width, y); + } } } @@ -3004,10 +3156,12 @@ static drawFn frameRect; static void frameRect(struct canvas * const canvasP, + blitList * const blitListP, int const version) { read_rect(&cur_rect); - do_frameRect(canvasP, cur_rect); + if (!blitListP) + do_frameRect(canvasP, cur_rect); } @@ -3016,9 +3170,11 @@ static drawFn frameSameRect; static void frameSameRect(struct canvas * const canvasP, + blitList * const blitListP, int const version) { - do_frameRect(canvasP, cur_rect); + if (!blitListP) + do_frameRect(canvasP, cur_rect); } @@ -3165,6 +3321,7 @@ static drawFn paintPoly; static void paintPoly(struct canvas * const canvasP, + blitList * const blitListP, int const version) { struct Rect bb; @@ -3176,7 +3333,7 @@ paintPoly(struct canvas * const canvasP, read_point(&pts[i]); /* scan convert poly ... */ - if (!fullres) + if (!blitListP) scan_poly(canvasP, np, pts); } @@ -3186,6 +3343,7 @@ static drawFn PnLocHFrac; static void PnLocHFrac(struct canvas * const canvasP, + blitList * const blitListP, int const version) { word frac = read_word(); @@ -3200,6 +3358,7 @@ static drawFn TxMode; static void TxMode(struct canvas * const canvasP, + blitList * const blitListP, int const version) { text_mode = read_word(); @@ -3220,6 +3379,7 @@ static drawFn TxFont; static void TxFont(struct canvas * const canvasP, + blitList * const blitListP, int const version) { text_font = read_word(); @@ -3233,6 +3393,7 @@ static drawFn TxFace; static void TxFace(struct canvas * const canvasP, + blitList * const blitListP, int const version) { text_face = read_byte(); @@ -3246,6 +3407,7 @@ static drawFn TxSize; static void TxSize(struct canvas * const canvasP, + blitList * const blitListP, int const version) { text_size = read_word(); @@ -3256,11 +3418,11 @@ TxSize(struct canvas * const canvasP, static void -skip_text(void) { +skip_text(blitList * const blitListP) { - pm_message("Warning: text is omitted from the output because " - "we don't know how to do text with -fullres."); skip(read_byte()); + + blitListP->unblittableText = true; } @@ -3279,6 +3441,7 @@ static struct font* get_font(int const font, int const size, int const style) { + int closeness, bestcloseness; struct fontinfo* fi, *best; @@ -3410,11 +3573,12 @@ do_ps_text(struct canvas * const canvasP, static void do_text(struct canvas * const canvasP, + blitList * const blitListP, word const startx, word const starty) { - if (fullres) - skip_text(); + if (blitListP) + skip_text(blitListP); else { if (!(tfont = get_font(text_font, text_size, text_face))) tfont = pbm_defaultfont("bdf"); @@ -3459,13 +3623,14 @@ static drawFn LongText; static void LongText(struct canvas * const canvasP, + blitList * const blitListP, int const version) { struct Point p; read_point(&p); - do_text(canvasP, p.x, p.y); + do_text(canvasP, blitListP, p.x, p.y); } @@ -3474,10 +3639,12 @@ static drawFn DHText; static void DHText(struct canvas * const canvasP, + blitList * const blitListP, int const version) { current.x += read_byte(); - do_text(canvasP, current.x, current.y); + + do_text(canvasP, blitListP, current.x, current.y); } @@ -3486,10 +3653,12 @@ static drawFn DVText; static void DVText(struct canvas * const canvasP, + blitList * const blitListP, int const version) { current.y += read_byte(); - do_text(canvasP, current.x, current.y); + + do_text(canvasP, blitListP, current.x, current.y); } @@ -3498,6 +3667,7 @@ static drawFn DHDVText; static void DHDVText(struct canvas * const canvasP, + blitList * const blitListP, int const version) { byte dh, dv; @@ -3509,7 +3679,8 @@ DHDVText(struct canvas * const canvasP, current.x += dh; current.y += dv; - do_text(canvasP, current.x, current.y); + + do_text(canvasP, blitListP, current.x, current.y); } @@ -3520,6 +3691,7 @@ DHDVText(struct canvas * const canvasP, static void directBits(struct canvas * const canvasP, + blitList * const blitListP, unsigned int const pictVersion, bool const skipRegion) { @@ -3561,11 +3733,11 @@ directBits(struct canvas * const canvasP, pm_message("transfer mode = %s", const_name(transfer_name, mode)); if (skipRegion) - skip_poly_or_region(canvasP, pictVersion); + skip_poly_or_region(canvasP, blitListP, pictVersion); unpackbits(ifp, &p.Bounds, 0, p.pixelSize, &raster); - blit(srcRect, p.Bounds, raster, canvasP, p.pixelSize, + blit(srcRect, p.Bounds, raster, canvasP, blitListP, p.pixelSize, dstRect, picFrame, rowlen, NULL, mode); freeRaster(raster); @@ -3580,9 +3752,10 @@ static drawFn DirectBitsRect; static void DirectBitsRect(struct canvas * const canvasP, + blitList * const blitListP, int const version) { - directBits(canvasP, version, SKIP_REGION_FALSE); + directBits(canvasP, blitListP, version, SKIP_REGION_FALSE); } @@ -3591,15 +3764,17 @@ static drawFn DirectBitsRgn; static void DirectBitsRgn(struct canvas * const canvasP, + blitList * const blitListP, int const version) { - directBits(canvasP, version, SKIP_REGION_TRUE); + directBits(canvasP, blitListP, version, SKIP_REGION_TRUE); } static void do_pixmap(struct canvas * const canvasP, + blitList * const blitListP, int const version, word const rowBytes, int const is_region) { @@ -3638,13 +3813,13 @@ do_pixmap(struct canvas * const canvasP, pm_message("transfer mode = %s", const_name(transfer_name, mode)); if (is_region) - skip_poly_or_region(canvasP, version); + skip_poly_or_region(canvasP, blitListP, version); stage = "unpacking rectangle"; unpackbits(ifp, &p.Bounds, rowBytes, p.pixelSize, &raster); - blit(srcRect, p.Bounds, raster, canvasP, 8, + blit(srcRect, p.Bounds, raster, canvasP, blitListP, 8, dstRect, picFrame, rowlen, color_table, mode); free(color_table); @@ -3656,6 +3831,7 @@ do_pixmap(struct canvas * const canvasP, static void do_bitmap(FILE * const ifP, struct canvas * const canvasP, + blitList * const blitListP, int const version, int const rowBytes, int const is_region) { @@ -3683,13 +3859,13 @@ do_bitmap(FILE * const ifP, pm_message("transfer mode = %s", const_name(transfer_name, mode)); if (is_region) - skip_poly_or_region(canvasP, version); + skip_poly_or_region(canvasP, blitListP, version); stage = "unpacking rectangle"; unpackbits(ifP, &Bounds, rowBytes, 1, &raster); - blit(srcRect, Bounds, raster, canvasP, 8, + blit(srcRect, Bounds, raster, canvasP, blitListP, 8, dstRect, picFrame, rowlen, color_table, mode); freeRaster(raster); @@ -3701,6 +3877,7 @@ static drawFn BitsRect; static void BitsRect(struct canvas * const canvasP, + blitList * const blitListP, int const version) { word rowBytesWord; @@ -3713,9 +3890,9 @@ BitsRect(struct canvas * const canvasP, interpretRowBytesWord(rowBytesWord, &pixMap, &rowBytes); if (pixMap) - do_pixmap(canvasP, version, rowBytes, 0); + do_pixmap(canvasP, blitListP, version, rowBytes, 0); else - do_bitmap(ifp, canvasP, version, rowBytes, 0); + do_bitmap(ifp, canvasP, blitListP, version, rowBytes, 0); } @@ -3724,6 +3901,7 @@ static drawFn BitsRegion; static void BitsRegion(struct canvas * const canvasP, + blitList * const blitListP, int const version) { word rowBytesWord; @@ -3736,9 +3914,9 @@ BitsRegion(struct canvas * const canvasP, interpretRowBytesWord(rowBytesWord, &pixMap, &rowBytes); if (pixMap) - do_pixmap(canvasP, version, rowBytes, 1); + do_pixmap(canvasP, blitListP, version, rowBytes, 1); else - do_bitmap(ifp, canvasP, version, rowBytes, 1); + do_bitmap(ifp, canvasP, blitListP, version, rowBytes, 1); } @@ -3921,15 +4099,85 @@ static struct opdef const optable[] = { static void +processOpcode(word const opcode, + struct canvas * const canvasP, + blitList * const blitListP, + unsigned int const version) { + + if (opcode < 0xa2) { + stage = optable[opcode].name; + if (verbose) { + if (streq(stage, "reserved")) + pm_message("reserved opcode=0x%x", opcode); + else + pm_message("Opcode: %s", optable[opcode].name); + } + + if (optable[opcode].impl != NULL) + (*optable[opcode].impl)(canvasP, blitListP, version); + else if (optable[opcode].len >= 0) + skip(optable[opcode].len); + else { + switch (optable[opcode].len) { + case WORD_LEN: { + word const len = read_word(); + skip(len); + } break; + default: + pm_error("can't do length %u", optable[opcode].len); + } + } + } else if (opcode == 0xc00) { + if (verbose) + pm_message("HeaderOp"); + stage = "HeaderOp"; + skip(24); + } else if (opcode >= 0xa2 && opcode <= 0xaf) { + stage = "skipping reserved"; + if (verbose) + pm_message("%s 0x%x", stage, opcode); + skip(read_word()); + } else if (opcode >= 0xb0 && opcode <= 0xcf) { + /* just a reserved opcode, no data */ + if (verbose) + pm_message("reserved 0x%x", opcode); + } else if (opcode >= 0xd0 && opcode <= 0xfe) { + stage = "skipping reserved"; + if (verbose) + pm_message("%s 0x%x", stage, opcode); + skip(read_long()); + } else if (opcode >= 0x100 && opcode <= 0x7fff) { + stage = "skipping reserved"; + if (verbose) + pm_message("%s 0x%x", stage, opcode); + skip((opcode >> 7) & 255); + } else if (opcode >= 0x8000 && opcode <= 0x80ff) { + /* just a reserved opcode */ + if (verbose) + pm_message("reserved 0x%x", opcode); + } else if (opcode >= 0x8100) { + stage = "skipping reserved"; + if (verbose) + pm_message("%s 0x%x", stage, opcode); + skip(read_long()); + } else + pm_error("This program does not understand opcode 0x%04x", opcode); +} + + + +static void interpret_pict(FILE * const ofP) { byte ch; word picSize; word opcode; - word len; unsigned int version; int i; struct canvas canvas; + blitList blitList; + + initBlitList(&blitList); for (i = 0; i < 64; i++) pen_pat.pix[i] = bkpat.pix[i] = fillpat.pix[i] = 1; @@ -3943,16 +4191,16 @@ interpret_pict(FILE * const ofP) { picSize = read_word(); if (verbose) - pm_message("picture size = %d (0x%x)", picSize, picSize); + pm_message("picture size = %u (0x%x)", picSize, picSize); stage = "reading picture frame"; read_rect(&picFrame); if (verbose) { dumpRect("Picture frame:", picFrame); - pm_message("Picture size is %d x %d", - picFrame.right - picFrame.left, - picFrame.bottom - picFrame.top); + pm_message("Picture size is %u x %u", + picFrame.right - picFrame.left, + picFrame.bottom - picFrame.top); } if (!fullres) { @@ -3988,68 +4236,15 @@ interpret_pict(FILE * const ofP) { if (verbose) pm_message("PICT version %u", version); - while((opcode = get_op(version)) != 0xff) { - if (opcode < 0xa2) { - stage = optable[opcode].name; - if (verbose) { - if (streq(stage, "reserved")) - pm_message("reserved opcode=0x%x", opcode); - else - pm_message("Opcode: %s", optable[opcode].name); - } - - if (optable[opcode].impl != NULL) - (*optable[opcode].impl)(&canvas, version); - else if (optable[opcode].len >= 0) - skip(optable[opcode].len); - else switch (optable[opcode].len) { - case WORD_LEN: - len = read_word(); - skip(len); - break; - default: - pm_error("can't do length %u", optable[opcode].len); - } - } else if (opcode == 0xc00) { - if (verbose) - pm_message("HeaderOp"); - stage = "HeaderOp"; - skip(24); - } else if (opcode >= 0xa2 && opcode <= 0xaf) { - stage = "skipping reserved"; - if (verbose) - pm_message("%s 0x%x", stage, opcode); - skip(read_word()); - } else if (opcode >= 0xb0 && opcode <= 0xcf) { - /* just a reserved opcode, no data */ - if (verbose) - pm_message("reserved 0x%x", opcode); - } else if (opcode >= 0xd0 && opcode <= 0xfe) { - stage = "skipping reserved"; - if (verbose) - pm_message("%s 0x%x", stage, opcode); - skip(read_long()); - } else if (opcode >= 0x100 && opcode <= 0x7fff) { - stage = "skipping reserved"; - if (verbose) - pm_message("%s 0x%x", stage, opcode); - skip((opcode >> 7) & 255); - } else if (opcode >= 0x8000 && opcode <= 0x80ff) { - /* just a reserved opcode */ - if (verbose) - pm_message("reserved 0x%x", opcode); - } else if (opcode >= 0x8100) { - stage = "skipping reserved"; - if (verbose) - pm_message("%s 0x%x", stage, opcode); - skip(read_long()); - } else - pm_error("This program does not understand opcode 0x%04x", opcode); - } + while((opcode = get_op(version)) != 0xff) + processOpcode(opcode, &canvas, fullres ? &blitList : NULL, version); - if (fullres) - do_blits(&canvas); - + if (fullres) { + if (blitList.unblittableText) + pm_message("Warning: text is omitted from the output because " + "we don't know how to do text with -fullres."); + doBlitList(&canvas, &blitList); + } outputPpm(ofP, canvas.planes); freePlanes(canvas.planes); @@ -4123,6 +4318,7 @@ main(int argc, char * argv[]) { if (header) { stage = "Reading 512 byte header"; + /* Note that the "header" in PICT is entirely comment! */ skip(512); } diff --git a/converter/ppm/ppmtomitsu.c b/converter/ppm/ppmtomitsu.c index 837d9e2b..e59f09b3 100644 --- a/converter/ppm/ppmtomitsu.c +++ b/converter/ppm/ppmtomitsu.c @@ -1,10 +1,10 @@ -/* ppmtomitsu.c - read a portable pixmap and produce output for the +/* ppmtomitsu.c - read a PPM image and produce output for the ** Mitsubishi S340-10 Thermo-Sublimation Printer ** (or the S3410-30 parallel interface) ** ** Copyright (C) 1992,93 by S.Petra Zeidler ** Minor modifications by Ingo Wilken: -x** - mymalloc() and check_and_rotate() functions for often used +** - mymalloc() and check_and_rotate() functions for often used ** code fragments. Reduces code size by a few KB. ** - use pm_error() instead of fprintf(stderr) ** - localized allocation of colorhastable @@ -271,12 +271,12 @@ frametransferinit(int const cols, static void -colorRow(colorhist_vector const table, - unsigned int const colanz, - hashinfo * const colorhashtable) { +doLookupTableColors(colorhist_vector const table, + unsigned int const nColor, + hashinfo * const colorhashtable) { unsigned int colval; - for (colval = 0; colval < colanz; ++colval) { + for (colval = 0; colval < nColor; ++colval) { struct hashinfo * const hashchain = &colorhashtable[myhash((table[colval]).color)]; @@ -308,12 +308,12 @@ colorRow(colorhist_vector const table, static void -grayRow(colorhist_vector const table, - unsigned int const colanz, - hashinfo * const colorhashtable) { +doLookupTableGrays(colorhist_vector const table, + unsigned int const nColor, + hashinfo * const colorhashtable) { unsigned int colval; - for (colval = 0; colval < colanz; ++colval) { + for (colval = 0; colval < nColor; ++colval) { struct hashinfo * const hashchain = &colorhashtable[myhash((table[colval]).color)]; struct hashinfo * hashrun; @@ -329,8 +329,7 @@ grayRow(colorhist_vector const table, if (hashrun->flag == -1) { hashrun->color = (table[colval]).color; hashrun->flag = colval; - } - else { + } else { while (hashrun->next != NULL) hashrun = hashrun->next; MALLOCVAR_NOFAIL(hashrun->next); @@ -345,20 +344,28 @@ grayRow(colorhist_vector const table, static void -useLookupTable(pixel ** const pixels, - colorhist_vector const table, - int const sharpness, - int const enlarge, - int const copy, - struct mediasize const medias, - unsigned int const cols, - unsigned int const rows, - int const format, - unsigned int const colanz) { - +generateLookupTable(colorhist_vector const table, + unsigned int const nColor, + unsigned int const cols, + unsigned int const rows, + int const format, + int const sharpness, + int const enlarge, + int const copy, + struct mediasize const medias, + hashinfo ** const colorhashtableP) { +/*---------------------------------------------------------------------------- + Write to the output file the palette (color lookup table) indicated by + 'table' and generate a hash table to use with it: *colorhashtableP. + + Also write the various properties 'sharpness', 'enlarge', 'copy', and + 'medias' to the output file. +-----------------------------------------------------------------------------*/ hashinfo * colorhashtable; - pm_message("found %u colors - using the lookuptable-method", colanz); + lookuptableinit(sharpness, enlarge, copy, medias); + + /* Initialize the hash table to empty */ MALLOCARRAY_NOFAIL(colorhashtable, HASHSIZE); { @@ -369,34 +376,75 @@ useLookupTable(pixel ** const pixels, } } - lookuptableinit(sharpness, enlarge, copy, medias); switch(PPM_FORMAT_TYPE(format)) { case PPM_TYPE: - colorRow(table, colanz, colorhashtable); + doLookupTableColors(table, nColor, colorhashtable); break; default: - grayRow(table, colanz, colorhashtable); + doLookupTableGrays(table, nColor, colorhashtable); } lookuptabledata(cols, rows, enlarge, medias); - { - unsigned int row; - for (row = 0; row < rows; ++row) { - unsigned int col; - for (col = 0; col < cols; ++col) { - pixel * const pixrow = pixels[row]; - struct hashinfo * const hashchain = - &colorhashtable[myhash(pixrow[col])]; - struct hashinfo * p; + + *colorhashtableP = colorhashtable; +} + + + +static void +writeColormapRaster(pixel ** const pixels, + unsigned int const cols, + unsigned int const rows, + hashinfo * const colorhashtable) { +/*---------------------------------------------------------------------------- + Write a colormapped raster: write the pixels pixels[][] (dimensions cols x + rows) as indices into the colormap (palette; lookup table) indicated by + 'colorhashtable'. +-----------------------------------------------------------------------------*/ + unsigned int row; + + for (row = 0; row < rows; ++row) { + unsigned int col; + + for (col = 0; col < cols; ++col) { + pixel * const pixrow = pixels[row]; + struct hashinfo * const hashchain = + &colorhashtable[myhash(pixrow[col])]; + struct hashinfo * p; - p = hashchain; - while (!PPM_EQUAL((p->color), pixrow[col])) { - assert(p->next); - p = p->next; - } - datum(p->flag); + p = hashchain; + while (!PPM_EQUAL((p->color), pixrow[col])) { + assert(p->next); + p = p->next; } + datum(p->flag); } } +} + + + +static void +useLookupTable(pixel ** const pixels, + colorhist_vector const table, + int const sharpness, + int const enlarge, + int const copy, + struct mediasize const medias, + unsigned int const cols, + unsigned int const rows, + int const format, + unsigned int const nColor) { + + hashinfo * colorhashtable; + + pm_message("found %u colors - using the lookuptable-method", nColor); + + generateLookupTable(table, nColor, cols, rows, format, + sharpness, enlarge, copy, medias, + &colorhashtable); + + writeColormapRaster(pixels, cols, rows, colorhashtable); + free(colorhashtable); } @@ -540,7 +588,7 @@ doTiny(FILE * const ifP, data(blurow, cols); data(blurow, cols); data(blurow, cols); - } + } } } } @@ -649,21 +697,21 @@ main(int argc, char * argv[]) { } else { pixel ** pixels; - int colanz; + int nColor; colorhist_vector table; unsigned int row; pixels = ppm_allocarray(cols, rows); - for (row = 0; row < rows; row++) + for (row = 0; row < rows; ++row) ppm_readppmrow(ifP, pixels[row], cols, maxval, format); /* first check wether we can use the lut transfer */ table = ppm_computecolorhist(pixels, cols, rows, MAXLUTCOL+1, - &colanz); + &nColor); if (table) useLookupTable(pixels, table, sharpness, enlarge, copy, medias, - cols, rows, format, colanz); + cols, rows, format, nColor); else useNoLookupTable(pixels, sharpness, enlarge, copy, medias, cols, rows, format); @@ -673,4 +721,3 @@ main(int argc, char * argv[]) { pm_close(ifP); return 0; } - diff --git a/converter/ppm/ppmtomitsu.test b/converter/ppm/ppmtomitsu.test index 1805838a..f574d927 100644 --- a/converter/ppm/ppmtomitsu.test +++ b/converter/ppm/ppmtomitsu.test @@ -2,9 +2,9 @@ echo Test 1. Should print 3110813682 101562 ./ppmtomitsu ../../testimg.ppm | cksum echo Test 2. Should print 239186803 34399 pnmquant 100 ../../testimg.ppm | ./ppmtomitsu | cksum -echo Test 3. Should print 816221676 310 +echo Test 3. Should print 3201293405 310 ./ppmtomitsu ../../testgrid.pbm | cksum -echo Test 4. Should print 629834989 752 +echo Test 4. Should print 3354679572 752 ./ppmtomitsu -tiny ../../testgrid.pbm | cksum echo Test 5. Should print 3999654426 101549 ./ppmtomitsu -tiny ../../testimg.ppm | cksum diff --git a/converter/ppm/ppmtopict.c b/converter/ppm/ppmtopict.c index 22456857..1b9f2d5c 100644 --- a/converter/ppm/ppmtopict.c +++ b/converter/ppm/ppmtopict.c @@ -398,7 +398,7 @@ char *packed; *p++ = counttochar(count); packcols = p - packed; /* how many did we write? */ - if (cols > 250) + if (cols > 200) { putShort(fd, packcols); oc = packcols + 2; @@ -436,7 +436,7 @@ char *packed; bzero(aux, cols); /* aux?? */ #endif /*notdef*/ bc = cols + (cols + MAX_COUNT - 1) / MAX_COUNT; - if (bc > 250) + if (bc > 200) { putShort(fd, bc); oc = bc + 2; |