source: trunk/src/libsrc/util/gd_lib/gd.c @ 6284

Revision 6284, 59.2 KB checked in by et, 4 years ago (diff)

Removed include of 'malloc.h'.

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