home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume3 / giftops / giftops.c
Encoding:
C/C++ Source or Header  |  1989-02-03  |  10.5 KB  |  337 lines

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