[comp.lang.postscript] IBM PC Graphics to PS

jonnyg@umd5.umd.edu (Jon Greenblatt) (02/13/88)

	Here is the epson to postscript program I promised earlier. It works
very well now but it's still a baby. I am distributing it in hopes to get
other postscript hackers interested in giving input. This program is
implemented using a finite state machine in readable format. I am not much
of a believer in comments but I strongly believe in readable code. If you
read the source carefully, you should know what's going on.


# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by rover!jonnyg on Fri Feb 12 12:33:06 EST 1988
# Contents:  epson.c set.h set.c crlf.c makefile
 
echo x - epson.c
sed 's/^@//' > "epson.c" <<'@//E*O*F epson.c//'
/*
 *  Version 0.5 {Supports about half of the more reasonable escapes}
 *
 *  IBM Graphics printer to postscript translator.
 *
 *	Copyright (c) 1988, Jonathan Greenblatt,
 *		<jonnyg@rover.umd.edu> (128.8.2.73)
 *		<jonnyg@umd5.umd.edu> (128.8.10.5)
 *		<pcproj@gymble.umd.edu> (128.8.128.16)
 *      This program may be redistributed in source form,
 *      provided no fee is charged and this copyright notice is preserved.
 *
 *  DESCRIPTION:
 *	This program uses standard input and output to convert epson printer
 *	codes to Postcript. This program is an execlent ASCII listing printer.
 *	The crlf program is include to add PC crlf to end of lines for
 *	printing UNIX listings. This program was written on an IBM RT running
 *	4.3. The RT does not do crlf conversions by default so some changes
 *	may have to be made on other systems. This is a working subset of
 *	what I plan to complete. I am distributing this in hopes someone else
 *	will take interest in this code.
 *
 *  SUPPORTS:
 *	1: ASCII text.
 *	2: Underlining.
 *	3: Overstrike.
 *	4: Double width.
 *	5: Highlighting <Esc>G
 *	6: Super/Subscript
 *	7: 80x66 character on a page.
 *
 *  NEEDED:
 *	1: Compressed mode.
 *	2: Variable line spacing.
 *	3: Option for hadling CRLF
 *	4: Non ASCII characters.
 *	5: Graphics escapes.
 *	6: I make an assumption that the font has a 6/10 ration, there are
 *	   better ways of doing this.
 *
 *  BUGS:
 *	1: Seems to timeout the apple laserwriter when I send large prinouts
 *	   through the tty line using no specail line controll.
 *
 *  PORTABILITY:
 *	I have not tried this anywhere else but it should be easily portable
 *	to the IBM PC with turbo or Microsoft C.
 *
 *  FILES:
 *	crlf.c:	Convert UNIX file to pc Carriage return linefeed format.
 *	epson.c: Main program.
 *	set.c: ASCII set functions, like pascal, will be used more as I write
 *		more.
 *	set.h: Include file for set handling code.
 *	makefile: Unix makefile.
 *
 */

#include	<stdio.h>
#include	"set.h" /* Set functions for characters */

#define	MAXX	480
#define	MAXY	396
#define	XSTART	0
#define	YSTART	point_sizey
#define	YSTOP	MAXY
#define	XSTOP	MAXX

#define	BNDX	(cx >= (XSTOP - point_sizex - 1))
#define	BNDY	(cy >= (YSTOP - 1))

#define	NUM_TABS	28
int tabs[NUM_TABS+1] = {8,16,32,40,48,56,64,72,80,88,96,104,112,124,
		-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};

char *printables =
" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890`,./\\[]=-!@#$%^&*()_+|{}:\"<>?~;'";
char *needesc = "()\\";

typedef enum {normal,bold,doublenorm,doublebold} _font_type;

char *font_descr[] = {"Courier","Courier-Bold","Courier","Courier-Bold"};
char *font_name[] = {"normalfont","boldfont","doublefont","doublebold"};
int font_size[][2] = {{10,10},{10,10},{5,10},{5,10}};

char_set printable_set;
char_set needesc_set;

_font_type font_type;

int cx, cy;
int point_sizex, point_sizey;

int underline = 0;
int subscript =  0;
int doublewidth = 0;
int highlight = 0;

char *start_doc[] = {
	"/saveobj1 save def",
	"/mt {moveto} def",
	"/s {show} def",
	"clippath pathbbox",
	"/ymax exch def /xmax exch def /ymin exch def /xmin exch def",
	"xmin ymax translate",
	"xmax xmin sub 480 div",
	"ymin ymax sub 396 div",
	"scale",
	"newpath",
	".5 setlinewidth",
	NULL};

char *start_page[] = {
	"/saveobj2 save def",
	NULL};

char *end_page[] = {
	"showpage",
	"saveobj2 restore",
	NULL};

