~ubuntu-branches/ubuntu/karmic/scilab/karmic

« back to all changes in this revision

Viewing changes to routines/gd/gd.c

  • Committer: Bazaar Package Importer
  • Author(s): Torsten Werner
  • Date: 2002-03-21 16:57:43 UTC
  • Revision ID: james.westby@ubuntu.com-20020321165743-e9mv12c1tb1plztg
Tags: upstream-2.6
ImportĀ upstreamĀ versionĀ 2.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <stdio.h>
 
2
#include <math.h>
 
3
#include <string.h>
 
4
#include <stdlib.h>
 
5
#include "gd.h"
 
6
#include "mtables.c"
 
7
#define Min(x,y)        (((x)<(y))?(x):(y))
 
8
#define Max(x,y)        (((x)>(y))?(x):(y))
 
9
/* MONO returns total intensity of r,g,b components */
 
10
#define MONO(rd,gn,bl) (((rd)*11 + (gn)*16 + (bl)*5) >> 5)  /*.33R+ .5G+ .17B*/
 
11
 
 
12
static void gdImageBrushApply __PARAMS((gdImagePtr im, int x, int y));
 
13
static void gdImageTileApply __PARAMS((gdImagePtr im, int x, int y));
 
14
 
 
15
 
 
16
/*SG modified to add alu modes and clipping fiels */
 
17
gdImagePtr gdImageCreate(sx, sy)
 
18
     int sx;
 
19
     int sy;
 
20
{
 
21
        int i;
 
22
        gdImagePtr im;
 
23
        im = (gdImage *) malloc(sizeof(gdImage));
 
24
        /* NOW ROW-MAJOR IN GD 1.3 */
 
25
        im->pixels = (unsigned char **) malloc(sizeof(unsigned char *) * sy);
 
26
        im->polyInts = 0;
 
27
        im->polyAllocated = 0;
 
28
        im->brush = 0;
 
29
        im->tile = 0;
 
30
        im->style = 0;
 
31
        for (i=0; (i<sy); i++) {
 
32
                /* NOW ROW-MAJOR IN GD 1.3 */
 
33
                im->pixels[i] = (unsigned char *) calloc(
 
34
                        sx, sizeof(unsigned char));
 
35
        }       
 
36
        im->sx = sx;
 
37
        im->sy = sy;
 
38
        for (i=0;i<gdMaxColors;i++)
 
39
          im->open[i]=1;
 
40
        im->colorsTotal = 0;
 
41
        im->transparent = (-1);
 
42
        im->interlace = 0;
 
43
        /* modification to add alu and clipping */
 
44
        im->alu = 3;
 
45
        im->clipping = 0;
 
46
        im->cliprect[0] = 0; /* xmin */
 
47
        im->cliprect[1] = 0; /* ymin */
 
48
        im->cliprect[2] = sx; /* xmax */
 
49
        im->cliprect[3] = sy; /* ymax */
 
50
        return im;
 
51
}
 
52
 
 
53
void gdImageDestroy(im)
 
54
     gdImagePtr im;
 
55
{
 
56
        int i;
 
57
        for (i=0; (i<im->sy); i++) {
 
58
                free(im->pixels[i]);
 
59
        }       
 
60
        free(im->pixels);
 
61
        if (im->polyInts) {
 
62
                        free(im->polyInts);
 
63
        }
 
64
        if (im->style) {
 
65
                free(im->style);
 
66
        }
 
67
        free(im);
 
68
}
 
69
 
 
70
int gdImageColorClosest(im, r, g, b)
 
71
     gdImagePtr im;
 
72
     int r;
 
73
     int g;
 
74
     int b;
 
75
{
 
76
        int i;
 
77
        long rd, gd, bd;
 
78
        int ct = (-1);
 
79
        long mindist = 0;
 
80
        for (i=0; (i<(im->colorsTotal)); i++) {
 
81
                long dist;
 
82
                if (im->open[i]) {
 
83
                        continue;
 
84
                }
 
85
                rd = (im->red[i] - r);  
 
86
                gd = (im->green[i] - g);
 
87
                bd = (im->blue[i] - b);
 
88
                dist = rd * rd + gd * gd + bd * bd;
 
89
                if ((i == 0) || (dist < mindist)) {
 
90
                        mindist = dist; 
 
91
                        ct = i;
 
92
                }
 
93
        }
 
94
        return ct;
 
95
}
 
96
 
 
97
int gdImageColorExact(im, r, g, b)
 
98
     gdImagePtr im;
 
99
     int r;
 
100
     int g;
 
101
     int b;
 
102
{
 
103
        int i;
 
104
        for (i=0; (i<(im->colorsTotal)); i++) {
 
105
                if (im->open[i]) {
 
106
                        continue;
 
107
                }
 
108
                if ((im->red[i] == r) && 
 
109
                        (im->green[i] == g) &&
 
110
                        (im->blue[i] == b)) {
 
111
                        return i;
 
112
                }
 
113
        }
 
114
        return -1;
 
115
}
 
116
 
 
117
int gdImageColorAllocate(im, r, g, b)
 
118
     gdImagePtr im;
 
119
     int r;
 
120
     int g;
 
121
     int b;
 
122
{
 
123
        int i;
 
124
        int ct = (-1);
 
125
        for (i=0; (i<(im->colorsTotal)); i++) {
 
126
                if (im->open[i]) {
 
127
                        ct = i;
 
128
                        break;
 
129
                }
 
130
        }       
 
131
        if (ct == (-1)) {
 
132
                ct = im->colorsTotal;
 
133
                if (ct == gdMaxColors) {
 
134
                        return -1;
 
135
                }
 
136
                im->colorsTotal++;
 
137
        }
 
138
        im->red[ct] = r;
 
139
        im->green[ct] = g;
 
140
        im->blue[ct] = b;
 
141
        im->open[ct] = 0;
 
142
        return ct;
 
143
}
 
144
 
 
145
void gdImageColorDeallocate(im, color)
 
146
     gdImagePtr im;
 
147
     int color;
 
148
{
 
149
        /* Mark it open. */
 
150
        im->open[color] = 1;
 
151
}
 
152
 
 
153
void gdImageColorTransparent(im, color)
 
154
     gdImagePtr im;
 
155
     int color;
 
156
{
 
157
        im->transparent = color;
 
158
}
 
159
 
 
160
/*SG gdSetClipping and gdUnsetClipping have been added to handle clipping */
 
161
void gdSetClipping(im, xmin, ymin, xmax, ymax)
 
162
     gdImagePtr im;
 
163
     int xmin;
 
164
     int ymin;
 
165
     int xmax;
 
166
     int ymax;
 
167
{
 
168
        im->clipping = 1;
 
169
        im->cliprect[0] = xmin; /* xmin */
 
170
        im->cliprect[1] = ymin; /* ymin */
 
171
        im->cliprect[2] = xmax; /* xmax */
 
172
        im->cliprect[3] = ymax; /* ymax */
 
173
}
 
174
 
 
175
void gdUnsetClipping(im)
 
176
     gdImagePtr im;
 
177
{
 
178
        im->clipping = 0;
 
179
}
 
180
/*SG gdSetAlu and gdAluColor have been added to handle alu modes */
 
181
void gdSetAlu(im, alu)
 
182
     gdImagePtr im;
 
183
     int alu;
 
184
{
 
185
        im->alu = alu;
 
186
}
 
187
 
 
188
int gdAluColor(im, dst, src)
 
189
     gdImagePtr im;
 
190
     int dst;
 
191
     int src;
 
192
{
 
193
int new;
 
194
unsigned char r, g, b, rd, gd, bd, rs, gs, bs;
 
195
 
 
196
 switch (im->alu) {
 
197
 case 0: /* clear */
 
198
   return 0;
 
199
 case 3: /* src */
 
200
   return src;
 
201
 case 5: /* dst */
 
202
   return dst;
 
203
 }
 
204
 rd =  ~(unsigned char)im->red[dst];
 
205
 gd  =  ~(unsigned char)im->green[dst];
 
206
 bd  =  ~(unsigned char)im->blue[dst];
 
207
 
 
208
 rs =  ~(unsigned char)im->red[src];
 
209
 gs  =  ~(unsigned char)im->green[src];
 
210
 bs  =  ~(unsigned char)im->blue[src];
 
211
 
 
212
 switch (im->alu) {
 
213
 case 1: /* src AND dst */
 
214
   r = rs & rd;
 
215
   g = gs & gd;
 
216
   b = bs & bd;
 
217
   break;
 
218
 case 2: /* src AND NOT dst */
 
219
   r = rs & ~rd;
 
220
   g = gs & ~gd;
 
221
   b = bs & ~bd;
 
222
   break;
 
223
 case 4: /* NOT src AND dst */
 
224
   r = ~rs & rd;
 
225
   g = ~gs & gd;
 
226
   b = ~bs & bd;
 
227
   break;
 
228
 case 5: /* dst */
 
229
   return dst;
 
230
 case 6: /* src XOR dst */
 
231
   r = rs ^ rd;
 
232
   g = gs ^ gd;
 
233
   b = bs ^ bd;
 
234
   break;
 
235
 case 7: /* src OR dst */
 
236
   r = rs | rd;
 
237
   g = gs | gd;
 
238
   b = bs | bd;
 
239
   break;
 
240
 case 8: /*NOT src AND NOT dst */
 
241
   r = ~rs &  ~rd;
 
242
   g = ~gs &  ~gd;
 
243
   b = ~bs &  ~bd;
 
244
   break;
 
245
 case 9: /*NOT src XOR dst */
 
246
   r = ~rs ^ rd;
 
247
   g = ~gs ^ gd;
 
248
   b = ~bs ^ bd;
 
249
   break;
 
250
 case 10: /* NOT dst */
 
251
   r =~rd;
 
252
   g =~gd;
 
253
   b =~bd;
 
254
   break;
 
255
 case 11: /*src OR NOT dst */
 
256
   r = rs | ~rd;
 
257
   g = gs | ~gd;
 
258
   b = bs | ~bd;
 
259
   break;
 
260
 case 12: /* NOT src */
 
261
   r = ~rs;
 
262
   g = ~gs ;
 
263
   b = ~bs; 
 
264
   break;
 
265
 case 13: /* NOT src OR dst */
 
266
   r = ~rs | rd;
 
267
   g = ~gs | gd;
 
268
   b = ~bs | bd;
 
269
   break;
 
270
 case 14: /* NOT src OR NOT dst */
 
271
   r = ~rs  | ~rd;
 
272
   g = ~gs | ~gd;
 
273
   b = ~bs | ~bd;
 
274
   break;
 
275
 case 15: /* 1 */
 
276
   r = 0;
 
277
   g = 0;
 
278
   b = 0;
 
279
   break;
 
280
 }
 
281
 r = ~r;
 
282
 g = ~g;
 
283
 b = ~b;
 
284
 new = gdImageColorExact(im, (int)r, (int)g, (int)b);
 
285
 if (new==-1) 
 
286
   new = gdImageColorAllocate(im, (int)r, (int)g, (int)b);
 
287
 if (new==-1) 
 
288
   new = gdImageColorClosest(im, (int)r, (int)g, (int)b);
 
289
 return new;
 
290
}
 
291
 
 
292
void gdSetBackground(im, background)
 
293
     gdImagePtr im;
 
294
     int background;
 
295
{
 
296
        im->background = background;
 
297
}
 
298
/*SG gdImageSetPixel modified to handle alu modes */
 
299
void gdImageSetPixel(im, x, y, color)
 
300
     gdImagePtr im;
 
301
     int x;
 
302
     int y;
 
303
     int color;
 
304
{
 
305
        int p;
 
306
 
 
307
        switch(color) {
 
308
                case gdStyled:
 
309
                if (!im->style) {
 
310
                        /* Refuse to draw if no style is set. */
 
311
                        return;
 
312
                } else {
 
313
                        p = im->style[im->stylePos++];
 
314
                }
 
315
                if (p != (gdTransparent)) {
 
316
                        gdImageSetPixel(im, x, y, p);
 
317
                }
 
318
                im->stylePos = im->stylePos %  im->styleLength;
 
319
                break;
 
320
                case gdStyledBrushed:
 
321
                if (!im->style) {
 
322
                        /* Refuse to draw if no style is set. */
 
323
                        return;
 
324
                }
 
325
                p = im->style[im->stylePos++];
 
326
                if ((p != gdTransparent) && (p != 0)) {
 
327
                        gdImageSetPixel(im, x, y, gdBrushed);
 
328
                }
 
329
                im->stylePos = im->stylePos %  im->styleLength;
 
330
                break;
 
331
                case gdBrushed:
 
332
                gdImageBrushApply(im, x, y);
 
333
                break;
 
334
                case gdTiled:
 
335
                gdImageTileApply(im, x, y);
 
336
                break;
 
337
                default:
 
338
                if (gdImageBoundsSafe(im, x, y)) {
 
339
                  /* NOW ROW-MAJOR IN GD 1.3 */
 
340
                  /*SG modified here to handle alu modes */
 
341
                  im->pixels[y][x] = gdAluColor(im,im->pixels[y][x],color);
 
342
 
 
343
                }
 
344
                break;
 
345
        }
 
346
}
 
347
 
 
348
 
 
349
static void gdImageBrushApply(im, x, y)
 
350
     gdImagePtr im;
 
351
     int x;
 
352
     int y;
 
353
{
 
354
        int lx, ly;
 
355
        int hy;
 
356
        int hx;
 
357
        int x1, y1, x2, y2;
 
358
        int srcx, srcy;
 
359
        if (!im->brush) {
 
360
                return;
 
361
        }
 
362
        hy = gdImageSY(im->brush)/2;
 
363
        y1 = y - hy;
 
364
        y2 = y1 + gdImageSY(im->brush); 
 
365
        hx = gdImageSX(im->brush)/2;
 
366
        x1 = x - hx;
 
367
        x2 = x1 + gdImageSX(im->brush);
 
368
        srcy = 0;
 
369
        for (ly = y1; (ly < y2); ly++) {
 
370
                srcx = 0;
 
371
                for (lx = x1; (lx < x2); lx++) {
 
372
                        int p;
 
373
                        p = gdImageGetPixel(im->brush, srcx, srcy);
 
374
                        /* Allow for non-square brushes! */
 
375
                        if (p != gdImageGetTransparent(im->brush)) {
 
376
                                gdImageSetPixel(im, lx, ly,
 
377
                                        im->brushColorMap[p]);
 
378
                        }
 
379
                        srcx++;
 
380
                }
 
381
                srcy++;
 
382
        }       
 
383
}               
 
