From:	CSBVAX::CSBVAX::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX" 18-DEC-1988 16:56
To:	MRGATE::"ARISIA::EVERHART"
Subj:	Sixel to Postscript (7KB of C code).


Received: From KL.SRI.COM by CRVAX.SRI.COM with TCP; Sun, 18 DEC 88 13:06:43 PDT
Received: from ucbvax.Berkeley.EDU by KL.SRI.COM with TCP; Sun, 18 Dec 88 12:38:31 PST
Received: by ucbvax.Berkeley.EDU (5.61/1.33)
	id AA00617; Sun, 18 Dec 88 12:25:38 PST
Received: from USENET by ucbvax.Berkeley.EDU with netnews
	for info-vax@kl.sri.com (info-vax@kl.sri.com)
	(contact usenet@ucbvax.Berkeley.EDU if you have questions)
Date: 18 Dec 88 20:04:49 GMT
From: gjc@bu-cs.bu.edu  (George J. Carrette)
Organization: Boston U. Comp. Sci.
Subject: Sixel to Postscript (7KB of C code).
Message-Id: <26772@bu-cs.BU.EDU>
Sender: info-vax-request@kl.sri.com
To: info-vax@kl.sri.com

Here is something that is crude but effective. It would be much more
clever and space efficient to have a postscript program that did the
sixel conversion inside the laserprinter. This current  hack has been
tested with an apple laserwriter II and a VMS print symbiot that came
from DECUS (I think).

/* 6-OCT-88 George Carrette
   [Note: Unsupported, Public Domain]

   This work was supported by Mitech Corporation. 74 Junction Square.
   Concord MA. 01742. (508)-371-2002.

   Convert a sixel bitmap file into a post-script file, suitable for including
   into Tex documents. The file may also be printed stand-alone.

   The arguments are
   $ sixelps <infile> <outfile> [dpi] [xsize ysize]

   Where dpi is the number of dots per inch (default 300) of the bitmap
   on output. The xsize and ysize may be given to select a subset of the
   bitmap.

   On a VAXSTATION the workstation "printer setup" should specify an aspect 
   ratio of 1 to 1 and a "ribbon or toner saver" setup of positive image.
   A color display setup with display background of white or gray generally
   gives the best results when making screen printouts.

*/

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>

void convert_sixel_file();
void prescan_sixel_file();
void write_ps_program();

main(argc,argv)
 int argc; char **argv;
{FILE *fi,*fo;
 int xsize, ysize,dpi;
 char truename[512];
 if (!((argc == 3) || (argc == 4) || (argc == 6)))
   {fprintf(stderr,"sixelps <infile> <outfile> [dpi] [xsize ysize]\n");
    exit(1);}
 if (!(fi = fopen(argv[1],"rb")))
   {perror(argv[1]);exit(vaxc$errno);}
 if (!(fo = fopen(argv[2],"w"
		  /* ,"ctx=rec","mrs=512","rat=cr","rfm=var" */
		  )))
   {perror(argv[2]);exit(vaxc$errno);}
 if (fgetname(fi,truename))
   printf("Converting sixel file \"%s\"\n",truename);
 if (fgetname(fo,truename))
   printf("Into postscript file \"%s\"\n",truename);
 if (argc >= 4) dpi = atol(argv[3]); else dpi = 300;
 printf("with %d dots per inch resolution\n",dpi);
 if (argc == 6)
   {xsize = atol(argv[4]);
    ysize = atol(argv[5]);}
 else
   {prescan_sixel_file(&xsize,&ysize,fi);
    fclose(fi);
    if (!(fi = fopen(argv[1],"rb")))
      {perror(argv[1]);exit(vaxc$errno);}}
 if (xsize & 7) xsize = xsize + (8 - (xsize & 7));
 printf("xsize = %d, ysize = %d\n",xsize,ysize);
 write_ps_program(xsize,ysize,dpi,fo);
 convert_sixel_file(xsize,ysize,fi,fo);
 fprintf(fo,"\n\n%%end(plot)\n\n");
 fprintf(fo,"%% the showpage should be ignored when inserting\n");
 fprintf(fo,"%% into a larger document\n");
 fprintf(fo,"showpage\n");
 fclose(fo);}

#define PS_LLX 36
#define PS_LLY 36

void write_ps_program(xsize,ysize,dpi,f)
     int xsize,ysize; FILE *f;
{int xsizeu,ysizeu;
 xsizeu = (xsize*72)/dpi;
 ysizeu = (ysize*72)/dpi;
 fprintf(f,
	 "%%%%BoundingBox: %d %d %d %d\n%%plot follows\n",
	 /* llx lly urx ury */
	 PS_LLX,PS_LLY,PS_LLX+xsizeu,PS_LLY+ysizeu);
 fprintf(f,"%%begin(plot)\n");
 fprintf(f,"%% bitmap image converted from sixel format follows.\n");
 fprintf(f,"%% intended to be inserted into a document\n");
 fprintf(f,"%% with a program which includes only those commands inside\n");
 fprintf(f,"%% the begin(plot) and end(plot) statements\n");
 fprintf(f,"%d %d translate\n",PS_LLX,PS_LLY);
 fprintf(f,"/picstr 1 string def\n");
 fprintf(f,"%d %d scale\n",xsizeu,ysizeu);
 fprintf(f,"%d %d 1 \n",
	 xsize,ysize);
 fprintf(f,"[%d 0 0 -%d 0 %d]\n",
 	 xsize,ysize,ysize);
 fprintf(f,"{currentfile picstr readhexstring pop} image\n");
}


