From: leichter@lrw.com (Jerry Leichter)
Newsgroups: comp.os.vms
Subject: RE: Sixel to HPLJ III
Date: 27 Aug 92 21:26:07 GMT
Distribution: world
Organization: The Internet


	Does anyone have a PD program that will convert a sixel file to HPGL
	(or anything that an HP LaserJet III will understand)?  Output from
	the Decwindows program, Paint, seems to only support sixel and
	Postscript.  I want to be able to print to my HPLJ III but don't want
	to dish out $700 for a Postscript cartridge.  Any help is greatly
	appreciated.

All the world's in a loop, it seems.  In the last couple of weeks, there have
been several requests for setup modules for LaserJets.  Now, this.  I haven't
seen either kind of request in perhaps a year....

I've posted the following program before, but it seems not to be widely
known or archived.  If someone wants to put it in an archive, please feel
free....
							-- Jerry

/*
 *		S I X J E T . C
 *
 * Copyright ) 1988, 1992 by Jerrold Sol Leichter
 *
 * This software is provided to you free of charge for your own use.  Use it
 * as you see fit; if it doesn't work, I disclaim all responsibility.  You
 * may re-distribute this software UNCHANGED but only if you include this
 * copyright notice.  Alternatively, if you change this software, you may
 * re-distribute the result only if you include BOTH this copyright notice,
 * AND an additional notice identifying you and indicating that you have
 * changed it.
 *
 * Sixel to HP LaserJet bitmap converter.  Usage:
 *
 *	SIXJET [-iw] [-r <dpi>] sixel-file[.REN]
 *
 * (where SIXJET has been defined as a foreign command).  The command uses
 * standard VMS parsing and defaulting rules; the output file is always in
 * the default directory, with the same name as the input file and file type
 * .JET.
 *
 * The -i option inverts the sense of the image, exchanging black and white
 * pixels.
 *
 * The -w option requests that the bitmap produced cover the entire output
 * page, or at least as much of it as the sixel file itself covers.  By de-
 * fault, a minimal bounding rectangle containing all the "black" dots will
 * be calculated, and the output file will, when printed, place those at the
 * upper left-hand corner of the page.  Output files of the default form are
 * suitable for inclusion as parts of images, with appropriate placement con-
 * trolled by the composition software, while -w output files are intended for
 * "stand-alone" printing.
 *
 * The -r option, which must be followed by a resolution in dots per inch
 * (with spaces separating it from the -r) overrides the resolution specified
 * in the sixel file.  The only supported resolutions are 75, 100, 150 and 300
 * dots per inch.
 *
 * SIXJET was specifically intended to convert sixel files produced using the
 * VWS RENDER command with output device type LN03PLUS.  It is somewhat more
 * general than that - for example, it will handle sixel files produced by
 * the VWS "Print Portion of Screen" option - but it will not necessarily
 * produce anything meaningful for arbitrary sixel files intended for other
 * kinds of printers at lower resolutions or other aspect ratios.  It SHOULD
 * be able to read any such files - it's just that the resulting output may
 * be distorted.  You'll have to try it and see....
 *
 * SIXJET can read color sixel files, but will ignore any color specifiers.
 * The result may not be useful.
 *
 * The output uses LaserJet+ sequences that may not be available in the base
 * LaserJet.  (They should be available in LaserJet II's.)  In any case, the
 * available bitmap memory in a base LaserJet is so small that it's unlikely
 * you can print most useful pictures.  Even in a LaserJet+, be aware that you
 * can't cover more than about a quarter of the page at 300dpi unless you have
 * additional RAM.  (The LaserJet II is not subject to this limitation.)
 *
 * If you make any changes/improvements, I'd like to receive copies!
 *
 * Author:	Jerry Leichter (leichter@lrw.com)
 * Version:	0.1
 *	Revised, prior to distribution, to fix a long-standing small bug
 *	that could cause a loop if the input file ended within a repetition
 *	count or other numeric value.
 */
#include stdio
#include ctype

#define streq(s,t)	(strcmp(s,t) == 0)
#define issix(c)	((c) >= 0x3F && (c) <= 0x7E)

#define ESC	0x1B
#define DCS	0x90
#define SUB	0x1A
#define CAN	0x18
#define ST	0x9C

#define REPEAT	0x21
#define SETRAST	0x22
#define SLCTLR	0x23
#define GCR	0x24
#define GNL	0x2D