384
 
 
385
static void gdImageTileApply(im, x, y)
 
386
     gdImagePtr im;
 
387
     int x;
 
388
     int y;
 
389
{
 
390
        int srcx, srcy;
 
391
        int p;
 
392
        if (!im->tile) {
 
393
                return;
 
394
        }
 
395
        srcx = x % gdImageSX(im->tile);
 
396
        srcy = y % gdImageSY(im->tile);
 
397
        p = gdImageGetPixel(im->tile, srcx, srcy);
 
398
        /* Allow for transparency */
 
399
        if (p != gdImageGetTransparent(im->tile)) {
 
400
                gdImageSetPixel(im, x, y,
 
401
                        im->tileColorMap[p]);
 
402
        }
 
403
}               
 
404
 
 
405
int gdImageGetPixel(im, x, y)
 
406
     gdImagePtr im;
 
407
     int x;
 
408
     int y;
 
409
{
 
410
        if (gdImageBoundsSafe(im, x, y)) {
 
411
                /* NOW ROW-MAJOR IN GD 1.3 */
 
412
                return im->pixels[y][x];
 
413
        } else {
 
414
                return 0;
 
415
        }
 
416
}
 
417
 
 
418
/* Bresenham as presented in Foley & Van Dam */
 
419
/*SG added function to handle Thick lines with alu modes */
 
420
void gdImageThickLine(im, x1, y1, x2, y2, color, thick)
 
421
     gdImagePtr im;
 
422
     int x1;
 
423
     int y1;
 
424
     int x2;
 
425
     int y2;
 
426
     int color;
 
427
     int thick;
 
428
{
 
429
  int  virtual, c, c1, x, y, oldcmap, mnx, mxx, mny, mxy;
 
430
  gdImagePtr imv, brush, oldbrush;
 
431
 
 
432
  virtual= (im->alu!=3 && im->alu!=0 && im->alu!=5);
 
433
  if (virtual) {
 
434
    mnx=Max(0,Min(x1,x2)-thick/2);
 
435
    mny=Max(0,Min(y1,y2)-thick/2);
 
436
    mxx=Min(im->sx,Max(x1,x2)+thick/2);
 
437
    mxy=Min(im->sy,Max(y1,y2)+thick/2);
 
438
 
 
439
    imv=gdImageCreate(im->sx, im->sy);
 
440
    for (y=mny; (y <= mxy ); y++) {     
 
441
      for (x=mnx; (x <= mxx); x++) {    
 
442
        imv->pixels[y][x]=0;
 
443
      }
 
444
    }
 
445
    c=1;
 
446
  }
 
447
  else {
 
448
    imv = im;
 
449
    c = color;
 
450
  }
 
451
 
 
452
  if (thick > 1 && color >= 0) { /* create a square brush */
 
453
    brush=gdImageCreate(thick, thick);
 
454
    for (y=0; (y < thick ); y++) {      
 
455
      for (x=0; (x < thick); x++) {     
 
456
        brush->pixels[y][x]=c;
 
457
      }
 
458
    }
 
459
    oldbrush = imv->brush;
 
460
    imv->brush = brush;
 
461
    oldcmap = imv->brushColorMap[c];
 
462
    imv->brushColorMap[c] = c;
 
463
    c1 = c;
 
464
    c = gdBrushed;
 
465
  }
 
466
    gdImageLine(imv,x1, y1, x2, y2, c);
 
467
 
 
468
  if (thick > 1 && color >= 0) { /* deallocate square brush */
 
469
    gdImageDestroy(brush);
 
470
    imv->brush = oldbrush;
 
471
    imv->brushColorMap[c1] = oldcmap;
 
472
  }
 
473
  if (virtual) {
 
474
    for (y=mny; (y <= mxy ); y++) {     
 
475
      for (x=mnx; (x <= mxx); x++) {    
 
476
        if (imv->pixels[y][x] == 1)
 
477
          gdImageSetPixel(im, x, y, color);
 
478
      }
 
479
    }
 
480
    gdImageDestroy(imv);
 
481
  }
 
482
 
 
483
}
 
484
 
 
485
void gdImageLine(im, x1, y1, x2, y2, color)
 
486
     gdImagePtr im;
 
487
     int x1;
 
488
     int y1;
 
489
     int x2;
 
490
     int y2;
 
491
     int color;
 
492
{
 
493
        int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
 
494
        dx = abs(x2-x1);
 
495
        dy = abs(y2-y1);
 
496
        if (dy <= dx) {
 
497
                d = 2*dy - dx;
 
498
                incr1 = 2*dy;
 
499
                incr2 = 2 * (dy - dx);
 
500
                if (x1 > x2) {
 
501
                        x = x2;
 
502
                        y = y2;
 
503
                        ydirflag = (-1);
 
504
                        xend = x1;
 
505
                } else {
 
506
                        x = x1;
 
507
                        y = y1;
 
508
                        ydirflag = 1;
 
509
                        xend = x2;
 
510
                }
 
511
                gdImageSetPixel(im, x, y, color);
 
512
                if (((y2 - y1) * ydirflag) > 0) {
 
513
                        while (x < xend) {
 
514
                                x++;
 
515
                                if (d <0) {
 
516
                                        d+=incr1;
 
517
                                } else {
 
518
                                        y++;
 
519
                                        d+=incr2;
 
520
                                }
 
521
                                gdImageSetPixel(im, x, y, color);
 
522
                        }
 
523
                } else {
 
524
                        while (x < xend) {
 
525
                                x++;
 
526
                                if (d <0) {
 
527
                                        d+=incr1;
 
528
                                } else {
 
529
                                        y--;
 
530
                                        d+=incr2;
 
531
                                }
 
532
                                gdImageSetPixel(im, x, y, color);
 
533
                        }
 
534
                }               
 
535
        } else {
 
536
                d = 2*dx - dy;
 
537
                incr1 = 2*dx;
 
538
                incr2 = 2 * (dx - dy);
 
539
                if (y1 > y2) {
 
540
                        y = y2;
 
541
                        x = x2;
 
542
                        yend = y1;
 
543
                        xdirflag = (-1);
 
544
                } else {
 
545
                        y = y1;
 
546
                        x = x1;
 
547
                        yend = y2;
 
548
                        xdirflag = 1;
 
549
                }
 
550
                gdImageSetPixel(im, x, y, color);
 
551
                if (((x2 - x1) * xdirflag) > 0) {
 
552
                        while (y < yend) {
 
553
                                y++;
 
554
                                if (d <0) {
 
555
                                        d+=incr1;
 
556
                                } else {
 
557
                                        x++;
 
558
                                        d+=incr2;
 
559
                                }
 
560
                                gdImageSetPixel(im, x, y, color);
 
561
                        }
 
562
                } else {
 
563
                        while (y < yend) {
 
564
                                y++;
 
565
                                if (d <0) {
 
566
                                        d+=incr1;
 
567
                                } else {
 
568
                                        x--;
 
569
                                        d+=incr2;
 
570
                                }
 
571
                                gdImageSetPixel(im, x, y, color);
 
572
                        }
 
573
                }
 
574
        }
 
575
}
 
576
/*SG added to handle thick polylines along with alu mode */
 
577
void gdImagePolyLine(im, X, Y, n, color, thick, close)
 
578
     gdImagePtr im;
 
579
     int *X;
 
580
     int *Y;
 
581
     int n;
 
582
     int color;
 
583
     int thick;
 
584
     int close;
 
585
{
 
586
  int i;
 
587
  int x, y;
 
588
  int virtual, c, c1, mnx, mxx, mny, mxy, oldcmap1;
 
589
  gdImagePtr imv, brush, oldbrush;
 
590
  
 
591
 
 
592
  virtual= (im->alu!=3 && im->alu!=0 && im->alu!=5);
 
593
  if (virtual) {
 
594
    mnx=mxx=X[0];
 
595
    mny=mxy=Y[0];
 
596
    for (i=0;i<n;i++) {
 
597
      mnx=Min(mnx,X[i]);
 
598
      mny=Min(mny,Y[i]);
 
599
      mxx=Max(mxx,X[i]);
 
600
      mxy=Max(mxy,Y[i]);
 
601
    }
 
602
    mnx=Max(0,mnx-thick/2);
 
603
    mny=Max(0,mny-thick/2);
 
604
    mxx=Min(im->sx,mxx+thick/2);
 
605
    mxy=Min(im->sy,mxy+thick/2);
 
606
 
 
607
    imv=gdImageCreate(im->sx, im->sy);
 
608
    for (y=mny; (y <= mxy ); y++) {     
 
609
      for (x=mnx; (x <= mxx); x++) {    
 
610
        imv->pixels[y][x]=0;
 
611
      }
 
612
    }
 
613
    c=1;
 
614
  }
 
615
  else {
 
616
    imv = im;
 
617
    c = color;
 
618
  }
 
619
 
 
620
  if (thick > 1 && color >= 0) { /* create a square brush */
 
621
    brush=gdImageCreate(thick, thick);
 
622
    for (y=0; (y < thick ); y++) {      
 
623
      for (x=0; (x < thick); x++) {     
 
624
        brush->pixels[y][x]=c;
 
625
      }
 
626
    }
 
627
    oldbrush = imv->brush;
 
628
    imv->brush = brush;
 
629
    oldcmap1 = imv->brushColorMap[c];
 
630
    imv->brushColorMap[c] = c;
 
631
    c1 = c;
 
632
    c = gdBrushed;
 
633
  }
 
634
  for (i=0;i<n-1;i++) 
 
635
    gdImageLine(imv,X[i],Y[i],X[i+1],Y[i+1],c);
 
636
 
 
637
    
 
638
  if (close) 
 
639
    gdImageLine(imv,X[n-1],Y[n-1],X[0],Y[0],c);
 
640
 
 
641
 
 
642
  if (thick > 1 && color >= 0) { /* deallocate square brush */
 
643
    gdImageDestroy(brush);
 
644
    imv->brush = oldbrush;
 
645
    imv->brushColorMap[c1] = oldcmap1;
 
646
  }
 
647
 
 
648
  if (virtual) {
 
649
    for (y=mny; (y <= mxy ); y++) {     
 
650
      for (x=mnx; (x <= mxx); x++) {    
 
651
        if (imv->pixels[y][x] == 1)
 
652
          gdImageSetPixel(im, x, y, color);
 
653
      }
 
654
    }
 
655
    gdImageDestroy(imv);
 
656
  }
 
657
}
 
658
        
 
659
/*SG modified to add clipping region */
 
660
int gdImageBoundsSafe(im, x, y)
 
661
     gdImagePtr im;
 
662
     int x;
 
663
     int y;
 
664
{
 
665
  int bounds;
 
666
 
 
667
  bounds= (!(((y < 0) || (y >= im->sy)) ||
 
668
             ((x < 0) || (x >= im->sx))));
 
669
  /* next lines added to handle clipping region */
 
670
  if (im->clipping == 1) {
 
671
 
 
672
    bounds = bounds & 
 
673
      (!(((y < im->cliprect[1]) || (y > im->cliprect[3])) ||
 
674
         ((x < im->cliprect[0]) || (x > im->cliprect[2]))));
 
675
  }
 
676
  return bounds;
 
677
}
 
678
 
 
679
/*SG gdImageChar has been modified to handle variable width fonts; 
 
680
   it now returns the position of beginning of the next character */
 
681
int gdImageChar(im, f, x, y, c, color)
 
682
     gdImagePtr im;
 
683
     gdFontPtr f;
 
684
     int x;
 
685
     int y;
 
686
     int c;
 
687
     int color;
 
688
{
 
689
        int cx, cy;
 
690
        int px, py;
 
691
        int fline;
 
692
        int mx;
 
693
        cx = 0;
 
694
        cy = 0;
 
695
        mx = x;
 
696
        if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
 
697
                return(0);
 
698
        }
 
699
        fline = (c - f->offset) * f->h * f->w;
 
700
        for (py = y; (py < (y + f->h)); py++) {
 
701
                for (px = x; (px < (x + f->w)); px++) {
 
702
                        if (f->data[fline + cy * f->w + cx]) {
 
703
                                gdImageSetPixel(im, px, py, color);     
 
704
                                mx = Max(mx,px+1);
 
705
                        }
 
706
                        cx++;
 
707
                }
 
708
                cx = 0;
 
709
                cy++;
 
710
        }
 
711
        return(mx-x+1);
 
712
}
 
713
/*SG gdCharWidth has been added to compute the effective width of a character */
 
714
int gdCharWidth(f, c)
 
715
     gdFontPtr f;
 
716
     int c; 
 
717
{
 
718
        int cx, cy;
 
719
        int px, py;
 
720
        int fline;
 
721
        int mx;
 
722
 
 
723
        cx = 0;
 
724
        cy = 0;
 
725
 
 
726
        mx = 0;
 
727
        if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
 
728
                return(0);
 
729
        }
 
730
        fline = (c - f->offset) * f->h * f->w;
 
731
        for (py = 0; (py < ( f->h)); py++) {
 
732
                for (px = 0; (px < (f->w)); px++) {
 
733
                        if (f->data[fline + cy * f->w + cx]) {
 
734
                                mx = Max(mx,px+1);
 
735
                        }
 
736
                        cx++;
 
737
                }
 
738
                cx = 0;
 
739
                cy++;
 
740
        }
 
741
        return(mx+1);
 
742
}
 
743
 
 
744
 
 
745
void gdImageCharUp(im, f, x, y, c, color)
 
746
     gdImagePtr im;
 
747
     gdFontPtr f;
 
748
     int x;
 
749
     int y;
 
750
     int c;
 
751
     int color;
 
752
{
 
753
        int cx, cy;
 
754
        int px, py;
 
755
        int fline;
 
756
        int mx;
 
757
        cx = 0;
 
758
        cy = 0;
 
759
        mx = x;
 
760
        if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
 
761
                return;
 
762
        }
 
763
        fline = (c - f->offset) * f->h * f->w;
 
764
        for (py = y; (py > (y - f->w)); py--) {
 
765
                for (px = x; (px < (x + f->h)); px++) {
 
766
                        if (f->data[fline + cy * f->w + cx]) {
 
767
                                gdImageSetPixel(im, px, py, color);     
 
768
                                mx = Max(mx,px+1);
 
769
                        }
 
770
                        cy++;
 
771
                }
 
772
                cy = 0;
 
773
                cx++;
 
774
        }
 
775
}
 
776
/*SG gdImageString has been modified to handle variable width fonts */
 
777
void gdImageString(im, f, x, y, s, color)
 
778
     gdImagePtr im;
 
779
     gdFontPtr f;
 