#define CH_ESC (27)

skip_sixel_header(f)
     FILE *f;
{int c;
 c = getc(f);
 if (c != CH_ESC) ch_err("first character is 0%o, expecting 0%o\n",c,CH_ESC);
 c = getc(f);
 if (c != 'P') ch_err("second character is 0%o, expecting 0%o\n",c,'P');
 while ((c = getc(f)) != 'q')
   if (c == EOF) ch_err("got 0%o before 0%o at start of file\n",EOF,'q');}

read_decnum(f)
     FILE *f;
{int c,n;
 n = 0;
 while (1)
   {c = getc(f);
    if (c == EOF) ch_err("end of file inside decimal number\n",0,0);
    if ((c < '0') || (c > '9')) {ungetc(c,f); return(n);}
    n = 10*n + (c - '0');}}
 
 void
prescan_sixel_file(px,py,f)
     int *px, *py; FILE *f;
{int max_nx,nx,c,i,fresh_line;
 max_nx = 0;
 *py = 0;
 skip_sixel_header(f);
 nx = 0;
 fresh_line = 1;
 while(1)
   {c = getc(f);
    switch (c)
      {case '!':
	 i = read_decnum(f);
	 getc(f);
	 if (fresh_line)
	   {*py = *py + 6;
	    if (nx > max_nx) max_nx = nx;
	    nx = i;
	    fresh_line = 0;}
	 else
	   nx = nx + i;
	 break;
       case '#':
	 ch_err("color change character 0%o not handled\n",c,0);
       case '$':
	 ch_err("overprint character 0%o not handled\n",c,0);
       case '-':
	 fresh_line = 1;
	 break;
       case CH_ESC:
	 c = getc(f);
	 if (c != '\\')
	   ch_err("expecting terminator 0%o, but got 0%o\n",'\\',c);
	 if (nx > max_nx) max_nx = nx;
	 *px = max_nx;
	 return;
       default:
	 if ((c < 077) || (c > 0176))
	   ch_err("got character 0%o, out of sixel range\n",c,0);
	 if (fresh_line)
	   {*py = *py + 6;
	    if (nx > max_nx) max_nx = nx;
	    nx = 1;
	    fresh_line = 0;}
	 else
	   nx = nx + 1;}}}
			  
char *read_sixel_bitmap();
void write_sixel_bitmap();			

 void
convert_sixel_file(xsize,ysize,fi,fo)
 int xsize,ysize;
 FILE *fi,*fo;
{char *bits;
 bits = read_sixel_bitmap(xsize,ysize,fi);
 fclose(fi);
 write_sixel_bitmap(xsize,ysize,bits,fo);
 free(bits);}

     int
nbits_to_nbytes(x)
     int x;
{return( (x >> 3) + ((x & 7) ? 1 : 0));}
     
 void
write_sixel_bitmap(xsize,ysize,bits,f)
 int xsize,ysize;
 char *bits;
 FILE *f;
{int j,n,c;
 static char hex[] = "0123456789ABCDEF";
 n = nbits_to_nbytes(xsize*ysize);
 printf("%d bytes in hex dump of bitmap\n",n*2);
 for(j=0;j<n;++j)
   {putc(hex[(bits[j] & 0xF0) >> 4],f);
    putc(hex[bits[j] & 0xF],f);
    if ((j % 20) == 19) putc('\n',f);}
 putc('\n',f);}

 void
set_sixel(c,x,y,xsize,ysize,bitmap)
     int c,x,y,xsize,ysize;
     char *bitmap;
{int j,yy,bit_index,byte_index,bit_pos,bit;
 if (x >= xsize) return;
 for(j=0;j<6;++j)
   {yy = j + y;
    if (yy >= ysize) return;
    bit = (c>>j) & 1;
    if (!bit) continue;
    bit_index = (yy*xsize) + x;
    byte_index = bit_index >> 3;
    bit_pos = 7 - (bit_index & 7);
    bitmap[byte_index] = bitmap[byte_index] & ~(bit << bit_pos);}}

 char *
read_sixel_bitmap(xsize,ysize,f)
 int xsize,ysize;
 FILE *f;
{int x,y,c,i,j;
 char *bitmap;
 bitmap = (char *) malloc(nbits_to_nbytes(xsize*ysize));
 memset(bitmap,255,nbits_to_nbytes(xsize*ysize));
 x = 0;
 y = 0;
 skip_sixel_header(f);
 while(1)
   {c = getc(f);
    switch (c)
      {case '!':
	 i = read_decnum(f);
	 c = getc(f);
	 for(j=0;j<i;++j)
	   {set_sixel(c - 077,x,y,xsize,ysize,bitmap);
	    ++x;}
	 break;
       case '#':
	 ch_err("color change character 0%o not handled\n",c,0);
       case '$':
	 ch_err("overprint character 0%o not handled\n",c,0);
       case '-':
	 x = 0;
	 y = y + 6;
	 break;
       case CH_ESC:
	 c = getc(f);
	 if (c != '\\')
	   ch_err("expecting terminator 0%o, but got 0%o\n",'\\',c);
	 return(bitmap);
       default:
	 if ((c < 077) || (c > 0176))
	   ch_err("got character 0%o, out of sixel range\n",c,0);
	 set_sixel(c - 077,x,y,xsize,ysize,bitmap);
	 ++x;}}}




ch_err(msg,c1,c2)
     char *msg; int c1,c2;
{fprintf(stderr,msg,c1,c2);
 exit(1);}

