[alt.graphics.pixutils] ppmtopcl 01/01

ajcd@cs.ed.ac.uk (Angus Duggan) (05/09/91)

In article <475@fe2o3.laurel.md.us>, rusty@fe2o3.laurel.md.us (Rusty Haddock) writes:
> In article <15963@helios.TAMU.EDU> jdm5548@tamsun.tamu.edu (James Darrell McCauley) writes:
>    |I received some source once that would speak PaintJet via Sun Raster.
>    |...
>    |It does work very well though.  Particularly, if the image is 720 pixels
>    |...
>    |ppmtopj, anyone?
> 
> ppmtopj, yes!  After this semester is over, which isn't too far off
> now, I want to start on it.  Hopefully it won't take much more than
> a weekend.  If you will, bounce that code my way so I can get some
> more insight into programming the PJ.  I'm interested in how the
> 16-color limit is handled.  Thanks! 

Of course, if you have a PaintJet XL, you could use its internal imaging
capabilities with the following program.

> 
> 		-Rusty-

Followups directed to alt.graphics.pixutils.

a.
-- 
Angus Duggan, Department of Computer Science,	| I'm pink, therefore I'm Spam.
University of Edinburgh, JCMB,			| JANET:  ajcd@uk.ac.ed.lfcs
The King's Buildings, Mayfield Road,		| VOICE:  (UK) 031 650 5126
Edinburgh, EH9 3JZ, Scotland.	| OR:  ajcd%lfcs.ed.ac.uk@nsfnet-relay.ac.uk

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 1)."
# Contents:  ppmtopcl.1 ppmtopcl.c
# Wrapped by ajcd@davaar on Thu May  9 10:48:39 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f ppmtopcl.1 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"ppmtopcl.1\"
else
echo shar: Extracting \"ppmtopcl.1\" \(2191 characters\)
sed "s/^X//" >ppmtopcl.1 <<'END_OF_ppmtopcl.1'
X.TH PPMTOPCL 1 "14 March 1991"
X.SH NAME
Xppmtopcl - convert a portable pixmap into an HP PaintJet XL PCL file
X.SH SYNOPSIS
Xppmtopcl [-nopack] [-gamma
X.I <n>
X] [-presentation] [-dark] [-diffuse] [-cluster] [-dither] [-xshift
X.I <s>
X] [-yshift
X.I <s>
X] [-xshift
X.I <s>
X] [-yshift
X.I <s>
X] [-xsize|-width|-xscale
X.I <s>
X] [-ysize|-height|-yscale
X.I <s>
X] [ppmfile]
X
X.SH DESCRIPTION
XReads a portable pixmap as input.
XProduces a PCL file suitable for printing on an HP PaintJet XL printer as
Xoutput.
X.PP
XThe generated file is not suitable for printing on a normal PrintJet printer.
XThe
X.B \-nopack
Xoption generates a file which does not use the normal TIFF 4.0 compression
Xmethod. This file might be printable on a normal PaintJet printer (not an XL).
X.PP
XThe
X.B \-gamma
Xoption sets the gamma correction for the image. The useful range for the
XPaintJet XL is approximately 0.6 to 1.5.
X.PP
XThe rendering algorithm used for images can be altered with the
X.B -dither,
X.B -cluster,
Xand
X.B -diffuse
Xoptions. These options select ordered dithering, clustered ordered dithering,
Xor error diffusion respectively.
XThe
X.B \-dark
Xoption can be used to enhance images with a dark background when they are
Xreduced in size.
XThe
X.B \-presentation
Xoption turns on presentation mode, in which two passes are made over the paper
Xto increase ink density. This should be used only for images where quality is
Xcritical.
X
X.PP
XThe image can be resized by setting the 
X.B \-xsize
Xand 
X.B \-ysize
Xoptions. The parameter to either of these options is interpreted as the
Xnumber of dots to set the width or height to, but an optional dimension of
X`\fBpt\fR' (points), `\fBdp\fR' (decipoints), `\fBin\fR' (inches), or
X`\fBcm\fR' (centimetres) may be appended.
XIf only one dimension is specified, the other will be scaled appropriately.
X
XThe options
X.B \-width
Xand
X.B \-height
Xare synonyms of
X.B \-xsize
Xand
X.B \-ysize.
X
XThe
X.B \-xscale
Xand
X.B \-yscale
Xoptions can alternatively be used to scale the image by a simple factor.
X
X.PP
XThe image can be shifted on the page by using the
X.B \-xshift
Xand
X.B \-yshift
Xoptions. These move the image the specified dimensions right and down.
X
X.SH "SEE ALSO"
Xppm(5)
X.SH AUTHOR
XAngus Duggan
END_OF_ppmtopcl.1
if test 2191 -ne `wc -c <ppmtopcl.1`; then
    echo shar: \"ppmtopcl.1\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ppmtopcl.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"ppmtopcl.c\"
else
echo shar: Extracting \"ppmtopcl.c\" \(12077 characters\)
sed "s/^X//" >ppmtopcl.c <<'END_OF_ppmtopcl.c'
X/* ppmtopcl.c - convert portable pixmap into PCL language for HP PaintJet and
X *              PaintJet XL colour printers
X * AJCD 12/3/91
X * 
X * usage:
X *       ppmtopcl [-nopack] [-gamma <n>] [-presentation] [-dark]
X *          [-diffuse] [-cluster] [-dither]
X *          [-xshift <s>] [-yshift <s>]
X *          [-xshift <s>] [-yshift <s>]
X *          [-xsize|-width|-xscale <s>] [-ysize|-height|-yscale <s>]
X *          [ppmfile]
X *
X */
X
X#include <stdio.h>
X#include <ppm.h>
X#include <ppmcmap.h>
X
X#define MAXCOLORS 1024
X
Xextern double atof();
Xextern int atoi();
X
Xchar *usage="[-nopack] [-gamma <n>] [-presentation] [-dark]\n\
X            [-diffuse] [-cluster] [-dither]\n\
X            [-xshift <s>] [-yshift <s>]\n\
X            [-xshift <s>] [-yshift <s>]\n\
X            [-xsize|-width|-xscale <s>] [-ysize|-height|-yscale <s>]\n\
X            [ppmfile]";
X
X#define PCL_MAXWIDTH 2048
X#define PCL_MAXHEIGHT 32767
X#define PCL_MAXVAL 255
X
Xstatic int nopack = 0;
Xstatic int dark = 0;
Xstatic int diffuse = 0;
Xstatic int dither = 0;
Xstatic int cluster = 0;
Xstatic int xsize = 0;
Xstatic int ysize = 0;
Xstatic int xshift = 0;
Xstatic int yshift = 0;
Xstatic int quality = 0;
Xstatic double xscale = 0.0;
Xstatic double yscale = 0.0;
Xstatic double gamma = 0.0;
X
X/* argument types */
X#define DIM 0
X#define REAL 1
X#define BOOL 2
Xstatic struct options {
X   char *name;
X   int type;
X   char *value;
X} options[] = {
X   {"gamma",        REAL, (char *)&gamma },
X   {"presentation", BOOL, (char *)&quality },
X   {"width",        DIM,  (char *)&xsize },
X   {"xsize",        DIM,  (char *)&xsize },
X   {"height",       DIM,  (char *)&ysize },
X   {"ysize",        DIM,  (char *)&ysize },
X   {"xscale",       REAL, (char *)&xscale },
X   {"yscale",       REAL, (char *)&yscale },
X   {"xshift",       DIM,  (char *)&xshift },
X   {"yshift",       DIM,  (char *)&yshift },
X   {"dark",         BOOL, (char *)&dark },
X   {"diffuse",      BOOL, (char *)&diffuse },
X   {"dither",       BOOL, (char *)&dither },
X   {"cluster",      BOOL, (char *)&cluster },
X   {"nopack",       BOOL, (char *)&nopack },
X};
X
X#define putword(w) (putchar(((w)>>8) & 255), putchar((w) & 255))
X
Xint bitsperpixel(v)
X     int v;
X{
X   int bpp = 0;
X   while (v > 0) {  /* calculate # bits for value */
X      ++bpp;
X      v>>=1;
X   }
X   return (bpp);
X}
X
Xstatic char *inrow = NULL;
Xstatic char *outrow = NULL;
Xstatic /*signed*/ char *runcnt = NULL;
X
Xputbits(b, n) /* put #n bits in b out, packing into bytes; n=0 flushes bits */
X     int b, n; /* n should never be > 8 */
X{
X   static int out = 0;
X   static int cnt = 0;
X   static int num = 0;
X   static int pack = 0;
X   if (n) {
X      int xo = 0;
X      int xc = 0;
X      if (cnt+n > 8) {  /* overflowing current byte? */
X	 xc = cnt + n - 8;
X	 xo = (b & ~(-1 << xc)) << (8-xc);
X	 n -= xc;
X	 b >>= xc;
X      }
X      cnt += n;
X      out |= (b & ~(-1 << n)) << (8-cnt);
X      if (cnt >= 8) {
X	 inrow[num++] = out;
X	 out = xo;
X	 cnt = xc;
X      }
X   } else { /* flush row */
X      int i;
X      if (cnt) {
X	 inrow[num++] = out;
X	 out = cnt = 0;
X      }
X      for (; num > 0 && inrow[num-1] == 0; num--); /* remove trailing zeros */
X      printf("\033*b"); 
X      if (num && !nopack) {            /* TIFF 4.0 packbits encoding */
X	 int start = 0;
X	 int next;
X	 runcnt[start] = 0;
X	 for (i = 1; i < num; i++) {
X	    if (inrow[i] == inrow[i-1]) {
X	       if (runcnt[start] <= 0 && runcnt[start] > -127)
X		  runcnt[start]--;
X	       else
X		  runcnt[start = i] = 0;
X	    } else {
X	       if (runcnt[start] >= 0 && runcnt[start] < 127)
X		  runcnt[start]++;
X	       else
X		  runcnt[start = i] = 0;
X	    }
X	 }
X	 start = 0;
X	 for (i = 0; i < num; i = next) {
X	    int count = runcnt[i];
X	    int from = i;
X	    if (count >= 0) { /* merge two-byte runs */
X	       for (;;) {
X		  next = i+1+runcnt[i];
X		  if(next >= num || runcnt[next] < 0 ||
X		     count+runcnt[next]+1 > 127)
X		     break;
X		  count += runcnt[next]+1;
X		  i = next;
X	       }
X	    }
X	    next =  i + 1 + ((runcnt[i] < 0) ? -runcnt[i] : runcnt[i]);
X	    if (next < num && count > 0 &&
X		runcnt[next] < 0 && runcnt[next] > -127) {
X	       count--;
X	       next--;
X	       runcnt[next] = runcnt[next+1]-1;
X	    }
X	    outrow[start++] = count;
X	    if (count >= 0) {
X	       while (count-- >= 0)
X		  outrow[start++] = inrow[from++];
X	    } else
X	       outrow[start++] = inrow[from];
X	 }
X	 if (start < num) {
X	    num = start;
X	    if (!pack) {
X	       printf("2m");
X	       pack = 1;
X	    }
X	 } else {
X	    if (pack) {
X	       printf("0m");
X	       pack = 0;
X	    }
X	 }
X      }
X      printf("%dW", num);
X      for (i = 0; i < num; i++)
X	 putchar(pack ? outrow[i] : inrow[i]);
X      num = 0; /* new row */
X   }
X}
X
Xmain(argc, argv)
X     int argc;
X     char *argv[];
X{
X   FILE *ifd;
X   register pixel **pixels, *pixrow;
X   register int  row, col, bpp, i;
X   int rows, cols;
X   pixval maxval;
X   int bpr, bpg, bpb;
X   int render;
X   int colours, index;
X   colorhist_vector chv;
X   colorhash_table cht;
X   
X   pm_progname = argv[0];
X   
X   while (argc > 1 && argv[1][0] == '-') {
X      char *c, *val=argv[1]+1;
X      for (i = 0; i < sizeof(options)/sizeof(struct options); i++) {
X	 if (strlen(val) <= strlen(options[i].name) &&
X	     !strncmp(val, options[i].name, strlen(val))) {
X	    switch (options[i].type) {
X	    case DIM:
X	       if (++argv, --argc == 1)
X		  pm_usage(usage);
X	       for (c = argv[1]; isdigit(*c); c++);
X	       if (c[0] == 'p' && c[1] == 't') /* points */
X		  *(int *)(options[i].value) = atoi(argv[1])*10;
X	       else if (c[0] == 'd' && c[1] == 'p') /* decipoints */
X		  *(int *)(options[i].value) = atoi(argv[1]);
X	       else if (c[0] == 'i' && c[1] == 'n') /* inches */
X		  *(int *)(options[i].value) = atoi(argv[1])*720;
X	       else if (c[0] == 'c' && c[1] == 'm') /* centimetres */
X		  *(int *)(options[i].value) = atoi(argv[1])*283.46457;
X	       else if (!c[0]) /* dots */
X		  *(int *)(options[i].value) = atoi(argv[1])*4;
X	       else
X		  pm_error("illegal unit of measure %s", c);
X	       break;
X	    case REAL:
X	       if (++argv, --argc == 1)
X		  pm_usage(usage);
X	       *(double *)(options[i].value) = atof(argv[1]);
X	       break;
X	    case BOOL:
X	       *(int *)(options[i].value) = 1;
X	       break;
X	    }
X	    break;
X	 }
X      }
X      if (i >= sizeof(options)/sizeof(struct options))
X	 pm_usage(usage);
X      argv++; argc--;
X   }
X   if (argc > 2)
X      pm_usage(usage);
X   else if (argc == 2)
X      ifd = pm_openr(argv[1]);
X   else
X      ifd = stdin ;
X
X   /* validate arguments */
X   if (diffuse+cluster+dither > 1)
X      pm_error("only one of -diffuse, -dither and -cluster may be used");
X   render = diffuse ? 4 : dither ? 3 : cluster ? 7 : 0;
X
X   if (xsize != 0.0 && xscale != 0.0)
X      pm_error("only one of -xsize and -xscale may be used");
X
X   if (ysize != 0.0 && yscale != 0.0)
X      pm_error("only one of -ysize and -yscale may be used");
X
X   pixels = ppm_readppm( ifd, &cols, &rows, &maxval );
X   pm_close( ifd );
X
X   /* limit checks */
X   if (cols > PCL_MAXWIDTH || rows > PCL_MAXHEIGHT)
X      pm_error("image too large; reduce with ppmscale");
X   if (maxval > PCL_MAXVAL)
X      pm_error("colour range too large; reduce with ppmcscale");
X
X   /* Figure out the colormap. */
X   fprintf( stderr, "(Computing colormap..." ); fflush( stderr );
X   chv = ppm_computecolorhist( pixels, cols, rows, MAXCOLORS, &colours );
X   if ( chv == (colorhist_vector) 0 )
X      pm_error("too many colours; reduce with ppmquant", 0,0,0,0,0 );
X   fprintf( stderr, "  Done.  %d colors found.)\n", colours );
X
X   /* And make a hash table for fast lookup. */
X   cht = ppm_colorhisttocolorhash( chv, colours );
X
X   /* work out colour downloading mode */
X   index = bitsperpixel(colours);
X   if (index > 8) /* can't use indexed mode */
X      index = 0;
X   else
X      switch (index) { /* round up to 1,2,4,8 */
X      case 0: /* direct mode (no palette) */
X	 bpp = bitsperpixel(maxval); /* bits per pixel */
X	 bpg = bpp; bpb = bpp;
X	 bpp = (bpp*3+7)>>3;     /* bytes per pixel now */
X	 bpr = (bpp<<3)-bpg-bpb; 
X	 bpp *= cols;            /* bytes per row now */
X	 break;
X      case 5:         index++;
X      case 6:         index++;
X      case 3: case 7: index++;
X      default:
X	 bpp = 8/index;
X	 bpp = (cols+bpp-1)/bpp;      /* bytes per row */
X      }
X
X   if ((inrow = (char *)malloc((unsigned)bpp)) == NULL ||
X       (outrow = (char *)malloc((unsigned)bpp*2)) == NULL ||
X       (runcnt = (/*signed*/ char *)malloc((unsigned)bpp)) == NULL)
X      pm_error("can't allocate space for row", 0,0,0,0,0);
X
X   /* set up image details */
X   if (xscale != 0.0)
X      xsize = cols * xscale * 4;
X   if (yscale != 0.0)
X      ysize = rows * yscale * 4;
X
X#ifdef DEBUG
X   fprintf(stderr, "dark    =%d\n", dark);
X   fprintf(stderr, "diffuse =%d\n", diffuse);
X   fprintf(stderr, "dither  =%d\n", dither);
X   fprintf(stderr, "cluster =%d\n", cluster);
X   fprintf(stderr, "quality =%d\n", quality);
X   fprintf(stderr, "xsize   =%d\n", xsize);
X   fprintf(stderr, "ysize   =%d\n", ysize);
X   fprintf(stderr, "xshift  =%d\n", xshift);
X   fprintf(stderr, "yshift  =%d\n", yshift);
X   fprintf(stderr, "xscale  =%lf\n", xscale);
X   fprintf(stderr, "yscale  =%lf\n", yscale);
X   fprintf(stderr, "gamma   =%lf\n", gamma);
X   fprintf(stderr, "index   =%d\n", index);
X   fprintf(stderr, "nopack  =%d\n", nopack);
X#endif
X
X   /* write PCL header */
X/*   printf("\033&l26A");                         /* paper size */
X   printf("\033*r%ds%dT", cols, rows);          /* source width, height */
X   if (xshift != 0 || yshift != 0)
X      printf("\033&a%+dh%+dV", xshift, yshift); /* xshift, yshift */
X   if (quality)
X      printf("\033*o%dQ", quality);             /* print quality */
X   printf("\033*t");
X   if (xsize == 0 && ysize == 0)
X      printf("180r");                   /* resolution */
X   else {                               /* destination width, height */
X      if (xsize != 0)
X	 printf("%dh", xsize);
X      if (ysize != 0)
X	 printf("%dv", ysize);
X   }
X   if (gamma != 0)
X      printf("%.3lfi", gamma);                    /* gamma correction */
X   if (dark)
X      printf("%dk", dark);              /* scaling algorithms */
X   printf("%dJ", render);               /* rendering algorithm */
X   printf("\033*v18W");                           /* configure image data */
X      putchar(0); /* relative colours */
X      putchar(index ? 1 : 3); /* index/direct pixel mode */
X      putchar(index); /* ignored in direct pixel mode */
X      if (index) {
X	 putchar(0);
X	 putchar(0);
X	 putchar(0);
X      } else {
X	 putchar(bpr); /* bits per red */
X	 putchar(bpg); /* bits per green */
X	 putchar(bpb); /* bits per blue */
X      }
X      putword(maxval); /* max red reference */
X      putword(maxval); /* max green reference */
X      putword(maxval); /* max blue reference */
X      putword(0); /* min red reference */
X      putword(0); /* min green reference */
X      putword(0); /* min blue reference */
X   if (index) {                        /* set palette */
X      for (i = 0; i < colours; i++) {
X	 int r, g, b;
X	 r = PPM_GETR( chv[i].color );
X	 g = PPM_GETG( chv[i].color );
X	 b = PPM_GETB( chv[i].color );
X	 if (i == 0)
X	    printf("\033*v");
X	 if (r)
X	    printf("%da", r);
X	 if (g)
X	    printf("%db", g);
X	 if (b)
X	    printf("%dc", b);
X	 if (i == colours-1)
X	    printf("%dI", i);    /* assign colour index */
X	 else
X	    printf("%di", i);    /* assign colour index */
X      }
X   }
X   ppm_freecolorhist( chv );
X
X   /* start raster graphics at CAP */
X   printf("\033*r%dA", (xsize != 0 || ysize != 0) ? 3 : 1);
X
X   for (row = 0; row < rows; row++) {
X      if (index) { /* indexed colour mode */
X	 int out, cnt;
X	 out = cnt = 0;
X	 for (col = 0, pixrow=pixels[row]; col < cols; col++, pixrow++) {
X	    putbits(ppm_lookupcolor( cht, *pixrow ), index);
X	 }
X	 putbits(0, 0); /* flush row */
X      } else { /* direct colour mode */
X	 for (col = 0, pixrow=pixels[row]; col < cols; col++, pixrow++) {
X	    putbits(PPM_GETR( *pixrow ), bpr);
X	    putbits(PPM_GETG( *pixrow ), bpg);
X	    putbits(PPM_GETB( *pixrow ), bpb); /* don't need to flush */
X	 }
X	 putbits(0, 0); /* flush row */
X      }
X   }
X   printf("\033*rC"); /* end raster graphics */
X   exit(0);
X}
END_OF_ppmtopcl.c
if test 12077 -ne `wc -c <ppmtopcl.c`; then
    echo shar: \"ppmtopcl.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 1 \(of 1\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 1 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0