780
     int x;
 
781
     int y;
 
782
     unsigned char *s;
 
783
     int color;
 
784
{
 
785
        int i;
 
786
        int l,dx;
 
787
        l = strlen((unsigned char *)s);
 
788
        for (i=0; (i<l); i++) {
 
789
                dx = gdImageChar(im, f, x, y, s[i], color);
 
790
                /*              x += f->w;*/
 
791
                x += dx;
 
792
        }
 
793
}
 
794
 
 
795
void gdImageStringUp(im, f, x, y, s, color)
 
796
     gdImagePtr im;
 
797
     gdFontPtr f;
 
798
     int x;
 
799
     int y;
 
800
     unsigned char *s;
 
801
     int color;
 
802
{
 
803
        int i;
 
804
        int l;
 
805
        l = strlen((unsigned char *)s);
 
806
        for (i=0; (i<l); i++) {
 
807
                gdImageCharUp(im, f, x, y, s[i], color);
 
808
                y -= f->w;
 
809
        }
 
810
}
 
811
 
 
812
static int strlen16();
 
813
 
 
814
void gdImageString16(im, f, x, y, s, color)
 
815
     gdImagePtr im;
 
816
     gdFontPtr f;
 
817
     int x;
 
818
     int y;
 
819
     short unsigned int *s;
 
820
     int color;
 
821
{
 
822
        int i;
 
823
        int l;
 
824
        l = strlen16(s);
 
825
        for (i=0; (i<l); i++) {
 
826
                gdImageChar(im, f, x, y, s[i], color);
 
827
                x += f->w;
 
828
        }
 
829
}
 
830
 
 
831
void gdImageStringUp16(im, f, x, y, s, color)
 
832
     gdImagePtr im;
 
833
     gdFontPtr f;
 
834
     int x;
 
835
     int y;
 
836
     short unsigned int *s;
 
837
     int color;
 
838
{
 
839
        int i;
 
840
        int l;
 
841
        l = strlen16(s);
 
842
        for (i=0; (i<l); i++) {
 
843
                gdImageCharUp(im, f, x, y, s[i], color);
 
844
                y -= f->w;
 
845
        }
 
846
}
 
847
 
 
848
static int strlen16(s)
 
849
     short unsigned int *s;
 
850
{
 
851
        int len = 0;
 
852
        while (*s) {
 
853
                s++;
 
854
                len++;
 
855
        }
 
856
        return len;
 
857
}
 
858
 
 
859
/* s and e are integers modulo 360 (degrees), with 0 degrees
 
860
  being the rightmost extreme and degrees changing clockwise.
 
861
  cx and cy are the center in pixels; w and h are the horizontal 
 
862
  and vertical diameter in pixels. Nice interface, but slow, since
 
863
  I don't yet use Bresenham (I'm using an inefficient but
 
864
  simple solution with too much work going on in it; generalizing
 
865
  Bresenham to ellipses and partial arcs of ellipses is non-trivial,
 
866
  at least for me) and there are other inefficiencies (small circles
 
867
  do far too much work). */
 
868
 
 
869
void gdImageArc(im, cx, cy, w, h, s, e, color)
 
870
     gdImagePtr im;
 
871
     int cx;
 
872
     int cy;
 
873
     int w;
 
874
     int h;
 
875
     int s;
 
876
     int e;
 
877
     int color;
 
878
{
 
879
        int i;
 
880
        int lx = 0, ly = 0;
 
881
        int w2, h2;
 
882
        w2 = w/2;
 
883
        h2 = h/2;
 
884
        while (e < s) {
 
885
                e += 360;
 
886
        }
 
887
        for (i=s; (i <= e); i++) {
 
888
                int x, y;
 
889
                x = ((long)cost[i % 360] * (long)w2 / costScale) + cx; 
 
890
                y = ((long)sint[i % 360] * (long)h2 / sintScale) + cy;
 
891
                if (i != s) {
 
892
                        gdImageLine(im, lx, ly, x, y, color);   
 
893
                }
 
894
                lx = x;
 
895
                ly = y;
 
896
        }
 
897
}
 
898
 
 
899
 
 
900
#if 0
 
901
        /* Bresenham octant code, which I should use eventually */
 
902
        int x, y, d;
 
903
        x = 0;
 
904
        y = w;
 
905
        d = 3-2*w;
 
906
        while (x < y) {
 
907
                gdImageSetPixel(im, cx+x, cy+y, color);
 
908
                if (d < 0) {
 
909
                        d += 4 * x + 6;
 
910
                } else {
 
911
                        d += 4 * (x - y) + 10;
 
912
                        y--;
 
913
                }
 
914
                x++;
 
915
        }
 
916
        if (x == y) {
 
917
                gdImageSetPixel(im, cx+x, cy+y, color);
 
918
        }
 
919
#endif
 
920
 
 
921
void gdImageFillToBorder(im, x, y, border, color)
 
922
     gdImagePtr im;
 
923
     int x;
 
924
     int y;
 
925
     int border;
 
926
     int color;
 
927
{
 
928
        int lastBorder;
 
929
        /* Seek left */
 
930
        int leftLimit, rightLimit;
 
931
        int i;
 
932
        leftLimit = (-1);
 
933
        if (border < 0) {
 
934
                /* Refuse to fill to a non-solid border */
 
935
                return;
 
936
        }
 
937
        for (i = x; (i >= 0); i--) {
 
938
                if (gdImageGetPixel(im, i, y) == border) {
 
939
                        break;
 
940
                }
 
941
                gdImageSetPixel(im, i, y, color);
 
942
                leftLimit = i;
 
943
        }
 
944
        if (leftLimit == (-1)) {
 
945
                return;
 
946
        }
 
947
        /* Seek right */
 
948
        rightLimit = x;
 
949
        for (i = (x+1); (i < im->sx); i++) {    
 
950
                if (gdImageGetPixel(im, i, y) == border) {
 
951
                        break;
 
952
                }
 
953
                gdImageSetPixel(im, i, y, color);
 
954
                rightLimit = i;
 
955
        }
 
956
        /* Look at lines above and below and start paints */
 
957
        /* Above */
 
958
        if (y > 0) {
 
959
                lastBorder = 1;
 
960
                for (i = leftLimit; (i <= rightLimit); i++) {
 
961
                        int c;
 
962
                        c = gdImageGetPixel(im, i, y-1);
 
963
                        if (lastBorder) {
 
964
                                if ((c != border) && (c != color)) {    
 
965
                                        gdImageFillToBorder(im, i, y-1, 
 
966
                                                border, color);         
 
967
                                        lastBorder = 0;
 
968
                                }
 
969
                        } else if ((c == border) || (c == color)) {
 
970
                                lastBorder = 1;
 
971
                        }
 
972
                }
 
973
        }
 
974
        /* Below */
 
975
        if (y < ((im->sy) - 1)) {
 
976
                lastBorder = 1;
 
977
                for (i = leftLimit; (i <= rightLimit); i++) {
 
978
                        int c;
 
979
                        c = gdImageGetPixel(im, i, y+1);
 
980
                        if (lastBorder) {
 
981
                                if ((c != border) && (c != color)) {    
 
982
                                        gdImageFillToBorder(im, i, y+1, 
 
983
                                                border, color);         
 
984
                                        lastBorder = 0;
 
985
                                }
 
986
                        } else if ((c == border) || (c == color)) {
 
987
                                lastBorder = 1;
 
988
                        }
 
989
                }
 
990
        }
 
991
}
 
992
 
 
993
void gdImageFill(im, x, y, color)
 
994
     gdImagePtr im;
 
995
     int x;
 
996
     int y;
 
997
     int color;
 
998
{
 
999
        int lastBorder;
 
1000
        int old;
 
1001
        int leftLimit, rightLimit;
 
1002
        int i;
 
1003
        old = gdImageGetPixel(im, x, y);
 
1004
        if (color == gdTiled) {
 
1005
                /* Tile fill -- got to watch out! */
 
1006
                int p, tileColor;       
 
1007
                int srcx, srcy;
 
1008
                if (!im->tile) {
 
1009
                        return;
 
1010
                }
 
1011
                /* Refuse to flood-fill with a transparent pattern --
 
1012
                        I can't do it without allocating another image */
 
1013
                if (gdImageGetTransparent(im->tile) != (-1)) {
 
1014
                        return;
 
1015
                }       
 
1016
                srcx = x % gdImageSX(im->tile);
 
1017
                srcy = y % gdImageSY(im->tile);
 
1018
                p = gdImageGetPixel(im->tile, srcx, srcy);
 
1019
                tileColor = im->tileColorMap[p];
 
1020
                if (old == tileColor) {
 
1021
                        /* Nothing to be done */
 
1022
                        return;
 
1023
                }
 
1024
        } else {
 
1025
                if (old == color) {
 
1026
                        /* Nothing to be done */
 
1027
                        return;
 
1028
                }
 
1029
        }
 
1030
        /* Seek left */
 
1031
        leftLimit = (-1);
 
1032
        for (i = x; (i >= 0); i--) {
 
1033
                if (gdImageGetPixel(im, i, y) != old) {
 
1034
                        break;
 
1035
                }
 
1036
                gdImageSetPixel(im, i, y, color);
 
1037
                leftLimit = i;
 
1038
        }
 
1039
        if (leftLimit == (-1)) {
 
1040
                return;
 
1041
        }
 
1042
        /* Seek right */
 
1043
        rightLimit = x;
 
1044
        for (i = (x+1); (i < im->sx); i++) {    
 
1045
                if (gdImageGetPixel(im, i, y) != old) {
 
1046
                        break;
 
1047
                }
 
1048
                gdImageSetPixel(im, i, y, color);
 
1049
                rightLimit = i;
 
1050
        }
 
1051
        /* Look at lines above and below and start paints */
 
1052
        /* Above */
 
1053
        if (y > 0) {
 
1054
                lastBorder = 1;
 
1055
                for (i = leftLimit; (i <= rightLimit); i++) {
 
1056
                        int c;
 
1057
                        c = gdImageGetPixel(im, i, y-1);
 
1058
                        if (lastBorder) {
 
1059
                                if (c == old) { 
 
1060
                                        gdImageFill(im, i, y-1, color);         
 
1061
                                        lastBorder = 0;
 
1062
                                }
 
1063
                        } else if (c != old) {
 
1064
                                lastBorder = 1;
 
1065
                        }
 
1066
                }
 
1067
        }
 
1068
        /* Below */
 
1069
        if (y < ((im->sy) - 1)) {
 
1070
                lastBorder = 1;
 
1071
                for (i = leftLimit; (i <= rightLimit); i++) {
 
1072
                        int c;
 
1073
                        c = gdImageGetPixel(im, i, y+1);
 
1074
                        if (lastBorder) {
 
1075
                                if (c == old) {
 
1076
                                        gdImageFill(im, i, y+1, color);         
 
1077
                                        lastBorder = 0;
 
1078
                                }
 
1079
                        } else if (c != old) {
 
1080
                                lastBorder = 1;
 
1081
                        }
 
1082
                }
 
1083
        }
 
1084
}
 
1085
        
 
1086
/* Code drawn from ppmtogif.c, from the pbmplus package
 
1087
**
 
1088
** Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>. A
 
1089
** Lempel-Zim compression based on "compress".
 
1090
**
 
1091
** Modified by Marcel Wijkstra <wijkstra@fwi.uva.nl>
 
1092
**
 
1093
** Copyright (C) 1989 by Jef Poskanzer.
 
1094
**
 
1095
** Permission to use, copy, modify, and distribute this software and its
 
1096
** documentation for any purpose and without fee is hereby granted, provided
 
1097
** that the above copyright notice appear in all copies and that both that
 
1098
** copyright notice and this permission notice appear in supporting
 
1099
** documentation.  This software is provided "as is" without express or
 
1100
** implied warranty.
 
1101
**
 
1102
** The Graphics Interchange Format(c) is the Copyright property of
 
1103
** CompuServe Incorporated.  GIF(sm) is a Service Mark property of
 
1104
** CompuServe Incorporated.
 
1105
*
 
1106
*  Heavily modified by Mouse, 1998-02-12.  
 
1107
*  Remove LZW compression.
 
1108
*  Added miGIF run length compression.
 
1109
*
 
1110
*/
 
1111
 
 
1112
/*
 
1113
 * a code_int must be able to hold 2**GIFBITS values of type int, and also -1
 
1114
 */
 
1115
typedef int code_int;
 
1116
 
 
1117
static int colorstobpp();
 
1118
static void BumpPixel ();
 
1119
static int GIFNextPixel ();
 
1120
static void GIFEncode ();
 
1121
static void Putword ();
 
1122
static void compress ();
 
1123
static void output ();
 
1124
static void char_init ();
 
1125
static void char_out ();
 
1126
/* Allows for reuse */
 
1127
static void init_statics();
 
1128
 
 
1129
void gdImageGif(im, out)
 
1130
     gdImagePtr im;
 
1131
     FILE *out;
 
1132
{
 
1133
        int interlace, transparent, background, BitsPerPixel;
 
1134
        interlace = im->interlace;
 
1135
        transparent = im->transparent;
 
1136
        background = im->background;
 
1137
        BitsPerPixel = colorstobpp(im->colorsTotal);
 
1138
        /* Clear any old values in statics strewn through the GIF code */
 
1139
        init_statics();
 
1140
        /* All set, let's do it. */
 
1141
        GIFEncode(
 
1142
                out, im->sx, im->sy, interlace, background, transparent, 
 
1143
                BitsPerPixel, im->red, im->green, im->blue, im);
 
1144
}
 
1145
 
 
1146
static int
 
1147
colorstobpp(colors)
 
1148
     int colors;
 
1149
{
 
1150
    int bpp = 0;
 
1151
 
 
1152
    if ( colors <= 2 )
 
1153
        bpp = 1;
 
1154
    else if ( colors <= 4 )
 
1155
        bpp = 2;
 
1156
    else if ( colors <= 8 )
 
1157
        bpp = 3;
 
1158
    else if ( colors <= 16 )
 
1159
        bpp = 4;
 
1160
    else if ( colors <= 32 )
 
1161
        bpp = 5;
 
1162
    else if ( colors <= 64 )
 
1163
        bpp = 6;
 
1164
    else if ( colors <= 128 )
 
1165
        bpp = 7;
 
1166
    else if ( colors <= 256 )
 
1167
        bpp = 8;
 
1168
    return bpp;
 
1169
    }
 