#define WIDTH		 8500			/* Max width, milliin	*/
#define HEIGHT		11000			/* Max height, milliin	*/
#define BPI		300			/* Max output res, bpi	*/

#define BITWIDTH 	((WIDTH*BPI + 999)/1000)
#define BITHEIGHT	((HEIGHT*BPI + 999)/1000)

typedef unsigned char BYTE;

BYTE mem[BITHEIGHT][(BITWIDTH + 7)/8];		/* The bitmap		*/
int	row;					/* Current row		*/
int	col;					/* Current column (bit)	*/
int	maxrow;
int	maxcol;
int	minrow;
int	mincol;
int	invert;					/* Invert image bits	*/

main(argc,argv)
int	argc;
char	*argv[];
{	int	c;				/* Input character	*/
	int	rep;				/* Repetition count	*/
	int	maxcb;				/* Maximum column byte	*/
	int	mincb;				/* Minimum column byte	*/
	FILE	*in;				/* Input file		*/
	FILE	*out;				/* Output file		*/
	char	*fn;				/* Input file name	*/
	char	dn[255+4+1];			/* Default name		*/
	int	res;				/* Output resolution	*/
	int	aratio;				/* Pixel aspect ratio	*/
	int	i;

	minrow = maxrow = maxcol = -1;
	mincol = 9999999;
	res = 300;
	invert = FALSE;
	aratio = 1;

	fn = NULL;
	for (i = 1; i < argc; i++)
	{	if (argv[i][0] != '-')
		{	if (fn != NULL)
				usage();
			fn = argv[i];
		}
		else if (streq(argv[i],"-w"))
		{	minrow = mincol = 0;
			continue;
		}
		else if (streq(argv[i],"-i"))
		{	invert = TRUE;
			continue;
		}
		else if (streq(argv[i],"-r"))
		{	if (++i == argc)
				usage();
			res = atoi(argv[i]);
		}
		else	usage();
	}
	checkres(res);

	if (fn == NULL)
		usage();
	if ((in = fopen(fn,"r","dna=.REN")) == NULL)
	{	perror("");
		error("Can't open input file");
	}
	sprintf(dn,"dna=%s",fn);
	if ((out = fopen("SYS$DISK:[].JET;","w",dn,
		"rfm=fix","bls=512","mrs=512")) == NULL)
	{	perror("");
		error("Can't open output file");
	}

	row = col = 0;
	c = getc(in);
find_DCS:
	while (c != EOF && c != DCS)
	{	if (c == ESC && getc(in) == 'P')
			break;
		c = getc(in);
	}
	if (c == EOF)
		error("No sixel DCS found");

	c = getc(in);
	while (isdigit(c) || c == ';' || c < 0x20)
		c = getc(in);

	if (c != 'q')
		goto find_DCS;

	c = getc(in);
	while (c != EOF && c != ESC && c != ST)
	{	if (issix(c))
		{	set(c,1);
			c = getc(in);
			continue;
		}
		switch(c)
		{
	case REPEAT:				/* Repeat count		*/
			rep = 0;
			c = getc(in);
			while (c != EOF && (isdigit(c) || (c < 0x20)))
			{	if (isdigit(c))
					rep = 10*rep + (c - '0');
				c = getc(in);
			}
			if (c == SUB)
				c = 0x3F;
			if (issix(c))
			{	set(c,rep);
				c = getc(in);
			}
			break;

	case SLCTLR:				/* Select colors	*/
			/*
			 * Ignore them
			 */
			c = getc(in);
			while (c != EOF
			    && (isdigit(c) || c == ';' || c < 0x20))
			{	c = getc(in);
			}
			break;
	case SETRAST:				/* Raster attributes	*/
			{	int pan;
				int pad;

				pad = pan = 0;
				c = getc(in);
				while (c != EOF && (isdigit(c) || (c < 0x20)))
				{	if (isdigit(c))
						pan = 10*pan + (c - '0');
					c = getc(in);
				}
				if (c != ';')
					break;
				c = getc(in);
				while (c != EOF && (isdigit(c) || (c < 0x20)))
				{	if (isdigit(c))
						pad = 10*pad + (c - '0');
					c = getc(in);
				}
				if (pad != 0)
					aratio = (float)pan/pad + 0.5;
			}
			/*
			 * Ignore Ph, Pv
			 */
			c = getc(in);
			while (c != EOF
			    && (isdigit(c) || c == ';' || c < 0x20))
			{	c = getc(in);
			}
			break;
	case GNL:				/* Graphics newline	*/
			/*
			 * If anything was set in this row, update the
			 * boundary values:  minrow, if it has never been
			 * set before; maxrow - since we always proceed
			 * forward by rows, no test is needed; and maxcol.
			 */
			if (col != 0)
			{	if (minrow < 0)
					minrow = row;
				maxrow = row+5;
				if (col > maxcol)
					maxcol = col;
			}
			row += 6;
			/*
			 * Fall through...
			 */
	case GCR:				/* Graphics RETURN	*/
			/*
			 * If anything was set in this row, update the
			 * boundary values:  minrow, if it has never been
			 * set before; maxrow - since we always proceed
			 * forward by rows, no test is needed; and maxcol.
			 */
			if (col != 0)
			{	if (minrow < 0)
					minrow = row;
				maxrow = row+5;
				if (col > maxcol)
					maxcol = col;
			}
			col = 0;
			c = getc(in);
			break;
	case SUB:				/* Sub => 0 bits	*/
			set(0x3F,1);
			c = getc(in);
			break;
	case CAN:				/* Emergency exit	*/
			c = EOF;
			break;
	default:
			if (c >= 0x20)
			{	fprintf(stderr,
					"Unexpected character %02X ignored\n",
					c);
			}
			c = getc(in);
			break;
		}
	}
	if (c == EOF)
		error("Unexpected EOF");
	if (c == ESC && getc(in) != '\\')
		error("ST not found when expected");
	printf(
	 "Observed boundaries:  mincol %d, maxcol %d, minrow %d, maxrow %d\n",
		mincol,maxcol,minrow,maxrow);
	printf("Image is %.2f in (%.2f cm) wide by %.2f in (%.2f cm) high\n",
			(float)(maxcol-mincol+1)/res + .005,
			 2.54*(float)(maxcol-mincol+1)/res + .005,
			(float)(maxrow-minrow+1)/res + .005,
			 2.54*(float)(maxrow-minrow+1)/res + .005);
	fprintf(out,"%c*t%dR%c*r1A",ESC,res,ESC);
	maxcb = (maxcol+7)/8;
	mincb = mincol/8;
	for (row = minrow; row <= maxrow; row++)
	{	int	mnz;
		BYTE	*memrow;

		memrow = mem[row];
		for (mnz = maxcb+1; mnz > mincb; mnz--)
			if (memrow[mnz] != 0)
				break;
		for (i = 0; i < aratio; i++)
		{	fprintf(out,"%c*b%dW",ESC,mnz+1-mincb);
			for (col = mincb; col <= mnz; col++)
				putc(memrow[col],out);
		}
	}
	fprintf(out,"%c*rB\n",ESC);
	fclose(out);
}

