/* ppmtolj.c - convert a portable pixmap to an HP PCL 5 color image
**
** Copyright (C) 2000 by Jonathan Melvin (jonathan.melvin@heywood.co.uk)
**
** 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 "ppm.h"
static int compress_row_delta (unsigned char *op, unsigned char *prev_op,
unsigned char *cp, int bufsize);
#define C_RESET "\033E"
#define C_PRESENTATION "\033*r%dF"
#define C_PRESENTATION_LOGICAL 0
#define C_PRESENTATION_PHYSICAL 3
#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 /*compression modes*/
#define C_TRANS_MODE_RLE 1 /*no good for rgb*/
#define C_TRANS_MODE_TIFF 2 /*no good for rgb*/
#define C_TRANS_MODE_DELTA 3 /*only on to use for rgb values*/
#define C_CONFIG_IMAGE_DATA "\033*v6W"
#define C_SEND_ROW "\033*b%dW"
#define C_BEGIN_RASTER "\033*r%dA"
#define C_BEGIN_RASTER_CUR 1
#define C_END_RASTER "\033*r%dC"
#define C_END_RASTER_UNUSED 0
#define C_RESOLUTION "\033*t%dR"
#define C_RESOLUTION_300DPI 300
#define C_MOVE_X "\033*p+%dX"
#define C_MOVE_Y "\033*p+%dY"
#define C_LEFT_MARGIN "\033*r%dA"
#define C_Y_OFFSET "\033*b%dY"
/*
* delta encoding.
*/
/*
op row buffer
prev_op previous row buffer
bufsize length of row
cp buffer for compressed data
*/
static int
compress_row_delta(op, prev_op, cp, bufsize)
unsigned char *op, *prev_op, *cp;
int bufsize;
{
int burstStart, burstEnd, burstCode, mustBurst, ptr, skip, skipped, code;
int deltaBufferIndex = 0;
if (memcmp(op, prev_op , bufsize/*rowBufferIndex*/) == 0)
return 0; /* exact match, no deltas required */
ptr = 0;
skipped = 0;
burstStart = -1;
burstEnd = -1;
mustBurst = 0;
while (ptr < bufsize/*rowBufferIndex*/)
{
skip = 0;
if (ptr == 0 || skipped == 30 || op[ptr] != prev_op[ptr] ||
(burstStart != -1 && ptr == bufsize - 1))
{
/* we want to output this byte... */
if (burstStart == -1)
{
burstStart = ptr;
}
if (ptr - burstStart == 7 || ptr == bufsize - 1)
{
/* we have to output it now... */
burstEnd = ptr;
mustBurst = 1;
}
}
else
{
/* duplicate byte, we can skip it */
if (burstStart != -1)
{
burstEnd = ptr - 1;
mustBurst = 1;
}
skip = 1;
}
if (mustBurst)
{
burstCode = burstEnd - burstStart; /* 0-7 means 1-8 bytes follow */
code = (burstCode << 5) | skipped;
cp[deltaBufferIndex++] = (char) code;
memcpy(cp+deltaBufferIndex, op+burstStart, burstCode + 1);
deltaBufferIndex += burstCode + 1;
burstStart = -1;
burstEnd = -1;
mustBurst = 0;
skipped = 0;
}
if (skip)
{
skipped ++;
}
ptr ++;
}
return deltaBufferIndex;
}
int main(int argc, char *argv[]) {
pixel * pixelrow;
FILE *ifp;
int argn, rows, cols, r, c, k;
pixval maxval;
unsigned char *obuf, *op, *cbuf, *previous_obuf;
int format;
int gamma = 0;
int mode = C_TRANS_MODE_STD;
int currentmode = 0;
int floating = 0; /* suppress the ``ESC & l 0 E'' ? */
int resets = 3; /* bit mask for when to emit printer reset seq */
int resolution = C_RESOLUTION_300DPI;
char CID[6] = { 0, 3, 0, 8, 8, 8 };
/*data for the configure image data command*/
const char * const usage = "[-noreset][-float][-delta][-gamma <val>] [-resolution N] "
"[ppmfile]\n\tresolution = [75|100|150|300|600] (dpi)";
ppm_init( &argc, argv );
argn = 1;
while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
{
if( pm_keymatch( argv[argn], "-resolution", 2 ) && argn + 1 < argc )
{
++argn;
if ( argn == argc || sscanf( argv[argn], "%d", &resolution ) != 1 )
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],"-delta",2))
mode = C_TRANS_MODE_DELTA;
else if (pm_keymatch(argv[argn],"-float",2))
floating = 1;
else if (pm_keymatch(argv[argn],"-noreset",2))
resets = 0;
else
pm_usage( usage );
++argn;
}
if ( argn < argc )
{
ifp = pm_openr( argv[argn] );
++argn;
}
else
ifp = stdin;
if ( argn != argc )
pm_usage( usage );
ppm_readppminit( ifp, &cols, &rows, &maxval, &format );
pixelrow = ppm_allocrow( cols );
overflow2(cols, 6);
obuf = (unsigned char *) pm_allocrow(cols * 3, sizeof(unsigned char));
cbuf = (unsigned char *) pm_allocrow(cols * 6, sizeof(unsigned char));
if (mode == C_TRANS_MODE_DELTA)
{
previous_obuf =
(unsigned char *) pm_allocrow(cols * 3, sizeof(unsigned char));
memset(previous_obuf, 0, cols * 3);
}
if(resets & 1)
{
/* Printer reset. */
printf(C_RESET);
}
if(!floating)
{
/* Ensure top margin is zero */
printf("\033&l0E");
}
/*Set Presentation mode*/
(void) printf(C_PRESENTATION, C_PRESENTATION_PHYSICAL);
/* Set the resolution */
(void) printf(C_RESOLUTION, resolution);
/* Set raster height*/
(void) printf(C_IMAGE_HEIGHT, rows);
/* Set raster width*/
(void) printf(C_IMAGE_WIDTH, cols);
/* set left margin to current x pos*/
/*(void) printf(C_LEFT_MARGIN, 1);*/
/* set the correct color mode */
(void) printf(C_CONFIG_IMAGE_DATA);
(void) fwrite(CID, 1, 6, stdout);
/* Start raster graphics */
(void) printf(C_BEGIN_RASTER, C_BEGIN_RASTER_CUR); /*posscale);*/
/* set Y offset to 0 */
(void) printf(C_Y_OFFSET, 0);
/*
if (xoff)
(void) printf(C_MOVE_X, xoff);
if (yoff)
(void) printf(C_MOVE_Y, yoff);
*/
/* Set raster compression */
(void) printf(C_TRANS_MODE, mode);
currentmode = mode;
if(gamma)
(void) printf(C_GAMMA, gamma);
for (r = 0; r < rows; r++)
{
ppm_readppmrow(ifp, pixelrow, cols, maxval, format);
/* get a row of data with 3 bytes per pixel */
for (c = 0, op = &obuf[-1]; c < cols; c++)
{
++op;
*op = (PPM_GETR(pixelrow[c])*255)/maxval;
++op;
*op = (PPM_GETG(pixelrow[c])*255)/maxval;
++op;
*op = (PPM_GETB(pixelrow[c])*255)/maxval;
}
++op;
k = op - obuf; /*size of row*/
/*compress the row if required*/
if(mode == C_TRANS_MODE_STD)
{/*no compression*/
op = obuf;
}
if(mode == C_TRANS_MODE_DELTA)
{/*delta compression*/
int newmode = 0;
int deltasize =
compress_row_delta(obuf, previous_obuf, cbuf, cols*3);
if(deltasize >= k)/*normal is best?*/
{
op = obuf;
}
else /*delta is best*/
{
k = deltasize;
op = cbuf;
newmode = C_TRANS_MODE_DELTA;
}
memcpy(previous_obuf, obuf, cols*3);
if(currentmode != newmode)
{
(void) printf(C_TRANS_MODE, newmode);
currentmode = newmode;
}
}
(void) printf(C_SEND_ROW, k);
(void) fwrite(op, 1, k, stdout);
}
(void) printf(C_END_RASTER, C_END_RASTER_UNUSED);
if(resets & 2)
{
/* Printer reset. */
printf(C_RESET);
}
pm_close( ifp );
ppm_freerow(pixelrow);
return 0;
}