[comp.graphics] "Sixels" and the Xerox 3700 laser printer

cccdan@castor.ucdavis.edu (Dan Bauhaus) (06/08/89)

Does anyone know what a sixel might be?  The Xerox 3700 manual states
that after a command to draw a graphics window is delivered to the printer,  
a bitmap can be printed using a bitmap in "sixel" form.  The naive 
guess of six bits in a row seems to easy.

Also, has anyone printed bitmaps out on a Xerox 3700 printer and if so, what
might the command(s) be?

Thanks--Dan

jwl@ernie.Berkeley.EDU (James Wilbur Lewis) (06/08/89)

In article <4581@ucdavis.ucdavis.edu> cccdan@castor.ucdavis.edu (Dan Bauhaus) writes:
>
>Does anyone know what a sixel might be?  The Xerox 3700 manual states
>that after a command to draw a graphics window is delivered to the printer,  
>a bitmap can be printed using a bitmap in "sixel" form.  The naive 
>guess of six bits in a row seems to easy.

Some DEC terminals, like the VT340, have a "sixel graphics" mode.  Yes,
six bits in a row IS too easy.  It's six bits stacked VERTICALLY, so 
instead of using the sixel commands to send out individual scanlines,
you send out six rows at a time, column by column.

I have no idea if Xerox uses the same convention, though.

-- Jim Lewis
   U.C. Berkeley

djh@cci632.UUCP (Daniel J. Hazekamp) (06/09/89)

Sixels are just what the name implies, six bit packets. They are generated
by taking six bits at a time from the graphic image, adding hex 3F, and
sending the resultant byte (8 bits) to the printer. Each scan line in the
image has to be padded with zeros such that the number of bits is evenly
divisible by 24.

Note: Xerox font files are sixel encoded.

Enclosed are 2 source files, sixel.c, which can be used to 'unsixel' data,
such as Xerox font files, and 'giftoxp.c', which will print GIF images on
a model 3700, 4045, or anuything else that supports 2700 mode with graphics.

Note: giftoxp will not work on a model 2700. Since I do not have a 3700 or
	4045, I'm not sure if it works poroperly, or at all.

