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