[net.sources] Sun screendump to QMS laser printer filter

uggworek@sunybcs.UUCP (Don Gworek) (12/07/86)

Here is a filter for converting Sun screendump output to
QMS quic codes.  

The filter takes advantage of the QMS data repeat commands
to reduce the printjob size by 65% on average.  From 260 kb
to 90 kb on average, for a 900 by 1152 pixel rasterfile.


-------------------------- cut here -----------------------------------
# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# screendump2qms.1 screendump2qms.c printer.h Makefile

echo x - screendump2qms.1
sed -e 's/^X//' > "screendump2qms.1" << '//E*O*F screendump2qms.1//'
X.\" @(#)screendump2qms.1	1.1 (Don Gworek) 7/19/86
X.\" This document uses the troff(1) -man macros
X.TH SCREENDUMP2QMS 1 "19 July 1986" "" "Local UNIX Programmer's Manual"
X.SH NAME
Xscreendump2qms \- filter Sun screendump output to QMS printer codes
X.SH SYNOPSIS
X.B screendump2qms
X[
X-l
X] [
Xrasterfile
X]
X.SH DESCRIPTION
XThis filter converts 
X.I screendump(1)
Xoutput to printer codes for a QMS Laser printer.  It reads
Xfrom standard input, or a file.
XThe image is printed in landscape mode.  Printjobs average 90 kb
Xfor a 900 by 1152 pixel screendump.
X.PP
XThe
X-l option
Xdisables QMS data repeat commands.  Instead, the screendump is
Xprinted in a ``long'' format, approximately 260 kb.  The option will print
Xthe same image, but the raster by raster output could piped
Xto
X.I sed(1)
Xto yield an ascii-hex bitmap.
X.SH SEE ALSO
Xscreendump(1)
X.SH AUTHOR
XDon Gworek
//E*O*F screendump2qms.1//

echo x - screendump2qms.c
sed -e 's/^X//' > "screendump2qms.c" << '//E*O*F screendump2qms.c//'
X#ifndef lint
Xstatic char rcsid[] =
X	"$Header: screendump2qms.c,v 1.1 86/08/30 22:14:33 gworek Exp $";
X#endif
X
X/*
X * screendump2qms - Filter SUN screendump into QMS quic code.
X *
X * Usage: screendump2qms [-l] [rasterfile]
X *
X * Option:
X *	-l  Don't use QMS data repeat commands.
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/file.h>
X#include <signal.h>
X
X#ifdef sun
X# include <rasterfile.h>
X#else
X# include "rasterfile.h"
X#endif
X
X#include "printer.h"
X
X#define STDIN_FDESC 0			/* stdin's file descriptor */
X#define BITSPERBYTE 8			/* number of bits per byte */
X#define TRUE 1
X#define FALSE 0
X
Xint count;				/* count of bytes read */
Xint total;				/* total to read (ras_length) */
Xint longf = FALSE;			/* Want printer codes in long format? */
X
Xchar *progname;				/* who am i? */
Xchar *inputfile;			/* where's my input from? */
X
Xunsigned char buf[BUFSIZ];		/* The input buffer */
X
Xint cleanup();
Xchar *rindex();
Xchar *ctime();
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X	int f, n;
X	struct rasterfile rh;
X
X	progname = (progname = rindex(*argv, '/')) ? ++progname : *argv;
X/*
X * Parse args
X */
X	for (argc--, argv++; (argc > 0) && (**argv == '-'); argc--, argv++)
X		switch (*++(*argv)) {
X		case 'l':
X			longf = TRUE;
X			break;
X		default:
X			usage();
X		}
X/*
X * Open the raster file, or use standard input.
X */
X	if (argc > 0) {
X		inputfile = *argv;
X		if ((f = open(*argv, O_RDONLY)) < 0) {
X			perror(*argv);
X			exit(1);
X		}
X	}
X	else {
X		inputfile = "stdin";
X		f = STDIN_FDESC;
X	}
X/*
X * Get the header information, and check that everything is okay.
X */
X	if ((n = read(f, (char *) &rh, sizeof(struct rasterfile))) < 0) {
X		perror(inputfile);
X		exit(1);
X	}
X	if (n == 0)
X		die_on_error("empty file");
X	if (rh.ras_magic != RAS_MAGIC)
X		die_on_error("bad magic number");
X	if (rh.ras_type != RT_STANDARD)
X		die_on_error("ras_type %d not RT_STANDARD", rh.ras_type);
X	if (rh.ras_maptype != RMT_NONE)
X		die_on_error("ras_maptype %d not RMT_NONE", rh.ras_maptype);
X	if (rh.ras_depth != 1)
X		die_on_error("depth %d != 1", rh.ras_depth);
X/*
X * Access, set, and check image parameters.
X */
X	total = rh.ras_length;
X	if (((rh.ras_width / BITSPERBYTE) * rh.ras_height) != rh.ras_length)
X		die_on_error("calculated data length %d != ras_length %d",
X			     ((rh.ras_width / BITSPERBYTE) * rh.ras_height),
X			     rh.ras_length);
X/*
X * Set up some cleaning up
X */
X	(void) signal(SIGHUP, cleanup);
X	(void) signal(SIGINT, cleanup);
X	(void) signal(SIGQUIT, cleanup);
X	(void) signal(SIGTERM, cleanup);
X/*
X * Set up the printer
X */
X	printf(RESETPRINTER);
X	printf(STARTPRINTER);
X	printf(MARGINSET);
X	printf(BITMAPSTART, rh.ras_width);
X/*
X * Print out in long form, or with data repeat commands?
X */
X	if (longf == TRUE)
X		printlong(f, rh.ras_width / BITSPERBYTE);
X	else
X		printrepeat(f);
X/*
X * Clean up shop
X */
X	printf(BITMAPEND);
X	printf(NEWPAGE);
X	if (count != rh.ras_length)
X		fprintf(stderr, "warning: %d bytes read != ras_length %d",
X			count, rh.ras_length);
X	(void) close(f);
X}
X
X/*
X * Print in long format.  Read a raster at a time, and print
X * it byte by byte.
X */
Xprintlong(f, rasterlen)
Xint f, rasterlen;
X{
X	int i, n;
X
X	if (rasterlen > BUFSIZ) {
X		fprintf(stderr, "%s: printlong: Internal error.  ", progname);
X		fprintf(stderr, "Increase buffer size from %d to at least %d\n",
X			BUFSIZ, rasterlen);
X		exit(1);
X	}
X	for (count=0; (n = read(f, (char *) buf, rasterlen)) > 0; count += n) {
X		for (i = 0; i < n; i++)
X			printf(DEFFORMAT, buf[i]);
X		printf("\n");
X	}
X}
X
X/*
X * Read bytes, counting repeated values.  If there are enough
X * repeats, use a data compression print command.  Otherwise,
X * print the data as is.
X */
Xprintrepeat(f)
Xint f;
X{
X	int i, n, rep;
X	unsigned char lastb;
X
X/*
X * Start things off.
X */
X	if ((n = read(f, (char *) buf, BUFSIZ)) <= 0)
X		return;
X	i = 0;
X	count = n;
X	rep = 1;
X	lastb = buf[0];
X/*
X * Read bytes until a different value is read.
X */
X	for (;;) {
X		if (++i >= n) {
X			if ((n = read(f, (char *) buf, BUFSIZ)) <= 0)
X				return;
X			i = 0;
X			count += n;
X		}
X		if (buf[i] == lastb) {
X			if (rep < MAXREPEAT) {
X				rep++;
X				continue;
X			}
X		}
X/*
X * If the byte pattern didn't repeat long enough, print out
X * that count of bytes.  Otherwise, print out the pattern
X * according to the correct repeat format.
X */
X		if (rep < MINREPEAT)
X			while (rep-- > 0)
X				printf(DEFFORMAT, lastb);
X		else
X			switch (lastb) {
X			case 0xFF:
X				printf(BITSON, 2 * rep);
X				break;
X			case 0x00:
X				printf(BITSOFF, 2 * rep);
X				break;
X			default:
X				printf(BITSOFFON, rep, lastb);
X				break;
X			}
X		lastb = buf[i];
X		rep = 1;
X	}
X}
X
X/*
X * Cleanup shop before you die
X */
Xcleanup()
X{
X	printf(BITMAPEND);
X	printf(NEWPAGE);
X	fprintf(stderr, "%s: cleaning up. read %d of %d bytes.\n",
X		progname, count, total);
X	exit(1);
X}
X
X/*
X * Print an error message with the program and input file names,
X * and then die.
X */
X
X/* VARARGS */
Xdie_on_error(mesg, arg1, arg2)
Xchar *mesg;
X{
X	fprintf(stderr, "%s: %s: ", progname, inputfile);
X	fprintf(stderr, mesg, arg1, arg2);
X	fprintf(stderr, ".\n");
X	exit(1);
X}
X
X/*
X * How do you use this darn thing anyway?
X */
Xusage()
X{
X	fprintf(stderr, "Usage: %s [-l] [rasterfile]", progname);
X	exit(1);
X}
//E*O*F screendump2qms.c//

