diff options
Diffstat (limited to 'converter/ppm/ppmtopjxl.c')
-rw-r--r-- | converter/ppm/ppmtopjxl.c | 552 |
1 files changed, 366 insertions, 186 deletions
diff --git a/converter/ppm/ppmtopjxl.c b/converter/ppm/ppmtopjxl.c index 90bcef0f..daaf7d59 100644 --- a/converter/ppm/ppmtopjxl.c +++ b/converter/ppm/ppmtopjxl.c @@ -1,7 +1,7 @@ /* ppmtopcl.c - convert PPM into PCL language for HP PaintJet and * PaintJet XL color printers * AJCD 12/3/91 - * + * * usage: * ppmtopcl [-nopack] [-gamma <n>] [-presentation] [-dark] * [-diffuse] [-cluster] [-dither] @@ -18,6 +18,7 @@ #include <string.h> #include "pm_c_util.h" +#include "mallocvar.h" #include "nstring.h" #include "ppm.h" #include "runlength.h" @@ -47,7 +48,7 @@ static int yshift = 0; static int quality = 0; static double xscale = 0.0; static double yscale = 0.0; -static double gamma_val = 0.0; +static double gammaVal = 0.0; /* argument types */ #define DIM 0 @@ -58,7 +59,7 @@ static const struct options { int type; void *value; } options[] = { - {"-gamma", REAL, &gamma_val }, + {"-gamma", REAL, &gammaVal }, {"-presentation", BOOL, &quality }, {"-width", DIM, &xsize }, {"-xsize", DIM, &xsize }, @@ -86,12 +87,12 @@ putword(unsigned short const w) { static unsigned int -bitsperpixel(unsigned int v) { +bitwidth(unsigned int v) { unsigned int bpp; /* calculate # bits for value */ - + for (bpp = 0; v > 0; ) { ++bpp; v >>= 1; @@ -101,83 +102,350 @@ bitsperpixel(unsigned int v) { -static char *inrow = NULL; -static char *outrow = NULL; -/* "signed" was commented out below, but it caused warnings on an SGI +/* The following belong to the bit putter. They really should be in a + struct passed to the methods of the bit putter instead. +*/ + +static char *inrow; +static char *outrow; +/* "signed" was commented out below, but it caused warnings on an SGI compiler, which defaulted to unsigned character. 2001.03.30 BJH */ -static signed char *runcnt = NULL; +static signed char * runcnt; +static int out = 0; +static int cnt = 0; +static int num = 0; +static bool pack = false; + +static void +initbits(unsigned int const bytesPerRow) { + + MALLOCARRAY(inrow, bytesPerRow); + MALLOCARRAY(outrow, bytesPerRow * 2); + MALLOCARRAY(runcnt, bytesPerRow); + + if (!inrow || !outrow || !runcnt) + pm_error("can't allocate space for row"); +} + + + +static void +termbits() { + + free(runcnt); + free(outrow); + free(inrow); +} -static void -putbits(int const bArg, - int const nArg) { + + +static void +putbits(unsigned int const bArg, + unsigned int const nArg) { /*---------------------------------------------------------------------------- - Put 'n' bits in 'b' out, packing into bytes; n=0 flushes bits. + Add 'bArg' to byte-packing output buffer as 'n' bits. - n should never be > 8 + n should never be > 8 -----------------------------------------------------------------------------*/ - static int out = 0; - static int cnt = 0; - static int num = 0; - static bool pack = false; - int b; int n; + int xo; + int xc; b = bArg; n = nArg; - if (n) { - int xo = 0; - int xc = 0; + assert(n <= 8); + + if (cnt + n > 8) { /* overflowing current byte? */ + xc = cnt + n - 8; + xo = (b & ~(-1 << xc)) << (8-xc); + n -= xc; + b >>= xc; + } else { + xo = 0; + xc = 0; + } + + cnt += n; - assert(n <= 8); + out |= (b & ~(-1 << n)) << (8-cnt); - if (cnt + n > 8) { /* overflowing current byte? */ - xc = cnt + n - 8; - xo = (b & ~(-1 << xc)) << (8-xc); - n -= xc; - b >>= xc; - } - cnt += n; - out |= (b & ~(-1 << n)) << (8-cnt); - if (cnt >= 8) { - inrow[num++] = out; - out = xo; - cnt = xc; + if (cnt >= 8) { + inrow[num++] = out; + out = xo; + cnt = xc; + } +} + + + +static void +flushbits() { +/*---------------------------------------------------------------------------- + flush a row of buffered bits. +-----------------------------------------------------------------------------*/ + if (cnt) { + inrow[num++] = out; + out = cnt = 0; + } + for (; num > 0 && inrow[num-1] == 0; --num); + /* remove trailing zeros */ + printf("\033*b"); + if (num && !nopack) { /* TIFF 4.0 packbits encoding */ + size_t outSize; + pm_rlenc_compressbyte( + (unsigned char *)inrow, (unsigned char *)outrow, + PM_RLE_PACKBITS, num, &outSize); + if (outSize < num) { + num = outSize; + if (!pack) { + printf("2m"); + pack = true; + } + } else { + if (pack) { + printf("0m"); + pack = false; + } } - } else { /* flush row */ - if (cnt) { - inrow[num++] = out; - out = cnt = 0; + } + printf("%dW", num); + { + unsigned int i; + for (i = 0; i < num; ++i) + putchar(pack ? outrow[i] : inrow[i]); + } + num = 0; /* new row */ +} + + + +static void +computeColormap(pixel ** const pixels, + unsigned int const cols, + unsigned int const rows, + unsigned int const maxColors, + colorhist_vector * const chvP, + colorhash_table * const chtP, + unsigned int * const colorCtP) { + + colorhist_vector chv; + colorhash_table cht; + int colorCt; + + pm_message("Computing colormap..."); + + chv = ppm_computecolorhist(pixels, cols, rows, MAXCOLORS, &colorCt); + if (!chv) + pm_error("too many colors; reduce to %u or fewer with 'pnmquant'", + MAXCOLORS); + + pm_message("... Done. %u colors found.", colorCt); + + /* And make a hash table for fast lookup. */ + cht = ppm_colorhisttocolorhash(chv, colorCt); + + *chvP = chv; + *chtP = cht; + *colorCtP = colorCt; +} + + + +static unsigned int +nextPowerOf2(unsigned int const arg) { +/*---------------------------------------------------------------------------- + Works only on 0-7 +-----------------------------------------------------------------------------*/ + switch (arg) { /* round up to 1,2,4,8 */ + case 0: return 0; break; + case 1: return 1; break; + case 2: return 2; break; + case 3: case 4: return 4; break; + case 5: case 6: case 7: case 8: return 8; break; + default: + assert(false); } - for (; num > 0 && inrow[num-1] == 0; --num); - /* remove trailing zeros */ - printf("\033*b"); - if (num && !nopack) { /* TIFF 4.0 packbits encoding */ - size_t outSize; - pm_rlenc_compressbyte( - (unsigned char *)inrow, (unsigned char *)outrow, - PM_RLE_PACKBITS, num, &outSize); - if (outSize < num) { - num = outSize; - if (!pack) { - printf("2m"); - pack = true; - } - } else { - if (pack) { - printf("0m"); - pack = false; - } +} + + + +static void +computeColorDownloadingMode(unsigned int const colorCt, + unsigned int const cols, + pixval const maxval, + unsigned int * const bytesPerRowP, + bool * const colorMappedP, + unsigned int * const bitsPerPixelRedP, + unsigned int * const bitsPerPixelGrnP, + unsigned int * const bitsPerPixelBluP, + unsigned int * const bitsPerIndexP) { +/*---------------------------------------------------------------------------- +-----------------------------------------------------------------------------*/ + unsigned int const indexBitCt = bitwidth(colorCt); + + assert(colorCt > 0); + assert(indexBitCt > 0); + + if (indexBitCt > 8) { + /* Can't use indexed mode */ + /* We will instead write 1-3 full bytes per pixel, with those + bytes divided into red bits, green bits, and blue bits. We + pad the red bits as needed to fill out whole bytes. We + stick to 1, 2, 4, or 8 bits per pixel only because this program's + bit writer can't handle more than 8, which would happen with those + padded red fields if we allowed e.g. 7 bits for green and blue + (ergo 10 bits for red). + */ + unsigned int const bitsPerSample = nextPowerOf2(bitwidth(maxval)); + unsigned int const bitsPerPixel = ROUNDUP(3 * bitsPerSample, 8); + unsigned int const bytesPerPixel = bitsPerPixel / 8; + + *colorMappedP = false; + *bitsPerPixelGrnP = bitsPerSample; + *bitsPerPixelBluP = bitsPerSample; + *bitsPerPixelRedP = + bitsPerPixel - *bitsPerPixelGrnP - *bitsPerPixelBluP; + *bytesPerRowP = bytesPerPixel * cols; + } else { + unsigned int const bitsPerPixel = nextPowerOf2(indexBitCt); + + unsigned int pixelsPerByte; + + *colorMappedP = true; + + *bitsPerIndexP = bitsPerPixel; + pixelsPerByte = 8 / bitsPerPixel; + *bytesPerRowP = (cols + pixelsPerByte - 1) / pixelsPerByte; + } + if (*colorMappedP) + pm_message("Writing %u bit color indices", *bitsPerIndexP); + else + pm_message("Writing direct color, %u red bits, %u green, %u blue", + *bitsPerPixelRedP, *bitsPerPixelGrnP, *bitsPerPixelBluP); +} + + + +static void +writePclHeader(unsigned int const cols, + unsigned int const rows, + pixval const maxval, + int const xshift, + int const yshift, + unsigned int const quality, + unsigned int const xsize, + unsigned int const ysize, + double const gammaVal, + unsigned int const dark, + unsigned int const render, + bool const colorMapped, + unsigned int const bitsPerPixelRed, + unsigned int const bitsPerPixelGrn, + unsigned int const bitsPerPixelBlu, + unsigned int const bitsPerIndex) { + +#if 0 + printf("\033&l26A"); /* paper size */ +#endif + printf("\033*r%us%uT", cols, rows); /* source width, height */ + if (xshift != 0 || yshift != 0) + printf("\033&a%+dh%+dV", xshift, yshift); /* xshift, yshift */ + if (quality) + printf("\033*o%uQ", quality); /* print quality */ + printf("\033*t"); + if (xsize == 0 && ysize == 0) + printf("180r"); /* resolution */ + else { /* destination width, height */ + if (xsize != 0) + printf("%uh", xsize); + if (ysize != 0) + printf("%uv", ysize); + } + if (gammaVal != 0) + printf("%.3fi", gammaVal); /* gamma correction */ + if (dark) + printf("%uk", dark); /* scaling algorithms */ + printf("%uJ", render); /* rendering algorithm */ + printf("\033*v18W"); /* configure image data */ + putchar(0); /* relative colors */ + putchar(colorMapped ? 1 : 3); /* index/direct pixel mode */ + putchar(bitsPerIndex); /* ignored in direct pixel mode */ + putchar(colorMapped ? 0 : bitsPerPixelRed); + putchar(colorMapped ? 0 : bitsPerPixelGrn); + putchar(colorMapped ? 0 : bitsPerPixelBlu); + putword(maxval); /* max red reference */ + putword(maxval); /* max green reference */ + putword(maxval); /* max blue reference */ + putword(0); /* min red reference */ + putword(0); /* min green reference */ + putword(0); /* min blue reference */ +} + + + +static void +writePalette(colorhist_vector const chv, + unsigned int const colorCt) { + + unsigned int i; + + for (i = 0; i < colorCt; ++i) { + unsigned int const r = PPM_GETR( chv[i].color); + unsigned int const g = PPM_GETG( chv[i].color); + unsigned int const b = PPM_GETB( chv[i].color); + + if (i == 0) + printf("\033*v"); + if (r) + printf("%ua", r); + if (g) + printf("%ub", g); + if (b) + printf("%uc", b); + if (i == colorCt - 1) + printf("%uI", i); /* assign color index */ + else + printf("%ui", i); /* assign color index */ + } +} + + + +static void +writeRaster(pixel ** const pixels, + unsigned int const rows, + unsigned int const cols, + colorhash_table const cht, + bool const colorMapped, + unsigned int const bitsPerIndex, + unsigned int const bitsPerPixelRed, + unsigned int const bitsPerPixelGrn, + unsigned int const bitsPerPixelBlu) { + + unsigned int row; + + for (row = 0; row < rows; ++row) { + pixel * const pixrow = pixels[row]; + + if (colorMapped) { + unsigned int col; + + for (col = 0; col < cols; ++col) + putbits(ppm_lookupcolor(cht, &pixrow[col]), bitsPerIndex); + flushbits(); + } else { + unsigned int col; + + for (col = 0; col < cols; ++col) { + putbits(PPM_GETR(pixrow[col]), bitsPerPixelRed); + putbits(PPM_GETG(pixrow[col]), bitsPerPixelGrn); + putbits(PPM_GETB(pixrow[col]), bitsPerPixelBlu); + /* don't need to flush */ } + flushbits(); } - printf("%dW", num); - { - unsigned int i; - for (i = 0; i < num; ++i) - putchar(pack ? outrow[i] : inrow[i]); - } - num = 0; /* new row */ } } @@ -188,16 +456,17 @@ main(int argc, const char * argv[]) { FILE * ifP; pixel ** pixels; - unsigned int row; - unsigned int bpp; int rows, cols; pixval maxval; - int bpr, bpg, bpb; + bool colorMapped; + unsigned int bytesPerRow; + unsigned int bitsPerPixelRed, bitsPerPixelGrn, bitsPerPixelBlu; + unsigned int bitsPerIndex; int render; - int colors, pclindex; + unsigned int colorCt; colorhist_vector chv; colorhash_table cht; - + pm_proginit(&argc, argv); while (argc > 1 && argv[1][0] == '-') { @@ -267,42 +536,14 @@ main(int argc, const char * argv[]) { if (maxval > PCL_MAXVAL) pm_error("color range too large; reduce with ppmcscale"); - /* Figure out the colormap. */ - pm_message("Computing colormap..."); - chv = ppm_computecolorhist(pixels, cols, rows, MAXCOLORS, &colors); - if (!chv) - pm_error("too many colors; reduce with pnmquant"); - pm_message("... Done. %u colors found.", colors); + computeColormap(pixels, cols, rows, MAXCOLORS, &chv, &cht, &colorCt); - /* And make a hash table for fast lookup. */ - cht = ppm_colorhisttocolorhash(chv, colors); - - /* work out color downloading mode */ - pclindex = bitsperpixel(colors); - if (pclindex > 8) /* can't use indexed mode */ - pclindex = 0; - else { - switch (pclindex) { /* round up to 1,2,4,8 */ - case 0: /* direct mode (no palette) */ - bpp = bitsperpixel(maxval); /* bits per pixel */ - bpg = bpp; bpb = bpp; - bpp = (bpp*3+7)>>3; /* bytes per pixel now */ - bpr = (bpp<<3)-bpg-bpb; - bpp *= cols; /* bytes per row now */ - break; - case 5: pclindex++; - case 6: pclindex++; - case 3: case 7: pclindex++; - default: - bpp = 8/pclindex; - bpp = (cols+bpp-1)/bpp; /* bytes per row */ - } - } - inrow = (char *)malloc((unsigned)bpp); - outrow = (char *)malloc((unsigned)bpp*2); - runcnt = (signed char *)malloc((unsigned)bpp); - if (inrow == NULL || outrow == NULL || runcnt == NULL) - pm_error("can't allocate space for row"); + computeColorDownloadingMode( + colorCt, cols, maxval, + &bytesPerRow, &colorMapped, + &bitsPerPixelRed, &bitsPerPixelGrn, &bitsPerPixelBlu, &bitsPerIndex); + + initbits(bytesPerRow); /* set up image details */ if (xscale != 0.0) @@ -310,92 +551,31 @@ main(int argc, const char * argv[]) { if (yscale != 0.0) ysize = rows * yscale * 4; - /* write PCL header */ -#if 0 - printf("\033&l26A"); /* paper size */ -#endif - printf("\033*r%ds%dT", cols, rows); /* source width, height */ - if (xshift != 0 || yshift != 0) - printf("\033&a%+dh%+dV", xshift, yshift); /* xshift, yshift */ - if (quality) - printf("\033*o%dQ", quality); /* print quality */ - printf("\033*t"); - if (xsize == 0 && ysize == 0) - printf("180r"); /* resolution */ - else { /* destination width, height */ - if (xsize != 0) - printf("%dh", xsize); - if (ysize != 0) - printf("%dv", ysize); - } - if (gamma_val != 0) - printf("%.3fi", gamma_val); /* gamma correction */ - if (dark) - printf("%dk", dark); /* scaling algorithms */ - printf("%dJ", render); /* rendering algorithm */ - printf("\033*v18W"); /* configure image data */ - putchar(0); /* relative colors */ - putchar(pclindex ? 1 : 3); /* index/direct pixel mode */ - putchar(pclindex); /* ignored in direct pixel mode */ - if (pclindex) { - putchar(0); - putchar(0); - putchar(0); - } else { - putchar(bpr); /* bits per red */ - putchar(bpg); /* bits per green */ - putchar(bpb); /* bits per blue */ - } - putword(maxval); /* max red reference */ - putword(maxval); /* max green reference */ - putword(maxval); /* max blue reference */ - putword(0); /* min red reference */ - putword(0); /* min green reference */ - putword(0); /* min blue reference */ - if (pclindex) { /* set palette */ - unsigned int i; - for (i = 0; i < colors; ++i) { - int const r = PPM_GETR( chv[i].color); - int const g = PPM_GETG( chv[i].color); - int const b = PPM_GETB( chv[i].color); - if (i == 0) - printf("\033*v"); - if (r) - printf("%da", r); - if (g) - printf("%db", g); - if (b) - printf("%dc", b); - if (i == colors-1) - printf("%dI", i); /* assign color index */ - else - printf("%di", i); /* assign color index */ - } - } - ppm_freecolorhist(chv); + writePclHeader(cols, rows, maxval, xshift, yshift, quality, xsize, ysize, + gammaVal, dark, render, + colorMapped, + bitsPerPixelRed, bitsPerPixelGrn, bitsPerPixelBlu, + bitsPerIndex); + + if (colorMapped) + writePalette(chv, colorCt); /* start raster graphics at CAP */ printf("\033*r%dA", (xsize != 0 || ysize != 0) ? 3 : 1); - for (row = 0; row < rows; row++) { - pixel * const pixrow = pixels[row]; - if (pclindex) { /* indexed color mode */ - unsigned int col; - for (col = 0; col < cols; ++col) - putbits(ppm_lookupcolor(cht, &pixrow[col]), pclindex); - putbits(0, 0); /* flush row */ - } else { /* direct color mode */ - unsigned int col; - for (col = 0; col < cols; ++col) { - putbits(PPM_GETR(pixrow[col]), bpr); - putbits(PPM_GETG(pixrow[col]), bpg); - putbits(PPM_GETB(pixrow[col]), bpb); - /* don't need to flush */ - } - putbits(0, 0); /* flush row */ - } - } + writeRaster(pixels, rows, cols, cht, colorMapped, + bitsPerIndex, + bitsPerPixelRed, bitsPerPixelGrn, bitsPerPixelBlu); + printf("\033*rC"); /* end raster graphics */ + ppm_freecolorhash(cht); + ppm_freecolorhist(chv); + + termbits(); + return 0; } + + + |