[comp.sys.next] Scanning images for the NeXT

epsilon@wet.UUCP (Eric P. Scott) (09/16/89)

Oh boy!  Another quick and dirty TIFF hack!  (Very quick, very
dirty.)

Situation: we have an Apple flatbed Scanner (and the AppleScan
software) we've been using for DTP.  One of the things that held
up moving DTP off the Macintoshes was the inability to scan
images for inclusion in NeXT documents.  No longer.
And we can now see our faces appear in the Mail utility!  :-)


The AppleScan program is capable of saving images as 4-bit
grayscale TIFF.  Unfortunately, the NeXT isn't too happy with
these in their native form (under 0.9, anyway).  The attached
program converts these to Encapsulated PostScript that can be
pasted into WriteNow (or used by Draw, Scene, what-have-you).

Since scan files can be quite large (1.5MB is not unusual), we
use an Ethernet interface in the Macintosh II and NCSA Telnet
2.3 to FTP images to the NeXT.

This code is furnished as-is, etc.
It's not meant to be portable.

Compile:
	cc -O -o tifftoeps -s -bsd tifftoeps.c
Use:
	tifftoeps whatever.tiff >whatever.eps

					-=EPS=-
------- tifftoeps.c
/*
 * tifftoeps - convert AppleScanned .tiff file to EPSF
 * Eric P. Scott, San Francisco State University, September 1989
 *
 * Disclaimer: this is a cheap hack; it does not attempt to
 * handle arbitrary .tiff files, nor does it make use of all the
 * information available to it.  In particular, the XResolution
 * and YResolution tags are ignored.  Heck, it doesn't even
 * accept little-endian TIFF...
 *
 * Future versions may (will?) support other kinds of scanners.
 *
 */
#include <stdio.h>
static char sccsid[]="@(#)tifftoeps   1.0  (SFSU)  9/15/89";
int iwidth=0, ilen=0, bits=0, invert=255;
long stripoff=0L;
main(argc, argv)
int argc;
char *argv[];
{
	char *malloc();
	register int i;
	register long value;
	long sig, ifdoff;
	short ifditems;
	struct ifdent {
		short ifd_tag;
		short ifd_type;
		long ifd_len;
		union {
			unsigned long ifd_long;
			unsigned short ifd_short;
			unsigned char ifd_byte;
		} ifd_off;
	} *ifdp;

	if (argc!=2) {
		fprintf(stderr, "Usage: %s tiff-file\n", *argv);
		exit(1);
	}
	if (strcmp(argv[1], "-")&&!freopen(argv[1], "r", stdin)) {
		perror(argv[1]);
		exit(1);
	}
	if (fread((char *)&sig, sizeof sig, 1, stdin)!=1) {
		perror("fread");
		exit(1);
	}
	if (sig!=0x4d4d002a) {
		fprintf(stderr, "%s: that's not a TIFF file!\n", *argv);
		exit(1);
	}
	if (fread((char *)&ifdoff, sizeof ifdoff, 1, stdin)!=1) {
		perror("fread");
		exit(1);
	}
	if (fseek(stdin, ifdoff, 0)<0L) {
		perror("fseek");
		exit(1);
	}
	if (fread((char *)&ifditems, sizeof ifditems, 1, stdin)!=1) {
		perror("fread");
		exit(1);
	}
	if (!(ifdp=(struct ifdent *)malloc(ifditems*sizeof (struct ifdent)))) {
		perror("malloc");
		exit(1);
	}
	if (fread((char *)ifdp, sizeof (struct ifdent), ifditems, stdin)!=
		ifditems) {
		perror("fread");
		exit(1);
	}
	for (i=0;i<ifditems;i++) {
		switch (ifdp->ifd_type) {
		case 1:
			value=ifdp->ifd_off.ifd_byte;
			break;
		case 3:
			value=ifdp->ifd_off.ifd_short;
			break;
		case 4:
			value=ifdp->ifd_off.ifd_long;
			break;
		default: /* ifdp->ifd_off.ifd_long is offset */
			value=0L;	/* do The Wrong Thing(tm) */
			break;
		}
		switch (ifdp->ifd_tag) {
		case 256:	/* ImageWidth */
			iwidth=value;
			break;
		case 257:	/* ImageLength */
			ilen=value;
			break;
		case 258:	/* BitsPerSample */
			bits=value;
			break;
		case 259:	/* Compression */
			if (value!=1) {
				fprintf(stderr, "%s: Compression=%ld\n",
					*argv, value);
				exit(1);
			}
			break;
		case 262:	/* PhotometricInterpretation */
			switch (value) {
			case 0:
				invert=255;
				break;
			case 1:
				invert=0;
				break;
			default:
				fprintf(stderr,
"%s: PhotometricInterpretation=%ld\n", *argv, value);
				if (value==5) fputs("\tI don't grok alpha\n",
					stderr);
				exit(1);
				break;
			}
			break;
		case 273:
			stripoff=value;
			break;
		case 277:	/* SamplesPerPixel */
			if (value!=1) {
				fprintf(stderr, "%s: SamplesPerPixel=%ld\n",
					*argv, value);
				exit(1);
			}
			break;
#ifdef NOTDEF
		case 284:	/* PlanarConfiguration */
			break;
#endif
		default:
			break;
		}
		ifdp++;
	}
	if (iwidth<=0L) {
		fprintf(stderr, "%s: missing ImageWidth\n", *argv);
		exit(1);
	}
	if (ilen<=0L) {
		fprintf(stderr, "%s: missing ImageLength\n", *argv);
		exit(1);
	}
	if (bits<=0L) {
		fprintf(stderr, "%s: missing BitsPerSample\n", *argv);
		exit(1);
	}
	if (stripoff<=0L) {
		fprintf(stderr, "%s: missing StripOffsets\n", *argv);
		exit(1);
	}
	if (fseek(stdin, stripoff, 0L)<0L) {
		perror("fseek");
		exit(1);
	}
	fputs("%!PS-Adobe-2.0 EPSF-1.2\n%%Creator:tifftoeps\n\
%%Origin:0 720\n%%BoundingBox: 0 0 ", stdout);
	printf("%d %d", iwidth, ilen);
	fputs("\n%%EndComments\n/picstr ", stdout);
	printf("%ld", ((long)iwidth*bits+7L)/8L);
	fputs(" string def\ngsave\n0 0 translate\n1 1 scale\n", stdout);
	printf("%d %d scale\n%d %d %d\n", iwidth, ilen, iwidth, ilen, bits);
	printf("[%d 0 0 %d neg 0 %d]\n", iwidth, ilen, ilen);
	fputs("{currentfile picstr readhexstring pop}\nimage", stdout);
	sig=(((long)iwidth*bits+7L)/8L)*ilen;
	value=0L; while ((i=getchar())!=EOF) {
		if (value>=sig) break;
		if ((value&31)==0) putchar('\n');
		printf("%02X", i^invert);
		value++;
	}
	fputs("\n\n\ngrestore\n", stdout);
	exit(0);
}