: to unbundle, "sh" this file -- DO NOT use csh
:  SHAR archive format.  Archive created Fri Jun 9 10:15:06 EDT 1989
echo x - sixel.c
sed 's/^X//' > sixel.c <<'+FUNKY+STUFF+'
X#include <stdio.h>
X
Xunsigned dsixel;
Xunsigned char data[4];
X
Xmain()
X{
X	register int i,n;
X	register unsigned sixel;
X
X	while ((n=read(0,data,4)) > 0) {
X		sixel = 0;
X		for (i=0; i<n; i++) {
X			if (data[i] >= 0x30 && data[i] <= 0x39)
X				fprintf(stderr,"found repeat count %X\n",data[i]);
X			sixel |= (data[i] - 0x3f) & 0x3f;
X			sixel <<= 6;
X		}
X		dsixel = sixel << 2;
X		write(1,&dsixel,3);
X	}
X}
+FUNKY+STUFF+
echo '-rw-r--r--  1 djh           392 Jun  9 10:14 sixel.c    (as sent)'
chmod u=rw,g=r,o=r sixel.c
ls -l sixel.c
echo x - giftoxp.c
sed 's/^X//' > giftoxp.c <<'+FUNKY+STUFF+'
X/*********************************************
X *       GIF to Xerox 3700 Converter         *
X *                                           *
X *      Aug 10, 1988  by Dan Hazekamp        *
X *         modified from GIFtoPS             *
X *           by Scott Hemphill               *
X *                                           *
X * I wrote this program, and hereby place it *
X * in the public domain, i.e. there are no   *
X * copying restrictions of any kind.         *
X *********************************************/
X
X#include <stdio.h>
Xchar *malloc();
Xint strncmp();
X
X#define min(x,y) ((x) < (y) ? (x) : (y))
X#define FALSE 0
X#define TRUE 1
X
Xtypedef int bool;
Xtypedef struct codestruct {
X            struct codestruct *prefix;
X            unsigned char first,suffix;
X        3 codetype;
X
XFILE *infile;
Xunsigned int screenwidth;           /* The dimensions of the screen */
Xunsigned int screenheight;          /*   (not those of the image)   */
Xbool global;                        /* Is there a global color map? */
Xint globalbits;                     /* Number of bits of global colors */
Xunsigned char globalmap[256][3];    /* RGB values for global color map */
Xunsigned char colortable[256];      /* 4-bit greyscale code */
Xunsigned char *raster;              /* Decoded image data */
Xcodetype *codetable;                /* LZW compression code data */
Xint datasize,codesize,codemask;     /* Decoder working variables */
Xint clear,eoi;                      /* Special code values */
Xchar *res = "300";
Xcflag = 0;			    /* Don't center image on page */
Xdflag = 0;			    /* Use 8x8 dots instead of 4x4 dots */
Xpflag = 0;			    /* Print in Portrait Orientation */
X
Xvoid usage()
X{
X        fprintf(stderr,"usage: giftohp [-c -d -p -rres] input-file > output-file\n");
X        exit(-1);
X}
X
Xvoid fatal(s)
Xchar *s;
X{
X        fprintf(stderr,"gifthp: %s\n",s);
X        exit(-1);
X}
X
Xvoid sixel(c)
Xunsigned char c;
X{
X	static bits = 0;
X	static int quad = 0;
X	char out[5];
X
X	quad = (quad << 8) | c;
X	bits += 8;
X	if (bits == 24) {
X		out[3] = (quad & 0x3f) + 0x3f;
X		quad >>= 6;
X		out[2] = (quad & 0x3f) + 0x3f;
X		quad >>= 6;
X		out[1] = (quad & 0x3f) + 0x3f;
X		quad >>= 6;
X		out[0] = (quad & 0x3f) + 0x3f;
X		out[4] = 0;
X		printf("%s",out);
X		bits = 0;
X	}
X}
X
Xvoid checksignature()
X{
X        char buf[6];
X
X        fread(buf,1,6,infile);
X        if (strncmp(buf,"GIF",3)) fatal("file is not a GIF file");
X        if (strncmp(&buf[3],"87a",3)) fatal("unknown GIF version number");
X}
X
X/* Get information which is global to all the images stored in the file */
X
Xvoid readscreen()
X{
X        unsigned char buf[7];
X
X        fread(buf,1,7,infile);
X        screenwidth = buf[0] + (buf[1] << 8);
X        screenheight = buf[2] + (buf[3] << 8);
X        global = buf[4] & 0x80;
X        if (global) {
X            globalbits = (buf[4] & 0x07) + 1;
X            fread(globalmap,3,1<<globalbits,infile);
X        }
X}
X
X/* Convert a color map (local or global) to an array of two character
X   hexadecimal strings, stored in colortable.  RGB is converted to
X   4-bit grayscale using integer arithmetic. */
X
Xvoid initcolors(colortable,colormap,ncolors)
Xunsigned char colortable[256];
Xunsigned char colormap[256][3];
Xint ncolors;
X{
X        register unsigned color;
X        register i;
X
X        for (i = 0; i < ncolors; i++) {
X            color = 77*colormap[i][0] + 150*colormap[i][1] + 29*colormap[i][2];
X            color >>= 12;
X            colortable[i] = color & 0xf;
X        }
X}
X
X/* Write a header to the standard output.  Standard paper size
X   (8.5 by 11) is hard-coded, as is the whole initialization sequence.  */
X
Xvoid writeheader(left,top,width,height)
Xint left,top,width,height;
X{
X	register int x,y;
X
X	/* if (cflag) {
X		x = pflag ? left : top;
X		y = pflag ? top : left;
X		if (!dflag) {
X			x *= 2;
X			y *= 2;
X		}
X	} else {
X		if (dflag) {
X			height *= 2;
X			width *= 2;
X		}
X		/* 600 =  8.0 usable inches x 300dpi / 4 */
X		/* 788 = 10.5 usable inches x 300dpi / 4 */
X		/* x = 600 - (pflag ? width : height);
X		y = 788 - (pflag ? height : width);
X	}
X	x *= 2;
X	y *= 2;*/
X	if (pflag)
X		printf("\033+1Titan10iso-P\r\n\0331");
X	else
X		printf("\033+1XCP14-L\r\n\0331");
X	printf("\033gw;,,%d,%d\r\n", dflag?width*8:width*4,
X		dflag?height*8:height*4);
X}
X
X/* Output the bytes associated with a code to the raster array */
X
Xvoid outcode(p,fill)
Xregister codetype *p;
Xregister unsigned char **fill;
X{
X        if (p->prefix) outcode(p->prefix,fill);
X        *(*fill)++ = p->suffix;
X}
X
X/* Process a compression code.  "clear" resets the code table.  Otherwise
X   make a new code table entry, and output the bytes associated with the
X   code. */
X
Xvoid process(code,fill)
Xregister code;
Xunsigned char **fill;
X{
X        static avail,oldcode;
X        register codetype *p;
X
X        if (code == clear) {
X            codesize = datasize + 1;
X            codemask = (1 << codesize) - 1;
X            avail = clear + 2;
X            oldcode = -1;
X        } else if (code < avail) {
X            outcode(&codetable[code],fill);
X            if (oldcode != -1) {
X                p = &codetable[avail++];
X                p->prefix = &codetable[oldcode];
X                p->first = p->prefix->first;
X                p->suffix = codetable[code].first;
X                if ((avail & codemask) == 0 && avail < 4096) {
X                    codesize++;
X                    codemask += avail;
X                }
X            }
X            oldcode = code;
X        } else if (code == avail && oldcode != -1) {
X            p = &codetable[avail++];
X            p->prefix = &codetable[oldcode];
X            p->first = p->prefix->first;
X            p->suffix = p->first;
X            outcode(p,fill);
X            if ((avail & codemask) == 0 && avail < 4096) {
X                codesize++;
X                codemask += avail;
X            }
X            oldcode = code;
X        } else {
X            fprintf(stderr,"giftohp: illegal code '%x' in raster data, avail: %x, oldcode: %x\n",code,avail,oldcode);
X	    exit(-1);
X        }
X}
X
X/* Decode a raster image */
X
Xvoid readraster(width,height)
Xunsigned width,height;
X{
X        unsigned char *fill = raster;
X        unsigned char buf[255];
X        register bits=0;
X        register unsigned count,datum=0;
X        register unsigned char *ch;
X        register int code;
X
X        datasize = getc(infile);
X        clear = 1 << datasize;
X        eoi = clear+1;
X        codesize = datasize + 1;
X        codemask = (1 << codesize) - 1;
X        codetable = (codetype*)malloc(4096*sizeof(codetype));
X        if (!codetable) fatal("not enough memory for code table");
X        for (code = 0; code < clear; code++) {
X            codetable[code].prefix = (codetype*)0;
X            codetable[code].first = code;
X            codetable[code].suffix = code;
X        }
X        for (count = getc(infile); count > 0; count = getc(infile)) {
X            fread(buf,1,count,infile);
X            for (ch=buf; count-- > 0; ch++) {
X                datum += *ch << bits;
X                bits += 8;
X                while (bits >= codesize) {
X                    code = datum & codemask;
X                    datum >>= codesize;
X                    bits -= codesize;
X                    if (code == eoi) goto exitloop;  /* This kludge put in
X                                                        because some GIF files
X                                                        aren't standard */
X                    process(code,&fill);
X                }
X            }
X        }
Xexitloop:
X        if (fill != raster + width*height) fatal("raster has the wrong size");
X        free(codetable);
X}
X
X/* Read a row out of the raster image and write it to the output file */
X
X
Xchar grey[][8] = {
X	{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
X	{ 0xff, 0xff, 0xee, 0xdd, 0xff, 0xff, 0xee, 0xdd },
X	{ 0xff, 0xff, 0xee, 0xcc, 0xff, 0xff, 0xee, 0xcc },
X	{ 0xee, 0xff, 0xee, 0xcc, 0xee, 0xff, 0xee, 0xcc },
X	{ 0xee, 0xff, 0xee, 0x44, 0xee, 0xff, 0xee, 0x44 },
X	{ 0xee, 0xee, 0xee, 0x44, 0xee, 0xee, 0xee, 0x44 },
X	{ 0xee, 0xee, 0xee, 0x00, 0xee, 0xee, 0xee, 0x00 },
X	{ 0xee, 0xee, 0xcc, 0x00, 0xee, 0xee, 0xcc, 0x00 },
X	{ 0xee, 0xee, 0x44, 0x00, 0xee, 0xee, 0x44, 0x00 },
X	{ 0xcc, 0xee, 0x44, 0x00, 0xcc, 0xee, 0x44, 0x00 },
X	{ 0xcc, 0xcc, 0x44, 0x00, 0xcc, 0xcc, 0x44, 0x00 },
X	{ 0xcc, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x00 },
X	{ 0xcc, 0x88, 0x00, 0x00, 0xcc, 0x88, 0x00, 0x00 },
X	{ 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00 },
X	{ 0x88, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00 },
X	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
X};
Xint *interleavetable;
Xbool interleaved;
X
Xvoid rasterize(height,width)
Xint height,width;
X{
X        register unsigned char *sp;
X        register row, col, x, y;
X	unsigned char rast;
X
X	y = dflag ? 8 : 4;
X        for (row=0; row<height; row++) {
X	    for(x=0; x<y; x++) {
X        	sp = raster;
X		sp += (interleaved?interleavetable[row]:row)*width;
X        	for (col=0; col<width; col++) {
X		    rast = grey[colortable[*sp++]][x];
X		    if (!dflag) {
X			col++;
X			rast &= 0xf0;
X			rast |= grey[colortable[*sp++]][x] & 0xf;
X		    }
X		    sixel(rast);
X		}
X	    }
X	}
X	x = (width * height * y) / 8;
X	y = 3 - (x % 3);
X	for (x=0; x<y; x++)
X		sixel(0);
X}
X
X/* write image trailer to standard output */
X
Xvoid writetrailer()
X{
X	printf("\f");
X}
X
X/* Read image information (position, size, local color map, etc.) and convert
X   to HP greyscale. */
X
Xvoid readimage()
X{
X        unsigned char buf[9];
X        unsigned left,top,width,height;
X        bool local;
X        char localmap[256][3];
X        int localbits;
X        register row;
X        register i;
X
X        fread(buf,1,9,infile);
X        left = buf[0] + (buf[1] << 8);
X        top = buf[2] + (buf[3] << 8);
X        width = buf[4] + (buf[5] << 8);
X        height = buf[6] + (buf[7] << 8);
X        local = buf[8] & 0x80;
X        interleaved = buf[8] & 0x40;
X        if (local) {
X            localbits = (buf[8] & 0x7) + 1;
X            fread(localmap,3,1<<localbits,infile);
X            initcolors(colortable,localmap,1<<localbits);
X        } else if (global) {
X            initcolors(colortable,globalmap,1<<globalbits);
X        } else {
X            fatal("no colormap present for image");
X        }
X        writeheader(left,top,width,height);
X        raster = (unsigned char*)malloc(width*height);
X        if (!raster) fatal("not enough memory for image");
X        readraster(width,height);
X        if (interleaved) {
X            interleavetable = (int*)malloc(height*sizeof(int));
X            if (!interleavetable) fatal("not enough memory for interleave table");
X            row = 0;
X            for (i = 0; i < height; i += 8) interleavetable[i] = row++;
X            for (i = 4; i < height; i += 8) interleavetable[i] = row++;
X            for (i = 2; i < height; i += 4) interleavetable[i] = row++;
X            for (i = 1; i < height; i += 2) interleavetable[i] = row++;
X        }
X	rasterize(height,width);
X        if (interleaved)
X            free(interleavetable);
X        free(raster);
X        writetrailer();
X}
X
X/* Read a GIF extension block (and do nothing with it). */
X
Xvoid readextension()
X{
X        unsigned char code,count;
X        char buf[255];
X
X        code = getc(infile);
X        while (count = getc(infile)) fread(buf,1,count,infile);
X}
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X        int quit = FALSE;
X        char ch, filename[40];
X
X        if (argc < 2) usage();
X	for( ; argc>1 && argv[1][0]=='-'; argc--,argv++) {
X		switch(argv[1][1]) {
X		case 'c':
X			cflag++;
X			break;
X		case 'd':
X			dflag++;
X			break;
X		case 'p':
X			pflag++;
X			break;
X		case 'r':
X			res = &argv[1][2];
X			break;
X		}
X	}
X	strcpy(filename,argv[1]);
X	if (index(filename,'.') == 0)
X		strcat(filename,".gif");
X        infile = fopen(filename,"r");
X        if (!infile) {
X            perror(filename);
X            exit(-1);
X        }
X        checksignature();
X        readscreen();
X        do {
X            ch = getc(infile);
X            switch (ch) {
X                case '\0':  break;  /* this kludge for non-standard files */
X                case ',':   readimage();
X                            break;
X                case ';':   quit = TRUE;
X                            break;
X                case '!':   readextension();
X                            break;
X                default:    fatal("illegal GIF block type");
X                            break;
X            }
X        } while (!quit);
X	exit(0);
X}
+FUNKY+STUFF+
echo '-rw-r--r--  1 djh         12314 Jun  9 10:14 giftoxp.c    (as sent)'
chmod u=rw,g=r,o=r giftoxp.c
ls -l giftoxp.c
exit 0
-- 
Dan Hazekamp					rochester!cci632!djh
Computer Consoles Inc. (CCI)			uunet!ccicpg!cci632!djh
Rochester, NY					uunet!rlgvax!cci632!djh