home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / source / giftops2 < prev    next >
Text File  |  1990-12-17  |  11KB  |  350 lines

  1.  
  2. /*********************************************
  3.  *             GIFtoPS Converter             *
  4.  *                                           *
  5.  *      May 16, 1988  by Scott Hemphill      *
  6.  *                                           *
  7.  * I wrote this program, and hereby place it *
  8.  * in the public domain, i.e. there are no   *
  9.  * copying restrictions of any kind.         *
  10.  * Compile:
  11.  * cc giftops.c -o giftops
  12.  *
  13.  *********************************************/
  14.  
  15. #include <stdio.h>
  16. char *malloc();
  17. int strncmp();
  18.  
  19. #define min(x,y) ((x) < (y) ? (x) : (y))
  20. #define FALSE 0
  21. #define TRUE 1
  22.  
  23. typedef int bool;
  24. typedef struct codestruct {
  25.             struct codestruct *prefix;
  26.             unsigned char first,suffix;
  27.         } codetype;
  28.  
  29. FILE *infile;
  30. unsigned int screenwidth;           /* The dimensions of the screen */
  31. unsigned int screenheight;          /*   (not those of the image)   */
  32. bool global;                        /* Is there a global color map? */
  33. int globalbits;                     /* Number of bits of global colors */
  34. unsigned char globalmap[256][3];    /* RGB values for global color map */
  35. char colortable[256][3];            /* Hex intensity strings for an image */
  36. unsigned char *raster;              /* Decoded image data */
  37. codetype *codetable;                /* LZW compression code data */
  38. int datasize,codesize,codemask;     /* Decoder working variables */
  39. int clear,eoi;                      /* Special code values */
  40.  
  41. void usage()
  42. {
  43.         fprintf(stderr,"usage: giftops input-file > output-file\n");
  44.         exit(-1);
  45. }
  46.  
  47. void fatal(s)
  48. char *s;
  49. {
  50.         fprintf(stderr,"giftops: %s\n",s);
  51.         exit(-1);
  52. }
  53.  
  54. void checksignature()
  55. {
  56.         char buf[6];
  57.  
  58.         fread(buf,1,6,infile);
  59.         if (strncmp(buf,"GIF",3)) fatal("file is not a GIF file");
  60.         if (strncmp(&buf[3],"87a",3)) fatal("unknown GIF version number");
  61. }
  62.  
  63. /* Get information which is global to all the images stored in the file */
  64.  
  65. void readscreen()
  66. {
  67.         unsigned char buf[7];
  68.  
  69.         fread(buf,1,7,infile);
  70.         screenwidth = buf[0] + (buf[1] << 8);
  71.         screenheight = buf[2] + (buf[3] << 8);
  72.         global = buf[4] & 0x80;
  73.         if (global) {
  74.             globalbits = (buf[4] & 0x07) + 1;
  75.             fread(globalmap,3,1<<globalbits,infile);
  76.         }
  77. }
  78.  
  79. /* Convert a color map (local or global) to an array of two character
  80.    hexadecimal strings, stored in colortable.  RGB is converted to
  81.    8-bit grayscale using integer arithmetic. */
  82.  
  83. void initcolors(colortable,colormap,ncolors)
  84. char colortable[256][3];
  85. unsigned char colormap[256][3];
  86. int ncolors;
  87. {
  88.         static char hextab[] = {'0','1','2','3','4','5','6','7',
  89.                                 '8','9','A','B','C','D','E','F'};
  90.         register unsigned color;
  91.         register i;
  92.  
  93.         for (i = 0; i < ncolors; i++) {
  94.             color = 77*colormap[i][0] + 150*colormap[i][1] + 29*colormap[i][2];
  95.             color >>= 8;
  96.             colortable[i][0] = hextab[color >> 4];
  97.             colortable[i][1] = hextab[color & 15];
  98.             colortable[i][2] = '\0';
  99.         }
  100. }
  101.  
  102. /* Write a postscript header to the standard output.  Standard paper size
  103.    (8.5 by 11) is hard-coded, as is the whole initialization sequence. */
  104.  
  105. void writeheader(left,top,width,height)
  106. unsigned left,top,width,height;
  107. {
  108.         double scale;
  109.         int scaledwidth,scaledheight;
  110.  
  111.         scale = min(648.0/screenwidth, 468.0/screenheight);
  112.         scaledwidth = (int)(scale*screenwidth+0.5);
  113.         scaledheight = (int)(scale*screenheight+0.5);
  114.  
  115.     printf("%%!\n");
  116.         printf("currentscreen /proc exch def /angle exch def /frequency exch def\n");
  117.         printf("/angle 90 def /frequency 60 def\n");
  118.         printf("frequency angle /proc load setscreen\n");
  119.         printf("/picstr %d string def\n",width);
  120.         printf("/screen {%d %d 8 [%d 0 0 -%d 0 %d]\n",
  121.             width,height,width,height,height);
  122.         printf("   {currentfile picstr readhexstring pop} image} def\n");
  123.         /*printf("%d %d translate 90 rotate %d %d scale screen\n",
  124.                306+(scaledheight>>1),396-(scaledwidth>>1),
  125.                scaledwidth, scaledheight);
  126.           was this*/
  127.         printf("%d %d translate 0 rotate %d %d scale screen\n",
  128.                0, 0,
  129.                scaledwidth, scaledheight);
  130. }
  131.  
  132. /* Output the bytes associated with a code to the raster array */
  133.  
  134. void outcode(p,fill)
  135. register codetype *p;
  136. register unsigned char **fill;
  137. {
  138.         if (p->prefix) outcode(p->prefix,fill);
  139.         *(*fill)++ = p->suffix;
  140. }
  141.  
  142. /* Process a compression code.  "clear" resets the code table. Otherwise
  143.    make a new code table entry, and output the bytes associated with the
  144.    code. */
  145.  
  146. void process(code,fill)
  147. register code;
  148. unsigned char **fill;
  149. {
  150.         static avail,oldcode;
  151.         register codetype *p;
  152.  
  153.         if (code == clear) {
  154.             codesize = datasize + 1;
  155.             codemask = (1 << codesize) - 1;
  156.             avail = clear + 2;
  157.             oldcode = -1;
  158.         } else if (code < avail) {
  159.             outcode(&codetable[code],fill);
  160.             if (oldcode != -1) {
  161.                 p = &codetable[avail++];
  162.                 p->prefix = &codetable[oldcode];
  163.                 p->first = p->prefix->first;
  164.                 p->suffix = codetable[code].first;
  165.                 if ((avail & codemask) == 0 && avail < 4096) {
  166.                     codesize++;
  167.                     codemask += avail;
  168.                 }
  169.             }
  170.             oldcode = code;
  171.         } else if (code == avail && oldcode != -1) {
  172.             p = &codetable[avail++];
  173.             p->prefix = &codetable[oldcode];
  174.             p->first = p->prefix->first;
  175.             p->suffix = p->first;
  176.             outcode(p,fill);
  177.             if ((avail & codemask) == 0 && avail < 4096) {
  178.                 codesize++;
  179.                 codemask += avail;
  180.             }
  181.             oldcode = code;
  182.         } else {
  183.             fatal("illegal code in raster data");
  184.         }
  185. }
  186.  
  187. /* Decode a raster image */
  188.  
  189. void readraster(width,height)
  190. unsigned width,height;
  191. {
  192.         unsigned char *fill = raster;
  193.         unsigned char buf[255];
  194.         register bits=0;
  195.         register unsigned count,datum=0;
  196.         register unsigned char *ch;
  197.         register int code;
  198.  
  199.         datasize = getc(infile);
  200.         clear = 1 << datasize;
  201.         eoi = clear+1;
  202.         codesize = datasize + 1;
  203.         codemask = (1 << codesize) - 1;
  204.         codetable = (codetype*)malloc(4096*sizeof(codetype));
  205.         if (!codetable) fatal("not enough memory for code table");
  206.         for (code = 0; code < clear; code++) {
  207.             codetable[code].prefix = (codetype*)0;
  208.             codetable[code].first = code;
  209.             codetable[code].suffix = code;
  210.         }
  211.         for (count = getc(infile); count > 0; count = getc(infile)) {
  212.             fread(buf,1,count,infile);
  213.             for (ch=buf; count-- > 0; ch++) {
  214.                 datum += *ch << bits;
  215.                 bits += 8;
  216.                 while (bits >= codesize) {
  217.                     code = datum & codemask;
  218.                     datum >>= codesize;
  219.                     bits -= codesize;
  220.                     if (code == eoi) goto exitloop;  /* This kludge put in
  221.                                                         because some GIF files
  222.                                                         aren't standard */
  223.                     process(code,&fill);
  224.                 }
  225.             }
  226.         }
  227. exitloop:
  228.         if (fill != raster + width*height) fatal("raster has the wrong size");
  229.         free(codetable);
  230. }
  231.  
  232. /* Read a row out of the raster image and write it to the output file */
  233.  
  234. void rasterize(row,width)
  235. int row,width;
  236. {
  237.         register unsigned char *scanline;
  238.         register i;
  239.  
  240.         scanline = raster + row*width;
  241.         for (i = 0; i < width; i++) {
  242.             if (i % 40 == 0) printf("\n");  /* break line every 80 chars */
  243.             fputs(colortable[*scanline++],stdout);
  244.         }
  245.         printf("\n");
  246. }
  247.  
  248. /* write image trailer to standard output */
  249.  
  250. void writetrailer()
  251. {
  252.         printf("showpage\n");
  253. }
  254.  
  255. /* Read image information (position, size, local color map, etc.) and convert
  256.    to postscript. */
  257.  
  258. void readimage()
  259. {
  260.         unsigned char buf[9];
  261.         unsigned left,top,width,height;
  262.         bool local,interleaved;
  263.         char localmap[256][3];
  264.         int localbits;
  265.         int *interleavetable;
  266.         register row;
  267.         register i;
  268.  
  269.         fread(buf,1,9,infile);
  270.         left = buf[0] + (buf[1] << 8);
  271.         top = buf[2] + (buf[3] << 8);
  272.         width = buf[4] + (buf[5] << 8);
  273.         height = buf[6] + (buf[7] << 8);
  274.         local = buf[8] & 0x80;
  275.         interleaved = buf[8] & 0x40;
  276.         if (local) {
  277.             localbits = (buf[8] & 0x7) + 1;
  278.             fread(localmap,3,1<<localbits,infile);
  279.             initcolors(colortable,localmap,1<<localbits);
  280.         } else if (global) {
  281.             initcolors(colortable,globalmap,1<<globalbits);
  282.         } else {
  283.             fatal("no colormap present for image");
  284.         }
  285.         writeheader(left,top,width,height);
  286.         raster = (unsigned char*)malloc(width*height);
  287.         if (!raster) fatal("not enough memory for image");
  288.         readraster(width,height);
  289.         if (interleaved) {
  290.             interleavetable = (int*)malloc(height*sizeof(int));
  291.             if (!interleavetable) fatal("not enough memory for interleave table");
  292.             row = 0;
  293.             for (i = top; i < top+height; i += 8) interleavetable[i] = row++;
  294.             for (i = top+4; i < top+height; i += 8) interleavetable[i] = row++;
  295.             for (i = top+2; i < top+height; i += 4) interleavetable[i] = row++;
  296.             for (i = top+1; i < top+height; i += 2) interleavetable[i] = row++;
  297.             for (row = top; row < top+height; row++)
  298. rasterize(interleavetable[row],width);
  299.             free(interleavetable);
  300.         } else {
  301.             for (row = top; row < top+height; row++) rasterize(row,width);
  302.         }
  303.         free(raster);
  304.         writetrailer();
  305. }
  306.  
  307. /* Read a GIF extension block (and do nothing with it). */
  308.  
  309. void readextension()
  310. {
  311.         unsigned char code,count;
  312.         char buf[255];
  313.  
  314.         code = getc(infile);
  315.         while (count = getc(infile)) fread(buf,1,count,infile);
  316. }
  317.  
  318. main(argc,argv)
  319. int argc;
  320. char *argv[];
  321. {
  322.         int quit = FALSE;
  323.         char ch;
  324.  
  325.         if (argc != 2) usage();
  326.         infile = fopen(argv[1],"r");
  327.         if (!infile) {
  328.             perror("giftops");
  329.             exit(-1);
  330.         }
  331.         checksignature();
  332.         readscreen();
  333.         do {
  334.             ch = getc(infile);
  335.             switch (ch) {
  336.                 case '\0':  break;  /* this kludge for non-standard files */
  337.                 case ',':   readimage();
  338.                             break;
  339.                 case ';':   quit = TRUE;
  340.                             break;
  341.                 case '!':   readextension();
  342.                             break;
  343.                 default:    fatal("illegal GIF block type");
  344.                             break;
  345.             }
  346.         } while (!quit);
  347. }
  348.  
  349.  
  350.