/* 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 <string.h>
#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 <instances>
* <value>, 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 <pos>] [-ypos <pos>] [-gamma <val>] [-back <dark|lite>] [-rle] [-render <none|snap|bw|dither|diffuse|monodither|monodiffuse|clusterdither|monoclusterdither>] [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 );
overflow2(cols,2);
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);
}