1170
 
 
1171
/*****************************************************************************
 
1172
 *
 
1173
 * GIFENCODE.C    - GIF Image compression interface
 
1174
 *
 
1175
 * GIFEncode( FName, GHeight, GWidth, GInterlace, Background, Transparent,
 
1176
 *            BitsPerPixel, Red, Green, Blue, gdImagePtr )
 
1177
 *
 
1178
 *****************************************************************************/
 
1179
 
 
1180
#define TRUE 1
 
1181
#define FALSE 0
 
1182
 
 
1183
static int Width, Height;
 
1184
static int curx, cury;
 
1185
static long CountDown;
 
1186
static int Pass = 0;
 
1187
static int Interlace;
 
1188
 
 
1189
/*
 
1190
 * Bump the 'curx' and 'cury' to point to the next pixel
 
1191
 */
 
1192
static void
 
1193
BumpPixel()
 
1194
{
 
1195
        /*
 
1196
         * Bump the current X position
 
1197
         */
 
1198
        ++curx;
 
1199
 
 
1200
        /*
 
1201
         * If we are at the end of a scan line, set curx back to the beginning
 
1202
         * If we are interlaced, bump the cury to the appropriate spot,
 
1203
         * otherwise, just increment it.
 
1204
         */
 
1205
        if( curx == Width ) {
 
1206
                curx = 0;
 
1207
 
 
1208
                if( !Interlace )
 
1209
                        ++cury;
 
1210
                else {
 
1211
                     switch( Pass ) {
 
1212
 
 
1213
                       case 0:
 
1214
                          cury += 8;
 
1215
                          if( cury >= Height ) {
 
1216
                                ++Pass;
 
1217
                                cury = 4;
 
1218
                          }
 
1219
                          break;
 
1220
 
 
1221
                       case 1:
 
1222
                          cury += 8;
 
1223
                          if( cury >= Height ) {
 
1224
                                ++Pass;
 
1225
                                cury = 2;
 
1226
                          }
 
1227
                          break;
 
1228
 
 
1229
                       case 2:
 
1230
                          cury += 4;
 
1231
                          if( cury >= Height ) {
 
1232
                             ++Pass;
 
1233
                             cury = 1;
 
1234
                          }
 
1235
                          break;
 
1236
 
 
1237
                       case 3:
 
1238
                          cury += 2;
 
1239
                          break;
 
1240
                        }
 
1241
                }
 
1242
        }
 
1243
}
 
1244
 
 
1245
/*
 
1246
 * Return the next pixel from the image
 
1247
 */
 
1248
static int
 
1249
GIFNextPixel(im)
 
1250
     gdImagePtr im;
 
1251
{
 
1252
        int r;
 
1253
 
 
1254
        if( CountDown == 0 )
 
1255
                return EOF;
 
1256
 
 
1257
        --CountDown;
 
1258
 
 
1259
        r = gdImageGetPixel(im, curx, cury);
 
1260
 
 
1261
        BumpPixel();
 
1262
 
 
1263
        return r;
 
1264
}
 
1265
 
 
1266
/* public */
 
1267
 
 
1268
static void
 
1269
GIFEncode(fp, GWidth, GHeight, GInterlace, Background, Transparent, BitsPerPixel, Red, Green, Blue, im)
 
1270
     FILE *fp;
 
1271
     int GWidth;
 
1272
     int GHeight;
 
1273
     int GInterlace;
 
1274
     int Background;
 
1275
     int Transparent;
 
1276
     int BitsPerPixel;
 
1277
     int *Red;
 
1278
     int *Green;
 
1279
     int *Blue;
 
1280
     gdImagePtr im;
 
1281
{
 
1282
        int B;
 
1283
        int RWidth, RHeight;
 
1284
        int LeftOfs, TopOfs;
 
1285
        int Resolution;
 
1286
        int ColorMapSize;
 
1287
        int InitCodeSize;
 
1288
        int i;
 
1289
 
 
1290
        Interlace = GInterlace;
 
1291
 
 
1292
        ColorMapSize = 1 << BitsPerPixel;
 
1293
 
 
1294
        RWidth = Width = GWidth;
 
1295
        RHeight = Height = GHeight;
 
1296
        LeftOfs = TopOfs = 0;
 
1297
 
 
1298
        Resolution = BitsPerPixel;
 
1299
 
 
1300
        /*
 
1301
         * Calculate number of bits we are expecting
 
1302
         */
 
1303
        CountDown = (long)Width * (long)Height;
 
1304
        /*
 
1305
         * Indicate which pass we are on (if interlace)
 
1306
         */
 
1307
        Pass = 0;
 
1308
 
 
1309
        /*
 
1310
         * The initial code size
 
1311
         */
 
1312
        if( BitsPerPixel <= 1 )
 
1313
                InitCodeSize = 2;
 
1314
        else
 
1315
                InitCodeSize = BitsPerPixel;
 
1316
 
 
1317
        /*
 
1318
         * Set up the current x and y position
 
1319
         */
 
1320
        curx = cury = 0;
 
1321
 
 
1322
        /*
 
1323
         * Write the Magic header
 
1324
         */
 
1325
        fwrite( Transparent < 0 ? "GIF87a" : "GIF89a", 1, 6, fp );
 
1326
 
 
1327
        /*
 
1328
         * Write out the screen width and height
 
1329
         */
 
1330
        Putword( RWidth, fp );
 
1331
        Putword( RHeight, fp );
 
1332
 
 
1333
        /*
 
1334
         * Indicate that there is a global colour map
 
1335
         */
 
1336
        B = 0x80;       /* Yes, there is a color map */
 
1337
 
 
1338
        /*
 
1339
         * OR in the resolution
 
1340
         */
 
1341
        B |= (Resolution - 1) << 4;
 
1342
 
 
1343
        /*
 
1344
         * OR in the Bits per Pixel
 
1345
         */
 
1346
        B |= (BitsPerPixel - 1);
 
1347
 
 
1348
        /*
 
1349
         * Write it out
 
1350
         */
 
1351
        fputc( B, fp );
 
1352
 
 
1353
        /*
 
1354
         * Write out the Background colour
 
1355
         */
 
1356
        fputc( Background, fp );
 
1357
 
 
1358
        /*
 
1359
         * Byte of 0's (future expansion)
 
1360
         */
 
1361
        fputc( 0, fp );
 
1362
 
 
1363
        /*
 
1364
         * Write out the Global Colour Map
 
1365
         */
 
1366
        for( i=0; i<ColorMapSize; ++i ) {
 
1367
                fputc( Red[i], fp );
 
1368
                fputc( Green[i], fp );
 
1369
                fputc( Blue[i], fp );
 
1370
        }
 
1371
 
 
1372
        /*
 
1373
         * Write out extension for transparent colour index, if necessary.
 
1374
         */
 
1375
        if ( Transparent >= 0 ) {
 
1376
            fputc( '!', fp );
 
1377
            fputc( 0xf9, fp );
 
1378
            fputc( 4, fp );
 
1379
            fputc( 1, fp );
 
1380
            fputc( 0, fp );
 
1381
            fputc( 0, fp );
 
1382
            fputc( (unsigned char) Transparent, fp );
 
1383
            fputc( 0, fp );
 
1384
        }
 
1385
 
 
1386
        /*
 
1387
         * Write an Image separator
 
1388
         */
 
1389
        fputc( ',', fp );
 
1390
 
 
1391
        /*
 
1392
         * Write the Image header
 
1393
         */
 
1394
 
 
1395
        Putword( LeftOfs, fp );
 
1396
        Putword( TopOfs, fp );
 
1397
        Putword( Width, fp );
 
1398
        Putword( Height, fp );
 
1399
 
 
1400
        /*
 
1401
         * Write out whether or not the image is interlaced
 
1402
         */
 
1403
        if( Interlace )
 
1404
                fputc( 0x40, fp );
 
1405
        else
 
1406
                fputc( 0x00, fp );
 
1407
        /*
 
1408
         * Write out the initial code size
 
1409
         */
 
1410
        fputc( InitCodeSize, fp );
 
1411
 
 
1412
        /*
 
1413
         * Go and actually compress the data
 
1414
         */
 
1415
        compress( InitCodeSize+1, fp, im, Background );
 
1416
 
 
1417
        /*
 
1418
         * Write out a Zero-length packet (to end the series)
 
1419
         */
 
1420
        fputc( 0, fp );
 
1421
 
 
1422
        /*
 
1423
         * Write the GIF file terminator
 
1424
         */
 
1425
        fputc( ';', fp );
 
1426
}
 
1427
 
 
1428
/*
 
1429
 * Write out a word to the GIF file
 
1430
 */
 
1431
static void
 
1432
Putword(w, fp)
 
1433
     int w;
 
1434
     FILE *fp;
 
1435
{
 
1436
        fputc( w & 0xff, fp );
 
1437
        fputc( (w / 256) & 0xff, fp );
 
1438
}
 
1439
 
 
1440
#define GIFBITS 12
 
1441
 
 
1442
/*-----------------------------------------------------------------------
 
1443
 *
 
1444
 * miGIF Compression - mouse and ivo's GIF-compatible compression
 
1445
 *
 
1446
 *          -run length encoding compression routines-
 
1447
 *
 
1448
 * Copyright (C) 1998 Hutchison Avenue Software Corporation
 
1449
 *               http://www.hasc.com
 
1450
 *               info@hasc.com
 
1451
 *
 
1452
 * Permission to use, copy, modify, and distribute this software and its
 
1453
 * documentation for any purpose and without fee is hereby granted, provided
 
1454
 * that the above copyright notice appear in all copies and that both that
 
1455
 * copyright notice and this permission notice appear in supporting
 
1456
 * documentation.  This software is provided "AS IS." The Hutchison Avenue 
 
1457
 * Software Corporation disclaims all warranties, either express or implied, 
 
1458
 * including but not limited to implied warranties of merchantability and 
 
1459
 * fitness for a particular purpose, with respect to this code and accompanying
 
1460
 * documentation. 
 
1461
 * 
 
1462
 * The miGIF compression routines do not, strictly speaking, generate files 
 
1463
 * conforming to the GIF spec, since the image data is not LZW-compressed 
 
1464
 * (this is the point: in order to avoid transgression of the Unisys patent 
 
1465
 * on the LZW algorithm.)  However, miGIF generates data streams that any 
 
1466
 * reasonably sane LZW decompresser will decompress to what we want.
 
1467
 *
 
1468
 * miGIF compression uses run length encoding. It compresses horizontal runs 
 
1469
 * of pixels of the same color. This type of compression gives good results
 
1470
 * on images with many runs, for example images with lines, text and solid 
 
1471
 * shapes on a solid-colored background. It gives little or no compression 
 
1472
 * on images with few runs, for example digital or scanned photos.
 
1473
 *
 
1474
 *                               der Mouse
 
1475
 *                      mouse@rodents.montreal.qc.ca
 
1476
 *            7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B
 
1477
 *
 
1478
 *                             ivo@hasc.com
 
1479
 *
 
1480
 * The Graphics Interchange Format(c) is the Copyright property of
 
1481
 * CompuServe Incorporated.  GIF(sm) is a Service Mark property of
 
1482
 * CompuServe Incorporated.
 
1483
 *
 
1484
 */
 
1485
 
 
1486
static int rl_pixel;
 
1487
static int rl_basecode;
 
1488
static int rl_count;
 
1489
static int rl_table_pixel;
 
1490
static int rl_table_max;
 
1491
static int just_cleared;
 
1492
static int out_bits;
 
1493
static int out_bits_init;
 
1494
static int out_count;
 
1495
static int out_bump;
 
1496
static int out_bump_init;
 
1497
static int out_clear;
 
1498
static int out_clear_init;
 
1499
static int max_ocodes;
 
1500
static int code_clear;
 
1501
static int code_eof;
 
1502
static unsigned int obuf;
 
1503
static int obits;
 
1504
static FILE *ofile;
 
1505
static unsigned char oblock[256];
 
1506
static int oblen;
 
1507
 
 
1508
/* Used only when debugging GIF compression code */
 
1509
/* #define DEBUGGING_ENVARS */
 
1510
 
 
1511
#ifdef DEBUGGING_ENVARS
 
1512
 
 
1513
static int verbose_set = 0;
 
1514
static int verbose;
 
1515
#define VERBOSE (verbose_set?verbose:set_verbose())
 
1516
 
 
1517
static int set_verbose(void)
 
1518
{
 
1519
 verbose = !!getenv("GIF_VERBOSE");
 
1520
 verbose_set = 1;
 
1521
 return(verbose);
 
1522
}
 
1523
 
 
1524
#else
 
1525
 
 
1526
#define VERBOSE 0
 
1527
 
 
1528
#endif
 
1529
 
 
1530
#ifdef __STDC__
 
1531
static const char *binformat(unsigned int v, int nbits)
 
1532
#else
 
1533
static char *binformat(v, nbits)
 
1534
     unsigned int v;
 
1535
     int nbits;
 
1536
#endif
 
1537
{
 
1538
 static char bufs[8][64];
 
1539
 static int bhand = 0;
 
1540
 unsigned int bit;
 
1541
 int bno;
 
1542
 char *bp;
 
1543
 
 
1544
 bhand --;
 
1545
 if (bhand < 0) bhand = (sizeof(bufs)/sizeof(bufs[0]))-1;
 
1546
 bp = &bufs[bhand][0];
 
1547
 for (bno=nbits-1,bit=(unsigned int)1<<bno;bno>=0;bno--,bit>>=1)
 
1548
  { *bp++ = (v & bit) ? '1' : '0';
 
1549
    if (((bno&3) == 0) && (bno != 0)) *bp++ = '.';
 
1550
  }
 
1551
 *bp = '\0';
 
1552
 return(&bufs[bhand][0]);
 
1553
}
 
1554
 
 
1555
static void write_block()
 
1556
{
 
1557
 int i;
 
1558
 
 
1559
 if (VERBOSE)
 
1560
  { printf("write_block %d:",oblen);
 
1561
    for (i=0;i<oblen;i++) printf(" %02x",oblock[i]);
 
1562
    printf("\n");
 
1563
  }
 
1564
 fputc(oblen,ofile);
 
1565
 fwrite(&oblock[0],1,oblen,ofile);
 
1566
 oblen = 0;
 
1567
}
 
1568
 
 
1569
static void block_out(c)
 
1570
     unsigned char c;
 
1571
{
 
1572
 if (VERBOSE) printf("block_out %s\n",binformat(c,8));
 
1573
 oblock[oblen++] = c;
 
1574
 if (oblen >= 255) write_block();
 
1575
}
 
1576
 
 
1577
static void block_flush()
 
1578
{
 
1579
 if (VERBOSE) printf("block_flush\n");
 
1580
 if (oblen > 0) write_block();
 
1581
}
 
