home *** CD-ROM | disk | FTP | other *** search
/ Carousel Volume 2 #1 / carousel.iso / mactosh / unix / unix_mpt.sh / macprint.c
C/C++ Source or Header  |  1985-01-16  |  14KB  |  519 lines

  1. /* convert from MacPaint document to a form that can be printed on the
  2.    Printronix printer
  3.  
  4.    This program should work with MacPaint and Screen dump files (made by
  5.    COMMAND-SHIFT-3).  However, it does not work with MacWrite files.
  6.  
  7.    This program was written for Berkeley Unix, version 4.2, running on a
  8.    VAX.
  9.  
  10.    Options:
  11.     -h turn off halftoning
  12.     -m <n>    where <n> is between 1 and 4.  This is an indication
  13.         of how much to magnify (and is called the "magfactor")
  14.  
  15.    Written by Richard Furuta, Computer Science, University of Washington.
  16.    Hacked by Steve Johnson for Printronix, ACC (Oct 16, 1984)
  17.  
  18.    Please report changes and fixes back to me.  By Arpanet and CSNet,
  19.    I am Furuta@Washington.  By uucp, I am ihnp4!uw-beaver!furuta.  I
  20.    prefer the Arpanet/CSNet address.
  21.  
  22.    I benefitted greatly from Ed Pattermann's code for macimp.  The
  23.    following description of the MacPaint font format comes from that
  24.    code.
  25.  
  26.    =============
  27.  
  28.        First, the Macintosh file ; This format is the common
  29.        interchange format for full-page bitmap images on the Macintosh.
  30.  
  31.        The first 512 bytes of the file are the header. The first four bytes
  32.        comprise the version number, followed by 38*8 = 304 bytes of
  33.        patterns.  The remaining 204 bytes of the header are reserved for
  34.        future expansion. If the version number is zero, the patterns are
  35.        ignored. Hence, programs that wish to create files to be read into
  36.        MACpaint can just write out 512 bytes of zero as the header.
  37.  
  38.        Following the header are 720 compressed scanlines of data which form
  39.        the 576 wide by 720 tall bitmap. The bitmap is compressed as follows ;
  40.        Any run of three or more equal bytes is compressed into a count byte
  41.        and a single data byte. Runs of unequal bytes are passed on literally,
  42.        preceded also by a count byte. i.e.
  43.  
  44.        <count byte> <data byte>
  45.          count = -1..-127 --> replicate byte 2..128 times
  46.        <count byte> <n data bytes>
  47.          count = 0.. 127 --> copy 1..128 bytes uncompressed
  48.          count = -128 ignored for backward compatibility
  49.  
  50.    =============
  51.  
  52.    This program produces a series of DEVICE "Define a Block of Raster Data"
  53.    commands which are used to produce a dump of the screen.  You have to be
  54.    careful about the syntax of the arguments to this command.  I had a bit of
  55.    trouble caused by forgetting that the byte ordering and bit ordering of the
  56.    raster words given to this command differ from those of the parameters to
  57.    the command.  I could have used the "Screen Dump" DEVICE command instead of
  58.    this command to dump the raster.  The advantage would have been that the
  59.    resolution of the device would have been halved probably eliminating the
  60.    need to half tone.  The disadvantage is that it is harder to support the
  61.    magnification factor of 3 that seems to make the most sense to me.
  62.  
  63.    An arbitrary magnification is used to blow up the figure in both dimensions
  64.    (x and y).  This is controlled by "magfactor" which should be at least one.
  65.    If it gets larger than 4, you'll have to expand the amount of storage given
  66.    to "outline" in procedure "makebitmap".  I try detect and skip blank scan
  67.    lines to help conserve bandwidth to the printer which is pretty horrid at
  68.    9600 baud.  Maybe one of these days our DR11/C interface will work again and
  69.    bandwidth won't be such a problem!
  70.  
  71. */
  72.  
  73. #include <stdio.h>
  74.  
  75. #define TRUE 1
  76. #define FALSE 0
  77.  
  78. /* for command line option processing */
  79. char *ProgName;
  80. extern char *optarg;
  81. extern int optind;
  82.  
  83. int checkwhite();
  84. char flipbits();
  85. int intoout();
  86.  
  87. /* a macpaint document in the worst case should occupy twice as many bytes
  88.    as a straight screen dump.  This pathological case comes when you have
  89.    only count bytes of 1.  Since the Mac screen is 576 x 720 bits or
  90.    72 x 720 bytes == 51840 bytes, this worst case would occupy 103680
  91.    bytes */
  92. char compressed[200];        /* lookahead storage for input - 152 is enough */
  93. int nextcompbyte;        /* next index into this array */
  94.  
  95. int whitestateflg;        /* TRUE if we last looked at a blank line */
  96.  
  97. /* The DEVICE washes out large black areas.  As an attempt to address this,
  98.    I'm trying to halftone the output */
  99.  
  100. #define DMASK 0377    /* 11111111 pass everything through */
  101. #define EMASK 0252    /* 10101010 even bits only */
  102. #define OMASK 0125    /* 01010101 odd bits only */
  103.  
  104. char curmask;        /* the current one to use */
  105. int hflg;        /* TRUE if we want to halftone */
  106.  
  107. #define CTRL_E    05    /* control E */
  108. #define LF    10    /* linefeed */
  109. #define void    int
  110.  
  111. main(argc, argv)
  112. int argc;
  113. char **argv;
  114. {
  115.     int optch;        /* option character */
  116.     int ctr;        /* temporary counter */
  117.     int scanctr;        /* count the 720 scan lines */
  118.     int byte;        /* incoming information */
  119.     int countbyte;        /* gives meaning of subsequent input bytes */
  120.     int linebytecount;    /* how many bytes seen so far on
  121.                    input? 0..71 */
  122.     int magfactor;        /* how many times do you want to expand
  123.                    this? 1..4 */
  124.     int linestart;        /* when collecting a line, recall where it
  125.                    all began */
  126.  
  127.     magfactor = 1;        /* by default, show at true size */
  128.     curmask = DMASK;    /* by default, in case no halftoning is set */
  129.     hflg = FALSE;        /* by default, halftoning */
  130.  
  131.     ProgName = *argv;
  132.  
  133.     /* grab some options */
  134.     while ((optch = getopt (argc, argv, "hm:")) != EOF) {
  135.         switch (optch) {
  136.         case 'h':    /* want halftoning */
  137.             hflg = TRUE;
  138.             curmask = DMASK;    /* unnecessary but for safety... */
  139.             break;
  140.         case 'm':    /* magnification factor */
  141.             magfactor = atoi(optarg);
  142.             break;
  143.         case '?':
  144.             fprintf(stderr, "Usage: %s [-m magfactor]\n",
  145.                 ProgName);
  146.             (void)fflush(stderr);
  147.             exit(1);    /* a bit harsh, but ... */
  148.         }
  149.     }
  150.     if((magfactor < 1) || (magfactor > 4))  {
  151.         fprintf(stderr, "%s: Sorry, magfactor can't be %d, must be between 1 and 4\n",
  152.             ProgName, magfactor);
  153.         exit(1);
  154.     }
  155.  
  156.     /* jump over the 512 bytes of header */
  157.     for(ctr=0; ctr < 512; ctr++)
  158.         byte = getc(stdin);
  159.  
  160.     nextcompbyte = 0;
  161.     whitestateflg = TRUE;
  162.  
  163.     /* for each scan line */
  164.     for(scanctr=0; scanctr < 720; scanctr++)  {
  165.         linebytecount = 0;
  166.  
  167.         linestart = nextcompbyte;
  168.  
  169.         /* capture incoming line, producing the output line */
  170.         while(linebytecount < 72)  {
  171.             countbyte = getc(stdin) & 0377;    /* count byte */
  172.             compressed[nextcompbyte++] = countbyte;
  173.             if(countbyte > 127)  {
  174.                 /* replicated bytes follow */
  175.                 countbyte = 256-countbyte+1;
  176.                  byte = getc(stdin) & 0377;
  177.                 compressed[nextcompbyte++] = byte;
  178.             }
  179.             else  {
  180.                 /* unreplicated bytes follow */
  181.                 countbyte++;
  182.                 for(ctr = 0; ctr < countbyte; ctr++)  {
  183.                     byte = getc(stdin) & 0377;
  184.                     compressed[nextcompbyte++] = byte;
  185.                 }
  186.             }
  187.             linebytecount += countbyte;
  188.         }
  189.         /* now see where we are */
  190.         whitestateflg = checkwhite(&compressed[linestart]);
  191.         if(whitestateflg)  {
  192.             nextcompbyte = 0;
  193.             put_white(stdout);
  194.         }
  195.         else {
  196.             /* dump bitmap line */
  197.             makebitmap(stdout, compressed, (int) 1,
  198.                 magfactor);
  199.             /* and reset for next time */
  200.             nextcompbyte = 0;
  201.         }
  202.     }
  203.  
  204.     /* put out some end of files to make the lgp happier */
  205.     for(ctr=0;ctr<100;ctr++)
  206.         dv_eof(stdout);
  207. }
  208.  
  209.  
  210. /* dump out a bitmap */
  211. makebitmap(outf, compressed, maclines, magfactor)
  212. FILE *outf;        /* where to put it */
  213. char compressed[];    /* input commands */
  214. int maclines;        /* how many scan lines are represented? */
  215. int magfactor;        /* correspondence between mac lines and lgp lines */
  216. {
  217.     int hsize;        /* expected horizontal size in words */
  218.     int vsize;        /* expected vertical size in scan lines */
  219.     int scanctr;        /* count the scan lines */
  220.     int linebytecount;    /* how many bytes seen so far on
  221.                    input? 0..71 */
  222.     int compcnt;        /* count into the compressed array */
  223.     int byte;        /* incoming information */
  224.     int countbyte;        /* gives meaning of subsequent input bytes */
  225.     char outline[288];    /* max one scan line at magfactor 4 (72*4) */
  226.     int outbytecount;    /* bytes produced so far on output */
  227.     int mask_line;
  228.     int ctr;        /* temporary counter */
  229.  
  230.     compcnt = 0;
  231.     mask_line = 0;
  232.     /* for each scan line */
  233.     for(scanctr=0; scanctr < maclines; scanctr++)  {
  234.         linebytecount = 0;
  235.         outbytecount = 0;
  236.  
  237.         /* capture incoming line, producing the output line */
  238.         while(linebytecount < 72)  {
  239.             countbyte = compressed[compcnt++] & 0377;
  240.             if(countbyte > 127)  {
  241.                 /* replicated bytes follow */
  242.                 countbyte = 256-countbyte+1;
  243.                  byte = compressed[compcnt++] & 0377;
  244.                 for(ctr = 0; ctr < countbyte; ctr++)
  245.                     outbytecount = intoout(byte,magfactor,
  246.                         outline,outbytecount);
  247.             }
  248.             else  {
  249.                 /* unreplicated bytes follow */
  250.                 countbyte++;
  251.                 for(ctr = 0; ctr < countbyte; ctr++)  {
  252.                     byte = compressed[compcnt++] & 0377;
  253.                     outbytecount = intoout(byte,magfactor,
  254.                         outline,outbytecount);
  255.                 }
  256.             }
  257.             linebytecount += countbyte;
  258.         }
  259.  
  260.         /* display the output line */
  261.         for(ctr=0; ctr < magfactor; ctr++)  {
  262.             /* if halftoning */
  263.             if(hflg)  {
  264.                 /* pick proper mask (want to alternate them */
  265.                 if(mask_line & 01)
  266.                     curmask = OMASK;
  267.                 else
  268.                     curmask = EMASK;
  269.                 mask_line--;
  270.             }
  271.             /* generate output bytes */
  272.             dv_format(outf,outline,outbytecount);
  273.         }
  274.     }
  275.  
  276. }
  277.  
  278. /* produce the printronix line */
  279.  
  280. dv_format(outf,outline,outbytecount)
  281. FILE *outf;
  282. char outline[];        /* output buffer */
  283. int outbytecount;
  284. {
  285.     register i,j;
  286.     register char *ptr;
  287.     int octr;        /* output counter for display */
  288.     char bit_stream[288*8];    /* bit stream */
  289.     char out_byte;        /* two-bit header, 6-bits of info ooutput byte */
  290.     char abyte;        /* input byte */
  291.  
  292.     if (outbytecount != 72)
  293.         {
  294.         printf(stderr,"dv_format:  Byte count not 72\n");
  295.         (void) fflush(stderr);
  296.         exit(1);
  297.         }
  298.     j = 0;
  299.     ptr = outline;
  300.     for (octr=0; octr < outbytecount; octr++) {
  301.         abyte = outline[octr];
  302.         for (i=7; i>=0; i--)    /* 8 bits per byte */
  303.             bit_stream[j++] = !!( abyte & (1<<i) );
  304.     }
  305.     putdevbyte(CTRL_E, outf);    /* CTRL-E means bitstream following to printronix */
  306.     j = 0;
  307.     for (octr=96; octr > 0; octr--) {    /* output 96 bytes */
  308.         out_byte = 0;        /* clean start */
  309.         for (i=0; i<=5; i++)    /* 6 info bits per byte */
  310.             out_byte |= (bit_stream[j++] << i);    /* pick off the bit */
  311.         out_byte = (out_byte | 0x40) & 0x7F;    /* fix two high order bits */
  312.         putdevbyte(out_byte&curmask, outf);    /* finally! */
  313.     }
  314.     putdevbyte(LF, outf);    /* end of bitstream */
  315. }
  316.  
  317. /* take the byte and produce an appropriate number of output bytes */
  318. int intoout(byte, magfactor, outline, outbytecount)
  319. int byte;        /* incoming byte */
  320. int magfactor;        /* how many repitions */
  321. char outline[];        /* output buffer */
  322. int outbytecount;    /* where are we in outline? */
  323. {
  324.     int bitctr;    /* count the bits in the byte */
  325.     int bit;
  326.     int magctr;    /* count down the copies */
  327.     char *cptr;    /* current character being stuffed */
  328.     int outbitctr;    /* and the bit within the character */
  329.  
  330.     /* optimization */
  331.     if(magfactor == 1)  {
  332.         outline[outbytecount] = byte;
  333.         outbytecount++;
  334.     }
  335.     else  {
  336.         /* make multiple copies of this bit */
  337.         cptr = &outline[outbytecount];
  338.         *cptr = 0;
  339.         outbitctr = 7;
  340.         for(bitctr = 7; bitctr >= 0; bitctr--)  {
  341.             bit = (byte >> bitctr) & 01;
  342.             /* replicate the bit in the output */
  343.             for(magctr=0; magctr < magfactor; magctr++)  {
  344.                 if(outbitctr < 0)  {
  345.                     /* to next output byte */
  346.                     cptr++;
  347.                     *cptr = 0;
  348.                     outbitctr = 7;
  349.                 }
  350.  
  351.                 *cptr |= (bit << outbitctr);
  352.                 outbitctr--;
  353.             }
  354.         }
  355.         outbytecount += magfactor;
  356.     }
  357.     return(outbytecount);
  358. }
  359.  
  360.  
  361. /* low order, high order */
  362. putdevword(value, outf)
  363. int value;
  364. FILE *outf;
  365. {
  366.     putc(value & 0377, outf);
  367.     putc((value >> 8) & 0377, outf);
  368. }
  369.  
  370. putdevbyte(value, outf)
  371. int value;
  372. FILE *outf;
  373. {
  374.     putc(value & 0377, outf);
  375. }
  376.  
  377. dv_eof(outf)
  378. FILE *outf;
  379. {
  380. ;
  381. }
  382.  
  383. put_white(outf)
  384. FILE *outf;
  385. {
  386.     putc(CTRL_E & 0377, outf);
  387.     putc(LF & 0377, outf);
  388. }
  389.  
  390. char flipbits(oldbyte)
  391. char oldbyte;
  392. {
  393.     char newbyte;
  394.  
  395.     newbyte = 0;
  396.  
  397.     /* 7 6 5 4 3 2 1 0 */
  398.     newbyte = ((oldbyte & 01) << 7) |    /* old 0 to new 7 */
  399.           ((oldbyte & 02) << 5) |    /* old 1 to new 6 */
  400.           ((oldbyte & 04) << 3) |    /* old 2 to new 5 */
  401.           ((oldbyte & 010) << 1) |    /* old 3 to new 4 */
  402.           ((oldbyte & 020) >> 1) |    /* old 4 to new 3 */
  403.           ((oldbyte & 040) >> 3) |    /* old 5 to new 2 */
  404.           ((oldbyte & 0100) >> 5) |    /* old 6 to new 1 */
  405.           ((oldbyte & 0200) >> 7);    /* old 7 to new 0 */
  406.     return(newbyte);
  407. }
  408.  
  409.  
  410. /* see if this line is all white */
  411. int checkwhite(bytes)
  412. char *bytes;
  413. {
  414.     int countbyte;
  415.     int linebytecount;
  416.     int iswhite;
  417.     int ctr;
  418.  
  419.     iswhite = TRUE;
  420.     linebytecount = 0;
  421.  
  422.     while(iswhite && (linebytecount < 72))  {
  423.         countbyte = *bytes & 0377;
  424.         bytes++;
  425.         if(countbyte > 127)  {
  426.             /* replicated byte case */
  427.             countbyte = 256-countbyte+1;
  428.             if(*bytes)  {
  429.                 iswhite = FALSE;
  430.                 break;
  431.             }
  432.             bytes++;
  433.         }
  434.         else  {
  435.             /* unreplicated bytes follow */
  436.             countbyte++;
  437.             for(ctr = 0; ctr < countbyte; ctr++)  {
  438.                 if(*bytes)  {
  439.                     iswhite = FALSE;
  440.                     break;
  441.                 }
  442.                 bytes++;
  443.             }
  444.         }
  445.         linebytecount += countbyte;
  446.     }
  447.     return(iswhite);
  448. }
  449.  
  450.  
  451. /* =================option processing via Chris Torek@Maryland=============*/
  452. /*
  453.  * getopt - get option letter from argv
  454.  * (From Henry Spencer @ U of Toronto Zoology, slightly modified)
  455.  */
  456.  
  457. /* #include <stdio.h> */
  458.  
  459. char    *optarg;    /* Global argument pointer. */
  460. int    optind;        /* Global argv index. */
  461.  
  462. static char    *scan;    /* Private scan pointer. */
  463.  
  464. extern char    *index();
  465.  
  466. int
  467. getopt (argc, argv, optstring)
  468. register int    argc;
  469. register char **argv;
  470. char *optstring;
  471. {
  472.     register int    c;
  473.     register char  *place;
  474.  
  475.     optarg = NULL;
  476.  
  477.     if (scan == NULL || *scan == 0) {
  478.     if (optind == 0)
  479.         optind++;
  480.  
  481.     if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == 0)
  482.         return EOF;
  483.     if (strcmp (argv[optind], "--") == 0) {
  484.         optind++;
  485.         return EOF;
  486.     }
  487.  
  488.     scan = argv[optind] + 1;
  489.     optind++;
  490.     }
  491.  
  492.     c = *scan++;
  493.     place = index (optstring, c);
  494.  
  495.     if (place == NULL || c == ':') {
  496.     fprintf (stderr, "%s: unknown option -%c\n", argv[0], c);
  497.     return '?';
  498.     }
  499.  
  500.     place++;
  501.     if (*place == ':') {
  502.     if (*scan != '\0') {
  503.         optarg = scan;
  504.         scan = NULL;
  505.     }
  506.     else {
  507.         if (optind >= argc) {
  508.         fprintf (stderr, "%s: missing argument after -%c\n",
  509.             argv[0], c);
  510.         return '?';
  511.         }
  512.         optarg = argv[optind];
  513.         optind++;
  514.     }
  515.     }
  516.  
  517.     return c;
  518. }
  519.