[comp.sys.next] mpnttotiff.c--another Mac-to-NeXT transition tool

eps@toaster.SFSU.EDU (Eric P. Scott) (10/25/90)

This is something to help us move local documentation production
from Macintoshes to the NeXT's superior DTP software and laser
printer (toner cartridges cost significant $$$, no point wasting
them on draft-quality output).  Since the resulting TIFF file is
usually "too big" to be directly useful, you probably want to
open it in Icon and save a selection from it.

Note that this only deals with B&W images in MacPaint format.
It won't meet everyone's needs, but you don't need any special
screen capture software on the Mac, either.  (This should
properly be named pntgtotiff, since PNTG is the file type,
but MPNT is more memorable.)

N.B.: this code has big-endian architecture dependencies, but no
NeXT software dependencies; e.g. it compiles and runs properly
under A/UX as well.

					-=EPS=-
-------
/* Convert Macintosh screen shot (MPNT/PNTG) to NeXT TIFF
 * Eric P. Scott, San Francisco State University, October 1990
 *
 * This input for this is the data fork of a Mac file created
 * with Command-Shift-3
 *
 * "For more information see"
 *   Tag Image File Format Specification, Revision 5.0
 *   Macintosh Technical Note #86, MacPaint Document Format
 *   Macintosh Technical Note #171, _PackBits Data Format
 *
 * Small-screen Macs (e.g. SEs) save in the normal orientation
 * Large-screen Macs (e.g. IIs) rotate their bitmap--use -r option
 *
 * To compile:
 * cc -s -o mpnttotiff -O -bsd mpnttotiff.c -lsys_s
 */
#include <stdio.h>
#ifndef lint
static char sccsid[]="@(#)mpnttotiff  1.0  (SFSU) 10/24/90";
#endif

struct {
	long tiff_magic, tiff_firstifd;
	short tiff_ifdents;
	struct ifdent {
		short ifd_tag, ifd_type;
		long ifd_len, ifd_off;
	} tiff_ifd[8];
	long tiff_ifdchain;
} header={	/* warning: nonportable */
	0x4d4d002aL, 8L, 8, {
		{ 255, 3, 1L, 1L<<16 },		/* SubfileType */
		{ 256, 3, 1L, 720L<<16 },	/* ImageWidth */
		{ 257, 3, 1L, 576L<<16 },	/* ImageLength */
		{ 262, 3, 1L, 1L<<16 },		/* PhotometricInterpretation */
		{ 277, 3, 1L, 1L<<16 },		/* SamplesPerPixel */
		{ 284, 3, 1L, 2L<<16 },		/* PlanarConfiguration */
		{ 258, 3, 1L, 1L<<16 },		/* BitsPerSample */
		{ 273, 4, 1L, 110L }		/* StripOffsets */
	}, 0L
};
int rotate=0;

main(argc, argv)
int argc;
char *argv[];
{
	extern int optind;
	extern char *optarg;
	register unsigned char *q, *p;
	int c;
	long lbuf[12960];	/* space for 576x720x1 image */

	while ((c=getopt(argc, argv, "r"))!=EOF) switch (c) {
	case 'r':
		rotate++;
		break;
	default:
	usage:
		(void)fprintf(stderr, "Usage: %s [-r] paint-file tiff-file\n",
			*argv);
		(void)fputs("\t-r  rotate 90 degrees counterclockwise\n",
			stderr);
		exit(1);
		break;
	}

	if (argc-optind!=2) goto usage;
	if (strcmp(argv[optind], "-")&&!freopen(argv[optind], "r", stdin)) {
		perror(argv[optind]);
		exit(1);
	}
	(void)fread((char *)lbuf, 512, 1, stdin);
	if (*lbuf!=0L) {
		(void)fprintf(stderr,
			"%s: input isn't in a format I can deal with\n",
			*argv);
		exit(1);
	}

	p=(unsigned char *)&lbuf[sizeof lbuf/sizeof lbuf[0]];
	q=(unsigned char *)lbuf;
	bzero((char *)q, sizeof lbuf);
	while ((c=getchar())!=EOF) {	/* UnPackBits */
		/* I'm cheating: you're supposed to do this a row at a time */
		register int b;

		if ((c&=255)<=127) {
			do {
				if (q>=p) {
				ovfl:
					(void)fprintf(stderr,
"%s: internal buffer overflow\n", *argv);
					exit(1);
				}
				if ((b=getchar())==EOF) {
				tooshort:
					(void)fprintf(stderr,
"%s: EOF in sequence\n", *argv);
					exit(1);
				}
				*q++=b;
			} while (--c>=0);
		}
		else {
			c-=256;
			if ((b=getchar())==EOF) goto tooshort;
			do {
				if (q>=p) goto ovfl;
				*q++=b;
			} while (++c<=0);
		}
	}

	if (strcmp(argv[++optind], "-")&&!freopen(argv[optind], "w", stdout)) {
		perror(argv[optind]);
		exit(1);
	}
	if (!rotate) {	/* swap dimensions */
		header.tiff_ifd[1].ifd_off=576L<<16;
		header.tiff_ifd[2].ifd_off=720L<<16;
	}
	(void)fwrite((char *)&header, sizeof header, 1, stdout);

	if (rotate) {	/* rotate 90 degrees clockwise and invert */
		long obuf[180];

		p=(unsigned char *)&lbuf[12816];
		c=72; do {
			register int r;

			q=(unsigned char *)obuf;
			bzero((char *)q, sizeof obuf);
			r=90; do {
#define twist(m) \
	if ((*p&m)==0) *q=1; \
	if ((p[72]&m)==0) *q|=2; \
	if ((p[144]&m)==0) *q|=4; \
	if ((p[216]&m)==0) *q|=8; \
	if ((p[288]&m)==0) *q|=16; \
	if ((p[360]&m)==0) *q|=32; \
	if ((p[432]&m)==0) *q|=64; \
	if ((p[504]&m)==0) *q|=128
				twist(128); q+=90;
				twist(64); q+=90;
				twist(32); q+=90;
				twist(16); q+=90;
				twist(8); q+=90;
				twist(4); q+=90;
				twist(2); q+=90;
				twist(1); q-=629;
				p-=576;
			} while (--r>0);
			(void)fwrite((char *)obuf, sizeof obuf, 1, stdout);
			p+=51841;	/* 1+sizeof lbuf */
		} while (--c>0);
	}
	else {	/* just invert */
		p=(unsigned char *)&lbuf[sizeof lbuf/sizeof lbuf[0]];
		q=(unsigned char *)lbuf;
		do {
			putchar(*q++^255);
		} while (q<p);
	}
	(void)fflush(stdout);
	exit(0);
}