1582
 
 
1583
static void output(val)
 
1584
     int val;
 
1585
{
 
1586
 if (VERBOSE) printf("output %s [%s %d %d]\n",binformat(val,out_bits),binformat(obuf,obits),obits,out_bits);
 
1587
 obuf |= val << obits;
 
1588
 obits += out_bits;
 
1589
 while (obits >= 8)
 
1590
  { block_out(obuf&0xff);
 
1591
    obuf >>= 8;
 
1592
    obits -= 8;
 
1593
  }
 
1594
 if (VERBOSE) printf("output leaving [%s %d]\n",binformat(obuf,obits),obits);
 
1595
}
 
1596
 
 
1597
static void output_flush()
 
1598
{
 
1599
 if (VERBOSE) printf("output_flush\n");
 
1600
 if (obits > 0) block_out(obuf);
 
1601
 block_flush();
 
1602
}
 
1603
 
 
1604
static void did_clear()
 
1605
{
 
1606
 if (VERBOSE) printf("did_clear\n");
 
1607
 out_bits = out_bits_init;
 
1608
 out_bump = out_bump_init;
 
1609
 out_clear = out_clear_init;
 
1610
 out_count = 0;
 
1611
 rl_table_max = 0;
 
1612
 just_cleared = 1;
 
1613
}
 
1614
 
 
1615
static void output_plain(c)
 
1616
     int c;
 
1617
{
 
1618
 if (VERBOSE) printf("output_plain %s\n",binformat(c,out_bits));
 
1619
 just_cleared = 0;
 
1620
 output(c);
 
1621
 out_count ++;
 
1622
 if (out_count >= out_bump)
 
1623
  { out_bits ++;
 
1624
    out_bump += 1 << (out_bits - 1);
 
1625
  }
 
1626
 if (out_count >= out_clear)
 
1627
  { output(code_clear);
 
1628
    did_clear();
 
1629
  }
 
1630
}
 
1631
 
 
1632
static unsigned int isqrt(x)
 
1633
     unsigned int x;
 
1634
{
 
1635
 unsigned int r;
 
1636
 unsigned int v;
 
1637
 
 
1638
 if (x < 2) return(x);
 
1639
 for (v=x,r=1;v;v>>=2,r<<=1) ;
 
1640
 while (1)
 
1641
  { v = ((x / r) + r) / 2;
 
1642
    if ((v == r) || (v == r+1)) return(r);
 
1643
    r = v;
 
1644
  }
 
1645
}
 
1646
 
 
1647
static unsigned int compute_triangle_count(count, nrepcodes)
 
1648
     unsigned int count;
 
1649
     unsigned int nrepcodes;
 
1650
{
 
1651
 unsigned int perrep;
 
1652
 unsigned int cost;
 
1653
 
 
1654
 cost = 0;
 
1655
 perrep = (nrepcodes * (nrepcodes+1)) / 2;
 
1656
 while (count >= perrep)
 
1657
  { cost += nrepcodes;
 
1658
    count -= perrep;
 
1659
  }
 
1660
 if (count > 0)
 
1661
  { unsigned int n;
 
1662
    n = isqrt(count);
 
1663
    while ((n*(n+1)) >= 2*count) n --;
 
1664
    while ((n*(n+1)) < 2*count) n ++;
 
1665
    cost += n;
 
1666
  }
 
1667
 return(cost);
 
1668
}
 
1669
 
 
1670
static void max_out_clear()
 
1671
{
 
1672
 out_clear = max_ocodes;
 
1673
}
 
1674
 
 
1675
static void reset_out_clear()
 
1676
{
 
1677
 out_clear = out_clear_init;
 
1678
 if (out_count >= out_clear)
 
1679
  { output(code_clear);
 
1680
    did_clear();
 
1681
  }
 
1682
}
 
1683
 
 
1684
static void rl_flush_fromclear(count)
 
1685
     int count;
 
1686
{
 
1687
 int n;
 
1688
 
 
1689
 if (VERBOSE) printf("rl_flush_fromclear %d\n",count);
 
1690
 max_out_clear();
 
1691
 rl_table_pixel = rl_pixel;
 
1692
 n = 1;
 
1693
 while (count > 0)
 
1694
  { if (n == 1)
 
1695
     { rl_table_max = 1;
 
1696
       output_plain(rl_pixel);
 
1697
       count --;
 
1698
     }
 
1699
    else if (count >= n)
 
1700
     { rl_table_max = n;
 
1701
       output_plain(rl_basecode+n-2);
 
1702
       count -= n;
 
1703
     }
 
1704
    else if (count == 1)
 
1705
     { rl_table_max ++;
 
1706
       output_plain(rl_pixel);
 
1707
       count = 0;
 
1708
     }
 
1709
    else
 
1710
     { rl_table_max ++;
 
1711
       output_plain(rl_basecode+count-2);
 
1712
       count = 0;
 
1713
     }
 
1714
    if (out_count == 0) n = 1; else n ++;
 
1715
  }
 
1716
 reset_out_clear();
 
1717
 if (VERBOSE) printf("rl_flush_fromclear leaving table_max=%d\n",rl_table_max);
 
1718
}
 
1719
 
 
1720
static void rl_flush_clearorrep(count)
 
1721
     int count;
 
1722
{
 
1723
 int withclr;
 
1724
 
 
1725
 if (VERBOSE) printf("rl_flush_clearorrep %d\n",count);
 
1726
 withclr = 1 + (int)compute_triangle_count(count,max_ocodes);
 
1727
 if (withclr < count)
 
1728
  { output(code_clear);
 
1729
    did_clear();
 
1730
    rl_flush_fromclear(count);
 
1731
  }
 
1732
 else
 
1733
  { for (;count>0;count--) output_plain(rl_pixel);
 
1734
  }
 
1735
}
 
1736
 
 
1737
static void rl_flush_withtable(count)
 
1738
     int count;
 
1739
{
 
1740
 int repmax;
 
1741
 int repleft;
 
1742
 int leftover;
 
1743
 
 
1744
 if (VERBOSE) printf("rl_flush_withtable %d\n",count);
 
1745
 repmax = count / rl_table_max;
 
1746
 leftover = count % rl_table_max;
 
1747
 repleft = (leftover ? 1 : 0);
 
1748
 if (out_count+repmax+repleft > max_ocodes)
 
1749
  { repmax = max_ocodes - out_count;
 
1750
    leftover = count - (repmax * rl_table_max);
 
1751
    repleft = 1 + compute_triangle_count(leftover,max_ocodes);
 
1752
  }
 
1753
 if (VERBOSE) printf("rl_flush_withtable repmax=%d leftover=%d repleft=%d\n",repmax,leftover,repleft);
 
1754
 if (1+compute_triangle_count(count,max_ocodes) < repmax+repleft)
 
1755
  { output(code_clear);
 
1756
    did_clear();
 
1757
    rl_flush_fromclear(count);
 
1758
    return;
 
1759
  }
 
1760
 max_out_clear();
 
1761
 for (;repmax>0;repmax--) output_plain(rl_basecode+rl_table_max-2);
 
1762
 if (leftover)
 
1763
  { if (just_cleared)
 
1764
     { rl_flush_fromclear(leftover);
 
1765
     }
 
1766
    else if (leftover == 1)
 
1767
     { output_plain(rl_pixel);
 
1768
     }
 
1769
    else
 
1770
     { output_plain(rl_basecode+leftover-2);
 
1771
     }
 
1772
  }
 
1773
 reset_out_clear();
 
1774
}
 
1775
 
 
1776
static void rl_flush()
 
1777
{
 
1778
 if (VERBOSE) printf("rl_flush [ %d %d\n",rl_count,rl_pixel);
 
1779
 if (rl_count == 1)
 
1780
  { output_plain(rl_pixel);
 
1781
    rl_count = 0;
 
1782
    if (VERBOSE) printf("rl_flush ]\n");
 
1783
    return;
 
1784
  }
 
1785
 if (just_cleared)
 
1786
  { rl_flush_fromclear(rl_count);
 
1787
  }
 
1788
 else if ((rl_table_max < 2) || (rl_table_pixel != rl_pixel))
 
1789
  { rl_flush_clearorrep(rl_count);
 
1790
  }
 
1791
 else
 
1792
  { rl_flush_withtable(rl_count);
 
1793
  }
 
1794
 if (VERBOSE) printf("rl_flush ]\n");
 
1795
 rl_count = 0;
 
1796
}
 
1797
 
 
1798
static void compress(init_bits, outfile, im, background)
 
1799
     int init_bits;
 
1800
     FILE *outfile;
 
1801
     gdImagePtr im;
 
1802
     int background;
 
1803
{
 
1804
 int c;
 
1805
 
 
1806
 ofile = outfile;
 
1807
 obuf = 0;
 
1808
 obits = 0;
 
1809
 oblen = 0;
 
1810
 code_clear = 1 << (init_bits - 1);
 
1811
 code_eof = code_clear + 1;
 
1812
 rl_basecode = code_eof + 1;
 
1813
 out_bump_init = (1 << (init_bits - 1)) - 1;
 
1814
 /* for images with a lot of runs, making out_clear_init larger will
 
1815
    give better compression. */ 
 
1816
 out_clear_init = (init_bits <= 3) ? 9 : (out_bump_init-1);
 
1817
 
 
1818
#ifdef DEBUGGING_ENVARS
 
1819
  { const char *ocienv;
 
1820
    ocienv = getenv("GIF_OUT_CLEAR_INIT");
 
1821
    if (ocienv)
 
1822
     { out_clear_init = atoi(ocienv);
 
1823
       if (VERBOSE) printf("[overriding out_clear_init to %d]\n",out_clear_init);
 
1824
     }
 
1825
  }
 
1826
#endif
 
1827
 
 
1828
 out_bits_init = init_bits;
 
1829
 
 
1830
 max_ocodes = (1 << GIFBITS) - ((1 << (out_bits_init - 1)) + 3);
 
1831
 did_clear();
 
1832
 output(code_clear);
 
1833
 rl_count = 0;
 
1834
 while (1)
 
1835
  { c = GIFNextPixel(im);
 
1836
    if ((rl_count > 0) && (c != rl_pixel)) rl_flush();
 
1837
    if (c == EOF) break;
 
1838
    if (rl_pixel == c)
 
1839
     { rl_count ++;
 
1840
     }
 
1841
    else
 
1842
     { rl_pixel = c;
 
1843
       rl_count = 1;
 
1844
     }
 
1845
  }
 
1846
 output(code_eof);
 
1847
 output_flush();
 
1848
}
 
1849
 
 
1850
/*-----------------------------------------------------------------------
 
1851
 *
 
1852
 * End of miGIF section  - See copyright notice at start of section.
 
1853
 *
 
1854
 *-----------------------------------------------------------------------*/
 
1855
 
 
1856
 
 
1857
/******************************************************************************
 
1858
 *
 
1859
 * GIF Specific routines
 
1860
 *
 
1861
 ******************************************************************************/
 
1862
 
 
1863
/*
 
1864
 * Number of characters so far in this 'packet'
 
1865
 */
 
1866
static int a_count;
 
1867
 
 
1868
/*
 
1869
 * Set up the 'byte output' routine
 
1870
 */
 
1871
static void
 
1872
char_init()
 
1873
{
 
1874
        a_count = 0;
 
1875
}
 
1876
 
 
1877
/*
 
1878
 * Define the storage for the packet accumulator
 
1879
 */
 
1880
static char accum[ 256 ];
 
1881
 
 
1882
static void init_statics()
 
1883
 {
 
1884
        /* Some of these are properly initialized later. What I'm doing
 
1885
                here is making sure code that depends on C's initialization
 
1886
                of statics doesn't break when the code gets called more
 
1887
                than once. */
 
1888
        Width = 0;
 
1889
        Height = 0;
 
1890
        curx = 0;
 
1891
        cury = 0;
 
1892
        CountDown = 0;
 
1893
        Pass = 0;
 
1894
        Interlace = 0;
 
1895
        a_count = 0;
 
1896
}
 
1897
 
 
1898
 
 
1899
/* +-------------------------------------------------------------------+ */
 
1900
/* | Copyright 1990, 1991, 1993, David Koblas.  (koblas@netcom.com)    | */
 
1901
/* |   Permission to use, copy, modify, and distribute this software   | */
 
1902
/* |   and its documentation for any purpose and without fee is hereby | */
 
1903
/* |   granted, provided that the above copyright notice appear in all | */
 
1904
/* |   copies and that both that copyright notice and this permission  | */
 
1905
/* |   notice appear in supporting documentation.  This software is    | */
 
1906
/* |   provided "as is" without express or implied warranty.           | */
 
1907
/* +-------------------------------------------------------------------+ */
 
1908
 
 
1909
 
 
1910
#define        MAXCOLORMAPSIZE         256
 
1911
 
 
1912
#define        TRUE    1
 
1913
#define        FALSE   0
 
1914
 
 
1915
#define CM_RED         0
 
1916
#define CM_GREEN       1
 
1917
#define CM_BLUE                2
 
1918
 
 
1919
#define        MAX_LWZ_BITS            12
 
1920
 
 
1921
#define INTERLACE              0x40
 
1922
#define LOCALCOLORMAP  0x80
 
1923
#define BitSet(byte, bit)      (((byte) & (bit)) == (bit))
 
1924
 
 
1925
#define        ReadOK(file,buffer,len) (fread(buffer, len, 1, file) != 0)
 
1926
 
 
1927
#define LM_to_uint(a,b)                        (((b)<<8)|(a))
 
1928
 
 
1929
/* We may eventually want to use this information, but def it out for now */
 
1930
#if 0
 
1931
static struct {
 
1932
       unsigned int    Width;
 
1933
       unsigned int    Height;
 
1934
       unsigned char   ColorMap[3][MAXCOLORMAPSIZE];
 
1935
       unsigned int    BitPixel;
 
1936
       unsigned int    ColorResolution;
 
1937
       unsigned int    Background;
 
1938
       unsigned int    AspectRatio;
 
1939
} GifScreen;
 
1940
#endif
 
1941
 
 
1942
static struct {
 
1943
       int     transparent;
 
1944
       int     delayTime;
 
1945
       int     inputFlag;
 
1946
       int     disposal;
 
1947
} Gif89 = { -1, -1, -1, 0 };
 
1948
 
 
1949
static int ReadColorMap ();
 
1950
static int DoExtension ();
 
1951
static int GetDataBlock ();
 
1952
static int GetCode ();
 
1953
static int LWZReadByte ();
 
1954
static void ReadImage ();
 