char *end_doc[] = {
	"saveobj1 restore",
	"\004",
	NULL};

define_font(name,font,sizex,sizey)
char *name, *font;
	{
	printf("/%s {/%s findfont [%d 10 6 div mul 0 0 -%d 0 0] makefont setfont} def\n",name,font,sizex,sizey);
	}

new_page() {
	cx = XSTART;
	cy = YSTART;
	plist(start_page);
	set_font();
	}

set_font()
	{
	font_type = 
		(doublewidth) ?
			(highlight) ?	doublebold : doublenorm
		:	(highlight) ?	bold: normal;
	point_sizex = get_pointx(font_size[(int)font_type][0]);
	point_sizey = get_pointy(font_size[(int)font_type][1]);
	printf("%s\n",font_name[(int)font_type]);
	}

eject_page() {
	plist(end_page);
	new_page();
	}

init_sets() {
	clear_set(printable_set);
	clear_set(needesc_set);
	str_add_set(printable_set,printables);
	str_add_set(needesc_set,needesc);
	}

get_pointx(char_per_inch)
	{
	return(60/char_per_inch);
	}

get_pointy(char_per_inch)
	{
	return(60/char_per_inch);
	}

init_printer() {
	point_sizex = get_pointx(font_size[(int)normal][0]);
	point_sizey = get_pointy(font_size[(int)normal][1]);
	plist(start_doc);
	define_font(font_name[(int)normal],font_descr[(int)normal],point_sizex,point_sizey);
	define_font(font_name[(int)bold],font_descr[(int)bold],point_sizex,point_sizey);
	point_sizex = get_pointx(font_size[(int)doublenorm][0]);
	point_sizey = get_pointy(font_size[(int)doublenorm][1]);
	define_font(font_name[(int)doublenorm],font_descr[(int)doublenorm],point_sizex,point_sizey);
	define_font(font_name[(int)doublebold],font_descr[(int)doublebold],point_sizex,point_sizey);
	font_type = normal;
	new_page();
	}

plist(l)
char **l;
	{
	while (*l != NULL)
		printf("%s\n",*l++);
	}

#define	LINE_SIZE	256
char pline[256];
int ptr = 0;

char outline[258];

putline()
	{
	char *s = pline;
	int p;
	int lx;

	if (BNDY) eject_page();
	while (*s == ' ' && ptr > 0)
		{
		s++;
		ptr--;
		if (BNDX) {cx = XSTART; newline();}
		cx += point_sizex;
		}
	while (ptr>0) {
		p = 0;
		if (BNDY) eject_page();
		if (BNDX) {cx = XSTART; newline();}
		lx = cx;
		while ((lx+point_sizex-1) < XSTOP && ptr > 0) {
			if (in_set(needesc_set,*s)) outline[p++] = '\\';
			outline[p++] = *s++;
			ptr--;
			lx += point_sizex;
			}
		outline[p] = 0;
		if (p > 0) {
		   int i = strlen(outline);
		   /* Forward slash won't work at the end of a string */
		   if (outline[i-1] == '/') {
				outline[i] = ' ';
				outline[i+1] = '\0';
				}
		   if (subscript)
			if (subscript == 1) /* Subscript */
			   printf("%d %d mt gsave 1 .5 scale (%s) s grestore\n",cx,cy,outline);
			else /* Superscript */
			   printf("%d %d mt gsave 1 .5 scale (%s) s grestore\n",cx,cy-(point_sizey>>1),outline);
		   else /* Normal printing */
			printf("%d %d mt (%s) s\n",cx,cy,outline);
		   if (underline)
			printf("%d %d mt %d %d lineto stroke\n",cx,cy+1,lx-1,cy+1);
		   }
		cx = lx;
		}
		
	}

newline() {
	cy += point_sizey;
	if (BNDY) eject_page();
	}

typedef enum {S_BASE,S_ESC,S_UNDERLINE,S_SUBSCRIPT,S_DOUBLE} states;

states state = S_BASE;

