home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / giftops2.zip / giftops2.c next >
C/C++ Source or Header  |  1994-04-07  |  15KB  |  513 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.  * Command line processing, EPSF support,    *
  11.  * and image positioning by Mic Kaczmarczik, *
  12.  * modeled after James Frew's ``suntops''    *
  13.  *                         *
  14.  * All ints were assumed 32 bits, changed to *
  15.  * work with 16 bit ints with mwc on Atari ST*
  16.  * The routine below provides the getopt()   *
  17.  * routine unavailable with mwc.             *
  18.  * A GEM version for the Atari ST may be     *
  19.  * appearing soon in the Atari SIG.          *
  20.  * Mark Storkamp 3/24/90.             *
  21.  *                                           *
  22.  * Converted to compile under Turbo C 2.0    *
  23.  * Changed "raster","fill", and "scanline"   *
  24.  * to HUGE pointers and compiled using       *
  25.  * "compact" memory model. Also stripped out *
  26.  * the getopt() function (for troubleshooting*
  27.  * purposes). Turbo C includes getopt() if   *
  28.  * you want it. Atof() were substituted for  *
  29.  * sscanf() in the command line parser (for  *
  30.  * getting imageheight and imagewidth values,*
  31.  * I was unable to get atof to work with my  *
  32.  * compiler).                                *
  33.  * Craig Moore 4/13/90                       *
  34.  *                                           *
  35.  * Converted to compile under Borland C++ for*
  36.  * OS/2 2.xx 32 bit                          *
  37.  * Function parameters declaration converted *
  38.  * from K&R style to ANSI.                   *
  39.  * Definition of type UCHAR for UNSIGNED     *
  40.  * CHAR, UINT for UNSIGNED INT, and ULONG for*
  41.  * UNSIGNED LONG (also if ULONG and UINT have*
  42.  * the same size under this compiler).       *
  43.  * Stripped HUGE pointer, not necessary under*
  44.  * OS/2 2.xx because of flat memory model.   *
  45.  * Stripped register var declaration because *
  46.  * BORLAND compiler for OS/2 ignores the     *
  47.  * declaration putting vars in register as   *
  48.  * often as possible.                        *
  49.  * Modified functions:                       *
  50.  *     readimage()                          *
  51.  * Stripped farmalloc and farfree, because of*
  52.  * flat memory model.                        *
  53.  * Stripped left var because was not used.   *
  54.  *     writeheader()                        *
  55.  * Stripped parameters UINT left and UINT top*
  56.  * because they are not used.                *
  57.  *     readextension()                      *
  58.  * count type converted from UCHAR to int.   *
  59.  * modified while loop to shut a worning out.*
  60.  *     main()                               *
  61.  * Added check for no args.                  *
  62.  * Original program crashes with no argument *
  63.  * because it try to make an attempt to      *
  64.  * strcpy(gifname, \0) !!!!                  *
  65.  * Fabrizio Fioravanti 23/8/93               *
  66.  * Maurizio Giunti     23/8/93               *
  67.  *********************************************/
  68.  
  69. #include <stdlib.h>
  70. #include <stdio.h>
  71. #include <string.h>
  72. #include <alloc.h>
  73.  
  74.  
  75. #define FALSE 0
  76. #define TRUE 1
  77.  
  78. typedef int bool;
  79. typedef unsigned char UCHAR;
  80. typedef unsigned int UINT;
  81. typedef unsigned long ULONG;
  82.  
  83. typedef struct codestruct {
  84.         struct codestruct *prefix;
  85.         unsigned char first,suffix;
  86.     } codetype;
  87.  
  88.  
  89. FILE *infile;
  90. UINT screenwidth;           /* The dimensions of the screen */
  91. UINT screenheight;          /*   (not those of the image)   */
  92. bool global;                        /* Is there a global color map? */
  93. int globalbits;                     /* Number of bits of global colors */
  94. UCHAR globalmap[256][3];    /* RGB values for global color map */
  95. char colortable[256][3];            /* Hex intensity strings for an image */
  96. UCHAR *raster;              /* Decoded image data */
  97. codetype codetable[4096];                /* LZW compression code data */
  98. int datasize,codesize,codemask;     /* Decoder working variables */
  99. int clear,eoi;                      /* Special code values */
  100.  
  101. #define INCH  72.0
  102. int EPSF = FALSE;            /* should we generate EPSF?        */
  103. int screen = FALSE;                /* use alternate halftone screen?    */
  104. int landscape = FALSE;            /* display image in landscape mode? */
  105. int copies = 1;                /* number of copies to create    */
  106.  
  107. double pagewidth;
  108. double pageheight;
  109. double imagewidth;
  110. double imageheight;
  111.  
  112.  
  113. void usage(void)
  114. {
  115.     fprintf(stderr,"usage: GIFtoPS2 [-els] [-c{copies}] [-w{width}] [-h{height}] [file]\n");
  116.     exit(-1);
  117. }
  118.  
  119. void fatal(char *s)
  120. {
  121.     fprintf(stderr,"giftops: %s\n",s);
  122.     exit(-1);
  123. }
  124.  
  125. void checksignature(void)
  126. {
  127.     char buf[6];
  128.  
  129.     fread(buf,1,6,infile);
  130.     if (strncmp(buf,"GIF",3)) fatal("file is not a GIF file");
  131.     if (strncmp(&buf[3],"87a",3)) fatal("unknown GIF version number");
  132. }
  133.  
  134. /* Get information which is global to all the images stored in the file */
  135.  
  136. void readscreen(void)
  137. {
  138.     UCHAR buf[7];
  139.  
  140.     fread(buf,1,7,infile);
  141.     screenwidth = buf[0] + (buf[1] << 8);
  142.     screenheight = buf[2] + (buf[3] << 8);
  143.     global = buf[4] & 0x80;
  144.     if (global) {
  145.         globalbits = (buf[4] & 0x07) + 1;
  146.         fread(globalmap,3,1<<globalbits,infile);
  147.     }
  148. }
  149.  
  150. /* Convert a color map (local or global) to an array of two character
  151.    hexadecimal strings, stored in colortable.  RGB is converted to
  152.    8-bit grayscale using integer arithmetic. */
  153.  
  154. void initcolors(char colortable[256][3],UCHAR colormap[256][3],int ncolors)
  155. {
  156.     static char hextab[] = {'0','1','2','3','4','5','6','7',
  157.                 '8','9','A','B','C','D','E','F'};
  158.     UINT color;
  159.     int i;
  160.  
  161.     for (i = 0; i < ncolors; i++) {
  162.         color = 77*colormap[i][0] + 150*colormap[i][1] + 29*colormap[i][2];
  163.         color >>= 8;
  164.         colortable[i][0] = hextab[color >> 4];
  165.         colortable[i][1] = hextab[color & 15];
  166.         colortable[i][2] = '\0';
  167.     }
  168. }
  169.  
  170. /* Write a postscript header to the standard output.
  171.  *
  172.  * imagewidth and imageheight always represent the width/height of the
  173.  * bounding box in the standard PostScript coordinate system, even when
  174.  * the image rotated 90 degrees.
  175.  */
  176.  
  177. void writeheader(UINT width,UINT height)
  178. {
  179.     double aspect, xorg, yorg;
  180.  
  181.     /*
  182.      * using imagewidth and imageheight as maxima, figure out how
  183.      * tall and wide the image will be on the PostScript page.
  184.      */
  185.     aspect = ((double) width) / ((double) height);
  186.     if (landscape) {
  187.         if (aspect >= imageheight / imagewidth)
  188.             imagewidth = imageheight / aspect;
  189.         else
  190.             imageheight = imagewidth * aspect;
  191.     } else {
  192.         if (aspect >= imagewidth / imageheight)
  193.             imageheight = imagewidth / aspect;
  194.         else
  195.             imagewidth = imageheight * aspect;
  196.     }
  197.  
  198.     /*
  199.      * For simplicity's sake, EPSF files have origin (0, 0).
  200.      */
  201.     if (EPSF) {
  202.         xorg = yorg = 0.0;
  203.         printf("%%!PS-Adobe-2.0 EPSF-1.2\n");    /* magic number */
  204.     } else {
  205.         xorg = (pagewidth - imagewidth) / 2.0;
  206.         yorg = (pageheight - imageheight) / 2.0;
  207.         printf("%%!\n");
  208.     }
  209.  
  210.     printf("%%%%BoundingBox: %.3f %.3f %.3f %.3f\n",
  211.            xorg, yorg, xorg + imagewidth, yorg + imageheight);
  212.     printf("%%%%Creator: GIFtoPS2\n");
  213.     printf("%%%%EndComments\n");
  214.  
  215.     /*
  216.      * setting # of copies doesn't make sense if creating EPSF file
  217.      */
  218.     if (!EPSF)
  219.         printf("/#copies %d def\n", copies);
  220.     printf("gsave\n");
  221.     printf("/alternatehalftone %s def\n", screen ? "true" : "false");
  222.     printf("alternatehalftone {\n");
  223.     printf("   currentscreen\n");
  224.     printf("   /proc exch def /angle exch def /frequency exch def\n");
  225.     printf("   /angle 90 def /frequency 60 def\n");
  226.     printf("   frequency angle /proc load setscreen\n");
  227.     printf("} if\n");
  228.  
  229.     printf("/picstr %d string def\n",width);
  230.     printf("/screen {\n");
  231.     printf("   %d %d 8 [%d 0 0 -%d 0 %d]\n",
  232.            width, height, width, height, height);
  233.     printf("   {currentfile picstr readhexstring pop} image} def\n");
  234.     printf("%.3f %.3f translate\n", xorg, yorg);
  235.     if (landscape) {
  236.         printf("%.3f 0 translate 90 rotate %.3f %.3f scale\n",
  237.                imagewidth, imageheight, imagewidth);
  238.     } else {
  239.         printf("%.3f %.3f scale\n", imagewidth, imageheight);
  240.     }
  241.     printf("screen\n");
  242. }
  243.  
  244.  
  245. /* Output the bytes associated with a code to the raster array */
  246.  
  247. void outcode(codetype *p,UCHAR **fill)
  248. {
  249.     if (p->prefix) outcode(p->prefix,fill);
  250.     *(*fill)++ = p->suffix;
  251. }
  252.  
  253. /* Process a compression code.  "clear" resets the code table.  Otherwise
  254.    make a new code table entry, and output the bytes associated with the
  255.    code. */
  256.  
  257. void process(int code,UCHAR **fill)
  258. {
  259.     static avail,oldcode;
  260.     codetype *p;
  261.  
  262.     if (code == clear) {
  263.         codesize = datasize + 1;
  264.         codemask = (1 << codesize) - 1;
  265.         avail = clear + 2;
  266.         oldcode = -1;
  267.     } else if (code < avail) {
  268.         outcode(&codetable[code],fill);
  269.         if (oldcode != -1) {
  270.         p = &codetable[avail++];
  271.         p->prefix = &codetable[oldcode];
  272.         p->first = p->prefix->first;
  273.         p->suffix = codetable[code].first;
  274.         if ((avail & codemask) == 0 && avail < 4096) {
  275.             codesize++;
  276.             codemask += avail;
  277.         }
  278.         }
  279.         oldcode = code;
  280.     } else if (code == avail && oldcode != -1) {
  281.         p = &codetable[avail++];
  282.         p->prefix = &codetable[oldcode];
  283.         p->first = p->prefix->first;
  284.         p->suffix = p->first;
  285.         outcode(p,fill);
  286.         if ((avail & codemask) == 0 && avail < 4096) {
  287.         codesize++;
  288.         codemask += avail;
  289.         }
  290.         oldcode = code;
  291.     } else {
  292.         fatal("illegal code in raster data");
  293.     }
  294. }
  295.  
  296. /* Decode a raster image */
  297.  
  298. void readraster(UINT width,UINT height)
  299. {
  300.     UCHAR *fill = raster;
  301.     UCHAR buf[255];
  302.     int bits=0;
  303.     UINT count;
  304.     ULONG datum=0L;
  305.     UCHAR *ch;
  306.     int code;
  307.  
  308.     datasize = getc(infile);
  309.     clear = 1 << datasize;
  310.     eoi = clear+1;
  311.     codesize = datasize + 1;
  312.     codemask = (1 << codesize) - 1;
  313.     for (code = 0; code < clear; code++) {
  314.         codetable[code].prefix = (codetype*)0;
  315.         codetable[code].first = code;
  316.         codetable[code].suffix = code;
  317.     }
  318.     for (count = getc(infile); count > 0; count = getc(infile)) {
  319.         fread(buf,1,count,infile);
  320.         for (ch=buf; count-- > 0; ch++) {
  321.         datum += (long)*ch << bits;
  322.         bits += 8;
  323.         while (bits >= codesize) {
  324.             code = datum & codemask;
  325.             datum >>= codesize;
  326.             bits -= codesize;
  327.             if (code == eoi) goto exitloop;  /* This kludge put in
  328.                             because some GIF files
  329.                             aren't standard */
  330.             process(code,&fill);
  331.         }
  332.         }
  333.     }
  334. exitloop:
  335.     if (fill != raster + (long)width*height) fatal("raster has the wrong size");
  336. }
  337.  
  338. /* Read a row out of the raster image and write it to the output file */
  339.  
  340. void rasterize(int row,int width)
  341. {
  342.     UCHAR *scanline;
  343.     int i;
  344.  
  345.        scanline = raster + (long)row*width;
  346.     for (i = 0; i < width; i++) {
  347.         if (i % 40 == 0) printf("\n");  /* break line every 80 chars */
  348.         fputs(colortable[*scanline++],stdout);
  349.     }
  350.     printf("\n");
  351. }
  352.  
  353. /* write image trailer to standard output */
  354.  
  355. void writetrailer(void)
  356. {
  357.     printf("\n\ngrestore\n");
  358.     if (!EPSF)
  359.         printf("showpage\n");
  360. }
  361.  
  362. /* Read image information (position, size, local color map, etc.) and convert
  363.    to postscript. */
  364.  
  365. void readimage(void)
  366. {
  367.     UCHAR buf[9];
  368.     UINT top,width,height;
  369.     ULONG lwidth, lheight;
  370.     bool local,interleaved;
  371.     UCHAR localmap[256][3];
  372.     int localbits;
  373.     int *interleavetable;
  374.     int row;
  375.     int i;
  376.  
  377.     fread(buf,1,9,infile);
  378.     top = buf[2] + (buf[3] << 8);
  379.     lwidth = width = buf[4] + (buf[5] << 8);
  380.     lheight = height = buf[6] + (buf[7] << 8);
  381.     local = buf[8] & 0x80;
  382.     interleaved = buf[8] & 0x40;
  383.     if (local) {
  384.         localbits = (buf[8] & 0x7) + 1;
  385.         fread(localmap,3,1<<localbits,infile);
  386.         initcolors(colortable,localmap,1<<localbits);
  387.     } else if (global) {
  388.         initcolors(colortable,globalmap,1<<globalbits);
  389.     } else {
  390.         fatal("no colormap present for image");
  391.     }
  392.     writeheader(width,height);
  393.     raster=(UCHAR *)malloc(lwidth*lheight);
  394.     if (!raster) fatal("not enough memory for image");
  395.     readraster(width,height);
  396.     if (interleaved) {
  397.         interleavetable = (int*)malloc(lheight*sizeof(int));
  398.         if (!interleavetable) fatal("not enough memory for interleave table");
  399.         row = 0;
  400.         for (i = top; i < top+height; i += 8) interleavetable[i] = row++;
  401.         for (i = top+4; i < top+height; i += 8) interleavetable[i] = row++;
  402.         for (i = top+2; i < top+height; i += 4) interleavetable[i] = row++;
  403.         for (i = top+1; i < top+height; i += 2) interleavetable[i] = row++;
  404.         for (row = top; row < top+height; row++) rasterize(interleavetable[row],width);
  405.         free(interleavetable);
  406.     } else {
  407.         for (row = top; row < top+height; row++) rasterize(row,width);
  408.     }
  409.     free(raster);
  410.     writetrailer();
  411. }
  412.  
  413. /* Read a GIF extension block (and do nothing with it). */
  414.  
  415. void readextension(void)
  416. {
  417.     int count;
  418.     char buf[255];
  419.  
  420.     getc(infile);
  421.     count=getc(infile);
  422.     while (count)
  423.     {
  424.         fread(buf,1,count,infile);
  425.         count=getc(infile);
  426.     }
  427. }
  428.  
  429. extern char    *optarg;
  430. extern int      optind;
  431.  
  432. int main(int argc,char **argv)
  433. {
  434.  int quit = FALSE;
  435.  int opt, posn = 0;
  436.  char ch, gifname[40];
  437.  char optarg[10];
  438.  
  439.  pagewidth = 8.5 * INCH;        /* width, height of PostScript page    */
  440.  pageheight = 11.0 * INCH;
  441.  imagewidth = 7.5 * INCH;    /* default max image height        */
  442.  imageheight = 9.0 * INCH;
  443.  
  444.  if(argc<2)
  445.     usage();
  446.  
  447.  while((++posn < argc) && (argv[posn][0] == '-'))
  448.  {
  449.     opt = argv[posn][1];
  450.     if(strlen(argv[posn]) > 2) strcpy(optarg, argv[posn]+2);
  451.  
  452.  
  453.     switch (opt)
  454.     {
  455.         case 'c':
  456.             if ((copies = atoi(optarg)) <= 0)
  457.             fatal("#copies must be > 0");
  458.             break;
  459.         case 'e':
  460.             EPSF = TRUE;
  461.             break;
  462.         case 'l':
  463.             landscape = TRUE;
  464.             break;
  465.         case 's':
  466.             screen = TRUE;
  467.             break;
  468.         case 'w':
  469.             sscanf(optarg,"%lf",&imagewidth);
  470.             imagewidth *= INCH;
  471.             if (imagewidth <= 0.0)
  472.                 fatal("negative image width");
  473.             break;
  474.         case 'h':
  475.             sscanf(optarg,"%lf",&imageheight);
  476.             imageheight *= INCH;
  477.             if (imageheight <= 0.0)
  478.                 fatal("negative image height");
  479.             break;
  480.         default:
  481.             usage();
  482.             break;
  483.     }
  484.  }
  485.  strcpy(gifname, argv[posn]);
  486.  infile = fopen(gifname,"rb");
  487.  if (infile == NULL)
  488.  {
  489.     perror("giftops");
  490.     exit(-1);
  491.  }
  492.  
  493.  checksignature();
  494.  readscreen();
  495.  do
  496.  {
  497.     ch = getc(infile);
  498.     switch (ch)
  499.     {
  500.         case '\0':  break;  /* this kludge for non-standard files */
  501.         case ',':   readimage();
  502.                 break;
  503.         case ';':   quit = TRUE;
  504.                 break;
  505.         case '!':   readextension();
  506.                 break;
  507.         default:    fatal("illegal GIF block type");
  508.                 break;
  509.      }
  510.   } while (!quit);
  511.   return 0;
  512. }
  513.