1955
 
 
1956
int ZeroDataBlock;
 
1957
 
 
1958
gdImagePtr
 
1959
gdImageCreateFromGif(fd)
 
1960
     FILE *fd;
 
1961
{
 
1962
       int imageNumber;
 
1963
       int BitPixel;
 
1964
       int ColorResolution;
 
1965
       int Background;
 
1966
       int AspectRatio;
 
1967
       int Transparent = (-1);
 
1968
       unsigned char   buf[16];
 
1969
       unsigned char   c;
 
1970
       unsigned char   ColorMap[3][MAXCOLORMAPSIZE];
 
1971
       unsigned char   localColorMap[3][MAXCOLORMAPSIZE];
 
1972
       int             imw, imh;
 
1973
       int             useGlobalColormap;
 
1974
       int             bitPixel;
 
1975
       int             imageCount = 0;
 
1976
       char            version[4];
 
1977
       gdImagePtr im = 0;
 
1978
       ZeroDataBlock = FALSE;
 
1979
 
 
1980
       imageNumber = 1;
 
1981
       if (! ReadOK(fd,buf,6)) {
 
1982
                return 0;
 
1983
        }
 
1984
       if (strncmp((char *)buf,"GIF",3) != 0) {
 
1985
                return 0;
 
1986
        }
 
1987
       strncpy(version, (char *)buf + 3, 3);
 
1988
       version[3] = '\0';
 
1989
 
 
1990
       if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
 
1991
                return 0;
 
1992
        }
 
1993
       if (! ReadOK(fd,buf,7)) {
 
1994
                return 0;
 
1995
        }
 
1996
       BitPixel        = 2<<(buf[4]&0x07);
 
1997
       ColorResolution = (int) (((buf[4]&0x70)>>3)+1);
 
1998
       Background      = buf[5];
 
1999
       AspectRatio     = buf[6];
 
2000
 
 
2001
       if (BitSet(buf[4], LOCALCOLORMAP)) {    /* Global Colormap */
 
2002
               if (ReadColorMap(fd, BitPixel, ColorMap)) {
 
2003
                        return 0;
 
2004
                }
 
2005
       }
 
2006
       for (;;) {
 
2007
               if (! ReadOK(fd,&c,1)) {
 
2008
                       return 0;
 
2009
               }
 
2010
               if (c == ';') {         /* GIF terminator */
 
2011
                       int i;
 
2012
                       if (imageCount < imageNumber) {
 
2013
                               return 0;
 
2014
                       }
 
2015
                       /* Terminator before any image was declared! */
 
2016
                       if (!im) {
 
2017
                              return 0;
 
2018
                       }
 
2019
                       /* Check for open colors at the end, so
 
2020
                          we can reduce colorsTotal and ultimately
 
2021
                          BitsPerPixel */
 
2022
                       for (i=((im->colorsTotal-1)); (i>=0); i--) {
 
2023
                               if (im->open[i]) {
 
2024
                                       im->colorsTotal--;
 
2025
                               } else {
 
2026
                                       break;
 
2027
                               }
 
2028
                       } 
 
2029
                       return im;
 
2030
               }
 
2031
 
 
2032
               if (c == '!') {         /* Extension */
 
2033
                       if (! ReadOK(fd,&c,1)) {
 
2034
                               return 0;
 
2035
                       }
 
2036
                       DoExtension(fd, c, &Transparent);
 
2037
                       continue;
 
2038
               }
 
2039
 
 
2040
               if (c != ',') {         /* Not a valid start character */
 
2041
                       continue;
 
2042
               }
 
2043
 
 
2044
               ++imageCount;
 
2045
 
 
2046
               if (! ReadOK(fd,buf,9)) {
 
2047
                       return 0;
 
2048
               }
 
2049
 
 
2050
               useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP);
 
2051
 
 
2052
               bitPixel = 1<<((buf[8]&0x07)+1);
 
2053
 
 
2054
               imw = LM_to_uint(buf[4],buf[5]);
 
2055
               imh = LM_to_uint(buf[6],buf[7]);
 
2056
               if (!(im = gdImageCreate(imw, imh))) {
 
2057
                         return 0;
 
2058
               }
 
2059
               im->interlace = BitSet(buf[8], INTERLACE);
 
2060
               if (! useGlobalColormap) {
 
2061
                       if (ReadColorMap(fd, bitPixel, localColorMap)) { 
 
2062
                                 return 0;
 
2063
                       }
 
2064
                       ReadImage(im, fd, imw, imh, localColorMap, 
 
2065
                                 BitSet(buf[8], INTERLACE), 
 
2066
                                 imageCount != imageNumber);
 
2067
               } else {
 
2068
                       ReadImage(im, fd, imw, imh,
 
2069
                                 ColorMap, 
 
2070
                                 BitSet(buf[8], INTERLACE), 
 
2071
                                 imageCount != imageNumber);
 
2072
               }
 
2073
               if (Transparent != (-1)) {
 
2074
                       gdImageColorTransparent(im, Transparent);
 
2075
               }           
 
2076
       }
 
2077
}
 
2078
 
 
2079
static int
 
2080
ReadColorMap(fd, number, buffer)
 
2081
     FILE *fd;
 
2082
     int number;
 
2083
     unsigned char (*buffer)[256];
 
2084
{
 
2085
       int             i;
 
2086
       unsigned char   rgb[3];
 
2087
 
 
2088
 
 
2089
       for (i = 0; i < number; ++i) {
 
2090
               if (! ReadOK(fd, rgb, sizeof(rgb))) {
 
2091
                       return TRUE;
 
2092
               }
 
2093
               buffer[CM_RED][i] = rgb[0] ;
 
2094
               buffer[CM_GREEN][i] = rgb[1] ;
 
2095
               buffer[CM_BLUE][i] = rgb[2] ;
 
2096
       }
 
2097
 
 
2098
 
 
2099
       return FALSE;
 
2100
}
 
2101
 
 
2102
static int
 
2103
DoExtension(fd, label, Transparent)
 
2104
     FILE *fd;
 
2105
     int label;
 
2106
     int *Transparent;
 
2107
{
 
2108
       static unsigned char     buf[256];
 
2109
 
 
2110
       switch (label) {
 
2111
       case 0xf9:              /* Graphic Control Extension */
 
2112
               (void) GetDataBlock(fd, (unsigned char*) buf);
 
2113
               Gif89.disposal    = (buf[0] >> 2) & 0x7;
 
2114
               Gif89.inputFlag   = (buf[0] >> 1) & 0x1;
 
2115
               Gif89.delayTime   = LM_to_uint(buf[1],buf[2]);
 
2116
               if ((buf[0] & 0x1) != 0)
 
2117
                       *Transparent = buf[3];
 
2118
 
 
2119
               while (GetDataBlock(fd, (unsigned char*) buf) != 0)
 
2120
                       ;
 
2121
               return FALSE;
 
2122
       default:
 
2123
               break;
 
2124
       }
 
2125
       while (GetDataBlock(fd, (unsigned char*) buf) != 0)
 
2126
               ;
 
2127
 
 
2128
       return FALSE;
 
2129
}
 
2130
 
 
2131
static int
 
2132
GetDataBlock_(fd, buf)
 
2133
     FILE *fd;
 
2134
     unsigned char *buf;
 
2135
{
 
2136
       unsigned char   count;
 
2137
 
 
2138
       if (! ReadOK(fd,&count,1)) {
 
2139
               return -1;
 
2140
       }
 
2141
 
 
2142
       ZeroDataBlock = count == 0;
 
2143
 
 
2144
       if ((count != 0) && (! ReadOK(fd, buf, count))) {
 
2145
               return -1;
 
2146
       }
 
2147
 
 
2148
       return count;
 
2149
}
 
2150
 
 
2151
static int
 
2152
GetDataBlock(fd, buf)
 
2153
     FILE *fd;
 
2154
     unsigned char *buf;
 
2155
{
 
2156
 int rv;
 
2157
 int i;
 
2158
 
 
2159
 rv = GetDataBlock_(fd,buf);
 
2160
 if (VERBOSE)
 
2161
  { printf("[GetDataBlock returning %d",rv);
 
2162
    if (rv > 0)
 
2163
     { printf(":");
 
2164
       for (i=0;i<rv;i++) printf(" %02x",buf[i]);
 
2165
     }
 
2166
    printf("]\n");
 
2167
  }
 
2168
 return(rv);
 
2169
}
 
2170
 
 
2171
static int
 
2172
GetCode_(fd, code_size, flag)
 
2173
     FILE *fd;
 
2174
     int code_size;
 
2175
     int flag;
 
2176
{
 
2177
       static unsigned char    buf[280];
 
2178
       static int              curbit, lastbit, done, last_byte;
 
2179
       int                     i, j, ret;
 
2180
       unsigned char           count;
 
2181
 
 
2182
       if (flag) {
 
2183
               curbit = 0;
 
2184
               lastbit = 0;
 
2185
               done = FALSE;
 
2186
               return 0;
 
2187
       }
 
2188
 
 
2189
       if ( (curbit+code_size) >= lastbit) {
 
2190
               if (done) {
 
2191
                       if (curbit >= lastbit) {
 
2192
                                /* Oh well */
 
2193
                       }                        
 
2194
                       return -1;
 
2195
               }
 
2196
               buf[0] = buf[last_byte-2];
 
2197
               buf[1] = buf[last_byte-1];
 
2198
 
 
2199
               if ((count = GetDataBlock(fd, &buf[2])) == 0)
 
2200
                       done = TRUE;
 
2201
 
 
2202
               last_byte = 2 + count;
 
2203
               curbit = (curbit - lastbit) + 16;
 
2204
               lastbit = (2+count)*8 ;
 
2205
       }
 
2206
 
 
2207
       ret = 0;
 
2208
       for (i = curbit, j = 0; j < code_size; ++i, ++j)
 
2209
               ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
 
2210
 
 
2211
       curbit += code_size;
 
2212
       return ret;
 
2213
}
 
2214
 
 
2215
static int
 
2216
GetCode(fd, code_size, flag)
 
2217
     FILE *fd;
 
2218
     int code_size;
 
2219
     int flag;
 
2220
{
 
2221
 int rv;
 
2222
 
 
2223
 rv = GetCode_(fd,code_size,flag);
 
2224
 if (VERBOSE) printf("[GetCode(,%d,%d) returning %d]\n",code_size,flag,rv);
 
2225
 return(rv);
 
2226
}
 
2227
 
 
2228
static int
 
2229
LWZReadByte_(fd, flag, input_code_size)
 
2230
     FILE *fd;
 
2231
     int flag;
 
2232
     int input_code_size;
 
2233
{
 
2234
       static int      fresh = FALSE;
 
2235
       int             code, incode;
 
2236
       static int      code_size, set_code_size;
 
2237
       static int      max_code, max_code_size;
 
2238
       static int      firstcode, oldcode;
 
2239
       static int      clear_code, end_code;
 
2240
       static int      table[2][(1<< MAX_LWZ_BITS)];
 
2241
       static int      stack[(1<<(MAX_LWZ_BITS))*2], *sp;
 
2242
       register int    i;
 
2243
 
 
2244
       if (flag) {
 
2245
               set_code_size = input_code_size;
 
2246
               code_size = set_code_size+1;
 
2247
               clear_code = 1 << set_code_size ;
 
2248
               end_code = clear_code + 1;
 
2249
               max_code_size = 2*clear_code;
 
2250
               max_code = clear_code+2;
 
2251
 
 
2252
               GetCode(fd, 0, TRUE);
 
2253
               
 
2254
               fresh = TRUE;
 
2255
 
 
2256
               for (i = 0; i < clear_code; ++i) {
 
2257
                       table[0][i] = 0;
 
2258
                       table[1][i] = i;
 
2259
               }
 
2260
               for (; i < (1<<MAX_LWZ_BITS); ++i)
 
2261
                       table[0][i] = table[1][0] = 0;
 
2262
 
 
2263
               sp = stack;
 
2264
 
 
2265
               return 0;
 
2266
       } else if (fresh) {
 
2267
               fresh = FALSE;
 
2268
               do {
 
2269
                       firstcode = oldcode =
 
2270
                               GetCode(fd, code_size, FALSE);
 
2271
               } while (firstcode == clear_code);
 
2272
               return firstcode;
 
2273
       }
 
2274
 
 
2275
       if (sp > stack)
 
2276
               return *--sp;
 
2277
 
 
2278
       while ((code = GetCode(fd, code_size, FALSE)) >= 0) {
 
2279
               if (code == clear_code) {
 
2280
                       for (i = 0; i < clear_code; ++i) {
 
2281
                               table[0][i] = 0;
 
2282
                               table[1][i] = i;
 
2283
                       }
 
2284
                       for (; i < (1<<MAX_LWZ_BITS); ++i)
 
2285
                               table[0][i] = table[1][i] = 0;
 
2286
                       code_size = set_code_size+1;
 
2287
                       max_code_size = 2*clear_code;
 
2288
                       max_code = clear_code+2;
 
2289
                       sp = stack;
 
2290
                       firstcode = oldcode =
 
2291
                                       GetCode(fd, code_size, FALSE);
 
2292
                       return firstcode;
 
2293
               } else if (code == end_code) {
 
2294
                       int             count;
 
2295
                       unsigned char   buf[260];
 
2296
 
 
2297
                       if (ZeroDataBlock)
 
2298
                               return -2;
 
2299
 
 
2300
                       while ((count = GetDataBlock(fd, buf)) > 0)
 
2301
                               ;
 
2302
 
 
2303
                       if (count != 0)
 
2304
                       return -2;
 
2305
               }
 
2306
 
 
2307
               incode = code;
 
2308
 
 
2309
               if (code >= max_code) {
 
2310
                       *sp++ = firstcode;
 
2311
                       code = oldcode;
 
2312
               }
 
2313
 
 
2314
               while (code >= clear_code) {
 
2315
                       *sp++ = table[1][code];
 
2316
                       if (code == table[0][code]) {
 
2317
                               /* Oh well */
 
2318
                       }
 
2319
                       code = table[0][code];
 
2320
               }
 
2321
 
 
2322
               *sp++ = firstcode = table[1][code];
 
2323
 
 
2324
               if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
 
2325
                       table[0][code] = oldcode;
 
2326
                       table[1][code] = firstcode;
 
2327
                       ++max_code;
 
2328
                       if ((max_code >= max_code_size) &&
 
2329
                               (max_code_size < (1<<MAX_LWZ_BITS))) {
 
2330
                               max_code_size *= 2;
 
2331
                               ++code_size;
 
2332
                       }
 
2333
               }
 
2334
 
 
2335
               oldcode = incode;
 
2336
 
 
2337
               if (sp > stack)
 
2338
                       return *--sp;
 
2339
       }
 