dochar(c)
	{
	if (ptr >= LINE_SIZE) putline();
	switch (state) {
	   case S_UNDERLINE:
		state = S_BASE;
		if (c == '\0')	underline = 0;
		else if (c == '\1') underline = 1;
		break;
	   case S_DOUBLE:
		state = S_BASE;
		if (c == '\0')	doublewidth = 0;
		else if (c == '\1') doublewidth = 1;
		set_font();
		break;
	   case S_SUBSCRIPT:
		state = S_BASE;
		if (c == '\0') subscript = 2;
		else if (c == '\1') subscript = 1;
		break;
	   case S_ESC:
		state = S_BASE;
		switch (c)
			{
			case 'G':
				highlight = 1;
				set_font();
				break;
			case 'H':
				highlight = 0;
				set_font();
				break;
			case '-':
				state = S_UNDERLINE;
				break;
			case 'T':
				subscript = 0;
				break;
			case 'S':
				state = S_SUBSCRIPT;
				break;
			case 'W':
				state = S_DOUBLE;
				break;
			}
		break;
	   case S_BASE:
		switch(c) {
		   case '\011': {
			int i,l;

			l = cx / point_sizex + ptr;
			for (i = 0; i < NUM_TABS && tabs[i] <= l; i++);
			if (tabs[i] == -1) break;
			i = tabs[i] - l;
			while (i-- > 0) dochar(' ');
			}
			break;
		   case '\033':
			putline();
			state = S_ESC;
			break;
		   case '\014':
			putline();
			eject_page();
			break;
		   case '\n':
			putline();
			newline();
			break;
		   case '\r':
			putline();
			cx = XSTART;
			break;
		   case 26:	/* CTRL-Z */
			break;
		   default:
			if (in_set(printable_set,c)) pline[ptr++] = c;
			else pline[ptr++] = ' ';
			break;
		   }
		   break;
		}
	}

char istr[128];

main() {
	int n;
	char *p;

	init_sets();
	init_printer();
	while ((n = read(0,p = istr,128)) > 0)
		while (n--) dochar(*p++);
	if (cx > XSTART || cy > YSTART)
		plist(end_page);
	else	printf("saveobj2 restore\n");
	plist(end_doc);
	}
@//E*O*F epson.c//
chmod u=rw,g=r,o=r epson.c
 
echo x - set.h
sed 's/^@//' > "set.h" <<'@//E*O*F set.h//'
#define INTS_IN_SET	16

typedef unsigned int char_set[INTS_IN_SET];
@//E*O*F set.h//
chmod u=rw,g=r,o=r set.h
 
echo x - set.c
sed 's/^@//' > "set.c" <<'@//E*O*F set.c//'
#include "set.h"

clear_set(set)
char_set set;
	{
	int i;
	for (i = 0; i < INTS_IN_SET; i++) set[i] = 0;
	}

fill_set(set)
char_set set;
	{
	int i;
	for (i = 0; i < INTS_IN_SET; i++) set[i] = 0xffff;
	}

not_set(set)
char_set set;
	{
	int i;
	for (i = 0; i < INTS_IN_SET; i++) set[i] ^= 0xffff;
	}

and_set(set,set1)
char_set set, set1;
	{
	int i;
	for (i = 0; i < INTS_IN_SET; i++) set[i] &= set1[i];
	}

or_set(set,set1)
char_set set,set1;
	{
	int i;
	for (i = 0; i < INTS_IN_SET; i++) set[i] |= set1[i];
	}

add_set(set,c)
char_set set;
unsigned int c;
	{
	c &= 0xff;
	set[c >> 4] |= 1 << (c & 15);
	}

del_set(set,c)
char_set set;
unsigned int c;
	{
	c &= 0xff;
	set[c >> 4] &= ~(1 << (c & 15));
	}

in_set(set,c)
char_set set;
unsigned int c;
	{
	c &= 0xff;
	return ((set[c >> 4] & (1 << (c & 15))) != 0);
	}

str_add_set(set,s)
char_set set;
char *s;
	{
	unsigned int c;
	while (*s) {
		c = *s++;
		c &= 0xff;
		set[c >> 4] |= 1 << (c & 15);
		}
	}

str_del_set(set,s)
char_set set;
char *s;
	{
	unsigned int c;
	while (*s) {
		c = *s++;
		c &= 0xff;
		set[c >> 4] &= ~(1 << (c & 15));
		}
	}
@//E*O*F set.c//
chmod u=rw,g=r,o=r set.c
 
echo x - crlf.c
sed 's/^@//' > "crlf.c" <<'@//E*O*F crlf.c//'
main() {
	char ibuff[512], *ip;
	char obuff[1024];
	int ic, oc;

	while ((ic = read(0,ip = ibuff,512)) > 0) {
		oc = 0;
		while (ic--)
			if (*ip == '\n')
				{
				ip++;
				obuff[oc++] = '\r';
				obuff[oc++] = '\n';
				}
			else	obuff[oc++] = *ip++;
		write(1,obuff,oc);
		}
	}
@//E*O*F crlf.c//
chmod u=rw,g=r,o=r crlf.c
 
echo x - makefile
sed 's/^@//' > "makefile" <<'@//E*O*F makefile//'
CC=cc

all: epson crlf

epson: epson.o set.o
	$(CC) epson.o set.o -o epson

epson.o: epson.c set.h
	$(CC) -O -c epson.c

set.o: set.c set.h
	$(CC) -O -c set.c

crlf: crlf.c
	$(CC) -O crlf.c -o crlf
@//E*O*F makefile//
chmod u=rw,g=r,o=r makefile
 
exit 0