BYTE bitmasks[] = {128, 64, 32, 16, 8, 4, 2, 1};

set(c,rep)
int	c;
int	rep;
{	BYTE	mask;
	int	cb;
	BYTE	*memrow[6];
	int	i;

	c -= 0x3F;
	if (invert)
		c = ~c;
	if (c == 0)
	{	col += rep;
		return;
	}
	if (col < mincol)
		mincol = col;

	for (i = 0; i < 6; i++)
		memrow[i] = mem[row+i];

	while (rep--)
	{	mask = bitmasks[col & 7];
		cb = col >> 3;
		if (c & 1)
			memrow[0][cb] |= mask;
		if (c & 2)
			memrow[1][cb] |= mask;
		if (c & 4)
			memrow[2][cb] |= mask;
		if (c & 8)
			memrow[3][cb] |= mask;
		if (c & 16)
			memrow[4][cb] |= mask;
		if (c & 32)
			memrow[5][cb] |= mask;
		col++;
	}
}

error(s)
char	s[];
{
	fprintf(stderr,"%s\n",s);
	exit(44);
}

usage()
{
	fprintf(stderr,"Usage:  sixjet [-iw] [-r <dpi>] file\n");
	fprintf(stderr," -i\t\tInvert image\n");
	fprintf(stderr," -r <dpi>\tSet output resolution\n");
	fprintf(stderr," -w\t\tUse whole page\n");
	exit(0);
}

checkres(res)
int	res;
{
	if (res != 300 && res != 150 && res != 100 && res != 75)
		error("Unsupported resolution - choose 75, 100, 150 or 300");
}

Newsgroups: comp.os.vms,vmsnet.sources.d