2340
       return code;
 
2341
}
 
2342
 
 
2343
static int
 
2344
LWZReadByte(fd, flag, input_code_size)
 
2345
     FILE *fd;
 
2346
     int flag;
 
2347
     int input_code_size;
 
2348
{
 
2349
 int rv;
 
2350
 
 
2351
 rv = LWZReadByte_(fd,flag,input_code_size);
 
2352
 if (VERBOSE) printf("[LWZReadByte(,%d,%d) returning %d]\n",flag,input_code_size,rv);
 
2353
 return(rv);
 
2354
}
 
2355
 
 
2356
static void
 
2357
ReadImage(im, fd, len, height, cmap, interlace, ignore)
 
2358
     gdImagePtr im;
 
2359
     FILE *fd;
 
2360
     int len;
 
2361
     int height;
 
2362
     unsigned char (*cmap)[256];
 
2363
     int interlace;
 
2364
     int ignore;
 
2365
{
 
2366
       unsigned char   c;      
 
2367
       int             v;
 
2368
       int             xpos = 0, ypos = 0, pass = 0;
 
2369
       int i;
 
2370
       /* Stash the color map into the image */
 
2371
       for (i=0; (i<gdMaxColors); i++) {
 
2372
               im->red[i] = cmap[CM_RED][i];    
 
2373
               im->green[i] = cmap[CM_GREEN][i];        
 
2374
               im->blue[i] = cmap[CM_BLUE][i];  
 
2375
               im->open[i] = 1;
 
2376
       }
 
2377
       /* Many (perhaps most) of these colors will remain marked open. */
 
2378
       im->colorsTotal = gdMaxColors;
 
2379
       /*
 
2380
       **  Initialize the Compression routines
 
2381
       */
 
2382
       if (! ReadOK(fd,&c,1)) {
 
2383
               return; 
 
2384
       }
 
2385
       if (LWZReadByte(fd, TRUE, c) < 0) {
 
2386
               return;
 
2387
       }
 
2388
 
 
2389
       /*
 
2390
       **  If this is an "uninteresting picture" ignore it.
 
2391
       */
 
2392
       if (ignore) {
 
2393
               while (LWZReadByte(fd, FALSE, c) >= 0)
 
2394
                       ;
 
2395
               return;
 
2396
       }
 
2397
 
 
2398
       while ((v = LWZReadByte(fd,FALSE,c)) >= 0 ) {
 
2399
               /* This how we recognize which colors are actually used. */
 
2400
               if (im->open[v]) {
 
2401
                       im->open[v] = 0;
 
2402
               }
 
2403
               gdImageSetPixel(im, xpos, ypos, v);
 
2404
               ++xpos;
 
2405
               if (xpos == len) {
 
2406
                       xpos = 0;
 
2407
                       if (interlace) {
 
2408
                               switch (pass) {
 
2409
                               case 0:
 
2410
                               case 1:
 
2411
                                       ypos += 8; break;
 
2412
                               case 2:
 
2413
                                       ypos += 4; break;
 
2414
                               case 3:
 
2415
                                       ypos += 2; break;
 
2416
                               }
 
2417
 
 
2418
                               if (ypos >= height) {
 
2419
                                       ++pass;
 
2420
                                       switch (pass) {
 
2421
                                       case 1:
 
2422
                                               ypos = 4; break;
 
2423
                                       case 2:
 
2424
                                               ypos = 2; break;
 
2425
                                       case 3:
 
2426
                                               ypos = 1; break;
 
2427
                                       default:
 
2428
                                               goto fini;
 
2429
                                       }
 
2430
                               }
 
2431
                       } else {
 
2432
                               ++ypos;
 
2433
                       }
 
2434
               }
 
2435
               if (ypos >= height)
 
2436
                       break;
 
2437
       }
 
2438
 
 
2439
fini:
 
2440
       if (LWZReadByte(fd,FALSE,c)>=0) {
 
2441
               /* Ignore extra */
 
2442
       }
 
2443
}
 
2444
 
 
2445
void gdImageRectangle(im, x1, y1, x2, y2, color)
 
2446
     gdImagePtr im;
 
2447
     int x1;
 
2448
     int y1;
 
2449
     int x2;
 
2450
     int y2;
 
2451
     int color;
 
2452
{
 
2453
        gdImageLine(im, x1, y1, x2, y1, color);         
 
2454
        gdImageLine(im, x1, y2, x2, y2, color);         
 
2455
        gdImageLine(im, x1, y1, x1, y2, color);
 
2456
        gdImageLine(im, x2, y1, x2, y2, color);
 
2457
}
 
2458
void gdImageThickRectangle(im, x1, y1, x2, y2, color, thick)
 
2459
     gdImagePtr im;
 
2460
     int x1;
 
2461
     int y1;
 
2462
     int x2;
 
2463
     int y2;
 
2464
     int color;
 
2465
     int thick;
 
2466
{
 
2467
        gdImageThickLine(im, x1, y1, x2, y1, color, thick);             
 
2468
        gdImageThickLine(im, x1, y2, x2, y2, color, thick);             
 
2469
        gdImageThickLine(im, x1, y1, x1, y2, color, thick);
 
2470
        gdImageThickLine(im, x2, y1, x2, y2, color, thick);
 
2471
}
 
2472
 
 
2473
void gdImageFilledRectangle(im, x1, y1, x2, y2, color)
 
2474
     gdImagePtr im;
 
2475
     int x1;
 
2476
     int y1;
 
2477
     int x2;
 
2478
     int y2;
 
2479
     int color;
 
2480
{
 
2481
        int x, y;
 
2482
        for (y=y1; (y<=y2); y++) {
 
2483
                for (x=x1; (x<=x2); x++) {
 
2484
                        gdImageSetPixel(im, x, y, color);
 
2485
                }
 
2486
        }
 
2487
}
 
2488
 
 
2489
void gdImageCopy(dst, src, dstX, dstY, srcX, srcY, w, h)
 
2490
     gdImagePtr dst;
 
2491
     gdImagePtr src;
 
2492
     int dstX;
 
2493
     int dstY;
 
2494
     int srcX;
 
2495
     int srcY;
 
2496
     int w;
 
2497
     int h;
 
2498
{
 
2499
        int c;
 
2500
        int x, y;
 
2501
        int tox, toy;
 
2502
        int i;
 
2503
        int colorMap[gdMaxColors];
 
2504
        for (i=0; (i<gdMaxColors); i++) {
 
2505
                colorMap[i] = (-1);
 
2506
        }
 
2507
        toy = dstY;
 
2508
        for (y=srcY; (y < (srcY + h)); y++) {
 
2509
                tox = dstX;
 
2510
                for (x=srcX; (x < (srcX + w)); x++) {
 
2511
                        int nc;
 
2512
                        c = gdImageGetPixel(src, x, y);
 
2513
                        /* Added 7/24/95: support transparent copies */
 
2514
                        if (gdImageGetTransparent(src) == c) {
 
2515
                                tox++;
 
2516
                                continue;
 
2517
                        }
 
2518
                        /* Have we established a mapping for this color? */
 
2519
                        if (colorMap[c] == (-1)) {
 
2520
                                /* If it's the same image, mapping is trivial */
 
2521
                                if (dst == src) {
 
2522
                                        nc = c;
 
2523
                                } else { 
 
2524
                                        /* First look for an exact match */
 
2525
                                        nc = gdImageColorExact(dst,
 
2526
                                                src->red[c], src->green[c],
 
2527
                                                src->blue[c]);
 
2528
                                }       
 
2529
                                if (nc == (-1)) {
 
2530
                                        /* No, so try to allocate it */
 
2531
                                        nc = gdImageColorAllocate(dst,
 
2532
                                                src->red[c], src->green[c],
 
2533
                                                src->blue[c]);
 
2534
                                        /* If we're out of colors, go for the
 
2535
                                                closest color */
 
2536
                                        if (nc == (-1)) {
 
2537
                                                nc = gdImageColorClosest(dst,
 
2538
                                                        src->red[c], src->green[c],
 
2539
                                                        src->blue[c]);
 
2540
                                        }
 
2541
                                }
 
2542
                                colorMap[c] = nc;
 
2543
                        }
 
2544
                        gdImageSetPixel(dst, tox, toy, colorMap[c]);
 
2545
                        tox++;
 
2546
                }
 
2547
                toy++;
 
2548
        }
 
2549
}                       
 
2550
 
 
2551
void gdImageCopyResized(dst, src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH)
 
2552
     gdImagePtr dst;
 
2553
     gdImagePtr src;
 
2554
     int dstX;
 
2555
     int dstY;
 
2556
     int srcX;
 
2557
     int srcY;
 
2558
     int dstW;
 
2559
     int dstH;
 
2560
     int srcW;
 
2561
     int srcH;
 
2562
{
 
2563
        int c;
 
2564
        int x, y;
 
2565
        int tox, toy;
 
2566
        int ydest;
 
2567
        int i;
 
2568
        int colorMap[gdMaxColors];
 
2569
        /* Stretch vectors */
 
2570
        int *stx;
 
2571
        int *sty;
 
2572
        /* We only need to use floating point to determine the correct
 
2573
                stretch vector for one line's worth. */
 
2574
        double accum;
 
2575
        stx = (int *) malloc(sizeof(int) * srcW);
 
2576
        sty = (int *) malloc(sizeof(int) * srcH);
 
2577
        accum = 0;
 
2578
        for (i=0; (i < srcW); i++) {
 
2579
                int got;
 
2580
                accum += (double)dstW/(double)srcW;
 
2581
                got = (int)floor(accum);
 
2582
                stx[i] = got;
 
2583
                accum -= got;
 
2584
        }
 
2585
        accum = 0;
 
2586
        for (i=0; (i < srcH); i++) {
 
2587
                int got;
 
2588
                accum += (double)dstH/(double)srcH;
 
2589
                got = (int)floor(accum);
 
2590
                sty[i] = got;
 
2591
                accum -= got;
 
2592
        }
 
2593
        for (i=0; (i<gdMaxColors); i++) {
 
2594
                colorMap[i] = (-1);
 
2595
        }
 
2596
        toy = dstY;
 
2597
        for (y=srcY; (y < (srcY + srcH)); y++) {
 
2598
                for (ydest=0; (ydest < sty[y-srcY]); ydest++) {
 
2599
                        tox = dstX;
 
2600
                        for (x=srcX; (x < (srcX + srcW)); x++) {
 
2601
                                int nc;
 
2602
                                if (!stx[x - srcX]) {
 
2603
                                        continue;
 
2604
                                }
 
2605
                                c = gdImageGetPixel(src, x, y);
 
2606
                                /* Added 7/24/95: support transparent copies */
 
2607
                                if (gdImageGetTransparent(src) == c) {
 
2608
                                        tox += stx[x-srcX];
 
2609
                                        continue;
 
2610
                                }
 
2611
                                /* Have we established a mapping for this color? */
 
2612
                                if (colorMap[c] == (-1)) {
 
2613
                                        /* If it's the same image, mapping is trivial */
 
2614
                                        if (dst == src) {
 
2615
                                                nc = c;
 
2616
                                        } else { 
 
2617
                                                /* First look for an exact match */
 
2618
                                                nc = gdImageColorExact(dst,
 
2619
                                                        src->red[c], src->green[c],
 
2620
                                                        src->blue[c]);
 
2621
                                        }       
 
2622
                                        if (nc == (-1)) {
 
2623
                                                /* No, so try to allocate it */
 
2624
                                                nc = gdImageColorAllocate(dst,
 
2625
                                                        src->red[c], src->green[c],
 
2626
                                                        src->blue[c]);
 
2627
                                                /* If we're out of colors, go for the
 
2628
                                                        closest color */
 
2629
                                                if (nc == (-1)) {
 
2630
                                                        nc = gdImageColorClosest(dst,
 
2631
                                                                src->red[c], src->green[c],
 
2632
                                                                src->blue[c]);
 
2633
                                                }
 
2634
                                        }
 
2635
                                        colorMap[c] = nc;
 
2636
                                }
 
2637
                                for (i=0; (i < stx[x - srcX]); i++) {
 
2638
                                        gdImageSetPixel(dst, tox, toy, colorMap[c]);
 
2639
                                        tox++;
 
2640
                                }
 
2641
                        }
 
2642
                        toy++;
 
2643
                }
 
2644
        }
 
2645
        free(stx);
 
2646
        free(sty);
 
2647
}
 
2648
 
 
2649
int gdGetWord(result, in)
 
2650
     int *result;
 
2651
     FILE *in;
 
2652
{
 
2653
        int r;
 
2654
        r = getc(in);
 
2655
        if (r == EOF) {
 
2656
                return 0;
 
2657
        }
 
2658
        *result = r << 8;
 
2659
        r = getc(in);   
 
2660
        if (r == EOF) {
 
2661
                return 0;
 
2662
        }
 
2663
        *result += r;
 
2664
        return 1;
 
2665
}
 
2666
 
 
2667
void gdPutWord(w, out)
 
2668
     int w;
 
2669
     FILE *out;
 
2670
{
 
2671
        putc((unsigned char)(w >> 8), out);
 
2672
        putc((unsigned char)(w & 0xFF), out);
 
2673
}
 
2674
 
 
2675
int gdGetByte(result, in)
 
2676
     int *result;
 
2677
     FILE *in;
 
2678
{
 
2679
        int r;
 
2680
        r = getc(in);
 
2681
        if (r == EOF) {
 
2682
                return 0;
 
2683
        }
 
2684
        *result = r;
 
2685
        return 1;
 
2686
}
 
2687
 
 
2688
gdImagePtr gdImageCreateFromGd(in)
 
2689
     FILE *in;
 
