home *** CD-ROM | disk | FTP | other *** search
- /* convert from MacPaint document to a form that can be printed on the
- Symbolics LGP-1 laser printer
-
- This program should work with MacPaint and Screen dump files (made by
- COMMAND-SHIFT-3). However, it does not work with MacWrite files.
-
- This program was written for Berkeley Unix, version 4.2, running on a
- VAX.
-
- Options:
- -h turn off halftoning
- -m <n> where <n> is between 1 and 4. This is an indication
- of how much to magnify (and is called the "magfactor")
-
- Written by Richard Furuta, Computer Science, University of Washington.
- (July 26, 1984)
-
- Please report changes and fixes back to me. By Arpanet and CSNet,
- I am Furuta@Washington. By uucp, I am ihnp4!uw-beaver!furuta. I
- prefer the Arpanet/CSNet address.
-
- I benefitted greatly from Ed Pattermann's code for macimp. The
- following description of the MacPaint font format comes from that
- code.
-
- =============
-
- First, the Macintosh file ; This format is the common
- interchange format for full-page bitmap images on the Macintosh.
-
- The first 512 bytes of the file are the header. The first four bytes
- comprise the version number, followed by 38*8 = 304 bytes of
- patterns. The remaining 204 bytes of the header are reserved for
- future expansion. If the version number is zero, the patterns are
- ignored. Hence, programs that wish to create files to be read into
- MACpaint can just write out 512 bytes of zero as the header.
-
- Following the header are 720 compressed scanlines of data which form
- the 576 wide by 720 tall bitmap. The bitmap is compressed as follows ;
- Any run of three or more equal bytes is compressed into a count byte
- and a single data byte. Runs of unequal bytes are passed on literally,
- preceded also by a count byte. i.e.
-
- <count byte> <data byte>
- count = -1..-127 --> replicate byte 2..128 times
- <count byte> <n data bytes>
- count = 0.. 127 --> copy 1..128 bytes uncompressed
- count = -128 ignored for backward compatibility
-
- =============
-
- This program produces a series of LGP "Define a Block of Raster Data"
- commands which are used to produce a dump of the screen. You have to be
- careful about the syntax of the arguments to this command. I had a bit of
- trouble caused by forgetting that the byte ordering and bit ordering of the
- raster words given to this command differ from those of the parameters to
- the command. I could have used the "Screen Dump" LGP command instead of
- this command to dump the raster. The advantage would have been that the
- resolution of the device would have been halved probably eliminating the
- need to half tone. The disadvantage is that it is harder to support the
- magnification factor of 3 that seems to make the most sense to me.
-
- An arbitrary magnification is used to blow up the figure in both dimensions
- (x and y). This is controlled by "magfactor" which should be at least one.
- If it gets larger than 4, you'll have to expand the amount of storage given
- to "outline" in procedure "makebitmap". I try detect and skip blank scan
- lines to help conserve bandwidth to the printer which is pretty horrid at
- 9600 baud. Maybe one of these days our DR11/C interface will work again and
- bandwidth won't be such a problem!
-
- */
-
- #include <stdio.h>
-
- #define TRUE 1
- #define FALSE 0
- #define LGPESC 27 /* flags LGP command to the LGP */
-
- /* for command line option processing */
- char *ProgName;
- extern char *optarg;
- extern int optind;
-
- int checkwhite();
- int dolgpheader();
- char flipbits();
- int intoout();
-
- /* a macpaint document in the worst case should occupy twice as many bytes
- as a straight screen dump. This pathological case comes when you have
- only count bytes of 1. Since the Mac screen is 576 x 720 bits or
- 72 x 720 bytes == 51840 bytes, this worst case would occupy 103680
- bytes */
- char compressed[103680]; /* lookahead storage for input */
- int nextcompbyte; /* next index into this array */
-
- int whitestateflg; /* TRUE if we last looked at a blank line */
-
- /* The LGP washes out large black areas. As an attempt to address this,
- I'm trying to halftone the output */
-
- #define DMASK 0377 /* 11111111 pass everything through */
- #define EMASK 0252 /* 10101010 even bits only */
- #define OMASK 0125 /* 01010101 odd bits only */
- char curmask; /* the current one to use */
- int hflg; /* TRUE if we want to halftone */
-
- main(argc, argv)
- int argc;
- char **argv;
- {
- int optch; /* option character */
- int ctr; /* temporary counter */
- int scanctr; /* count the 720 scan lines */
- int byte; /* incoming information */
- int countbyte; /* gives meaning of subsequent input bytes */
- int linebytecount; /* how many bytes seen so far on
- input? 0..71 */
- int magfactor; /* how many times do you want to expand
- this? 1..4 */
- int linecount; /* how many lines in this current spread? */
- int lgptop; /* top of this lgp line */
- int linestart; /* when collecting a line, recall where it
- all began */
- int laststate; /* to allow detection of change */
-
- magfactor = 3; /* by default, show at true size */
- curmask = DMASK; /* by default, in case no halftoning is set */
- hflg = TRUE; /* by default, halftoning */
-
- ProgName = *argv;
-
- /* grab some options */
- while ((optch = getopt (argc, argv, "hm:")) != EOF) {
- switch (optch) {
- case 'h': /* want halftoning */
- hflg = FALSE;
- curmask = DMASK; /* unnecessary but for safety... */
- break;
- case 'm': /* magnification factor */
- magfactor = atoi(optarg);
- break;
- case '?':
- fprintf(stderr, "Usage: %s [-m magfactor]\n",
- ProgName);
- (void)fflush(stderr);
- exit(1); /* a bit harsh, but ... */
- }
- }
- if((magfactor < 1) || (magfactor > 4)) {
- fprintf(stderr, "%s: Sorry, magfactor can't be %d, must be between 1 and 4\n",
- ProgName, magfactor);
- exit(1);
- }
-
- /* jump over the 512 bytes of header */
- for(ctr=0; ctr < 512; ctr++)
- byte = getc(stdin);
-
- nextcompbyte = 0;
- whitestateflg = TRUE;
- linecount = 0;
- lgptop = 240 * 10; /* leave an inch at the very top */
-
- /* for each scan line */
- for(scanctr=0; scanctr < 720; scanctr++) {
- linebytecount = 0;
-
- linestart = nextcompbyte;
- linecount++;
- laststate = whitestateflg;
-
- /* capture incoming line, producing the output line */
- while(linebytecount < 72) {
- countbyte = getc(stdin) & 0377; /* count byte */
- compressed[nextcompbyte++] = countbyte;
- if(countbyte > 127) {
- /* replicated bytes follow */
- countbyte = 256-countbyte+1;
- byte = getc(stdin) & 0377;
- compressed[nextcompbyte++] = byte;
- }
- else {
- /* unreplicated bytes follow */
- countbyte++;
- for(ctr = 0; ctr < countbyte; ctr++) {
- byte = getc(stdin) & 0377;
- compressed[nextcompbyte++] = byte;
- }
- }
- linebytecount += countbyte;
- }
- /* now see where we are */
- whitestateflg = checkwhite(&compressed[linestart]);
- /* in white, remaining white, and in white, coming from
- somewhere require actions. With others, just cumulate */
- if(whitestateflg && laststate) {
- /* in white, remaining white */
- nextcompbyte = 0;
- linecount = 0;
- lgptop -= magfactor;
- }
- else if(whitestateflg && !laststate) {
- /* went from stuff to white---dump bitmap */
- makebitmap(stdout, compressed, lgptop, linecount-1,
- magfactor, linestart);
- /* and reset for next time */
- nextcompbyte = 0;
- lgptop -= linecount * magfactor;
- linecount = 0;
- }
- }
-
- if(!whitestateflg) {
- /* need to dump out the final buffer */
- makebitmap(stdout, compressed, lgptop, linecount,
- magfactor, nextcompbyte);
- }
-
- /* put out some end of files to make the lgp happier */
- for(ctr=0;ctr<100;ctr++)
- dolgpeof(stdout);
- }
-
-
- /* dump out a bitmap */
- makebitmap(outf, compressed, toplgpoff, maclines, magfactor, usedbytes)
- FILE *outf; /* where to put it */
- char compressed[]; /* input commands */
- int toplgpoff; /* top of the bitmap box */
- int maclines; /* how many scan lines are represented? */
- int magfactor; /* correspondence between mac lines and lgp lines */
- int usedbytes; /* number of bytes produced */
- {
- int hsize; /* expected horizontal size in words */
- int vsize; /* expected vertical size in scan lines */
- int expectwords; /* predicted number of output LGP bytes */
- int outwordcount; /* to verify against expectwords */
- int scanctr; /* count the scan lines */
- int linebytecount; /* how many bytes seen so far on
- input? 0..71 */
- int compcnt; /* count into the compressed array */
- int byte; /* incoming information */
- int countbyte; /* gives meaning of subsequent input bytes */
- char outline[288]; /* max one scan line at magfactor 4 (72*4) */
- int outbytecount; /* bytes produced so far on output */
- int octr; /* output counter for display */
- int ctr; /* temporary counter */
- int lgpline; /* for use in deciding which mask to use */
-
- /* there are 72 *bytes* per scan line and this is expected to
- turn out a complete scan line */
- hsize = (72/2) * magfactor;
- vsize = maclines * magfactor;
-
- /* one inch horizontal margin by default */
- expectwords = dolgpheader(outf, hsize, vsize, 240, toplgpoff);
-
- outwordcount = 0;
-
- if(hflg)
- lgpline = toplgpoff;
- compcnt = 0;
- /* for each scan line */
- for(scanctr=0; scanctr < maclines; scanctr++) {
- linebytecount = 0;
- outbytecount = 0;
-
- /* capture incoming line, producing the output line */
- while(linebytecount < 72) {
- countbyte = compressed[compcnt++] & 0377;
- if(countbyte > 127) {
- /* replicated bytes follow */
- countbyte = 256-countbyte+1;
- byte = compressed[compcnt++] & 0377;
- for(ctr = 0; ctr < countbyte; ctr++)
- outbytecount = intoout(byte,magfactor,
- outline,outbytecount);
- }
- else {
- /* unreplicated bytes follow */
- countbyte++;
- for(ctr = 0; ctr < countbyte; ctr++) {
- byte = compressed[compcnt++] & 0377;
- outbytecount = intoout(byte,magfactor,
- outline,outbytecount);
- }
- }
- linebytecount += countbyte;
- }
-
- /* display the output line */
- for(ctr=0; ctr < magfactor; ctr++) {
- /* if halftoning */
- if(hflg) {
- /* pick proper mask (want to alternate them */
- if(lgpline & 01)
- curmask = OMASK;
- else
- curmask = EMASK;
- lgpline--;
- }
- /* generate output bytes */
- for(octr=0; octr < outbytecount; octr += 2) {
- putlgpbyte(flipbits(outline[octr])&curmask, outf);
- putlgpbyte(flipbits(outline[octr+1])&curmask, outf);
- outwordcount++;
- }
- }
- }
-
- if(compcnt != usedbytes)
- fprintf(stderr,"Warning, expected to use %d bytes, used %d\n",
- usedbytes, compcnt);
- if(expectwords != outwordcount)
- fprintf(stderr,"Warning, expected %d words, sent %d\n",
- expectwords, outwordcount);
-
- }
-
-
- /* take the byte and produce an appropriate number of output bytes */
- int intoout(byte, magfactor, outline, outbytecount)
- int byte; /* incoming byte */
- int magfactor; /* how many repitions */
- char outline[]; /* output buffer */
- int outbytecount; /* where are we in outline? */
- {
- int bitctr; /* count the bits in the byte */
- int bit;
- int magctr; /* count down the copies */
- char *cptr; /* current character being stuffed */
- int outbitctr; /* and the bit within the character */
-
- /* optimization */
- if(magfactor == 1) {
- outline[outbytecount] = byte;
- outbytecount++;
- }
- else {
- /* make multiple copies of this bit */
- cptr = &outline[outbytecount];
- *cptr = 0;
- outbitctr = 7;
- for(bitctr = 7; bitctr >= 0; bitctr--) {
- bit = (byte >> bitctr) & 01;
- /* replicate the bit in the output */
- for(magctr=0; magctr < magfactor; magctr++) {
- if(outbitctr < 0) {
- /* to next output byte */
- cptr++;
- *cptr = 0;
- outbitctr = 7;
- }
-
- *cptr |= (bit << outbitctr);
- outbitctr--;
- }
- }
- outbytecount += magfactor;
- }
- return(outbytecount);
- }
-
- /* produce the lgp header returning the expected number of bitmap bytes */
- int dolgpheader(outf, hsize, vsize, hoff, voff)
- FILE *outf; /* where to send this stuff */
- int hsize; /* expected horizontal word count */
- int vsize; /* expected vertical scan line count */
- int hoff; /* horizontal offset from origin */
- int voff; /* vertical offset from origin */
- {
- /* reposition to the origin */
- putlgpbyte(LGPESC, outf); putlgpbyte('m', outf);
- putlgpword(0, outf); /* x */
- putlgpword(0, outf); /* y */
- /* starting a bit map */
- /* ESC b */
- putlgpbyte(LGPESC, outf); putlgpbyte('b', outf);
- /* hsize (word). There are 72 *bytes* per scan line */
- putlgpword(hsize, outf);
- /* vsize (word). There are at most 720 scan lines */
- putlgpword(vsize, outf);
- /* hoff (word) */
- putlgpword(hoff, outf); /* one inch offset initially */
- /* voff (word) */
- putlgpword(voff, outf); /* on inch vertical offset initially */
- /* hinc (word) */
- putlgpword(0, outf); /* but no change in coordinates afterwards */
- /* vinc (word) */
- putlgpword(0, outf);
- /* bitmap follows */
-
- return(hsize * vsize);
- }
-
- /* put out an EOF escape sequence */
- dolgpeof(outf)
- FILE *outf;
- {
- putlgpbyte(LGPESC, outf);
- putlgpbyte('e', outf);
- }
-
-
- /* low order, high order */
- putlgpword(value, outf)
- int value;
- FILE *outf;
- {
- putc(value & 0377, outf);
- putc((value >> 8) & 0377, outf);
- }
-
- putlgpbyte(value, outf)
- int value;
- FILE *outf;
- {
- putc(value & 0377, outf);
- }
-
- char flipbits(oldbyte)
- char oldbyte;
- {
- char newbyte;
-
- newbyte = 0;
-
- /* 7 6 5 4 3 2 1 0 */
- newbyte = ((oldbyte & 01) << 7) | /* old 0 to new 7 */
- ((oldbyte & 02) << 5) | /* old 1 to new 6 */
- ((oldbyte & 04) << 3) | /* old 2 to new 5 */
- ((oldbyte & 010) << 1) | /* old 3 to new 4 */
- ((oldbyte & 020) >> 1) | /* old 4 to new 3 */
- ((oldbyte & 040) >> 3) | /* old 5 to new 2 */
- ((oldbyte & 0100) >> 5) | /* old 6 to new 1 */
- ((oldbyte & 0200) >> 7); /* old 7 to new 0 */
- return(newbyte);
- }
-
-
- /* see if this line is all white */
- int checkwhite(bytes)
- char *bytes;
- {
- int countbyte;
- int linebytecount;
- int iswhite;
- int ctr;
-
- iswhite = TRUE;
- linebytecount = 0;
-
- while(iswhite && (linebytecount < 72)) {
- countbyte = *bytes & 0377;
- bytes++;
- if(countbyte > 127) {
- /* replicated byte case */
- countbyte = 256-countbyte+1;
- if(*bytes) {
- iswhite = FALSE;
- break;
- }
- bytes++;
- }
- else {
- /* unreplicated bytes follow */
- countbyte++;
- for(ctr = 0; ctr < countbyte; ctr++) {
- if(*bytes) {
- iswhite = FALSE;
- break;
- }
- bytes++;
- }
- }
- linebytecount += countbyte;
- }
- return(iswhite);
- }
-
-
- /* =================option processing via Chris Torek@Maryland=============*/
- /*
- * getopt - get option letter from argv
- * (From Henry Spencer @ U of Toronto Zoology, slightly modified)
- */
-
- /* #include <stdio.h> */
-
- char *optarg; /* Global argument pointer. */
- int optind; /* Global argv index. */
-
- static char *scan; /* Private scan pointer. */
-
- extern char *index();
-
- int
- getopt (argc, argv, optstring)
- register int argc;
- register char **argv;
- char *optstring;
- {
- register int c;
- register char *place;
-
- optarg = NULL;
-
- if (scan == NULL || *scan == 0) {
- if (optind == 0)
- optind++;
-
- if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == 0)
- return EOF;
- if (strcmp (argv[optind], "--") == 0) {
- optind++;
- return EOF;
- }
-
- scan = argv[optind] + 1;
- optind++;
- }
-
- c = *scan++;
- place = index (optstring, c);
-
- if (place == NULL || c == ':') {
- fprintf (stderr, "%s: unknown option -%c\n", argv[0], c);
- return '?';
- }
-
- place++;
- if (*place == ':') {
- if (*scan != '\0') {
- optarg = scan;
- scan = NULL;
- }
- else {
- if (optind >= argc) {
- fprintf (stderr, "%s: missing argument after -%c\n",
- argv[0], c);
- return '?';
- }
- optarg = argv[optind];
- optind++;
- }
- }
-
- return c;
- }
-