/* ppmtopj.c - convert a portable pixmap to an HP PainJetXL image ** ** Copyright (C) 1990 by Christos Zoulas (christos@ee.cornell.edu) ** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, provided ** that the above copyright notice appear in all copies and that both that ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. */ #include #include "nstring.h" #include "ppm.h" static int compress_row ARGS((unsigned char *op, unsigned char *oe, unsigned char *cp)); /* * XXX: Only 8.5 x 11 paper */ #define WIDTH 8.5 #define HEIGHT 11.0 #define DPI 180 #define XPIX ((int) ((DPI * WIDTH + 7) / 8) << 3) #define YPIX ((int) ((DPI * HEIGHT + 7) / 8) << 3) #define C_RESET "\033E" #define C_RENDER "\033*t%dJ" # define C_RENDER_NONE 0 # define C_RENDER_SNAP 1 # define C_RENDER_BW 2 # define C_RENDER_DITHER 3 # define C_RENDER_DIFFUSE 4 # define C_RENDER_MONODITHER 5 # define C_RENDER_MONODIFFUSE 6 # define C_RENDER_MONO_CL_DITHER 5 # define C_RENDER_MONO_CL_DIFFUSE 6 #define C_BACK_SCALE "\033*t%dK" # define C_BACK_SCALE_LIGHT 0 # define C_BACK_SCALE_DARK 1 #define C_GAMMA "\033*t%dI" #define C_IMAGE_WIDTH "\033*r%dS" #define C_IMAGE_HEIGHT "\033*r%dT" #define C_DATA_PLANES "\033*r%dU" #define C_TRANS_MODE "\033*b%dM" # define C_TRANS_MODE_STD 0 # define C_TRANS_MODE_RLE 1 # define C_TRANS_MODE_TIFF 2 #define C_SEND_PLANE "\033*b%dV" #define C_LAST_PLANE "\033*b%dW" #define C_BEGIN_RASTER "\033*r%dA" # define C_BEGIN_RASTER_MARGIN 0 # define C_BEGIN_RASTER_ACTIVE 1 # define C_BEGIN_RASTER_NOSCALE 0 # define C_BEGIN_RASTER_SCALE 2 #define C_END_RASTER "\033*r%dC" # define C_END_RASTER_UNUSED 0 #define C_RESOLUTION "\033*t%dR" # define C_RESOLUTION_90DPI 90 # define C_RESOLUTION_180DPI 180 #define C_MOVE_X "\033*p+%dX" #define C_MOVE_Y "\033*p+%dY" static const char * const rmode[] = { "none", "snap", "bw", "dither", "diffuse", "monodither", "monodiffuse", "clusterdither", "monoclusterdither", NULL }; /* * Run-length encoding for the PaintJet. We have pairs of * , where instances goes from 0 (meaning one instance) to 255 * If we are unlucky we can double the size of the image. */ static int compress_row(op, oe, cp) unsigned char *op, *oe, *cp; { unsigned char *ce = cp; while ( op < oe ) { unsigned char px = *op++; unsigned char *pr = op; while ( op < oe && *op == px && op - pr < 255) op++; *ce++ = op - pr; *ce++ = px; } return ce - cp; } int main(argc, argv) int argc; char *argv[]; { pixel **pixels; FILE *ifp; int argn, rows, cols, r, c, k, p; pixval maxval; unsigned char *obuf, *op, *cbuf; int render_mode = C_RENDER_NONE; int back_scale = C_BACK_SCALE_DARK; int gamma = 0; int mode = C_TRANS_MODE_STD; int center = 0; int xoff = 0, yoff = 0; /* * XXX: Someday we could make this command line options. */ int posscale = C_BEGIN_RASTER_MARGIN | C_BEGIN_RASTER_NOSCALE; int resolution = C_RESOLUTION_180DPI; const char * const usage = "[-center] [-xpos ] [-ypos ] [-gamma ] [-back ] [-rle] [-render ] [ppmfile]"; ppm_init( &argc, argv ); argn = 1; while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) { if ( pm_keymatch(argv[argn],"-render",2) && argn + 1 < argc ) { ++argn; for (r = 0; rmode[r] != NULL; r++) if (streq(rmode[r], argv[argn])) break; if (rmode[r] != NULL) render_mode = r; else pm_usage(usage); } else if ( pm_keymatch(argv[argn],"-back",2) && argn + 1 < argc ) { ++argn; if (streq(argv[argn], "dark")) back_scale = C_BACK_SCALE_DARK; else if (streq(argv[argn], "lite")) back_scale = C_BACK_SCALE_LIGHT; else pm_usage(usage); } else if ( pm_keymatch(argv[argn],"-gamma",2) && argn + 1 < argc ) { ++argn; if ( sscanf( argv[argn], "%d",&gamma ) != 1 ) pm_usage( usage ); } else if ( pm_keymatch(argv[argn],"-xpos",2) && argn + 1 < argc ) { ++argn; if ( sscanf( argv[argn], "%d",&xoff ) != 1 ) pm_usage( usage ); } else if ( pm_keymatch(argv[argn],"-ypos",2) && argn + 1 < argc ) { ++argn; if ( sscanf( argv[argn], "%d",&yoff ) != 1 ) pm_usage( usage ); } else if (pm_keymatch(argv[argn],"-rle",2)) mode = C_TRANS_MODE_RLE; else if (pm_keymatch(argv[argn],"-center",2)) center = 1; else pm_usage( usage ); ++argn; } if ( argn < argc ) { ifp = pm_openr( argv[argn] ); ++argn; } else ifp = stdin; if ( argn != argc ) pm_usage( usage ); pixels = ppm_readppm( ifp, &cols, &rows, &maxval ); pm_close( ifp ); obuf = (unsigned char *) pm_allocrow(cols, sizeof(unsigned char)); cbuf = (unsigned char *) pm_allocrow(cols * 2, sizeof(unsigned char)); if (cols > XPIX || rows > YPIX) pm_message("image too large for page"); if (center) { if (xoff || yoff) pm_error("cannot specify both center and position"); xoff = (XPIX - cols) / 2; yoff = (YPIX - rows) / 2; } (void) printf(C_RESET); /* * Set the resolution before begin raster otherwise it * does not work. */ (void) printf(C_RESOLUTION, resolution); (void) printf(C_BEGIN_RASTER, posscale); if (xoff) (void) printf(C_MOVE_X, xoff); if (yoff) (void) printf(C_MOVE_Y, yoff); (void) printf(C_TRANS_MODE, mode); (void) printf(C_RENDER, render_mode); (void) printf(C_BACK_SCALE, back_scale); (void) printf(C_GAMMA, gamma); (void) printf(C_IMAGE_WIDTH, cols); (void) printf(C_IMAGE_HEIGHT, rows); (void) printf(C_DATA_PLANES, 3); for (r = 0; r < rows; r++) /* for each primary */ for (p = 0; p < 3; p++) { switch (p) { case 0: for (c = 0, op = &obuf[-1]; c < cols; c++) { if ((k = (c & 7)) == 0) *++op = 0; if (PPM_GETR(pixels[r][c]) > maxval / 2) *op |= 1 << (7 - k); } break; case 1: for (c = 0, op = &obuf[-1]; c < cols; c++) { if ((k = (c & 7)) == 0) *++op = 0; if (PPM_GETG(pixels[r][c]) > maxval / 2) *op |= 1 << (7 - k); } break; case 2: for (c = 0, op = &obuf[-1]; c < cols; c++) { if ((k = (c & 7)) == 0) *++op = 0; if (PPM_GETB(pixels[r][c]) > maxval / 2) *op |= 1 << (7 - k); } break; } ++op; if (mode == C_TRANS_MODE_RLE) { k = compress_row(obuf, op, cbuf); op = cbuf; } else { k = op - obuf; op = obuf; } (void) printf(p == 2 ? C_LAST_PLANE : C_SEND_PLANE, k); (void) fwrite(op, 1, k, stdout); } (void) printf(C_END_RASTER, C_END_RASTER_UNUSED); exit(0); }