[comp.sources.misc] Sun rasterfile -> PostScript converter

frew@huevos.UUCP (Jim Frew) (09/09/87)

Submission for comp.sources.misc:

"suntops" converts Sun rasterfiles to PostScript images, which may then be
spooled to a PostScript printer.  For example:

	screendump | suntops | lpr

prints an image of your screen.

suntops has been developed on a Sun-3/50 running Sun UNIX release 3.4, with
Adobe TranScript software driving an Apple LaserWriter Plus over a 9600 baud
RS232 connection.  Note that with a 9600 baud connection, it takes about 5
minutes for the LaserWriter to receive and process a full Sun screen dump
(1152 by 900 pixels).

I believe you get something similar to suntops when you buy TranScript
directly from Sun (we didn't).

Enjoy,

James Frew
CRSEO				ARPA:	frew%huevos@hub.ucsb.edu
University of California	UUCP:	{pyramid,sdcsvax,ucbvax}!ucsbcsl!frew
Santa Barbara, CA  93106	voice:	805-961-2309

"shar" archive follows:

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Makefile
#	error.c
#	main.c
#	suntops.1
#	suntops.c
#	suntops.h
# This archive created: Fri Sep  4 10:57:17 1987
# By:	Jim Frew ()
export PATH; PATH=/bin:$PATH
echo shar: extracting "'Makefile'" '(534 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
XPGM	= suntops
XSRCS	= error.c main.c suntops.c
XHDRS	= suntops.h
XOBJS	= error.o main.o suntops.o
XMAN	= suntops.1
X
XCFLAGS	= -O
XLDFLAGS	=
XLIBS	=
XBINDIR	= /usr/local/bin
XBINMODE	= 755
XMANDIR	= /usr/local/man/man1
XMANMODE	= 444
XLINTFLAGS = -chapb
X
X$(PGM): $(OBJS)
X	$(CC) $(LDFLAGS) -o $(PGM) $(OBJS) $(LIBS)
X
Xinstall: $(PGM) $(MAN)
X	strip $(PGM)
X	mv $(PGM) $(BINDIR)
X	chmod $(BINMODE) $(BINDIR)/$(PGM)
X	cp $(MAN) $(MANDIR)
X	chmod $(MANMODE) $(MANDIR)/$(MAN)
X
Xclean:
X	rm -f $(PGM) $(OBJS)
X
Xlint:
X	lint $(LINTFLAGS) $(SRCS)
X
X$(OBJS): $(HDRS)
SHAR_EOF
if test 534 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 534 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'error.c'" '(225 characters)'
if test -f 'error.c'
then
	echo shar: will not over-write existing file "'error.c'"
else
sed 's/^X//' << \SHAR_EOF > 'error.c'
X/*
X * error -- print error message and exit
X */
X
X#include <stdio.h>
X
Xextern int      errno;
X
Xvoid
Xerror(s)
X	char           *s;
X{
X	if (errno != 0) {
X		perror(s);
X	}
X	else {
X		(void) fprintf(stderr, "%s\n", s);
X	}
X
X	exit(1);
X}
SHAR_EOF
if test 225 -ne "`wc -c < 'error.c'`"
then
	echo shar: error transmitting "'error.c'" '(should have been 225 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'main.c'" '(1087 characters)'
if test -f 'main.c'
then
	echo shar: will not over-write existing file "'main.c'"
else
sed 's/^X//' << \SHAR_EOF > 'main.c'
X/*
X * main -- driver for suntops
X */
X
X#include <stdio.h>
X
Xextern double   atof();
Xextern char    *optarg;
Xextern int      optind;
X
X#include "suntops.h"
X
Xmain(argc, argv)
X	int             argc;
X	char          **argv;
X{
X	FILE           *fpi;
X	int             opt;
X	double          height;
X	int             rotate;
X	double          width;
X
X	rotate = FALSE;
X	height = IMG_HEIGHT;
X	width = IMG_WIDTH;
X
X	while ((opt = getopt(argc, argv, "h:rw:")) != EOF) {
X		switch (opt) {
X
X		case 'r':
X			rotate = TRUE;
X			break;
X
X		case 'h':
X			height = atof(optarg);
X			if (height <= 0.0 || height > PAGE_HEIGHT) {
X				error("-h: bad height");
X			}
X
X			break;
X
X		case 'w':
X			width = atof(optarg);
X			if (width <= 0.0 || width > PAGE_WIDTH) {
X				error("-w: bad width");
X			}
X
X			break;
X
X		default:
X			error(
X			 "Usage: suntops [-r] [-h height] [-w width] [file]"
X				);
X		}
X	}
X
X	if (argv[optind] == NULL) {
X		fpi = stdin;
X	}
X	else {
X		fpi = fopen(argv[optind], "r");
X		if (fpi == NULL) {
X			error(argv[optind]);
X		}
X	}
X
X	suntops(fpi, PAGE_HEIGHT, PAGE_WIDTH, height, width, rotate, stdout);
X
X	exit(0);
X}
SHAR_EOF
if test 1087 -ne "`wc -c < 'main.c'`"
then
	echo shar: error transmitting "'main.c'" '(should have been 1087 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'suntops.1'" '(1467 characters)'
if test -f 'suntops.1'
then
	echo shar: will not over-write existing file "'suntops.1'"
else
sed 's/^X//' << \SHAR_EOF > 'suntops.1'
X.TH SUNTOPS 1 "29 August 1987"
X.SH NAME
Xsuntops \- convert Sun rasterfile to PostScript
X.SH SYNOPSIS
X.B suntops
X.RB [ \-r ]
X.RB [ \-h
X.IR height ]
X.RB [ \-w
X.IR width ]
X.RI [ file ]
X.SH DESCRIPTION
X.I Suntops
Xconverts a Sun rasterfile to a PostScript image.
XThe rasterfile is read from either the standard input or the specified
X.IR file .
XThe PostScript image is written to the standard output.
X.SH OPTIONS
X.TP
X.B \-r
XRotate the PostScript output 90 degrees.
XUseful for printing landscape-mode rasterfiles (e.g. Sun
X.IR screendump s)
Xon portrait-mode printers (e.g. Apple LaserWriters).
X.TP
X.B \-h
XSet the maximum output image height to
X.I height
Xinches (default 9).
X.TP
X.B \-w
XSet the maximum output image width to
X.I width
Xinches (default 7.5).
X.SH EXAMPLES
XTo print the current Sun screen:
X.IP
Xscreendump\ |\ suntops \-r\ |\ lpr \-PPostScript
X.SH DIAGNOSTICS
X\*(lqself-explanatory\*(rq
X.SH RESTRICTIONS
XInput rasterfiles must be either 1 bit or 8 bits deep.
X.SH FUTURE DIRECTIONS
XSpecify page size on the command line.
X.PP
XAllow a \*(lqraw\*(rq output mode whereby the PostScript output is scaled to
Xexactly match the resolution of a specific printer.
XThis is supposed to print significantly faster.
X.PP
XProvide an alternative driver routine so that
X.I suntops
Xmay be invoked as
Xa line printer filter,
Xe.g.:
X.IP
Xlpr \-PPostScript \-v
X.SH AUTHOR
XJames Frew.
X.PP
XPlease send bug reports,
Xfixes,
Xor enhancements to frew@hub.ucsb.edu
Xor
Xucbvax!ucsbcsl!frew.
X.SH BUGS
SHAR_EOF
if test 1467 -ne "`wc -c < 'suntops.1'`"
then
	echo shar: error transmitting "'suntops.1'" '(should have been 1467 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'suntops.c'" '(4157 characters)'
if test -f 'suntops.c'
then
	echo shar: will not over-write existing file "'suntops.c'"
else
sed 's/^X//' << \SHAR_EOF > 'suntops.c'
X/*
X * suntops -- convert Sun rasterfile to PostScript image
X */
X
X#include <assert.h>
X#include <rasterfile.h>
X#include <stdio.h>
X
X#include "suntops.h"
X
Xstatic void
Xxch(a, b)
X	double         *a;
X	double         *b;
X{
X	double          temp;
X
X	temp = *a;
X	*a = *b;
X	*b = temp;
X}
X
Xvoid
Xsuntops(fpi, h_page, w_page, h_img, w_img, rotate, fpo)
X	register FILE  *fpi;		/* rasterfile stdio pointer	 */
X	double          h_page;		/* PostScript page height	 */
X	double          w_page;		/* PostScript page width	 */
X	double          h_img;		/* PostScript image height	 */
X	double          w_img;		/* PostScript image width	 */
X	int             rotate;		/* ? rotate output image 90 deg	 */
X	register FILE  *fpo;		/* PostScript stdio pointer	 */
X{
X	int             hexdig[16];	/* hexadecimal digit map	 */
X	double          aspect;		/* rasterfile aspect ratio	 */
X	register int    byte;		/* current rasterfile data byte	 */
X	register int   *hexp;		/* fast pointer to hexdig array	 */
X	struct rasterfile ras;		/* rasterfile header		 */
X
X /*
X  * read rasterfile header
X  */
X /* NOSTRICT */
X	if (fread((char *) (&ras), sizeof(ras), 1, fpi) != 1) {
X		error("can't read rasterfile header");
X	}
X
X	if (ras.ras_magic != RAS_MAGIC) {
X		error("input is not a Sun rasterfile");
X	}
X /*
X  * compute rasterfile aspect ratio
X  */
X	if (rotate) {
X		xch(&h_img, &w_img);
X		xch(&h_page, &w_page);
X	}
X
X	aspect = ras.ras_width;
X	aspect /= ras.ras_height;
X /*
X  * adjust PostScript image size to preserve aspect ratio
X  */
X	if (aspect >= w_img / h_img) {
X		h_img = w_img / aspect;
X	}
X	else {
X		w_img = h_img * aspect;
X	}
X
X	assert(h_page >= h_img);
X	assert(w_page >= w_img);
X /*
X  * rasterfile lines are padded to a multiple of 16 bits (see rasterfile(5));
X  * adjust rasterfile line length accordingly
X  * 
X  * initialize integer -> hexadecimal digit mapping
X  */
X	switch (ras.ras_depth) {
X
X	case 1:
X		if (ras.ras_width % 16 != 0) {
X			ras.ras_width += 16 - ras.ras_width % 16;
X		}
X /*
X  * Sun black/white bitmap convention is opposite of PostScript, so reverse
X  * int->hex map
X  */
X		hexdig[0] = 'f';
X		hexdig[1] = 'e';
X		hexdig[2] = 'd';
X		hexdig[3] = 'c';
X		hexdig[4] = 'b';
X		hexdig[5] = 'a';
X		hexdig[6] = '9';
X		hexdig[7] = '8';
X		hexdig[8] = '7';
X		hexdig[9] = '6';
X		hexdig[10] = '5';
X		hexdig[11] = '4';
X		hexdig[12] = '3';
X		hexdig[13] = '2';
X		hexdig[14] = '1';
X		hexdig[15] = '0';
X
X		break;
X
X	case 8:
X		ras.ras_width += ras.ras_width & 1;
X /*
X  * normal int->hex map
X  */
X		hexdig[0] = '0';
X		hexdig[1] = '1';
X		hexdig[2] = '2';
X		hexdig[3] = '3';
X		hexdig[4] = '4';
X		hexdig[5] = '5';
X		hexdig[6] = '6';
X		hexdig[7] = '7';
X		hexdig[8] = '8';
X		hexdig[9] = '9';
X		hexdig[10] = 'a';
X		hexdig[11] = 'b';
X		hexdig[12] = 'c';
X		hexdig[13] = 'd';
X		hexdig[14] = 'e';
X		hexdig[15] = 'f';
X
X		break;
X
X	default:
X		error("bad rasterfile depth");
X	}
X /*
X  * PostScript header
X  */
X	(void) printf("%%!\n");
X /*
X  * if "rotate" set then rotate PostScript image 90 degrees
X  */
X	if (rotate) {
X		(void) printf("90 rotate\n");
X		(void) printf("0 -%d translate\n", ITOP(h_page));
X	}
X /*
X  * center the PostScript image on the output page
X  */
X	(void) printf("%d %d translate\n",
X		      ITOP(((w_page - w_img) / 2.0) + XTRANS_FUDGE),
X		      ITOP((h_page - h_img) / 2.0));
X	(void) printf("%d %d scale\n", ITOP(w_img), ITOP(h_img));
X /*
X  * I/O buffer for readhexstring
X  */
X	(void) printf("/linebuf %d string def\n",
X		ras.ras_width / (8 / ras.ras_depth));
X /*
X  * set PostScript image parameters
X  */
X	(void) printf("%ld %ld %d\n",
X		      ras.ras_width, ras.ras_height, ras.ras_depth);
X	(void) printf("[%ld 0 0 -%ld 0 %ld]\n",
X		      ras.ras_width, ras.ras_height, ras.ras_height);
X	(void) printf("{currentfile linebuf readhexstring pop}\n");
X /*
X  * image data follows
X  */
X	(void) printf("image\n");
X /*
X  * convert rasterfile bytes to pairs of ASCII hexadecimal digits
X  */
X	hexp = hexdig;
X
X	while ((byte = getc(fpi)) != EOF) {
X		putc(hexp[HI_NYBBLE(byte)], fpo);
X		putc(hexp[LO_NYBBLE(byte)], fpo);
X	}
X
X	if (ferror(fpi)) {
X		error("input error");
X	}
X
X	if (ferror(fpo)) {
X		error("output error");
X	}
X /*
X  * display PostScript image on output device
X  */
X	(void) fprintf(fpo, "showpage\n");
X}
SHAR_EOF
if test 4157 -ne "`wc -c < 'suntops.c'`"
then
	echo shar: error transmitting "'suntops.c'" '(should have been 4157 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'suntops.h'" '(410 characters)'
if test -f 'suntops.h'
then
	echo shar: will not over-write existing file "'suntops.h'"
else
sed 's/^X//' << \SHAR_EOF > 'suntops.h'
X/*
X * suntops.h -- header file for suntops program
X */
X
X#define	PAGE_HEIGHT	11.0
X#define	PAGE_WIDTH	8.5
X
X#define	IMG_HEIGHT	9.0
X#define	IMG_WIDTH	7.5
X
X#define	ITOP(in)	( (int)((in) * 72.0) )
X
X#define	XTRANS_FUDGE	(1.0 / 16.0)	/* LaserWriter X bias		 */
X
X#define	HI_NYBBLE(i)	( ((i) >> 4) & 0xF )
X#define	LO_NYBBLE(i)	( (i) & 0xF )
X
X#define	TRUE		1
X#define	FALSE		0
X
Xextern void	error();
Xextern void	suntops();
SHAR_EOF
if test 410 -ne "`wc -c < 'suntops.h'`"
then
	echo shar: error transmitting "'suntops.h'" '(should have been 410 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0