2690
{
 
2691
        int sx, sy;
 
2692
        int x, y;
 
2693
        int i;
 
2694
        gdImagePtr im;
 
2695
        if (!gdGetWord(&sx, in)) {
 
2696
                goto fail1;
 
2697
        }
 
2698
        if (!gdGetWord(&sy, in)) {
 
2699
                goto fail1;
 
2700
        }
 
2701
        im = gdImageCreate(sx, sy);
 
2702
        if (!gdGetByte(&im->colorsTotal, in)) {
 
2703
                goto fail2;
 
2704
        }
 
2705
        if (!gdGetWord(&im->transparent, in)) {
 
2706
                goto fail2;
 
2707
        }
 
2708
        if (im->transparent == 257) {
 
2709
                im->transparent = (-1);
 
2710
        }
 
2711
        for (i=0; (i<gdMaxColors); i++) {
 
2712
                if (!gdGetByte(&im->red[i], in)) {
 
2713
                        goto fail2;
 
2714
                }
 
2715
                if (!gdGetByte(&im->green[i], in)) {
 
2716
                        goto fail2;
 
2717
                }
 
2718
                if (!gdGetByte(&im->blue[i], in)) {
 
2719
                        goto fail2;
 
2720
                }
 
2721
        }       
 
2722
        for (y=0; (y<sy); y++) {
 
2723
                for (x=0; (x<sx); x++) {        
 
2724
                        int ch;
 
2725
                        ch = getc(in);
 
2726
                        if (ch == EOF) {
 
2727
                                gdImageDestroy(im);
 
2728
                                return 0;
 
2729
                        }
 
2730
                        /* ROW-MAJOR IN GD 1.3 */
 
2731
                        im->pixels[y][x] = ch;
 
2732
                }
 
2733
        }
 
2734
        return im;
 
2735
fail2:
 
2736
        gdImageDestroy(im);
 
2737
fail1:
 
2738
        return 0;
 
2739
}
 
2740
        
 
2741
void gdImageGd(im, out)
 
2742
     gdImagePtr im;
 
2743
     FILE *out;
 
2744
{
 
2745
        int x, y;
 
2746
        int i;
 
2747
        int trans;
 
2748
        gdPutWord(im->sx, out);
 
2749
        gdPutWord(im->sy, out);
 
2750
        putc((unsigned char)im->colorsTotal, out);
 
2751
        trans = im->transparent;
 
2752
        if (trans == (-1)) {
 
2753
                trans = 257;
 
2754
        }       
 
2755
        gdPutWord(trans, out);
 
2756
        for (i=0; (i<gdMaxColors); i++) {
 
2757
                putc((unsigned char)im->red[i], out);
 
2758
                putc((unsigned char)im->green[i], out); 
 
2759
                putc((unsigned char)im->blue[i], out);  
 
2760
        }
 
2761
        for (y=0; (y < im->sy); y++) {  
 
2762
                for (x=0; (x < im->sx); x++) {  
 
2763
                        /* ROW-MAJOR IN GD 1.3 */
 
2764
                        putc((unsigned char)im->pixels[y][x], out);
 
2765
                }
 
2766
        }
 
2767
}
 
2768
 
 
2769
gdImagePtr
 
2770
gdImageCreateFromXbm(fd)
 
2771
     FILE *fd;
 
2772
{
 
2773
        gdImagePtr im;  
 
2774
        int bit;
 
2775
        int w, h;
 
2776
        int bytes;
 
2777
        int ch;
 
2778
        int i, x, y;
 
2779
        char *sp;
 
2780
        char s[161];
 
2781
        if (!fgets(s, 160, fd)) {
 
2782
                return 0;
 
2783
        }
 
2784
        sp = &s[0];
 
2785
        /* Skip #define */
 
2786
        sp = strchr(sp, ' ');
 
2787
        if (!sp) {
 
2788
                return 0;
 
2789
        }
 
2790
        /* Skip width label */
 
2791
        sp++;
 
2792
        sp = strchr(sp, ' ');
 
2793
        if (!sp) {
 
2794
                return 0;
 
2795
        }
 
2796
        /* Get width */
 
2797
        w = atoi(sp + 1);
 
2798
        if (!w) {
 
2799
                return 0;
 
2800
        }
 
2801
        if (!fgets(s, 160, fd)) {
 
2802
                return 0;
 
2803
        }
 
2804
        sp = s;
 
2805
        /* Skip #define */
 
2806
        sp = strchr(sp, ' ');
 
2807
        if (!sp) {
 
2808
                return 0;
 
2809
        }
 
2810
        /* Skip height label */
 
2811
        sp++;
 
2812
        sp = strchr(sp, ' ');
 
2813
        if (!sp) {
 
2814
                return 0;
 
2815
        }
 
2816
        /* Get height */
 
2817
        h = atoi(sp + 1);
 
2818
        if (!h) {
 
2819
                return 0;
 
2820
        }
 
2821
        /* Skip declaration line */
 
2822
        if (!fgets(s, 160, fd)) {
 
2823
                return 0;
 
2824
        }
 
2825
        bytes = ((w * h) / 8) + 1;
 
2826
        im = gdImageCreate(w, h);
 
2827
        gdImageColorAllocate(im, 255, 255, 255);
 
2828
        gdImageColorAllocate(im, 0, 0, 0);
 
2829
        x = 0;
 
2830
        y = 0;
 
2831
        for (i=0; (i < bytes); i++) {
 
2832
                char h[3];
 
2833
                int b;
 
2834
                /* Skip spaces, commas, CRs, 0x */
 
2835
                while(1) {
 
2836
                        ch = getc(fd);
 
2837
                        if (ch == EOF) {
 
2838
                                goto fail;
 
2839
                        }
 
2840
                        if (ch == 'x') {
 
2841
                                break;
 
2842
                        }       
 
2843
                }
 
2844
                /* Get hex value */
 
2845
                ch = getc(fd);
 
2846
                if (ch == EOF) {
 
2847
                        goto fail;
 
2848
                }
 
2849
                h[0] = ch;
 
2850
                ch = getc(fd);
 
2851
                if (ch == EOF) {
 
2852
                        goto fail;
 
2853
                }
 
2854
                h[1] = ch;
 
2855
                h[2] = '\0';
 
2856
                sscanf(h, "%x", &b);            
 
2857
                for (bit = 1; (bit <= 128); (bit = bit << 1)) {
 
2858
                        gdImageSetPixel(im, x++, y, (b & bit) ? 1 : 0); 
 
2859
                        if (x == im->sx) {
 
2860
                                x = 0;
 
2861
                                y++;
 
2862
                                if (y == im->sy) {
 
2863
                                        return im;
 
2864
                                }
 
2865
                                /* Fix 8/8/95 */
 
2866
                                break;
 
2867
                        }
 
2868
                }
 
2869
        }
 
2870
        /* Shouldn't happen */
 
2871
        /*      fprintf(stderr, "Error: bug in gdImageCreateFromXbm x=%d,sx=%d,y=%dsy=%d!\n",x,im->sx,y,im->sy);*/
 
2872
        return im;
 
2873
fail:
 
2874
        gdImageDestroy(im);
 
2875
        return 0;
 
2876
}
 
2877
 
 
2878
void gdImagePolygon(im, p, n, c)
 
2879
     gdImagePtr im;
 
2880
     gdPointPtr p;
 
2881
     int n;
 
2882
     int c;
 
2883
{
 
2884
        int i;
 
2885
        int lx, ly;
 
2886
        if (!n) {
 
2887
                return;
 
2888
        }
 
2889
        lx = p->x;
 
2890
        ly = p->y;
 
2891
        gdImageLine(im, lx, ly, p[n-1].x, p[n-1].y, c);
 
2892
        for (i=1; (i < n); i++) {
 
2893
                p++;
 
2894
                gdImageLine(im, lx, ly, p->x, p->y, c);
 
2895
                lx = p->x;
 
2896
                ly = p->y;
 
2897
        }
 
2898
}       
 
2899
        
 
2900
int gdCompareInt();
 
2901
void gdImageFilledPolygon(im,p,n,c)
 
2902
     gdImagePtr im; gdPointPtr p; int n; int c;
 
2903
{
 
2904
        int i;
 
2905
        int y;
 
2906
        int miny, maxy;
 
2907
        int x1, y1;
 
2908
        int x2, y2;
 
2909
        int ind1, ind2;
 
2910
        int ints;
 
2911
        if (!n) {
 
2912
                return;
 
2913
        }
 
2914
        if (!im->polyAllocated) {
 
2915
                im->polyInts = (int *) malloc(sizeof(int) * n);
 
2916
                im->polyAllocated = n;
 
2917
        }               
 
2918
        if (im->polyAllocated < n) {
 
2919
                while (im->polyAllocated < n) {
 
2920
                        im->polyAllocated *= 2;
 
2921
                }       
 
2922
                im->polyInts = (int *) realloc(im->polyInts,
 
2923
                        sizeof(int) * im->polyAllocated);
 
2924
        }
 
2925
        miny = p[0].y;
 
2926
        maxy = p[0].y;
 
2927
        for (i=1; (i < n); i++) {
 
2928
                if (p[i].y < miny) {
 
2929
                        miny = p[i].y;
 
2930
                }
 
2931
                if (p[i].y > maxy) {
 
2932
                        maxy = p[i].y;
 
2933
                }
 
2934
        }
 
2935
        /* Fix in 1.3: count a vertex only once */
 
2936
        for (y=miny; (y <= maxy); y++) {
 
2937
/*1.4           int interLast = 0; */
 
2938
/*              int dirLast = 0; */
 
2939
/*              int interFirst = 1; */
 
2940
                ints = 0;
 
2941
                for (i=0; (i < n); i++) {
 
2942
                        if (!i) {
 
2943
                                ind1 = n-1;
 
2944
                                ind2 = 0;
 
2945
                        } else {
 
2946
                                ind1 = i-1;
 
2947
                                ind2 = i;
 
2948
                        }
 
2949
                        y1 = p[ind1].y;
 
2950
                        y2 = p[ind2].y;
 
2951
                        if (y1 < y2) {
 
2952
                                x1 = p[ind1].x;
 
2953
                                x2 = p[ind2].x;
 
2954
                        } else if (y1 > y2) {
 
2955
                                y2 = p[ind1].y;
 
2956
                                y1 = p[ind2].y;
 
2957
                                x2 = p[ind1].x;
 
2958
                                x1 = p[ind2].x;
 
2959
                        } else {
 
2960
                                continue;
 
2961
                        }
 
2962
                        if ((y >= y1) && (y < y2)) {
 
2963
                                im->polyInts[ints++] = (y-y1) * (x2-x1) / (y2-y1) + x1;
 
2964
                        } else if ((y == maxy) && (y > y1) && (y <= y2)) {
 
2965
                                im->polyInts[ints++] = (y-y1) * (x2-x1) / (y2-y1) + x1;
 
2966
                        }
 
2967
                }
 
2968
                qsort(im->polyInts, ints, sizeof(int), gdCompareInt);
 
2969
 
 
2970
                for (i=0; (i < (ints)); i+=2) {
 
2971
                        gdImageLine(im, im->polyInts[i], y,
 
2972
                                im->polyInts[i+1], y, c);
 
2973
                }
 
2974
        }
 
2975
}
 
2976
int gdCompareInt(a, b)
 
2977
     /*     const void *a;
 
2978
            const void *b; */
 
2979
  void *a;
 
2980
  void *b; 
 
2981
{
 
2982
  /*    return (*(const int *)a) - (*(const int *)b); */
 
2983
        return (*(int *)a) - (*(int *)b);
 
2984
}
 
2985
 
 
2986
void gdImageSetStyle(im, style, noOfPixels)
 
2987
     gdImagePtr im;
 
2988
     int *style;
 
2989
     int noOfPixels;
 
2990
{
 
2991
        if (im->style) {
 
2992
                free(im->style);
 
2993
        }
 
2994
        im->style = (int *) 
 
2995
                malloc(sizeof(int) * noOfPixels);
 
2996
        memcpy(im->style, style, sizeof(int) * noOfPixels);
 
2997
        im->styleLength = noOfPixels;
 
2998
        im->stylePos = 0;
 
2999
}
 
3000
 
 
3001
void gdImageSetBrush(im, brush)
 
3002
     gdImagePtr im;
 
3003
     gdImagePtr brush;
 
3004
{
 
3005
        int i;
 
3006
        im->brush = brush;
 
3007
        for (i=0; (i < gdImageColorsTotal(brush)); i++) {
 
3008
                int index;
 
3009
                index = gdImageColorExact(im, 
 
3010
                        gdImageRed(brush, i),
 
3011
                        gdImageGreen(brush, i),
 
3012
                        gdImageBlue(brush, i));
 
3013
                if (index == (-1)) {
 
3014
                        index = gdImageColorAllocate(im,
 
3015
                                gdImageRed(brush, i),
 
3016
                                gdImageGreen(brush, i),
 
3017
                                gdImageBlue(brush, i));
 
3018
                        if (index == (-1)) {
 
3019
                                index = gdImageColorClosest(im,
 
3020
                                        gdImageRed(brush, i),
 
3021
                                        gdImageGreen(brush, i),
 
3022
                                        gdImageBlue(brush, i));
 
3023
                        }
 
3024
                }
 
3025
                im->brushColorMap[i] = index;
 
3026
        }
 
3027
}
 
3028
        
 
3029
void gdImageSetTile(im, tile)
 
3030
     gdImagePtr im;
 
3031
     gdImagePtr tile;
 
3032
{
 
3033
        int i;
 
3034
        im->tile = tile;
 
3035
        for (i=0; (i < gdImageColorsTotal(tile)); i++) {
 
3036
                int index;
 
3037
                index = gdImageColorExact(im, 
 
3038
                        gdImageRed(tile, i),
 
3039
                        gdImageGreen(tile, i),
 
3040
                        gdImageBlue(tile, i));
 
3041
                if (index == (-1)) {
 
3042
                        index = gdImageColorAllocate(im,
 
3043
                                gdImageRed(tile, i),
 
3044
                                gdImageGreen(tile, i),
 
3045
                                gdImageBlue(tile, i));
 
3046
                        if (index == (-1)) {
 
3047
                                index = gdImageColorClosest(im,
 
3048
                                        gdImageRed(tile, i),
 
3049
                                        gdImageGreen(tile, i),
 
3050
                                        gdImageBlue(tile, i));
 
3051
                        }
 
3052
                }
 
3053
                im->tileColorMap[i] = index;
 
3054
        }
 
3055
}
 
3056
 
 
3057
void gdImageInterlace(im, interlaceArg)
 
3058
     gdImagePtr im;
 
3059
     int interlaceArg;
 
3060
{
 
3061
        im->interlace = interlaceArg;
 
3062
}
 
3063
 
 
3064
/*SG added function to change a given color with another */
 
3065
void gdImageChangeColor(im, old, new)
 
3066
     gdImagePtr im;
 
3067
     int old;
 
3068
     int new;
 
3069
{
 
3070
  int x, y,mx=0,mn=0;
 
3071
  for (y=0; (y < im->sy); y++) {        
 
3072
    for (x=0; (x < im->sx); x++) {      
 
3073
      if (im->pixels[y][x]==old) 
 
3074
        im->pixels[y][x]=new;
 
3075
 
 
3076
    }
 
3077
  }
 
3078
}