1 /***********************************************************
2  *
3  * GXGIF: a grads metafile to GIF converter.
4  * Written by Matthias Muennich
5  *
6  *   $Log: gxgif.c,v $
7  *   Revision 1.3  2003/06/24 21:31:08  joew
8  *   put conditionals around #include malloc.h, for Mac OS X
9  *
10  *   Revision 1.2  2002/10/28 19:08:33  joew
11  *   Preliminary change for 'autonconfiscation' of GrADS: added a conditional
12  *   #include "config.h" to each C file. The GNU configure script generates a unique config.h for each platform in place of -D arguments to the compiler.
13  *   The include is only done when GNU configure is used.
14  *
15  *   Revision 1.1.1.1  2002/06/27 19:44:05  cvsadmin
16  *   initial GrADS CVS import - release 1.8sl10
17  *
18  *   Revision 1.1.1.1  2001/10/18 02:00:54  Administrator
19  *   Initial repository: v1.8SL8 plus slight MSDOS mods
20  *
21  *   Revision 0.4  1997/12/19 10:43:56  m211033
22  *   Added a version statement in verbose mode.
23  *
24  *   Revision 0.3  1997/12/04 10:08:26  m211033
25  *   Copied the subroutines used from gd1.2 into gxgif.c
26  *   to make the code independent of the gd library.
27  *   Added an option "-h" for horizontal filling of polygons
28  *   (=> horizontal spurious lines).
29  *   Fixed the output file names for more that 1 image.
30  *   Fixed the "-r" option.
31  *
32  *   Revision 0.2  1997/02/25 13:30:35  m211033
33  *   Added support for different line thicknesses and
34  *   cleaned up the code.
35  *
36  *   Revision 0.1  1997/02/21 15:20:51  m211033
37  *   different line width are not yet supported.
38  *   The gdImageFilledPolygon routine gives wrong height
39  *   when filling horizontally. This led to flaud horizontal
40  *   lines in the GIF file. I rewrote it switching x and y
41  *   coordinates. The lines disappeared. Now vertical lines
42  *   may show up. For a fix we have to wait for a better
43  *   version on gdImageFilledPolygon.
44  *   No black and white mode is available right now.
45  *
46  *
47  *
48  ***********************************************************/
49 
50 #ifdef HAVE_CONFIG_H
51 #include <config.h>
52 
53 /* If autoconfed, only include malloc.h when it's presen */
54 #ifdef HAVE_MALLOC_H
55 #include <malloc.h>
56 #endif
57 
58 #else /* undef HAVE_CONFIG_H */
59 
60 #include <malloc.h>
61 
62 #endif /* HAVE_CONFIG_H */
63 
64 #include <stdio.h>
65 #include <math.h>
66 #include <string.h>
67 #include <stdlib.h>
68 /*  #include "gd.h" */
69 static char rcsid[] = "$Id: gxgif.c,v 1.3 2003/06/24 21:31:08 joew Exp $";
70 
71 /* ---------------------------- begin gd.h -------------------------------------- */
72 #ifndef GD_H
73 #define GD_H 1
74 
75 /* gd.h: declarations file for the gifdraw module.
76 
77 	Written by Tom Boutell, 5/94.
78 	Copyright 1994, Cold Spring Harbor Labs.
79 	Permission granted to use this code in any fashion provided
80 	that this notice is retained and any alterations are
81 	labeled as such. It is requested, but not required, that
82 	you share extensions to this module with us so that we
83 	can incorporate them into new versions. */
84 
85 /* stdio is needed for file I/O. */
86 #include <stdio.h>
87 
88 /* This can't be changed, it's part of the GIF specification. */
89 
90 #define gdMaxColors 256
91 
92 /* Image type. See functions below; you will not need to change
93 	the elements directly. Use the provided macros to
94 	access sx, sy, the color table, and colorsTotal for
95 	read-only purposes. */
96 
97 typedef struct gdImageStruct {
98 	unsigned char ** pixels;
99 	int sx;
100 	int sy;
101 	int colorsTotal;
102 	int red[gdMaxColors];
103 	int green[gdMaxColors];
104 	int blue[gdMaxColors];
105 	int open[gdMaxColors];
106 	int transparent;
107 	int *polyInts;
108 	int polyAllocated;
109 	struct gdImageStruct *brush;
110 	struct gdImageStruct *tile;
111 	int brushColorMap[gdMaxColors];
112 	int tileColorMap[gdMaxColors];
113 	int styleLength;
114 	int stylePos;
115 	int *style;
116 	int interlace;
117 } gdImage;
118 
119 typedef gdImage * gdImagePtr;
120 
121 typedef struct {
122 	/* # of characters in font */
123 	int nchars;
124 	/* First character is numbered... (usually 32 = space) */
125 	int offset;
126 	/* Character width and height */
127 	int w;
128 	int h;
129 	/* Font data; array of characters, one row after another.
130 		Easily included in code, also easily loaded from
131 		data files. */
132 	char *data;
133 } gdFont;
134 
135 /* Text functions take these. */
136 typedef gdFont *gdFontPtr;
137 
138 /* For backwards compatibility only. Use gdImageSetStyle()
139 	for MUCH more flexible line drawing. Also see
140 	gdImageSetBrush(). */
141 #define gdDashSize 4
142 
143 /* Special colors. */
144 
145 #define gdStyled (-2)
146 #define gdBrushed (-3)
147 #define gdStyledBrushed (-4)
148 #define gdTiled (-5)
149 
150 /* NOT the same as the transparent color index.
151 	This is used in line styles only. */
152 #define gdTransparent (-6)
153 
154 /* Functions to manipulate images. */
155 
156 gdImagePtr gdImageCreate(int sx, int sy);
157 gdImagePtr gdImageCreateFromGif(FILE *fd);
158 gdImagePtr gdImageCreateFromGd(FILE *in);
159 gdImagePtr gdImageCreateFromXbm(FILE *fd);
160 void gdImageDestroy(gdImagePtr im);
161 void gdImageSetPixel(gdImagePtr im, int x, int y, int color);
162 int gdImageGetPixel(gdImagePtr im, int x, int y);
163 void gdImageLine(gdImagePtr im, int x1, int y1, int x2, int y2, int color);
164 /* For backwards compatibility only. Use gdImageSetStyle()
165 	for much more flexible line drawing. */
166 void gdImageDashedLine(gdImagePtr im, int x1, int y1, int x2, int y2, int color);
167 /* Corners specified (not width and height). Upper left first, lower right
168  	second. */
169 void gdImageRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color);
170 /* Solid bar. Upper left corner first, lower right corner second. */
171 void gdImageFilledRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color);
172 int gdImageBoundsSafe(gdImagePtr im, int x, int y);
173 void gdImageChar(gdImagePtr im, gdFontPtr f, int x, int y, int c, int color);
174 void gdImageCharUp(gdImagePtr im, gdFontPtr f, int x, int y, char c, int color);
175 void gdImageString(gdImagePtr im, gdFontPtr f, int x, int y, char *s, int color);
176 void gdImageStringUp(gdImagePtr im, gdFontPtr f, int x, int y, char *s, int color);
177 
178 /* Point type for use in polygon drawing. */
179 
180 typedef struct {
181 	int x, y;
182 } gdPoint, *gdPointPtr;
183 
184 void gdImagePolygon(gdImagePtr im, gdPointPtr p, int n, int c);
185 void gdImageFilledPolygon(gdImagePtr im, gdPointPtr p, int n, int c);
186 
187 int gdImageColorAllocate(gdImagePtr im, int r, int g, int b);
188 int gdImageColorClosest(gdImagePtr im, int r, int g, int b);
189 int gdImageColorExact(gdImagePtr im, int r, int g, int b);
190 void gdImageColorDeallocate(gdImagePtr im, int color);
191 void gdImageColorTransparent(gdImagePtr im, int color);
192 void gdImageGif(gdImagePtr im, FILE *out);
193 void gdImageGd(gdImagePtr im, FILE *out);
194 void gdImageArc(gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color);
195 void gdImageFillToBorder(gdImagePtr im, int x, int y, int border, int color);
196 void gdImageFill(gdImagePtr im, int x, int y, int color);
197 void gdImageCopy(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h);
198 /* Stretches or shrinks to fit, as needed */
199 void gdImageCopyResized(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH);
200 void gdImageSetBrush(gdImagePtr im, gdImagePtr brush);
201 void gdImageSetTile(gdImagePtr im, gdImagePtr tile);
202 void gdImageSetStyle(gdImagePtr im, int *style, int noOfPixels);
203 /* On or off (1 or 0) */
204 void gdImageInterlace(gdImagePtr im, int interlaceArg);
205 
206 /* Macros to access information about images. READ ONLY. Changing
207 	these values will NOT have the desired result. */
208 #define gdImageSX(im) ((im)->sx)
209 #define gdImageSY(im) ((im)->sy)
210 #define gdImageColorsTotal(im) ((im)->colorsTotal)
211 #define gdImageRed(im, c) ((im)->red[(c)])
212 #define gdImageGreen(im, c) ((im)->green[(c)])
213 #define gdImageBlue(im, c) ((im)->blue[(c)])
214 #define gdImageGetTransparent(im) ((im)->transparent)
215 #define gdImageGetInterlaced(im) ((im)->interlace)
216 #endif
217 
218 /* ---------------------------- end gd.h -------------------------------------- */
219 
220 
221 
222 /* default file extensions */
223 #define IN_EXT "gm"
224 #define OUT_EXT "gif"
225 
226 /* default size of the graph */
227 #define SX 550
228 #define SY 425
229 
230 /* PNMAX: maximal points in polygons */
231 #define PNMAX 4096
232 #ifdef __GNUC__
233 #define fpos_t long
234 #endif
235 
236 /* ---------------------------- global vars -------------------------------------- */
237 
238 struct options {int reverse, fillx, verbose, sx, sy;}; /* command line options (flags) */
239 FILE *infile, *outfile;
240 gdImagePtr im,w[12];
241 int cidx[13][100];  /* color index table [0][*]: filling, [1-12][*] brush images */
242 int r[100]={0, 255, 240,   0,  31,   0, 220, 230, 240, 161, 161,   0, 230,   0, 110, 125},
243     g[100]={0, 255,   0, 220,  61, 199,   0, 220, 130,   0, 230, 161, 176, 209,   0, 125},
244     b[100]={0, 255,   0,   0, 250, 199,  99,  51,  41, 199,  51, 230,  46, 140, 220, 125};
245 
246 /* ---------------------------- prototypes --------------------------------------- */
247 
248 void printOptions(char *argv[]); /* print command line options */
249 void drawLine(gdPoint pnts[],short *pcnt,int wd,int color); /* draw a polygon */
250 void parseArg(int argc,char *argv[],struct options *o,char **fin, char **fout); /* parse command line */
251 void openFiles(char **fin, char **fout, short verbose); /* Open files */
252 void defBGround(gdImagePtr im,short reverse); /* set background */
253 
254 /* changed gd-library routines */
255 void gdImagePolygonUnclosed(gdImagePtr im, gdPointPtr p, int n, int c);
256 void gdImageFilledPolygonx(gdImagePtr im, gdPointPtr p, int n, int c);
257 extern int gdCompareInt(const void *a, const void *b);
258 
259 /* --------------------------------------------------------------------------------- */
main(int argc,char * argv[])260 int main (int argc, char *argv[])  {
261    short cmd,opts[4], rotate=0;
262    int col=0, wd=0;
263    int sx=SX,sy=SY,sh,lly,ury;
264    short coldef[100];
265    float blowx,blowy;
266    gdPoint pnts[PNMAX];                    /* points of a polygon */
267    struct options o;                      /* command line options */
268    register int  i,j;
269    short pcnt,fcnt;
270    char *fin=NULL,*fout=NULL,*fout_new=NULL;              /* file names */
271    fpos_t infile_pos;
272    short width[12] = {                      /* width (units: .001 inch) */
273                2 ,7 ,10 ,14 ,17 ,20 ,
274 	       24 ,27 ,31 ,34 ,38 ,41 };
275 
276    o.reverse=o.verbose=o.fillx=o.sx=o.sy=0;
277    for(i=0;i<13;i++)
278      for(j=0;j<100;j++) cidx[i][j]=-1;
279    for(i=0;i<16;i++) coldef[i]=1;
280    for(i=16;i<100;i++) coldef[i]=0;
281 
282   parseArg(argc,argv,&o,&fin,&fout);     /* Parse command line arguments */
283   openFiles(&fin,&fout,o.verbose);                  /* open files */
284 
285   /* Translate metafile */
286 
287   fcnt = 1;
288   while (1) {
289     fread (&cmd, sizeof(short), 1, infile);
290 
291     if (cmd==-11){				/* Draw to */
292       fread (opts, sizeof(short), 2, infile);
293       pnts[++pcnt].x=opts[0]*blowx;
294       pnts[pcnt].y= sy-opts[1]*blowy;
295     }
296     else if (cmd==-10){				/* Move to */
297       if (pcnt) drawLine(pnts,&pcnt,wd,col);
298       fread ((char *) opts, sizeof(short), 2, infile);
299       pnts[pcnt].x=opts[0]*blowx;
300       pnts[pcnt].y= sy-opts[1]*blowy;
301     }
302     else if (cmd==-4) {				/* Set line width */
303       if (pcnt) drawLine(pnts,&pcnt,wd,col);
304       fread ((char *)opts, sizeof(short), 2, infile);
305       i = opts[0];
306       if (i>12) i=12;
307       else if (i<1) i=1;
308       wd=width[i-1]*blowx+1;
309     }
310     else if (cmd==-3) {				/* Set color */
311       if (pcnt) drawLine(pnts,&pcnt,wd,col);
312       fread ((char *)opts, sizeof(short), 1, infile);
313       col = opts[0];
314       if (col<0) col=0;
315       if (col>99) col=99;
316       if (!(coldef[i])) col=15;
317       if(o.reverse){
318 	  if(col==1) col=0;
319 	  else if(col==0) col=1;
320       }
321     }
322     else if (cmd==-7){				/* Start fill */
323       fread ((char *)opts, sizeof(short), 1, infile);
324     }
325     else if (cmd==-8){				/* End fill */
326       if (pcnt>1)
327         if(cidx[0][col]<0){
328 	  cidx[0][col]=gdImageColorAllocate(im, r[col],g[col],b[col]);
329 	}
330         if(o.fillx) gdImageFilledPolygon(im, pnts, ++pcnt, cidx[0][col]);
331         else gdImageFilledPolygonx(im, pnts, ++pcnt, cidx[0][col]);
332         pcnt=0;
333     }
334     else if (cmd==-6){				/* Rectangle fill */
335       if (pcnt) drawLine(pnts,&pcnt,wd,col);
336       fread ((char *)opts, sizeof(short), 4, infile);
337       lly=sy-opts[2]*blowy;
338       ury=sy-opts[3]*blowy;
339         if(cidx[0][col]<0)
340 	  cidx[0][col]=gdImageColorAllocate(im, r[col],g[col],b[col]);
341       gdImageFilledRectangle(im, (int) opts[0]*blowx,ury,
342 			     (int) opts[1]*blowx,lly, cidx[0][col]);
343     }
344     else if (cmd==-9) {				/* End of plotting */
345       if(o.verbose) printf ("Number of pages = %i\n",fcnt);
346       /*       gdImageInterlace(im, 1); */
347       gdImageGif(im, outfile);
348       fclose(outfile);
349       gdImageDestroy(im);
350       return(0);
351     }
352     else if (cmd==-1) {				/* Start of plotting */
353       fread ((char *)opts, sizeof(short), 2, infile);
354       if(opts[0]<opts[1]) {sh=sx; sx=sy; sy=sh;}
355       if(o.sx) {
356           sx=o.sx;
357          if(o.sy==0) sy=sx *(opts[1]/100)/(opts[0]/100);
358       }
359       if(o.sy) {
360           sy=o.sy;
361           if(o.sx==0) sx=sy*(opts[0]/100)/(opts[1]/100);
362       }
363       blowx=(float)sx/(float)opts[0];  /* picture size in metafile: opts[0] x opts[1] */
364       blowy=(float)sy/(float)opts[1];
365       if(o.verbose) printf("Image size: %d x %d pixels\n",sx,sy);
366 
367       for (i=0;i<=width[11]*blowx;i++)
368 	  w[i] = gdImageCreate(i+1,i+1);
369       im = gdImageCreate(sx,sy);
370       defBGround(im,o.reverse);
371       col=1;
372       pcnt = 0;
373     }
374     else if (cmd==-2) {				/* New Page */
375       if (pcnt) drawLine(pnts,&pcnt,wd,col);
376       /* gdImageInterlace(im, 1); */
377       gdImageGif(im, outfile);
378       fclose(outfile);
379       gdImageDestroy(im);
380       for (i=0;i<=width[11]*blowx;i++)
381 	  gdImageDestroy(w[i]);
382       fgetpos(infile,&infile_pos);
383       fread (&cmd , sizeof(short), 1, infile);
384       fsetpos(infile,&infile_pos);
385       if (cmd != -9) {  /* if next command is not end_of_plotting */
386 	  if(fout_new==NULL){
387              fout[strlen(fout)-4]='\0';
388              fout_new = (char *) malloc(sizeof(char)*150);
389 	  }
390           strcpy(fout_new,fout);
391 	  sprintf(fout_new+strlen(fout_new), "_%d",++fcnt);
392           strcpy((fout_new)+strlen(fout_new),"."OUT_EXT);
393           if(o.verbose) printf ("New GIF-file:%s\n",fout_new);
394           outfile = fopen(fout_new,"wb");
395 #ifdef NOTDEF
396 	  strcpy(fout+strlen(fout),"1");
397           outfile = fopen(fout,"wb");
398 #endif
399           for (i=0;i<=width[11]*blowx;i++)
400 	      w[i] = gdImageCreate(i+1,i+1);
401           im = gdImageCreate(sx,sy);
402           defBGround(im,o.reverse);
403           col=1;
404           pcnt = 0;
405       }
406       else return(0);
407     }
408     else if (cmd==-5){				/* Define new color */
409       fread ((char *)opts, sizeof(short), 4, infile);
410       i = opts[0];
411       if (i>15 && i<100) {
412 	  r[i]=opts[1];
413 	  g[i]=opts[2];
414 	  b[i]=opts[3];
415 	  coldef[i]=1;
416       }
417     }
418     else if (cmd==-20) {		/* Draw button -- ignore */
419       fread ((char *)opts, sizeof(short), 1, infile);
420     }
421     else {
422        printf ("Fatal error: Invalid command \"%i\" found in metafile\"%s\".\n",cmd,fin);
423        printf ("Is \"%s\" really a GrADS (v1.5 or higher) metafile?\n",fin);
424       return(1);
425     }
426   }
427 }
428 /* --------------------------------------------------------------------------------- */
429 /* --------------------------------------------------------------------------------- */
430 
defBGround(gdImagePtr im,short reverse)431 void defBGround(gdImagePtr im, short reverse){
432     if(reverse)
433          cidx[0][1]=gdImageColorAllocate(im, 255, 255, 255); /* white background */
434     else
435          cidx[0][0]=gdImageColorAllocate(im, 0, 0, 0);       /* black background */
436     return;
437 }
438 
439 /* --------------------------------------------------------------------------------- */
440 
drawLine(gdPoint pnts[],short * pcnt,int wd,int col)441 void drawLine(gdPoint pnts[],short *pcnt,int wd, int col){
442     if(cidx[wd][col]<0)
443       cidx[wd][col]=gdImageColorAllocate(w[wd-1],r[col],g[col],b[col]);
444     gdImageFilledRectangle(w[wd-1],0,0,wd,wd, cidx[wd][col]);
445     gdImageSetBrush(im, w[wd-1]);
446     if(*pcnt>1) gdImagePolygonUnclosed(im, pnts, (*pcnt)+1, gdBrushed);
447     else gdImageLine(im, pnts[0].x, pnts[0].y,pnts[1].x,pnts[1].y,gdBrushed);
448    *pcnt=0;
449    return;
450 }
451 /* --------------------------------------------------------------------------------- */
parseArg(int argc,char * argv[],struct options * o,char ** fin,char ** fout)452 void parseArg(int argc,char *argv[],struct options *o,char **fin, char **fout){
453      register int i,j;
454      if(argc==1) printOptions(argv);
455      for (i=1;i<argc;i++) {
456        if (*(argv[i])=='-') {  /* parse options */
457          j = 0;
458          while (*(argv[i]+(++j))) {
459            if (*(argv[i]+j)=='i') {*fin = argv[++i];break;}
460            else if (*(argv[i]+j)=='h') o->fillx = 1;
461            else if (*(argv[i]+j)=='o') {*fout = argv[++i];break;}
462            else if (*(argv[i]+j)=='r') o->reverse = 1;
463            else if (*(argv[i]+j)=='x') {
464 	     sscanf(argv[++i],"%d",&(o->sx));break;
465 	   }
466            else if (*(argv[i]+j)=='y') {
467 	     sscanf(argv[++i],"%d",&(o->sy));break;
468 	   }
469            else if (*(argv[i]+j)=='v') {
470 	       o->verbose = 1;
471 	       printf("This is gxgif $Revision: 1.3 $, $Date: 2003/06/24 21:31:08 $\n");
472 	   }
473            else {
474 	     fprintf(stderr,"Unknown option: %s\n\n",argv[i]);
475 	     printOptions(argv);
476 	     exit(1);
477 	   }
478          }
479        }
480       else  /* No command line "-" */
481         *fin=argv[i];
482     }
483     return;
484 }
485 /* --------------------------------------------------------------------------------- */
486 
printOptions(char * argv[])487 void printOptions(char *argv[]){
488        fprintf(stderr,"%s%s%s","Usage: ",argv[0],
489 	   " [-hrv -x <pixels> -y <pixels> -i <in_file>[."  IN_EXT
490            "] -o <out_file>] [<in_file>[."IN_EXT"]].\n");
491        fprintf(stderr,"Options:\n");
492        fprintf(stderr,"     -i   <in_file>[."IN_EXT"].\n");;
493        fprintf(stderr,"     -h   Fill polygons horizontally.\n");
494        fprintf(stderr,"     -o   <out_file> (default: basename(in_file)."OUT_EXT", '-' = stdout).\n");
495        fprintf(stderr,"     -r   Black background.\n");
496        fprintf(stderr,"     -v   Verbose.\n");
497        fprintf(stderr,"     -x <pixels>  # pixels horizontally.\n");
498        fprintf(stderr,"     -y <pixels>  # pixels vertically.\n");
499      exit(8);
500      }
501 /* --------------------------------------------------------------------------------- */
502 
openFiles(char ** fin,char ** fout,short verbose)503 void openFiles(char **fin, char **fout,short verbose){ /* Open files */
504   int i;
505 
506   if (*fin==NULL) {
507     *fin = (char *) malloc(sizeof(char)*150);
508      fgets(*fin,150,stdin);
509      printf("read infile = %s\n",*fin);
510   }
511   infile = fopen(*fin ,"rb");
512   if (infile == NULL) {
513     *fin=strcat(*fin,"."IN_EXT);
514     infile = fopen(*fin,"rb");
515     if (infile == NULL) {
516       (*fin)[strlen(*fin)-3]='\0';
517       printf ("Input file %s[."IN_EXT"] not found.\n",*fin);
518       exit(1);
519     }
520   }
521   if (*fout==NULL) {
522     *fout = (char *) malloc(sizeof(char)*150);
523     strcpy(*fout,*fin);
524     for (i=strlen(*fout)-1;i>=0;i--) {
525       if((*fout)[i]=='.') {strcpy((*fout)+i+1,OUT_EXT);
526 	break;
527       }
528       if(i==0){strcpy((*fout)+strlen(*fout),"."OUT_EXT);}
529     }
530   }
531   if(strcmp(*fout,"-")==0) outfile=stdout;
532   else outfile = fopen(*fout,"wb");
533   if (outfile==NULL) {
534     printf ("Error opening output file %s \n",*fout);
535     exit(1);
536   }
537   if(verbose) {
538     printf("GrADS metafile: %s\n",*fin);
539     if(strcmp(*fout,"-")==0) printf("output to stdout\n");
540     else printf("GIF-file: %s\n",*fout);
541   }
542   return;
543 }
544 /* --------------------------------------------------------------------------------- */
gdImagePolygonUnclosed(gdImagePtr im,gdPointPtr p,int n,int c)545 void gdImagePolygonUnclosed(gdImagePtr im, gdPointPtr p, int n, int c)
546 {
547         int i;
548         int lx, ly;
549         if (!n) {
550                 return;
551         }
552         lx = p->x;
553         ly = p->y;
554         /* gdImageLine(im, lx, ly, p[n-1].x, p[n-1].y, c); */
555         for (i=1; (i < n); i++) {
556                 p++;
557                 gdImageLine(im, lx, ly, p->x, p->y, c);
558                 lx = p->x;
559                 ly = p->y;
560         }
561 }
562 
563 /* --------------------------------------------------------------------------------- */
564 
gdImageFilledPolygonx(gdImagePtr im,gdPointPtr p,int n,int c)565 void gdImageFilledPolygonx(gdImagePtr im, gdPointPtr p, int n, int c)
566 {
567 	int i;
568 	int x;
569 	int x1, x2;
570 	int ints;
571 	if (!n) {
572 		return;
573 	}
574 	if (!im->polyAllocated) {
575 		im->polyInts = (int *) malloc(sizeof(int) * n);
576 		im->polyAllocated = n;
577 	}
578 	if (im->polyAllocated < n) {
579 		while (im->polyAllocated < n) {
580 			im->polyAllocated *= 2;
581 		}
582 		im->polyInts = (int *) realloc(im->polyInts,
583 			sizeof(int) * im->polyAllocated);
584 	}
585 	x1 = p[0].x;
586 	x2 = p[0].x;
587 	for (i=1; (i < n); i++) {
588 		if (p[i].x < x1) {
589 			x1 = p[i].x;
590 		}
591 		if (p[i].x > x2) {
592 			x2 = p[i].x;
593 		}
594 	}
595 	for (x=x1; (x <= x2); x++) {
596 		int interLast = 0;
597 		int dirLast = 0;
598 		int interFirst = 1;
599 		ints = 0;
600 		for (i=0; (i <= n); i++) {
601 			int y1, y2;
602 			int x1, x2;
603 			int dir;
604 			int ind1, ind2;
605 			int lastInd1 = 0;
606 			if ((i == n) || (!i)) {
607 				ind1 = n-1;
608 				ind2 = 0;
609 			} else {
610 				ind1 = i-1;
611 				ind2 = i;
612 			}
613 			x1 = p[ind1].x;
614 			x2 = p[ind2].x;
615 			if (x1 < x2) {
616 				x1 = p[ind1].x;
617 				x2 = p[ind2].x;
618 				y1 = p[ind1].y;
619 				y2 = p[ind2].y;
620 				dir = -1;
621 			} else if (x1 > x2) {
622 				x2 = p[ind1].x;
623 				x1 = p[ind2].x;
624 				y2 = p[ind1].y;
625 				y1 = p[ind2].y;
626 				dir = 1;
627 			} else {
628 				/* Horizontal; just draw it */
629 				gdImageLine(im,
630 					 x1, p[ind1].y,
631 					x1, p[ind2].y,
632 					c);
633 				continue;
634 			}
635 			if ((x >= x1) && (x <= x2)) {
636 				int inter =
637 					(x-x1) * (y2-y1) / (x2-x1) + y1;
638 				/* Only count intersections once
639 					except at maxima and minima. Also,
640 					if two consecutive intersections are
641 					endpoints of the same horizontal line
642 					that is not at a maxima or minima,
643 					discard the leftmost of the two. */
644 				if (!interFirst) {
645 					if ((p[ind1].x == p[lastInd1].x) &&
646 						(p[ind1].y != p[lastInd1].y)) {
647 						if (dir == dirLast) {
648 							if (inter > interLast) {
649 								/* Replace the old one */
650 								im->polyInts[ints] = inter;
651 							} else {
652 								/* Discard this one */
653 							}
654 							continue;
655 						}
656 					}
657 					if (inter == interLast) {
658 						if (dir == dirLast) {
659 							continue;
660 						}
661 					}
662 				}
663 				if (i > 0) {
664 					im->polyInts[ints++] = inter;
665 				}
666 				lastInd1 = i;
667 				dirLast = dir;
668 				interLast = inter;
669 				interFirst = 0;
670 			}
671 		}
672 		qsort(im->polyInts, ints, sizeof(int), gdCompareInt);
673 		for (i=0; (i < (ints-1)); i+=2) {
674 			gdImageLine(im, x, im->polyInts[i],
675 				 x, im->polyInts[i+1],  c);
676 		}
677 	}
678 }
679 /* ---------------------------- begin gd.c -------------------------------------- */
680 static void gdImageBrushApply(gdImagePtr im, int x, int y);
681 static void gdImageTileApply(gdImagePtr im, int x, int y);
682 
gdImageCreate(int sx,int sy)683 gdImagePtr gdImageCreate(int sx, int sy)
684 {
685 	int i;
686 	gdImagePtr im;
687 	im = (gdImage *) malloc(sizeof(gdImage));
688 	im->pixels = (unsigned char **) malloc(sizeof(unsigned char *) * sx);
689 	im->polyInts = 0;
690 	im->polyAllocated = 0;
691 	im->brush = 0;
692 	im->tile = 0;
693 	im->style = 0;
694 	for (i=0; (i<sx); i++) {
695 		im->pixels[i] = (unsigned char *) calloc(
696 			sy, sizeof(unsigned char));
697 	}
698 	im->sx = sx;
699 	im->sy = sy;
700 	im->colorsTotal = 0;
701 	im->transparent = (-1);
702 	im->interlace = 0;
703 	return im;
704 }
705 
gdImageDestroy(gdImagePtr im)706 void gdImageDestroy(gdImagePtr im)
707 {
708 	int i;
709 	for (i=0; (i<im->sx); i++) {
710 		free(im->pixels[i]);
711 	}
712 	free(im->pixels);
713 	if (im->polyInts) {
714 			free(im->polyInts);
715 	}
716 	if (im->style) {
717 		free(im->style);
718 	}
719 	free(im);
720 }
721 
gdImageColorClosest(gdImagePtr im,int r,int g,int b)722 int gdImageColorClosest(gdImagePtr im, int r, int g, int b)
723 {
724 	int i;
725 	long rd, gd, bd;
726 	int ct = (-1);
727 	long mindist = 0;
728 	for (i=0; (i<(im->colorsTotal)); i++) {
729 		long dist;
730 		if (im->open[i]) {
731 			continue;
732 		}
733 		rd = (im->red[i] - r);
734 		gd = (im->green[i] - g);
735 		bd = (im->blue[i] - b);
736 		dist = rd * rd + gd * gd + bd * bd;
737 		if ((i == 0) || (dist < mindist)) {
738 			mindist = dist;
739 			ct = i;
740 		}
741 	}
742 	return ct;
743 }
744 
gdImageColorExact(gdImagePtr im,int r,int g,int b)745 int gdImageColorExact(gdImagePtr im, int r, int g, int b)
746 {
747 	int i;
748 	for (i=0; (i<(im->colorsTotal)); i++) {
749 		if (im->open[i]) {
750 			continue;
751 		}
752 		if ((im->red[i] == r) &&
753 			(im->green[i] == g) &&
754 			(im->blue[i] == b)) {
755 			return i;
756 		}
757 	}
758 	return -1;
759 }
760 
gdImageColorAllocate(gdImagePtr im,int r,int g,int b)761 int gdImageColorAllocate(gdImagePtr im, int r, int g, int b)
762 {
763 	int i;
764 	int ct = (-1);
765 	for (i=0; (i<(im->colorsTotal)); i++) {
766 		if (im->open[i]) {
767 			ct = i;
768 			break;
769 		}
770 	}
771 	if (ct == (-1)) {
772 		ct = im->colorsTotal;
773 		if (ct == gdMaxColors) {
774 			return -1;
775 		}
776 		im->colorsTotal++;
777 	}
778 	im->red[ct] = r;
779 	im->green[ct] = g;
780 	im->blue[ct] = b;
781 	im->open[ct] = 0;
782 	return ct;
783 }
784 
gdImageColorDeallocate(gdImagePtr im,int color)785 void gdImageColorDeallocate(gdImagePtr im, int color)
786 {
787 	/* Mark it open. */
788 	im->open[color] = 1;
789 }
790 
gdImageColorTransparent(gdImagePtr im,int color)791 void gdImageColorTransparent(gdImagePtr im, int color)
792 {
793 	im->transparent = color;
794 }
795 
gdImageSetPixel(gdImagePtr im,int x,int y,int color)796 void gdImageSetPixel(gdImagePtr im, int x, int y, int color)
797 {
798 	int p;
799 	switch(color) {
800 		case gdStyled:
801 		if (!im->style) {
802 			/* Refuse to draw if no style is set. */
803 			return;
804 		} else {
805 			p = im->style[im->stylePos++];
806 		}
807 		if (p != (gdTransparent)) {
808 			gdImageSetPixel(im, x, y, p);
809 		}
810 		im->stylePos = im->stylePos %  im->styleLength;
811 		break;
812 		case gdStyledBrushed:
813 		if (!im->style) {
814 			/* Refuse to draw if no style is set. */
815 			return;
816 		}
817 		p = im->style[im->stylePos++];
818 		if ((p != gdTransparent) && (p != 0)) {
819 			gdImageSetPixel(im, x, y, gdBrushed);
820 		}
821 		im->stylePos = im->stylePos %  im->styleLength;
822 		break;
823 		case gdBrushed:
824 		gdImageBrushApply(im, x, y);
825 		break;
826 		case gdTiled:
827 		gdImageTileApply(im, x, y);
828 		break;
829 		default:
830 		if (gdImageBoundsSafe(im, x, y)) {
831 			 im->pixels[x][y] = color;
832 		}
833 		break;
834 	}
835 }
836 
gdImageBrushApply(gdImagePtr im,int x,int y)837 static void gdImageBrushApply(gdImagePtr im, int x, int y)
838 {
839 	int lx, ly;
840 	int hy;
841 	int hx;
842 	int x1, y1, x2, y2;
843 	int srcx, srcy;
844 	if (!im->brush) {
845 		return;
846 	}
847 	hy = gdImageSY(im->brush)/2;
848 	y1 = y - hy;
849 	y2 = y1 + gdImageSY(im->brush);
850 	hx = gdImageSX(im->brush)/2;
851 	x1 = x - hx;
852 	x2 = x1 + gdImageSX(im->brush);
853 	srcy = 0;
854 	for (ly = y1; (ly < y2); ly++) {
855 		srcx = 0;
856 		for (lx = x1; (lx < x2); lx++) {
857 			int p;
858 			p = gdImageGetPixel(im->brush, srcx, srcy);
859 			/* Allow for non-square brushes! */
860 			if (p != gdImageGetTransparent(im->brush)) {
861 				gdImageSetPixel(im, lx, ly,
862 					im->brushColorMap[p]);
863 			}
864 			srcx++;
865 		}
866 		srcy++;
867 	}
868 }
869 
gdImageTileApply(gdImagePtr im,int x,int y)870 static void gdImageTileApply(gdImagePtr im, int x, int y)
871 {
872 	int srcx, srcy;
873 	int p;
874 	if (!im->tile) {
875 		return;
876 	}
877 	srcx = x % gdImageSX(im->tile);
878 	srcy = y % gdImageSY(im->tile);
879 	p = gdImageGetPixel(im->tile, srcx, srcy);
880 	/* Allow for transparency */
881 	if (p != gdImageGetTransparent(im->tile)) {
882 		gdImageSetPixel(im, x, y,
883 			im->tileColorMap[p]);
884 	}
885 }
886 
gdImageGetPixel(gdImagePtr im,int x,int y)887 int gdImageGetPixel(gdImagePtr im, int x, int y)
888 {
889 	if (gdImageBoundsSafe(im, x, y)) {
890 		return im->pixels[x][y];
891 	} else {
892 		return 0;
893 	}
894 }
895 
896 /* Bresenham as presented in Foley & Van Dam */
897 
gdImageLine(gdImagePtr im,int x1,int y1,int x2,int y2,int color)898 void gdImageLine(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
899 {
900 	int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
901 	dx = abs(x2-x1);
902 	dy = abs(y2-y1);
903 	if (dy <= dx) {
904 		d = 2*dy - dx;
905 		incr1 = 2*dy;
906 		incr2 = 2 * (dy - dx);
907 		if (x1 > x2) {
908 			x = x2;
909 			y = y2;
910 			ydirflag = (-1);
911 			xend = x1;
912 		} else {
913 			x = x1;
914 			y = y1;
915 			ydirflag = 1;
916 			xend = x2;
917 		}
918 		gdImageSetPixel(im, x, y, color);
919 		if (((y2 - y1) * ydirflag) > 0) {
920 			while (x < xend) {
921 				x++;
922 				if (d <0) {
923 					d+=incr1;
924 				} else {
925 					y++;
926 					d+=incr2;
927 				}
928 				gdImageSetPixel(im, x, y, color);
929 			}
930 		} else {
931 			while (x < xend) {
932 				x++;
933 				if (d <0) {
934 					d+=incr1;
935 				} else {
936 					y--;
937 					d+=incr2;
938 				}
939 				gdImageSetPixel(im, x, y, color);
940 			}
941 		}
942 	} else {
943 		d = 2*dx - dy;
944 		incr1 = 2*dx;
945 		incr2 = 2 * (dx - dy);
946 		if (y1 > y2) {
947 			y = y2;
948 			x = x2;
949 			yend = y1;
950 			xdirflag = (-1);
951 		} else {
952 			y = y1;
953 			x = x1;
954 			yend = y2;
955 			xdirflag = 1;
956 		}
957 		gdImageSetPixel(im, x, y, color);
958 		if (((x2 - x1) * xdirflag) > 0) {
959 			while (y < yend) {
960 				y++;
961 				if (d <0) {
962 					d+=incr1;
963 				} else {
964 					x++;
965 					d+=incr2;
966 				}
967 				gdImageSetPixel(im, x, y, color);
968 			}
969 		} else {
970 			while (y < yend) {
971 				y++;
972 				if (d <0) {
973 					d+=incr1;
974 				} else {
975 					x--;
976 					d+=incr2;
977 				}
978 				gdImageSetPixel(im, x, y, color);
979 			}
980 		}
981 	}
982 }
983 
984 
gdImageBoundsSafe(gdImagePtr im,int x,int y)985 int gdImageBoundsSafe(gdImagePtr im, int x, int y)
986 {
987 	return (!(((y < 0) || (y >= im->sy)) ||
988 		((x < 0) || (x >= im->sx))));
989 }
990 
991 
992 /* Code drawn from ppmtogif.c, from the pbmplus package
993 **
994 ** Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>. A
995 ** Lempel-Zim compression based on "compress".
996 **
997 ** Modified by Marcel Wijkstra <wijkstra@fwi.uva.nl>
998 **
999 ** Copyright (C) 1989 by Jef Poskanzer.
1000 **
1001 ** Permission to use, copy, modify, and distribute this software and its
1002 ** documentation for any purpose and without fee is hereby granted, provided
1003 ** that the above copyright notice appear in all copies and that both that
1004 ** copyright notice and this permission notice appear in supporting
1005 ** documentation.  This software is provided "as is" without express or
1006 ** implied warranty.
1007 **
1008 ** The Graphics Interchange Format(c) is the Copyright property of
1009 ** CompuServe Incorporated.  GIF(sm) is a Service Mark property of
1010 ** CompuServe Incorporated.
1011 */
1012 
1013 /*
1014  * a code_int must be able to hold 2**GIFBITS values of type int, and also -1
1015  */
1016 typedef int             code_int;
1017 
1018 #ifdef SIGNED_COMPARE_SLOW
1019 typedef unsigned long int count_int;
1020 typedef unsigned short int count_short;
1021 #else /*SIGNED_COMPARE_SLOW*/
1022 typedef long int          count_int;
1023 #endif /*SIGNED_COMPARE_SLOW*/
1024 
1025 static int colorstobpp(int colors);
1026 static void BumpPixel (void);
1027 static int GIFNextPixel (gdImagePtr im);
1028 static void GIFEncode (FILE *fp, int GWidth, int GHeight, int GInterlace, int Background, int Transparent, int BitsPerPixel, int *Red, int *Green, int *Blue, gdImagePtr im);
1029 static void Putword (int w, FILE *fp);
1030 static void compress (int init_bits, FILE *outfile, gdImagePtr im);
1031 static void output (code_int code);
1032 static void cl_block (void);
1033 static void cl_hash (register count_int hsize);
1034 static void char_init (void);
1035 static void char_out (int c);
1036 static void flush_char (void);
1037 /* Allows for reuse */
1038 static void init_statics(void);
1039 
gdImageGif(gdImagePtr im,FILE * out)1040 void gdImageGif(gdImagePtr im, FILE *out)
1041 {
1042 	int interlace, transparent, BitsPerPixel;
1043 	interlace = im->interlace;
1044 	transparent = im->transparent;
1045 
1046 	BitsPerPixel = colorstobpp(im->colorsTotal);
1047 	/* Clear any old values in statics strewn through the GIF code */
1048 	init_statics();
1049 	/* All set, let's do it. */
1050 	GIFEncode(
1051 		out, im->sx, im->sy, interlace, 0, transparent, BitsPerPixel,
1052 		im->red, im->green, im->blue, im);
1053 }
1054 
1055 static int
colorstobpp(int colors)1056 colorstobpp(int colors)
1057 {
1058     int bpp = 0;
1059 
1060     if ( colors <= 2 )
1061         bpp = 1;
1062     else if ( colors <= 4 )
1063         bpp = 2;
1064     else if ( colors <= 8 )
1065         bpp = 3;
1066     else if ( colors <= 16 )
1067         bpp = 4;
1068     else if ( colors <= 32 )
1069         bpp = 5;
1070     else if ( colors <= 64 )
1071         bpp = 6;
1072     else if ( colors <= 128 )
1073         bpp = 7;
1074     else if ( colors <= 256 )
1075         bpp = 8;
1076     return bpp;
1077     }
1078 
1079 /*****************************************************************************
1080  *
1081  * GIFENCODE.C    - GIF Image compression interface
1082  *
1083  * GIFEncode( FName, GHeight, GWidth, GInterlace, Background, Transparent,
1084  *            BitsPerPixel, Red, Green, Blue, gdImagePtr )
1085  *
1086  *****************************************************************************/
1087 
1088 #define TRUE 1
1089 #define FALSE 0
1090 
1091 static int Width, Height;
1092 static int curx, cury;
1093 static long CountDown;
1094 static int Pass = 0;
1095 static int Interlace;
1096 
1097 /*
1098  * Bump the 'curx' and 'cury' to point to the next pixel
1099  */
1100 static void
BumpPixel(void)1101 BumpPixel(void)
1102 {
1103         /*
1104          * Bump the current X position
1105          */
1106         ++curx;
1107 
1108         /*
1109          * If we are at the end of a scan line, set curx back to the beginning
1110          * If we are interlaced, bump the cury to the appropriate spot,
1111          * otherwise, just increment it.
1112          */
1113         if( curx == Width ) {
1114                 curx = 0;
1115 
1116                 if( !Interlace )
1117                         ++cury;
1118                 else {
1119                      switch( Pass ) {
1120 
1121                        case 0:
1122                           cury += 8;
1123                           if( cury >= Height ) {
1124                                 ++Pass;
1125                                 cury = 4;
1126                           }
1127                           break;
1128 
1129                        case 1:
1130                           cury += 8;
1131                           if( cury >= Height ) {
1132                                 ++Pass;
1133                                 cury = 2;
1134                           }
1135                           break;
1136 
1137                        case 2:
1138                           cury += 4;
1139                           if( cury >= Height ) {
1140                              ++Pass;
1141                              cury = 1;
1142                           }
1143                           break;
1144 
1145                        case 3:
1146                           cury += 2;
1147                           break;
1148                         }
1149                 }
1150         }
1151 }
1152 
1153 /*
1154  * Return the next pixel from the image
1155  */
1156 static int
GIFNextPixel(gdImagePtr im)1157 GIFNextPixel(gdImagePtr im)
1158 {
1159         int r;
1160 
1161         if( CountDown == 0 )
1162                 return EOF;
1163 
1164         --CountDown;
1165 
1166         r = gdImageGetPixel(im, curx, cury);
1167 
1168         BumpPixel();
1169 
1170         return r;
1171 }
1172 
1173 /* public */
1174 
1175 static void
GIFEncode(FILE * fp,int GWidth,int GHeight,int GInterlace,int Background,int Transparent,int BitsPerPixel,int * Red,int * Green,int * Blue,gdImagePtr im)1176 GIFEncode(FILE *fp, int GWidth, int GHeight, int GInterlace, int Background, int Transparent, int BitsPerPixel, int *Red, int *Green, int *Blue, gdImagePtr im)
1177 {
1178         int B;
1179         int RWidth, RHeight;
1180         int LeftOfs, TopOfs;
1181         int Resolution;
1182         int ColorMapSize;
1183         int InitCodeSize;
1184         int i;
1185 
1186         Interlace = GInterlace;
1187 
1188         ColorMapSize = 1 << BitsPerPixel;
1189 
1190         RWidth = Width = GWidth;
1191         RHeight = Height = GHeight;
1192         LeftOfs = TopOfs = 0;
1193 
1194         Resolution = BitsPerPixel;
1195 
1196         /*
1197          * Calculate number of bits we are expecting
1198          */
1199         CountDown = (long)Width * (long)Height;
1200 
1201         /*
1202          * Indicate which pass we are on (if interlace)
1203          */
1204         Pass = 0;
1205 
1206         /*
1207          * The initial code size
1208          */
1209         if( BitsPerPixel <= 1 )
1210                 InitCodeSize = 2;
1211         else
1212                 InitCodeSize = BitsPerPixel;
1213 
1214         /*
1215          * Set up the current x and y position
1216          */
1217         curx = cury = 0;
1218 
1219         /*
1220          * Write the Magic header
1221          */
1222         fwrite( Transparent < 0 ? "GIF87a" : "GIF89a", 1, 6, fp );
1223 
1224         /*
1225          * Write out the screen width and height
1226          */
1227         Putword( RWidth, fp );
1228         Putword( RHeight, fp );
1229 
1230         /*
1231          * Indicate that there is a global colour map
1232          */
1233         B = 0x80;       /* Yes, there is a color map */
1234 
1235         /*
1236          * OR in the resolution
1237          */
1238         B |= (Resolution - 1) << 5;
1239 
1240         /*
1241          * OR in the Bits per Pixel
1242          */
1243         B |= (BitsPerPixel - 1);
1244 
1245         /*
1246          * Write it out
1247          */
1248         fputc( B, fp );
1249 
1250         /*
1251          * Write out the Background colour
1252          */
1253         fputc( Background, fp );
1254 
1255         /*
1256          * Byte of 0's (future expansion)
1257          */
1258         fputc( 0, fp );
1259 
1260         /*
1261          * Write out the Global Colour Map
1262          */
1263         for( i=0; i<ColorMapSize; ++i ) {
1264                 fputc( Red[i], fp );
1265                 fputc( Green[i], fp );
1266                 fputc( Blue[i], fp );
1267         }
1268 
1269 	/*
1270 	 * Write out extension for transparent colour index, if necessary.
1271 	 */
1272 	if ( Transparent >= 0 ) {
1273 	    fputc( '!', fp );
1274 	    fputc( 0xf9, fp );
1275 	    fputc( 4, fp );
1276 	    fputc( 1, fp );
1277 	    fputc( 0, fp );
1278 	    fputc( 0, fp );
1279 	    fputc( (unsigned char) Transparent, fp );
1280 	    fputc( 0, fp );
1281 	}
1282 
1283         /*
1284          * Write an Image separator
1285          */
1286         fputc( ',', fp );
1287 
1288         /*
1289          * Write the Image header
1290          */
1291 
1292         Putword( LeftOfs, fp );
1293         Putword( TopOfs, fp );
1294         Putword( Width, fp );
1295         Putword( Height, fp );
1296 
1297         /*
1298          * Write out whether or not the image is interlaced
1299          */
1300         if( Interlace )
1301                 fputc( 0x40, fp );
1302         else
1303                 fputc( 0x00, fp );
1304 
1305         /*
1306          * Write out the initial code size
1307          */
1308         fputc( InitCodeSize, fp );
1309 
1310         /*
1311          * Go and actually compress the data
1312          */
1313         compress( InitCodeSize+1, fp, im );
1314 
1315         /*
1316          * Write out a Zero-length packet (to end the series)
1317          */
1318         fputc( 0, fp );
1319 
1320         /*
1321          * Write the GIF file terminator
1322          */
1323         fputc( ';', fp );
1324 }
1325 
1326 /*
1327  * Write out a word to the GIF file
1328  */
1329 static void
Putword(int w,FILE * fp)1330 Putword(int w, FILE *fp)
1331 {
1332         fputc( w & 0xff, fp );
1333         fputc( (w / 256) & 0xff, fp );
1334 }
1335 
1336 
1337 /***************************************************************************
1338  *
1339  *  GIFCOMPR.C       - GIF Image compression routines
1340  *
1341  *  Lempel-Ziv compression based on 'compress'.  GIF modifications by
1342  *  David Rowley (mgardi@watdcsu.waterloo.edu)
1343  *
1344  ***************************************************************************/
1345 
1346 /*
1347  * General DEFINEs
1348  */
1349 
1350 #define GIFBITS    12
1351 
1352 #define HSIZE  5003            /* 80% occupancy */
1353 
1354 #ifdef NO_UCHAR
1355  typedef char   char_type;
1356 #else /*NO_UCHAR*/
1357  typedef        unsigned char   char_type;
1358 #endif /*NO_UCHAR*/
1359 
1360 /*
1361  *
1362  * GIF Image compression - modified 'compress'
1363  *
1364  * Based on: compress.c - File compression ala IEEE Computer, June 1984.
1365  *
1366  * By Authors:  Spencer W. Thomas       (decvax!harpo!utah-cs!utah-gr!thomas)
1367  *              Jim McKie               (decvax!mcvax!jim)
1368  *              Steve Davies            (decvax!vax135!petsd!peora!srd)
1369  *              Ken Turkowski           (decvax!decwrl!turtlevax!ken)
1370  *              James A. Woods          (decvax!ihnp4!ames!jaw)
1371  *              Joe Orost               (decvax!vax135!petsd!joe)
1372  *
1373  */
1374 #include <ctype.h>
1375 
1376 #define ARGVAL() (*++(*argv) || (--argc && *++argv))
1377 
1378 static int n_bits;                        /* number of bits/code */
1379 static int maxbits = GIFBITS;                /* user settable max # bits/code */
1380 static code_int maxcode;                  /* maximum code, given n_bits */
1381 static code_int maxmaxcode = (code_int)1 << GIFBITS; /* should NEVER generate this code */
1382 #ifdef COMPATIBLE               /* But wrong! */
1383 # define MAXCODE(n_bits)        ((code_int) 1 << (n_bits) - 1)
1384 #else /*COMPATIBLE*/
1385 # define MAXCODE(n_bits)        (((code_int) 1 << (n_bits)) - 1)
1386 #endif /*COMPATIBLE*/
1387 
1388 static count_int htab [HSIZE];
1389 static unsigned short codetab [HSIZE];
1390 #define HashTabOf(i)       htab[i]
1391 #define CodeTabOf(i)    codetab[i]
1392 
1393 static code_int hsize = HSIZE;                 /* for dynamic table sizing */
1394 
1395 /*
1396  * To save much memory, we overlay the table used by compress() with those
1397  * used by decompress().  The tab_prefix table is the same size and type
1398  * as the codetab.  The tab_suffix table needs 2**GIFBITS characters.  We
1399  * get this from the beginning of htab.  The output stack uses the rest
1400  * of htab, and contains characters.  There is plenty of room for any
1401  * possible stack (stack used to be 8000 characters).
1402  */
1403 
1404 #define tab_prefixof(i) CodeTabOf(i)
1405 #define tab_suffixof(i)        ((char_type*)(htab))[i]
1406 #define de_stack               ((char_type*)&tab_suffixof((code_int)1<<GIFBITS))
1407 
1408 static code_int free_ent = 0;                  /* first unused entry */
1409 
1410 /*
1411  * block compression parameters -- after all codes are used up,
1412  * and compression rate changes, start over.
1413  */
1414 static int clear_flg = 0;
1415 
1416 static int offset;
1417 static long int in_count = 1;            /* length of input */
1418 static long int out_count = 0;           /* # of codes output (for debugging) */
1419 
1420 /*
1421  * compress stdin to stdout
1422  *
1423  * Algorithm:  use open addressing double hashing (no chaining) on the
1424  * prefix code / next character combination.  We do a variant of Knuth's
1425  * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
1426  * secondary probe.  Here, the modular division first probe is gives way
1427  * to a faster exclusive-or manipulation.  Also do block compression with
1428  * an adaptive reset, whereby the code table is cleared when the compression
1429  * ratio decreases, but after the table fills.  The variable-length output
1430  * codes are re-sized at this point, and a special CLEAR code is generated
1431  * for the decompressor.  Late addition:  construct the table according to
1432  * file size for noticeable speed improvement on small files.  Please direct
1433  * questions about this implementation to ames!jaw.
1434  */
1435 
1436 static int g_init_bits;
1437 static FILE* g_outfile;
1438 
1439 static int ClearCode;
1440 static int EOFCode;
1441 
1442 static void
compress(int init_bits,FILE * outfile,gdImagePtr im)1443 compress(int init_bits, FILE *outfile, gdImagePtr im)
1444 {
1445     register long fcode;
1446     register code_int i /* = 0 */;
1447     register int c;
1448     register code_int ent;
1449     register code_int disp;
1450     register code_int hsize_reg;
1451     register int hshift;
1452 
1453     /*
1454      * Set up the globals:  g_init_bits - initial number of bits
1455      *                      g_outfile   - pointer to output file
1456      */
1457     g_init_bits = init_bits;
1458     g_outfile = outfile;
1459 
1460     /*
1461      * Set up the necessary values
1462      */
1463     offset = 0;
1464     out_count = 0;
1465     clear_flg = 0;
1466     in_count = 1;
1467     maxcode = MAXCODE(n_bits = g_init_bits);
1468 
1469     ClearCode = (1 << (init_bits - 1));
1470     EOFCode = ClearCode + 1;
1471     free_ent = ClearCode + 2;
1472 
1473     char_init();
1474 
1475     ent = GIFNextPixel( im );
1476 
1477     hshift = 0;
1478     for ( fcode = (long) hsize;  fcode < 65536L; fcode *= 2L )
1479         ++hshift;
1480     hshift = 8 - hshift;                /* set hash code range bound */
1481 
1482     hsize_reg = hsize;
1483     cl_hash( (count_int) hsize_reg);            /* clear hash table */
1484 
1485     output( (code_int)ClearCode );
1486 
1487 #ifdef SIGNED_COMPARE_SLOW
1488     while ( (c = GIFNextPixel( im )) != (unsigned) EOF ) {
1489 #else /*SIGNED_COMPARE_SLOW*/
1490     while ( (c = GIFNextPixel( im )) != EOF ) {  /* } */
1491 #endif /*SIGNED_COMPARE_SLOW*/
1492 
1493         ++in_count;
1494 
1495         fcode = (long) (((long) c << maxbits) + ent);
1496         i = (((code_int)c << hshift) ^ ent);    /* xor hashing */
1497 
1498         if ( HashTabOf (i) == fcode ) {
1499             ent = CodeTabOf (i);
1500             continue;
1501         } else if ( (long)HashTabOf (i) < 0 )      /* empty slot */
1502             goto nomatch;
1503         disp = hsize_reg - i;           /* secondary hash (after G. Knott) */
1504         if ( i == 0 )
1505             disp = 1;
1506 probe:
1507         if ( (i -= disp) < 0 )
1508             i += hsize_reg;
1509 
1510         if ( HashTabOf (i) == fcode ) {
1511             ent = CodeTabOf (i);
1512             continue;
1513         }
1514         if ( (long)HashTabOf (i) > 0 )
1515             goto probe;
1516 nomatch:
1517         output ( (code_int) ent );
1518         ++out_count;
1519         ent = c;
1520 #ifdef SIGNED_COMPARE_SLOW
1521         if ( (unsigned) free_ent < (unsigned) maxmaxcode) {
1522 #else /*SIGNED_COMPARE_SLOW*/
1523         if ( free_ent < maxmaxcode ) {  /* } */
1524 #endif /*SIGNED_COMPARE_SLOW*/
1525             CodeTabOf (i) = free_ent++; /* code -> hashtable */
1526             HashTabOf (i) = fcode;
1527         } else
1528                 cl_block();
1529     }
1530     /*
1531      * Put out the final code.
1532      */
1533     output( (code_int)ent );
1534     ++out_count;
1535     output( (code_int) EOFCode );
1536 }
1537 
1538 /*****************************************************************
1539  * TAG( output )
1540  *
1541  * Output the given code.
1542  * Inputs:
1543  *      code:   A n_bits-bit integer.  If == -1, then EOF.  This assumes
1544  *              that n_bits =< (long)wordsize - 1.
1545  * Outputs:
1546  *      Outputs code to the file.
1547  * Assumptions:
1548  *      Chars are 8 bits long.
1549  * Algorithm:
1550  *      Maintain a GIFBITS character long buffer (so that 8 codes will
1551  * fit in it exactly).  Use the VAX insv instruction to insert each
1552  * code in turn.  When the buffer fills up empty it and start over.
1553  */
1554 
1555 static unsigned long cur_accum = 0;
1556 static int cur_bits = 0;
1557 
1558 static unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
1559                                   0x001F, 0x003F, 0x007F, 0x00FF,
1560                                   0x01FF, 0x03FF, 0x07FF, 0x0FFF,
1561                                   0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
1562 
1563 static void
1564 output(code_int code)
1565 {
1566     cur_accum &= masks[ cur_bits ];
1567 
1568     if( cur_bits > 0 )
1569         cur_accum |= ((long)code << cur_bits);
1570     else
1571         cur_accum = code;
1572 
1573     cur_bits += n_bits;
1574 
1575     while( cur_bits >= 8 ) {
1576         char_out( (unsigned int)(cur_accum & 0xff) );
1577         cur_accum >>= 8;
1578         cur_bits -= 8;
1579     }
1580 
1581     /*
1582      * If the next entry is going to be too big for the code size,
1583      * then increase it, if possible.
1584      */
1585    if ( free_ent > maxcode || clear_flg ) {
1586 
1587             if( clear_flg ) {
1588 
1589                 maxcode = MAXCODE (n_bits = g_init_bits);
1590                 clear_flg = 0;
1591 
1592             } else {
1593 
1594                 ++n_bits;
1595                 if ( n_bits == maxbits )
1596                     maxcode = maxmaxcode;
1597                 else
1598                     maxcode = MAXCODE(n_bits);
1599             }
1600         }
1601 
1602     if( code == EOFCode ) {
1603         /*
1604          * At EOF, write the rest of the buffer.
1605          */
1606         while( cur_bits > 0 ) {
1607                 char_out( (unsigned int)(cur_accum & 0xff) );
1608                 cur_accum >>= 8;
1609                 cur_bits -= 8;
1610         }
1611 
1612         flush_char();
1613 
1614         fflush( g_outfile );
1615 
1616         if( ferror( g_outfile ) )
1617 		return;
1618     }
1619 }
1620 
1621 /*
1622  * Clear out the hash table
1623  */
1624 static void
1625 cl_block (void)             /* table clear for block compress */
1626 {
1627 
1628         cl_hash ( (count_int) hsize );
1629         free_ent = ClearCode + 2;
1630         clear_flg = 1;
1631 
1632         output( (code_int)ClearCode );
1633 }
1634 
1635 static void
1636 cl_hash(register count_int hsize)          /* reset code table */
1637 
1638 {
1639 
1640         register count_int *htab_p = htab+hsize;
1641 
1642         register long i;
1643         register long m1 = -1;
1644 
1645         i = hsize - 16;
1646         do {                            /* might use Sys V memset(3) here */
1647                 *(htab_p-16) = m1;
1648                 *(htab_p-15) = m1;
1649                 *(htab_p-14) = m1;
1650                 *(htab_p-13) = m1;
1651                 *(htab_p-12) = m1;
1652                 *(htab_p-11) = m1;
1653                 *(htab_p-10) = m1;
1654                 *(htab_p-9) = m1;
1655                 *(htab_p-8) = m1;
1656                 *(htab_p-7) = m1;
1657                 *(htab_p-6) = m1;
1658                 *(htab_p-5) = m1;
1659                 *(htab_p-4) = m1;
1660                 *(htab_p-3) = m1;
1661                 *(htab_p-2) = m1;
1662                 *(htab_p-1) = m1;
1663                 htab_p -= 16;
1664         } while ((i -= 16) >= 0);
1665 
1666         for ( i += 16; i > 0; --i )
1667                 *--htab_p = m1;
1668 }
1669 
1670 /******************************************************************************
1671  *
1672  * GIF Specific routines
1673  *
1674  ******************************************************************************/
1675 
1676 /*
1677  * Number of characters so far in this 'packet'
1678  */
1679 static int a_count;
1680 
1681 /*
1682  * Set up the 'byte output' routine
1683  */
1684 static void
1685 char_init(void)
1686 {
1687         a_count = 0;
1688 }
1689 
1690 /*
1691  * Define the storage for the packet accumulator
1692  */
1693 static char accum[ 256 ];
1694 
1695 /*
1696  * Add a character to the end of the current packet, and if it is 254
1697  * characters, flush the packet to disk.
1698  */
1699 static void
1700 char_out(int c)
1701 {
1702         accum[ a_count++ ] = c;
1703         if( a_count >= 254 )
1704                 flush_char();
1705 }
1706 
1707 /*
1708  * Flush the packet to disk, and reset the accumulator
1709  */
1710 static void
1711 flush_char(void)
1712 {
1713         if( a_count > 0 ) {
1714                 fputc( a_count, g_outfile );
1715                 fwrite( accum, 1, a_count, g_outfile );
1716                 a_count = 0;
1717         }
1718 }
1719 
1720 static void init_statics(void) {
1721 	/* Some of these are properly initialized later. What I'm doing
1722 		here is making sure code that depends on C's initialization
1723 		of statics doesn't break when the code gets called more
1724 		than once. */
1725 	Width = 0;
1726 	Height = 0;
1727 	curx = 0;
1728 	cury = 0;
1729 	CountDown = 0;
1730 	Pass = 0;
1731 	Interlace = 0;
1732 	a_count = 0;
1733 	cur_accum = 0;
1734 	cur_bits = 0;
1735 	g_init_bits = 0;
1736 	g_outfile = 0;
1737 	ClearCode = 0;
1738 	EOFCode = 0;
1739 	free_ent = 0;
1740 	clear_flg = 0;
1741 	offset = 0;
1742 	in_count = 1;
1743 	out_count = 0;
1744 	hsize = HSIZE;
1745 	n_bits = 0;
1746 	maxbits = GIFBITS;
1747 	maxcode = 0;
1748 	maxmaxcode = (code_int)1 << GIFBITS;
1749 }
1750 
1751 
1752 /* +-------------------------------------------------------------------+ */
1753 /* | Copyright 1990, 1991, 1993, David Koblas.  (koblas@netcom.com)    | */
1754 /* |   Permission to use, copy, modify, and distribute this software   | */
1755 /* |   and its documentation for any purpose and without fee is hereby | */
1756 /* |   granted, provided that the above copyright notice appear in all | */
1757 /* |   copies and that both that copyright notice and this permission  | */
1758 /* |   notice appear in supporting documentation.  This software is    | */
1759 /* |   provided "as is" without express or implied warranty.           | */
1760 /* +-------------------------------------------------------------------+ */
1761 
1762 
1763 #define        MAXCOLORMAPSIZE         256
1764 
1765 #define        TRUE    1
1766 #define        FALSE   0
1767 
1768 #define CM_RED         0
1769 #define CM_GREEN       1
1770 #define CM_BLUE                2
1771 
1772 #define        MAX_LWZ_BITS            12
1773 
1774 #define INTERLACE              0x40
1775 #define LOCALCOLORMAP  0x80
1776 #define BitSet(byte, bit)      (((byte) & (bit)) == (bit))
1777 
1778 #define        ReadOK(file,buffer,len) (fread(buffer, len, 1, file) != 0)
1779 
1780 #define LM_to_uint(a,b)                        (((b)<<8)|(a))
1781 
1782 /* We may eventually want to use this information, but def it out for now */
1783 #if 0
1784 static struct {
1785        unsigned int    Width;
1786        unsigned int    Height;
1787        unsigned char   ColorMap[3][MAXCOLORMAPSIZE];
1788        unsigned int    BitPixel;
1789        unsigned int    ColorResolution;
1790        unsigned int    Background;
1791        unsigned int    AspectRatio;
1792 } GifScreen;
1793 #endif
1794 
1795 static struct {
1796        int     transparent;
1797        int     delayTime;
1798        int     inputFlag;
1799        int     disposal;
1800 } Gif89 = { -1, -1, -1, 0 };
1801 
1802 static int ReadColorMap (FILE *fd, int number, unsigned char (*buffer)[256]);
1803 static int DoExtension (FILE *fd, int label, int *Transparent);
1804 static int GetDataBlock (FILE *fd, unsigned char *buf);
1805 static int GetCode (FILE *fd, int code_size, int flag);
1806 static int LWZReadByte (FILE *fd, int flag, int input_code_size);
1807 static void ReadImage (gdImagePtr im, FILE *fd, int len, int height, unsigned char (*cmap)[256], int interlace, int ignore);
1808 
1809 int ZeroDataBlock;
1810 
1811 gdImagePtr
1812 gdImageCreateFromGif(FILE *fd)
1813 {
1814        int imageNumber;
1815        int BitPixel;
1816        int ColorResolution;
1817        int Background;
1818        int AspectRatio;
1819        int Transparent = (-1);
1820        unsigned char   buf[16];
1821        unsigned char   c;
1822        unsigned char   ColorMap[3][MAXCOLORMAPSIZE];
1823        unsigned char   localColorMap[3][MAXCOLORMAPSIZE];
1824        int             imw, imh;
1825        int             useGlobalColormap;
1826        int             bitPixel;
1827        int             imageCount = 0;
1828        char            version[4];
1829        gdImagePtr im = 0;
1830        ZeroDataBlock = FALSE;
1831 
1832        imageNumber = 1;
1833        if (! ReadOK(fd,buf,6)) {
1834 		return 0;
1835 	}
1836        if (strncmp((char *)buf,"GIF",3) != 0) {
1837 		return 0;
1838 	}
1839        strncpy(version, (char *)buf + 3, 3);
1840        version[3] = '\0';
1841 
1842        if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
1843 		return 0;
1844 	}
1845        if (! ReadOK(fd,buf,7)) {
1846 		return 0;
1847 	}
1848        BitPixel        = 2<<(buf[4]&0x07);
1849        ColorResolution = (int) (((buf[4]&0x70)>>3)+1);
1850        Background      = buf[5];
1851        AspectRatio     = buf[6];
1852 
1853        if (BitSet(buf[4], LOCALCOLORMAP)) {    /* Global Colormap */
1854                if (ReadColorMap(fd, BitPixel, ColorMap)) {
1855 			return 0;
1856 		}
1857        }
1858        for (;;) {
1859                if (! ReadOK(fd,&c,1)) {
1860                        return 0;
1861                }
1862                if (c == ';') {         /* GIF terminator */
1863                        int i;
1864                        if (imageCount < imageNumber) {
1865                                return 0;
1866                        }
1867                        /* Terminator before any image was declared! */
1868                        if (!im) {
1869                               return 0;
1870                        }
1871 		       /* Check for open colors at the end, so
1872                           we can reduce colorsTotal and ultimately
1873                           BitsPerPixel */
1874                        for (i=((im->colorsTotal-1)); (i>=0); i--) {
1875                                if (im->open[i]) {
1876                                        im->colorsTotal--;
1877                                } else {
1878                                        break;
1879                                }
1880                        }
1881                        return im;
1882                }
1883 
1884                if (c == '!') {         /* Extension */
1885                        if (! ReadOK(fd,&c,1)) {
1886                                return 0;
1887                        }
1888                        DoExtension(fd, c, &Transparent);
1889                        continue;
1890                }
1891 
1892                if (c != ',') {         /* Not a valid start character */
1893                        continue;
1894                }
1895 
1896                ++imageCount;
1897 
1898                if (! ReadOK(fd,buf,9)) {
1899 	               return 0;
1900                }
1901 
1902                useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP);
1903 
1904                bitPixel = 1<<((buf[8]&0x07)+1);
1905 
1906                imw = LM_to_uint(buf[4],buf[5]);
1907                imh = LM_to_uint(buf[6],buf[7]);
1908 	       if (!(im = gdImageCreate(imw, imh))) {
1909 			 return 0;
1910 	       }
1911                im->interlace = BitSet(buf[8], INTERLACE);
1912                if (! useGlobalColormap) {
1913                        if (ReadColorMap(fd, bitPixel, localColorMap)) {
1914                                  return 0;
1915                        }
1916                        ReadImage(im, fd, imw, imh, localColorMap,
1917                                  BitSet(buf[8], INTERLACE),
1918                                  imageCount != imageNumber);
1919                } else {
1920                        ReadImage(im, fd, imw, imh,
1921                                  ColorMap,
1922                                  BitSet(buf[8], INTERLACE),
1923                                  imageCount != imageNumber);
1924                }
1925                if (Transparent != (-1)) {
1926                        gdImageColorTransparent(im, Transparent);
1927                }
1928        }
1929 }
1930 
1931 static int
1932 ReadColorMap(FILE *fd, int number, unsigned char (*buffer)[256])
1933 {
1934        int             i;
1935        unsigned char   rgb[3];
1936 
1937 
1938        for (i = 0; i < number; ++i) {
1939                if (! ReadOK(fd, rgb, sizeof(rgb))) {
1940                        return TRUE;
1941                }
1942                buffer[CM_RED][i] = rgb[0] ;
1943                buffer[CM_GREEN][i] = rgb[1] ;
1944                buffer[CM_BLUE][i] = rgb[2] ;
1945        }
1946 
1947 
1948        return FALSE;
1949 }
1950 
1951 static int
1952 DoExtension(FILE *fd, int label, int *Transparent)
1953 {
1954        static unsigned char     buf[256];
1955 
1956        switch (label) {
1957        case 0xf9:              /* Graphic Control Extension */
1958                (void) GetDataBlock(fd, (unsigned char*) buf);
1959                Gif89.disposal    = (buf[0] >> 2) & 0x7;
1960                Gif89.inputFlag   = (buf[0] >> 1) & 0x1;
1961                Gif89.delayTime   = LM_to_uint(buf[1],buf[2]);
1962                if ((buf[0] & 0x1) != 0)
1963                        *Transparent = buf[3];
1964 
1965                while (GetDataBlock(fd, (unsigned char*) buf) != 0)
1966                        ;
1967                return FALSE;
1968        default:
1969                break;
1970        }
1971        while (GetDataBlock(fd, (unsigned char*) buf) != 0)
1972                ;
1973 
1974        return FALSE;
1975 }
1976 
1977 static int
1978 GetDataBlock(FILE *fd, unsigned char *buf)
1979 {
1980        unsigned char   count;
1981 
1982        if (! ReadOK(fd,&count,1)) {
1983                return -1;
1984        }
1985 
1986        ZeroDataBlock = count == 0;
1987 
1988        if ((count != 0) && (! ReadOK(fd, buf, count))) {
1989                return -1;
1990        }
1991 
1992        return count;
1993 }
1994 
1995 static int
1996 GetCode(FILE *fd, int code_size, int flag)
1997 {
1998        static unsigned char    buf[280];
1999        static int              curbit, lastbit, done, last_byte;
2000        int                     i, j, ret;
2001        unsigned char           count;
2002 
2003        if (flag) {
2004                curbit = 0;
2005                lastbit = 0;
2006                done = FALSE;
2007                return 0;
2008        }
2009 
2010        if ( (curbit+code_size) >= lastbit) {
2011                if (done) {
2012                        if (curbit >= lastbit) {
2013                                 /* Oh well */
2014                        }
2015                        return -1;
2016                }
2017                buf[0] = buf[last_byte-2];
2018                buf[1] = buf[last_byte-1];
2019 
2020                if ((count = GetDataBlock(fd, &buf[2])) == 0)
2021                        done = TRUE;
2022 
2023                last_byte = 2 + count;
2024                curbit = (curbit - lastbit) + 16;
2025                lastbit = (2+count)*8 ;
2026        }
2027 
2028        ret = 0;
2029        for (i = curbit, j = 0; j < code_size; ++i, ++j)
2030                ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
2031 
2032        curbit += code_size;
2033 
2034        return ret;
2035 }
2036 
2037 static int
2038 LWZReadByte(FILE *fd, int flag, int input_code_size)
2039 {
2040        static int      fresh = FALSE;
2041        int             code, incode;
2042        static int      code_size, set_code_size;
2043        static int      max_code, max_code_size;
2044        static int      firstcode, oldcode;
2045        static int      clear_code, end_code;
2046        static int      table[2][(1<< MAX_LWZ_BITS)];
2047        static int      stack[(1<<(MAX_LWZ_BITS))*2], *sp;
2048        register int    i;
2049 
2050        if (flag) {
2051                set_code_size = input_code_size;
2052                code_size = set_code_size+1;
2053                clear_code = 1 << set_code_size ;
2054                end_code = clear_code + 1;
2055                max_code_size = 2*clear_code;
2056                max_code = clear_code+2;
2057 
2058                GetCode(fd, 0, TRUE);
2059 
2060                fresh = TRUE;
2061 
2062                for (i = 0; i < clear_code; ++i) {
2063                        table[0][i] = 0;
2064                        table[1][i] = i;
2065                }
2066                for (; i < (1<<MAX_LWZ_BITS); ++i)
2067                        table[0][i] = table[1][0] = 0;
2068 
2069                sp = stack;
2070 
2071                return 0;
2072        } else if (fresh) {
2073                fresh = FALSE;
2074                do {
2075                        firstcode = oldcode =
2076                                GetCode(fd, code_size, FALSE);
2077                } while (firstcode == clear_code);
2078                return firstcode;
2079        }
2080 
2081        if (sp > stack)
2082                return *--sp;
2083 
2084        while ((code = GetCode(fd, code_size, FALSE)) >= 0) {
2085                if (code == clear_code) {
2086                        for (i = 0; i < clear_code; ++i) {
2087                                table[0][i] = 0;
2088                                table[1][i] = i;
2089                        }
2090                        for (; i < (1<<MAX_LWZ_BITS); ++i)
2091                                table[0][i] = table[1][i] = 0;
2092                        code_size = set_code_size+1;
2093                        max_code_size = 2*clear_code;
2094                        max_code = clear_code+2;
2095                        sp = stack;
2096                        firstcode = oldcode =
2097                                        GetCode(fd, code_size, FALSE);
2098                        return firstcode;
2099                } else if (code == end_code) {
2100                        int             count;
2101                        unsigned char   buf[260];
2102 
2103                        if (ZeroDataBlock)
2104                                return -2;
2105 
2106                        while ((count = GetDataBlock(fd, buf)) > 0)
2107                                ;
2108 
2109                        if (count != 0)
2110                        return -2;
2111                }
2112 
2113                incode = code;
2114 
2115                if (code >= max_code) {
2116                        *sp++ = firstcode;
2117                        code = oldcode;
2118                }
2119 
2120                while (code >= clear_code) {
2121                        *sp++ = table[1][code];
2122                        if (code == table[0][code]) {
2123                                /* Oh well */
2124                        }
2125                        code = table[0][code];
2126                }
2127 
2128                *sp++ = firstcode = table[1][code];
2129 
2130                if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
2131                        table[0][code] = oldcode;
2132                        table[1][code] = firstcode;
2133                        ++max_code;
2134                        if ((max_code >= max_code_size) &&
2135                                (max_code_size < (1<<MAX_LWZ_BITS))) {
2136                                max_code_size *= 2;
2137                                ++code_size;
2138                        }
2139                }
2140 
2141                oldcode = incode;
2142 
2143                if (sp > stack)
2144                        return *--sp;
2145        }
2146        return code;
2147 }
2148 
2149 static void
2150 ReadImage(gdImagePtr im, FILE *fd, int len, int height, unsigned char (*cmap)[256], int interlace, int ignore)
2151 {
2152        unsigned char   c;
2153        int             v;
2154        int             xpos = 0, ypos = 0, pass = 0;
2155        int i;
2156        /* Stash the color map into the image */
2157        for (i=0; (i<gdMaxColors); i++) {
2158                im->red[i] = cmap[CM_RED][i];
2159                im->green[i] = cmap[CM_GREEN][i];
2160                im->blue[i] = cmap[CM_BLUE][i];
2161                im->open[i] = 1;
2162        }
2163        /* Many (perhaps most) of these colors will remain marked open. */
2164        im->colorsTotal = gdMaxColors;
2165        /*
2166        **  Initialize the Compression routines
2167        */
2168        if (! ReadOK(fd,&c,1)) {
2169                return;
2170        }
2171        if (LWZReadByte(fd, TRUE, c) < 0) {
2172                return;
2173        }
2174 
2175        /*
2176        **  If this is an "uninteresting picture" ignore it.
2177        */
2178        if (ignore) {
2179                while (LWZReadByte(fd, FALSE, c) >= 0)
2180                        ;
2181                return;
2182        }
2183 
2184        while ((v = LWZReadByte(fd,FALSE,c)) >= 0 ) {
2185                /* This how we recognize which colors are actually used. */
2186                if (im->open[v]) {
2187                        im->open[v] = 0;
2188                }
2189                gdImageSetPixel(im, xpos, ypos, v);
2190                ++xpos;
2191                if (xpos == len) {
2192                        xpos = 0;
2193                        if (interlace) {
2194                                switch (pass) {
2195                                case 0:
2196                                case 1:
2197                                        ypos += 8; break;
2198                                case 2:
2199                                        ypos += 4; break;
2200                                case 3:
2201                                        ypos += 2; break;
2202                                }
2203 
2204                                if (ypos >= height) {
2205                                        ++pass;
2206                                        switch (pass) {
2207                                        case 1:
2208                                                ypos = 4; break;
2209                                        case 2:
2210                                                ypos = 2; break;
2211                                        case 3:
2212                                                ypos = 1; break;
2213                                        default:
2214                                                goto fini;
2215                                        }
2216                                }
2217                        } else {
2218                                ++ypos;
2219                        }
2220                }
2221                if (ypos >= height)
2222                        break;
2223        }
2224 
2225 fini:
2226        if (LWZReadByte(fd,FALSE,c)>=0) {
2227                /* Ignore extra */
2228        }
2229 }
2230 
2231 void gdImageRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
2232 {
2233 	gdImageLine(im, x1, y1, x2, y1, color);
2234 	gdImageLine(im, x1, y2, x2, y2, color);
2235 	gdImageLine(im, x1, y1, x1, y2, color);
2236 	gdImageLine(im, x2, y1, x2, y2, color);
2237 }
2238 
2239 void gdImageFilledRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
2240 {
2241 	int x, y;
2242 	for (y=y1; (y<=y2); y++) {
2243 		for (x=x1; (x<=x2); x++) {
2244 			gdImageSetPixel(im, x, y, color);
2245 		}
2246 	}
2247 }
2248 
2249 int gdGetWord(int *result, FILE *in)
2250 {
2251 	int r;
2252 	r = getc(in);
2253 	if (r == EOF) {
2254 		return 0;
2255 	}
2256 	*result = r << 8;
2257 	r = getc(in);
2258 	if (r == EOF) {
2259 		return 0;
2260 	}
2261 	*result += r;
2262 	return 1;
2263 }
2264 
2265 void gdPutWord(int w, FILE *out)
2266 {
2267 	putc((unsigned char)(w >> 8), out);
2268 	putc((unsigned char)(w & 0xFF), out);
2269 }
2270 
2271 int gdGetByte(int *result, FILE *in)
2272 {
2273 	int r;
2274 	r = getc(in);
2275 	if (r == EOF) {
2276 		return 0;
2277 	}
2278 	*result = r;
2279 	return 1;
2280 }
2281 
2282 gdImagePtr gdImageCreateFromGd(FILE *in)
2283 {
2284 	int sx, sy;
2285 	int x, y;
2286 	int i;
2287 	gdImagePtr im;
2288 	if (!gdGetWord(&sx, in)) {
2289 		goto fail1;
2290 	}
2291 	if (!gdGetWord(&sy, in)) {
2292 		goto fail1;
2293 	}
2294 	im = gdImageCreate(sx, sy);
2295 	if (!gdGetByte(&im->colorsTotal, in)) {
2296 		goto fail2;
2297 	}
2298 	if (!gdGetWord(&im->transparent, in)) {
2299 		goto fail2;
2300 	}
2301 	if (im->transparent == 257) {
2302 		im->transparent = (-1);
2303 	}
2304 	for (i=0; (i<gdMaxColors); i++) {
2305 		if (!gdGetByte(&im->red[i], in)) {
2306 			goto fail2;
2307 		}
2308 		if (!gdGetByte(&im->green[i], in)) {
2309 			goto fail2;
2310 		}
2311 		if (!gdGetByte(&im->blue[i], in)) {
2312 			goto fail2;
2313 		}
2314 	}
2315 	for (y=0; (y<sy); y++) {
2316 		for (x=0; (x<sx); x++) {
2317 			int ch;
2318 			ch = getc(in);
2319 			if (ch == EOF) {
2320 				gdImageDestroy(im);
2321 				return 0;
2322 			}
2323 			im->pixels[x][y] = ch;
2324 		}
2325 	}
2326 	return im;
2327 fail2:
2328 	gdImageDestroy(im);
2329 fail1:
2330 	return 0;
2331 }
2332 
2333 void gdImageGd(gdImagePtr im, FILE *out)
2334 {
2335 	int x, y;
2336 	int i;
2337 	int trans;
2338 	gdPutWord(im->sx, out);
2339 	gdPutWord(im->sy, out);
2340 	putc((unsigned char)im->colorsTotal, out);
2341 	trans = im->transparent;
2342 	if (trans == (-1)) {
2343 		trans = 257;
2344 	}
2345 	gdPutWord(trans, out);
2346 	for (i=0; (i<gdMaxColors); i++) {
2347 		putc((unsigned char)im->red[i], out);
2348 		putc((unsigned char)im->green[i], out);
2349 		putc((unsigned char)im->blue[i], out);
2350 	}
2351 	for (y=0; (y < im->sy); y++) {
2352 		for (x=0; (x < im->sx); x++) {
2353 			putc((unsigned char)im->pixels[x][y], out);
2354 		}
2355 	}
2356 }
2357 
2358 gdImagePtr
2359 gdImageCreateFromXbm(FILE *fd)
2360 {
2361 	gdImagePtr im;
2362 	int bit;
2363 	int w, h;
2364 	int bytes;
2365 	int ch;
2366 	int i, x, y;
2367 	char *sp;
2368 	char s[161];
2369 	if (!fgets(s, 160, fd)) {
2370 		return 0;
2371 	}
2372 	sp = &s[0];
2373 	/* Skip #define */
2374 	sp = strchr(sp, ' ');
2375 	if (!sp) {
2376 		return 0;
2377 	}
2378 	/* Skip width label */
2379 	sp++;
2380 	sp = strchr(sp, ' ');
2381 	if (!sp) {
2382 		return 0;
2383 	}
2384 	/* Get width */
2385 	w = atoi(sp + 1);
2386 	if (!w) {
2387 		return 0;
2388 	}
2389 	if (!fgets(s, 160, fd)) {
2390 		return 0;
2391 	}
2392 	sp = s;
2393 	/* Skip #define */
2394 	sp = strchr(sp, ' ');
2395 	if (!sp) {
2396 		return 0;
2397 	}
2398 	/* Skip height label */
2399 	sp++;
2400 	sp = strchr(sp, ' ');
2401 	if (!sp) {
2402 		return 0;
2403 	}
2404 	/* Get height */
2405 	h = atoi(sp + 1);
2406 	if (!h) {
2407 		return 0;
2408 	}
2409 	/* Skip declaration line */
2410 	if (!fgets(s, 160, fd)) {
2411 		return 0;
2412 	}
2413 	bytes = (w * h / 8) + 1;
2414 	im = gdImageCreate(w, h);
2415 	gdImageColorAllocate(im, 255, 255, 255);
2416 	gdImageColorAllocate(im, 0, 0, 0);
2417 	x = 0;
2418 	y = 0;
2419 	for (i=0; (i < bytes); i++) {
2420 		char h[3];
2421 		int b;
2422 		/* Skip spaces, commas, CRs, 0x */
2423 		while(1) {
2424 			ch = getc(fd);
2425 			if (ch == EOF) {
2426 				goto fail;
2427 			}
2428 			if (ch == 'x') {
2429 				break;
2430 			}
2431 		}
2432 		/* Get hex value */
2433 		ch = getc(fd);
2434 		if (ch == EOF) {
2435 			goto fail;
2436 		}
2437 		h[0] = ch;
2438 		ch = getc(fd);
2439 		if (ch == EOF) {
2440 			goto fail;
2441 		}
2442 		h[1] = ch;
2443 		h[2] = '\0';
2444 		sscanf(h, "%x", &b);
2445 		for (bit = 1; (bit <= 128); (bit = bit << 1)) {
2446 			gdImageSetPixel(im, x++, y, (b & bit) ? 1 : 0);
2447 			if (x == im->sx) {
2448 				x = 0;
2449 				y++;
2450 				if (y == im->sy) {
2451 					return im;
2452 				}
2453 				/* Fix 8/8/95 */
2454 				break;
2455 			}
2456 		}
2457 	}
2458 	/* Shouldn't happen */
2459 	fprintf(stderr, "Error: bug in gdImageCreateFromXbm!\n");
2460 	return 0;
2461 fail:
2462 	gdImageDestroy(im);
2463 	return 0;
2464 }
2465 
2466 void gdImagePolygon(gdImagePtr im, gdPointPtr p, int n, int c)
2467 {
2468 	int i;
2469 	int lx, ly;
2470 	if (!n) {
2471 		return;
2472 	}
2473 	lx = p->x;
2474 	ly = p->y;
2475 	gdImageLine(im, lx, ly, p[n-1].x, p[n-1].y, c);
2476 	for (i=1; (i < n); i++) {
2477 		p++;
2478 		gdImageLine(im, lx, ly, p->x, p->y, c);
2479 		lx = p->x;
2480 		ly = p->y;
2481 	}
2482 }
2483 
2484 int gdCompareInt(const void *a, const void *b);
2485 
2486 void gdImageFilledPolygon(gdImagePtr im, gdPointPtr p, int n, int c)
2487 {
2488 	int i;
2489 	int y;
2490 	int y1, y2;
2491 	int ints;
2492 	if (!n) {
2493 		return;
2494 	}
2495 	if (!im->polyAllocated) {
2496 		im->polyInts = (int *) malloc(sizeof(int) * n);
2497 		im->polyAllocated = n;
2498 	}
2499 	if (im->polyAllocated < n) {
2500 		while (im->polyAllocated < n) {
2501 			im->polyAllocated *= 2;
2502 		}
2503 		im->polyInts = (int *) realloc(im->polyInts,
2504 			sizeof(int) * im->polyAllocated);
2505 	}
2506 	y1 = p[0].y;
2507 	y2 = p[0].y;
2508 	for (i=1; (i < n); i++) {
2509 		if (p[i].y < y1) {
2510 			y1 = p[i].y;
2511 		}
2512 		if (p[i].y > y2) {
2513 			y2 = p[i].y;
2514 		}
2515 	}
2516 	for (y=y1; (y <= y2); y++) {
2517 		int interLast = 0;
2518 		int dirLast = 0;
2519 		int interFirst = 1;
2520 		ints = 0;
2521 		for (i=0; (i <= n); i++) {
2522 			int x1, x2;
2523 			int y1, y2;
2524 			int dir;
2525 			int ind1, ind2;
2526 			int lastInd1 = 0;
2527 			if ((i == n) || (!i)) {
2528 				ind1 = n-1;
2529 				ind2 = 0;
2530 			} else {
2531 				ind1 = i-1;
2532 				ind2 = i;
2533 			}
2534 			y1 = p[ind1].y;
2535 			y2 = p[ind2].y;
2536 			if (y1 < y2) {
2537 				y1 = p[ind1].y;
2538 				y2 = p[ind2].y;
2539 				x1 = p[ind1].x;
2540 				x2 = p[ind2].x;
2541 				dir = -1;
2542 			} else if (y1 > y2) {
2543 				y2 = p[ind1].y;
2544 				y1 = p[ind2].y;
2545 				x2 = p[ind1].x;
2546 				x1 = p[ind2].x;
2547 				dir = 1;
2548 			} else {
2549 				/* Horizontal; just draw it */
2550 				gdImageLine(im,
2551 					p[ind1].x, y1,
2552 					p[ind2].x, y1,
2553 					c);
2554 				continue;
2555 			}
2556 			if ((y >= y1) && (y <= y2)) {
2557 				int inter =
2558 					(y-y1) * (x2-x1) / (y2-y1) + x1;
2559 				/* Only count intersections once
2560 					except at maxima and minima. Also,
2561 					if two consecutive intersections are
2562 					endpoints of the same horizontal line
2563 					that is not at a maxima or minima,
2564 					discard the leftmost of the two. */
2565 				if (!interFirst) {
2566 					if ((p[ind1].y == p[lastInd1].y) &&
2567 						(p[ind1].x != p[lastInd1].x)) {
2568 						if (dir == dirLast) {
2569 							if (inter > interLast) {
2570 								/* Replace the old one */
2571 								im->polyInts[ints] = inter;
2572 							} else {
2573 								/* Discard this one */
2574 							}
2575 							continue;
2576 						}
2577 					}
2578 					if (inter == interLast) {
2579 						if (dir == dirLast) {
2580 							continue;
2581 						}
2582 					}
2583 				}
2584 				if (i > 0) {
2585 					im->polyInts[ints++] = inter;
2586 				}
2587 				lastInd1 = i;
2588 				dirLast = dir;
2589 				interLast = inter;
2590 				interFirst = 0;
2591 			}
2592 		}
2593 		qsort(im->polyInts, ints, sizeof(int), gdCompareInt);
2594 		for (i=0; (i < (ints-1)); i+=2) {
2595 			gdImageLine(im, im->polyInts[i], y,
2596 				im->polyInts[i+1], y, c);
2597 		}
2598 	}
2599 }
2600 
2601 int gdCompareInt(const void *a, const void *b)
2602 {
2603 	return (*(const int *)a) - (*(const int *)b);
2604 }
2605 
2606 void gdImageSetStyle(gdImagePtr im, int *style, int noOfPixels)
2607 {
2608 	if (im->style) {
2609 		free(im->style);
2610 	}
2611 	im->style = (int *)
2612 		malloc(sizeof(int) * noOfPixels);
2613 	memcpy(im->style, style, sizeof(int) * noOfPixels);
2614 	im->styleLength = noOfPixels;
2615 	im->stylePos = 0;
2616 }
2617 
2618 void gdImageSetBrush(gdImagePtr im, gdImagePtr brush)
2619 {
2620 	int i;
2621 	im->brush = brush;
2622 	for (i=0; (i < gdImageColorsTotal(brush)); i++) {
2623 		int index;
2624 		index = gdImageColorExact(im,
2625 			gdImageRed(brush, i),
2626 			gdImageGreen(brush, i),
2627 			gdImageBlue(brush, i));
2628 		if (index == (-1)) {
2629 			index = gdImageColorAllocate(im,
2630 				gdImageRed(brush, i),
2631 				gdImageGreen(brush, i),
2632 				gdImageBlue(brush, i));
2633 			if (index == (-1)) {
2634 				index = gdImageColorClosest(im,
2635 					gdImageRed(brush, i),
2636 					gdImageGreen(brush, i),
2637 					gdImageBlue(brush, i));
2638 			}
2639 		}
2640 		im->brushColorMap[i] = index;
2641 	}
2642 }
2643 
2644 void gdImageSetTile(gdImagePtr im, gdImagePtr tile)
2645 {
2646 	int i;
2647 	im->tile = tile;
2648 	for (i=0; (i < gdImageColorsTotal(tile)); i++) {
2649 		int index;
2650 		index = gdImageColorExact(im,
2651 			gdImageRed(tile, i),
2652 			gdImageGreen(tile, i),
2653 			gdImageBlue(tile, i));
2654 		if (index == (-1)) {
2655 			index = gdImageColorAllocate(im,
2656 				gdImageRed(tile, i),
2657 				gdImageGreen(tile, i),
2658 				gdImageBlue(tile, i));
2659 			if (index == (-1)) {
2660 				index = gdImageColorClosest(im,
2661 					gdImageRed(tile, i),
2662 					gdImageGreen(tile, i),
2663 					gdImageBlue(tile, i));
2664 			}
2665 		}
2666 		im->tileColorMap[i] = index;
2667 	}
2668 }
2669 
2670 void gdImageInterlace(gdImagePtr im, int interlaceArg)
2671 {
2672 	im->interlace = interlaceArg;
2673 }
2674 
2675