echo x - printer.h
sed -e 's/^X//' > "printer.h" << '//E*O*F printer.h//'
X/*
X * $Header: printer.h,v 1.6 86/07/19 12:47:17 gworek Exp $
X */
X
X/*
X * QMS quic code sequences are defined here
X */
X
X#define RESETPRINTER	"ReSeTrEsEtReSeT\n"
X#define STARTPRINTER	"^PY^-\n^F^ISYNTAX00000^ISTF00\n"
X#define MARGINSET	"^IOL^IJ01000^IT01000\n"
X#define BITMAPSTART	"^T00000^J00000^IP0202^P%04d\n"
X#define MINREPEAT	3
X#define MAXREPEAT	499			/* half of 999 */
X#define BITSON		"^B%03d"
X#define BITSOFF		"^D%03d"
X#define BITSOFFON	"^C%03d%02X"
X#define DEFFORMAT	"%02X"
X#define LO4MASK		0x0F
X#define HI4MASK		0xF0
X#define BITMAPEND	"^G\n"
X#define NEWPAGE		"^,\n"
//E*O*F printer.h//

echo x - Makefile
sed -e 's/^X//' > "Makefile" << '//E*O*F Makefile//'
X#
X# $Header: Makefile,v 1.6 86/07/19 16:53:52 gworek Exp $
X#
X# SUN screendump print filter for the QMS
X
XSRCS =	screendump2qms.c
XOBJS =	screendump2qms.o
XHDRS =	printer.h
XDEST =	screendump2qms
XINSTALLDIR = /usr/local/bin
X
XDFLAGS =
XCFLAGS = -O -s ${DFLAGS}
X
X${DEST}: ${OBJS}
X	cc ${CFLAGS} -o ${DEST} ${OBJS}
X
X${OBJS}: ${HDRS}
X
Xinstall:
X	install ${DEST} ${INSTALLDIR}
X
Xclean:
X	/bin/rm -f *.o ${DEST}
X
Xlint: ${HDRS} ${SRCS}
X	lint ${DFLAGS} ${SRCS}
//E*O*F Makefile//

exit 0