home *** CD-ROM | disk | FTP | other *** search
/ Carousel Volume 2 #1 / carousel.iso / mactosh / unix / paintps.sha / paintps.c < prev    next >
C/C++ Source or Header  |  1986-07-08  |  10KB  |  341 lines

  1. #ifndef lint
  2. static    char sccsid[] = "@(#)paintps.c    1.7 6/11/86 (UT)";
  3. #endif
  4.  
  5. /*
  6.  * paintps -- Convert MacPaint document to PostScript document 
  7.  * 
  8.  * Brian H. Powell, University of Texas at Austin
  9.  *    brian@sally.UTEXAS.EDU
  10.  *    brian@ut-sally.UUCP
  11.  *    CS.Powell@r20.UTEXAS.EDU
  12.  *
  13.  * This program may be used but not sold without permission.
  14.  *
  15.  * Modification History
  16.  *     BHP    7/25/85    Created.
  17.  *    BHP    7/31/85    Optimized output routines for execution speed.
  18.  *    BHP    4/22/86    Added -P option, extracted spool command to Makefile.
  19.  *    BHP    6/ 3/86 Fixed bug causing (rare) small white gaps between
  20.  *            bitmaps.
  21.  */
  22.  
  23. #include <stdio.h>
  24. #include <ctype.h>
  25.  
  26. #define FALSE 0
  27. #define TRUE  (-1)
  28.  
  29. #define MACPAINT_HDRSIZE    512
  30. #define MACRASTER_BITWIDTH    576
  31. #define    MACPAINT_BITHEIGHT    720
  32.  
  33.             /* DEFAULT OPTIONS */
  34. int smooth = TRUE;        /* smoothing enabled */
  35. int copies = 1;            /* one copy of the painting */
  36. char *printername = NULL;    /* default printer */
  37.  
  38. char hexbuffer[MACPAINT_BITHEIGHT][MACRASTER_BITWIDTH/8];
  39. int blank[MACPAINT_BITHEIGHT + 4];    /* we need the four extra blank */
  40.                     /* lines as filler for output */
  41.  
  42. char usage[] = "paintps [-d] [-#<n>] [-P<printer>] file";
  43.  
  44. main(ac, av)
  45. char **av;
  46. {
  47.    ac--; av++;
  48.    while (ac && (av[0][0] == '-') && av[0][1]) {
  49.       switch (av[0][1]) {
  50.      case 'd':            /* "draft" option */
  51.         smooth = FALSE;
  52.         break;
  53.  
  54.      case '#':            /* number of copies */
  55.         copies = atoi (&av[0][2]);
  56.         break;
  57.  
  58.      case 'P':            /* printer name */
  59.         printername = av[0];
  60.         break;
  61.  
  62.      default:
  63.         goto bad_usage;
  64.       }
  65.       ac--; av++;
  66.    }
  67.    open_output();        /* also starts spooling to the spool cmd. */
  68.    paintfilter(av[0]);
  69.    exit(0);
  70.  
  71. bad_usage:
  72.    fprintf(stderr, "usage: %s\n", usage);
  73.    exit(1);
  74. }
  75.  
  76. /* convert from MacPaint to PostScript */
  77.  
  78. paintfilter(name)
  79. char *name;
  80. {
  81.    register int x, y;
  82.    FILE *fp;
  83.    register int c;
  84.    int blankline;
  85.  
  86.    fp = fopen(name, "r");        /* open the MacPaint file. */
  87.    if (fp == NULL) {
  88.       perror(name);
  89.       return;
  90.    }
  91.  
  92.    (void) fseek(fp, (long)MACPAINT_HDRSIZE, 0);    /* skip the MacPaint patterns */
  93.  
  94.    begin_image();                /* print postscript header */
  95.  
  96. /*  We skip horizontal whitespace.  "blankline" is used to diagnose this
  97.     for the current line.  The boolean array "blank[y]" shows which lines
  98.     in the entire painting are blank. */
  99.  
  100.    for (y = 0; y < MACPAINT_BITHEIGHT; y++) {
  101.                 /* for each pixel row... */
  102.       blankline = TRUE;
  103.       for (x = 0; x < MACRASTER_BITWIDTH/8; x++) {
  104.  
  105.          if ((c = getbits(fp)) == EOF) {
  106.             fprintf(stderr, "Unexpected EOF, stopped.\n");
  107.             for ( ; y < MACPAINT_BITHEIGHT; y++)        /* Mark the */
  108.                blank[y] = TRUE;                /* rest of the page */
  109.             blankline = TRUE;               /* blank, print it and quit. */
  110.             break;
  111.  
  112.          } else {
  113.             hexbuffer[y][x] = (char) c;      /* else record the character and */
  114.             if (c)              /* mark the line as non-blank. */
  115.                blankline = FALSE;
  116.          }
  117.       }
  118.       blank[y] = blankline;
  119.    }
  120.    blank[y++] = TRUE;        /* put four blank lines at end */
  121.    blank[y++] = TRUE;        /* (I think this is needed for smoothing.) */
  122.    blank[y++] = TRUE;
  123.    blank[y] = TRUE;
  124.    dump_buffer(hexbuffer, blank);    /* print the buffer (entire page) */
  125.  
  126.    end_imag(copies);        /* print the postscript trailer. */
  127.    (void) fclose(fp);        /* close the file. */
  128. }
  129.  
  130. /* macpaint input routines */
  131.  
  132. getbits(fp)        /* this routine scarfed from paintimp. */
  133. FILE *fp;
  134. {
  135. /* This routine expands the PackBits encoded MacPaint file,
  136.    delivering one byte per call.
  137. */
  138.  
  139.    static int count, rep, chr;
  140.    int c;
  141.  
  142.    if (rep) {        /* if we are repeating a previous character, */
  143.       rep--;        /* reduce the repeat count and return the char. */
  144.       return chr;
  145.    }
  146.    if (count) {        /* if we are in an unrepeated section, reduce */
  147.       count--;        /* the count and return next char from the file. */
  148.       return getc(fp);
  149.    }
  150.    c = getc(fp);    /* otherwise, get the next repeat count.  */
  151.    if (c & 0x80) {    /* if negative, repeat the next */
  152.       rep = 0x100 - c;    /* byte (2's comp(c)+1) times. */
  153.       chr = getc(fp);        /* the character to repeat */
  154.       return chr;
  155.    }
  156.    else {        /* if repeat count is positive, next "count" bytes */
  157.       count = c;       /* are unencoded.  */
  158.       return getc(fp);
  159.    }
  160. }
  161.  
  162. /* PostScript output routines */
  163.  
  164. open_output()
  165. {
  166.    char lpr [64];
  167.    FILE *popen();
  168.  
  169. /* if stdout is going to the terminal, call the spool command to spool the
  170.    output, otherwise assume it's being piped somewhere else
  171.    or directed into a file.
  172. */
  173.    if (isatty (fileno (stdout)))
  174.    {
  175.       (void) sprintf (lpr, "%s %s", SPOOLCMD,
  176.             printername ? printername : "");
  177.         /* include printer name if it was specified.  */
  178.  
  179.     /* disconnect stdout from the tty and pipe it to lpr */
  180.       (void) fclose (stdout);
  181.       if (popen (lpr, "w") == NULL) {
  182.          fprintf(stderr, "%s failed, giving up.\n", lpr);
  183.          exit(2);
  184.       }
  185.       fprintf(stderr, "Spooling to '%s'.\n", lpr);
  186.    }
  187.  
  188. }
  189.  
  190. begin_image()        /* print the postscript header. */
  191. {
  192.    printf("%%!\n");        /* TranScript PostScript flag "%!" */
  193.    printf("md begin\n");    /* standard apple header */
  194.    printf("1320 od\n");
  195.    printf("(; user: )jn\n");
  196.    printf("%%%%EndProlog\n");
  197.    printf("%%%%Page: ? ?\n");
  198.    printf("op\n");
  199.    printf("0 0 moveto\n");
  200. }
  201.  
  202. /* The reason the following routine isn't called "end_image" is because */
  203. /* of a bug in the Sequent C compiler.  */
  204. end_imag(copies)    /* print the postscript trailer. */
  205. int copies;        /* copies == number of copies to print */
  206. {
  207.    printf("%d page\n", copies - 1);    /* "page" takes # of pages to */
  208.    printf("cp\n");                   /* print minus 1 */
  209.    printf("%%%%Trailer\n");
  210.    printf("end\n");
  211. }
  212.  
  213. #define OUTBUF_SIZE    28
  214. #define XSCALE        578
  215. #define XLOC        0
  216. #define ROWBYTES    74
  217. #define SRCMODE        1
  218.  
  219.     /* Modular code purists can close their eyes for the following */
  220.     /* routine.  */
  221. dump_buffer(hexbuffer, blank)
  222. char hexbuffer[MACPAINT_BITHEIGHT][MACRASTER_BITWIDTH/8];
  223. int blank[MACPAINT_BITHEIGHT];
  224.    /* hexbuffer contains the entire unencoded MacPaint file. */
  225.    /* blank is a boolean array for each row.  TRUE means the horizontal
  226.       line is blank. */
  227. {
  228.    int xscale, yscale, xloc, yloc, xactual, yactual;
  229.    char smoothing;
  230.    int i, j;
  231.    int curline, top_of_sect, begin_line, numblanks, lines_used;
  232.    char outstring[MACRASTER_BITWIDTH/4];
  233.  
  234.    xscale = XSCALE;        /* Postscript parameters describing the */
  235.    xloc = XLOC;            /* size of the image area.  */
  236.    xactual = XSCALE;
  237.    smoothing = smooth ? 'T' : 'F';
  238.  
  239. /*  The postscript output consists of calls to "dobits" for each group of */
  240. /* non-blank horizontal lines.  Due to LaserWriter memory limitations,    */
  241. /* only about 28 lines at a time can be sent per command.  Also, lines    */
  242. /* adjacent to the current section must be included (presumably for the   */
  243. /* smoothing function to work.)                          */
  244.  
  245.    curline = 0;
  246.    top_of_sect = TRUE;        /* begin a "dobits" call. */
  247.  
  248.    while (curline < MACPAINT_BITHEIGHT) {
  249.             /* for the entire picture... */
  250.  
  251. /*  If a previous section terminated because of white space, skip the */
  252. /* blank lines that precede the next section.  */
  253.       if (top_of_sect)
  254.      while ((curline < MACPAINT_BITHEIGHT) && blank[curline])
  255.             curline++;
  256.  
  257. /* check for end of page. */
  258.       if (curline >= MACPAINT_BITHEIGHT)
  259.          break;
  260.  
  261.       if (top_of_sect) {    /* At top of non-white section, include */
  262.          begin_line = curline - 2;    /* previous two lines; */
  263.          lines_used = 2;
  264.          top_of_sect = FALSE;
  265.       } else {            /* if continuing a non-white section, don't. */
  266.          begin_line = curline;
  267.          lines_used = 0;
  268.       }
  269.  
  270.       numblanks = 0;        /* compute height of non-white area. */
  271.       for (i = lines_used; i < (OUTBUF_SIZE - 1); i++) {
  272.          if (blank[curline++])
  273.             numblanks++;
  274.          else
  275.             numblanks = 0;   /* reset counter */
  276.          if (numblanks >= 4) {    /* Too much white space: break and print it. */
  277.                       /* The four blanks at the end of the */
  278.                 /* page will stop us at the bottom */
  279.             curline--;        /* We want curline to point */
  280.                       /* to the fourth blank line. */
  281.             break;
  282.          }
  283.       }
  284.       if (numblanks > 0)    /* If the bitmap ended in any whitespace, */
  285.      top_of_sect = TRUE;    /* we skip it the next time around.  */
  286.       curline++;
  287.       yactual = i - 3;        /* Height of current bitmap section. */
  288.       yscale = yactual;        /* Scale it 1 to 1.  */
  289.       yloc = begin_line + 2;
  290.  
  291. /* print the "dobits" call. */
  292.       printf("%d %d %d %d %d %d %d %c %d dobits\n",
  293.         xscale, yscale, xloc, yloc, ROWBYTES,
  294.         xactual, yactual, smoothing, SRCMODE);
  295. /* print the corresponding horizontal lines. */
  296.       for (i = begin_line; i < curline; i++) {
  297.          if ((i < 0) || blank[i])
  298.             /* if blank, print all zeros. */
  299.             for (j = 0; j< MACRASTER_BITWIDTH/4; j++)
  300.                putchar('0');
  301.          else {
  302.             /* else convert to a hex string and print it. */
  303.             tohex(hexbuffer[i], MACRASTER_BITWIDTH/8,
  304.                outstring);
  305.             printf("%s", outstring);
  306.          }
  307.         /* Put four extra nibbles at the ends of lines.  I think */
  308.         /* are for smoothing.  */
  309.      if ((i == (-2)) || blank[i+1])    /* Include the first four nibbles of */
  310.             printf("0000\n");        /* the next line.  */
  311.      else {
  312.         tohex(hexbuffer[i+1], 2, outstring);
  313.         printf("%s\n", outstring);
  314.      }
  315.       }
  316.       if (!top_of_sect)
  317.          curline -= 4;        /* we'll have to overlap the next section */
  318.    }                /* with this one, so back up four lines. */
  319. }
  320.  
  321. tohex(hexline, size, outstring)   /* convert binary bytes to a hex string. */
  322. char hexline[];
  323. int size;        /* number of bytes to convert. */
  324. char outstring[];
  325. {
  326.    int i, j;
  327.    register char c, c1;
  328.  
  329.    j = 0;
  330.    for (i = 0 ; i < size ; i++) {
  331.       c = hexline[i];
  332.       c1 = (c >> 4) & 0x0F;
  333.       c1 = (c1 <= 9) ? (c1 + '0') : (c1 - 10 + 'A');
  334.       outstring[j++] = c1;
  335.       c1 = c & 0x0F;
  336.       c1 = (c1 <= 9) ? (c1 + '0') : (c1 - 10 + 'A');
  337.       outstring[j++] = c1;
  338.    }
  339.    outstring[j] = NULL;
  340. }
  341.