Back to index

wims  3.65+svn20090927
gd.c
Go to the documentation of this file.
00001 /*#include <malloc.h>*/
00002 #include <stdio.h>
00003 #include <math.h>
00004 #include <string.h>
00005 #include <stdlib.h>
00006 #include "gd.h"
00007 #include "mtables.c"
00008 
00009 static void gdImageBrushApply(gdImagePtr im, int x, int y);
00010 static void gdImageTileApply(gdImagePtr im, int x, int y);
00011 
00012 gdImagePtr gdImageCreate(int sx, int sy)
00013 {
00014        int i;
00015        gdImagePtr im;
00016        im = (gdImage *) malloc(sizeof(gdImage));
00017        im->pixels = (unsigned char **) malloc(sizeof(unsigned char *) * sx);
00018        im->polyInts = 0;
00019        im->polyAllocated = 0;
00020        im->brush = 0;
00021        im->tile = 0;
00022        im->style = 0;
00023        for (i=0; (i<sx); i++) {
00024               im->pixels[i] = (unsigned char *) calloc(
00025                      sy, sizeof(unsigned char));
00026        }      
00027        im->sx = sx;
00028        im->sy = sy;
00029        im->colorsTotal = 0;
00030        im->transparent = (-1);
00031        im->interlace = 0;
00032        return im;
00033 }
00034 
00035 void gdImageDestroy(gdImagePtr im)
00036 {
00037        int i;
00038        for (i=0; (i<im->sx); i++) {
00039               free(im->pixels[i]);
00040        }      
00041        free(im->pixels);
00042        if (im->polyInts) {
00043                      free(im->polyInts);
00044        }
00045        if (im->style) {
00046               free(im->style);
00047        }
00048        free(im);
00049 }
00050 
00051 int gdImageColorClosest(gdImagePtr im, int r, int g, int b)
00052 {
00053        int i;
00054        long rd, gd, bd;
00055        int ct = (-1);
00056        long mindist = 0;
00057        for (i=0; (i<(im->colorsTotal)); i++) {
00058               long dist;
00059               if (im->open[i]) {
00060                      continue;
00061               }
00062               rd = (im->red[i] - r);      
00063               gd = (im->green[i] - g);
00064               bd = (im->blue[i] - b);
00065               dist = rd * rd + gd * gd + bd * bd;
00066               if ((i == 0) || (dist < mindist)) {
00067                      mindist = dist;      
00068                      ct = i;
00069               }
00070        }
00071        return ct;
00072 }
00073 
00074 int gdImageColorExact(gdImagePtr im, int r, int g, int b)
00075 {
00076        int i;
00077        for (i=0; (i<(im->colorsTotal)); i++) {
00078               if (im->open[i]) {
00079                      continue;
00080               }
00081               if ((im->red[i] == r) && 
00082                      (im->green[i] == g) &&
00083                      (im->blue[i] == b)) {
00084                      return i;
00085               }
00086        }
00087        return -1;
00088 }
00089 
00090 int gdImageColorAllocate(gdImagePtr im, int r, int g, int b)
00091 {
00092        int i;
00093        int ct = (-1);
00094        for (i=0; (i<(im->colorsTotal)); i++) {
00095               if (im->open[i]) {
00096                      ct = i;
00097                      break;
00098               }
00099        }      
00100        if (ct == (-1)) {
00101               ct = im->colorsTotal;
00102               if (ct == gdMaxColors) {
00103                      return -1;
00104               }
00105               im->colorsTotal++;
00106        }
00107        im->red[ct] = r;
00108        im->green[ct] = g;
00109        im->blue[ct] = b;
00110        im->open[ct] = 0;
00111        return ct;
00112 }
00113 
00114 void gdImageColorDeallocate(gdImagePtr im, int color)
00115 {
00116        /* Mark it open. */
00117        im->open[color] = 1;
00118 }
00119 
00120 void gdImageColorTransparent(gdImagePtr im, int color)
00121 {
00122        im->transparent = color;
00123 }
00124 
00125 void gdImageSetPixel(gdImagePtr im, int x, int y, int color)
00126 {
00127        int p;
00128        switch(color) {
00129               case gdStyled:
00130               if (!im->style) {
00131                      /* Refuse to draw if no style is set. */
00132                      return;
00133               } else {
00134                      p = im->style[im->stylePos++];
00135               }
00136               if (p != (gdTransparent)) {
00137                      gdImageSetPixel(im, x, y, p);
00138               }
00139               im->stylePos = im->stylePos %  im->styleLength;
00140               break;
00141               case gdStyledBrushed:
00142               if (!im->style) {
00143                      /* Refuse to draw if no style is set. */
00144                      return;
00145               }
00146               p = im->style[im->stylePos++];
00147               if ((p != gdTransparent) && (p != 0)) {
00148                      gdImageSetPixel(im, x, y, gdBrushed);
00149               }
00150               im->stylePos = im->stylePos %  im->styleLength;
00151               break;
00152               case gdBrushed:
00153               gdImageBrushApply(im, x, y);
00154               break;
00155               case gdTiled:
00156               gdImageTileApply(im, x, y);
00157               break;
00158               default:
00159               if (gdImageBoundsSafe(im, x, y)) {
00160                       im->pixels[x][y] = color;
00161               }
00162               break;
00163        }
00164 }
00165 
00166 static void gdImageBrushApply(gdImagePtr im, int x, int y)
00167 {
00168        int lx, ly;
00169        int hy;
00170        int hx;
00171        int x1, y1, x2, y2;
00172        int srcx, srcy;
00173        if (!im->brush) {
00174               return;
00175        }
00176        hy = gdImageSY(im->brush)/2;
00177        y1 = y - hy;
00178        y2 = y1 + gdImageSY(im->brush);    
00179        hx = gdImageSX(im->brush)/2;
00180        x1 = x - hx;
00181        x2 = x1 + gdImageSX(im->brush);
00182        srcy = 0;
00183        for (ly = y1; (ly < y2); ly++) {
00184               srcx = 0;
00185               for (lx = x1; (lx < x2); lx++) {
00186                      int p;
00187                      p = gdImageGetPixel(im->brush, srcx, srcy);
00188                      /* Allow for non-square brushes! */
00189                      if (p != gdImageGetTransparent(im->brush)) {
00190                             gdImageSetPixel(im, lx, ly,
00191                                    im->brushColorMap[p]);
00192                      }
00193                      srcx++;
00194               }
00195               srcy++;
00196        }      
00197 }             
00198 
00199 static void gdImageTileApply(gdImagePtr im, int x, int y)
00200 {
00201        int srcx, srcy;
00202        int p;
00203        if (!im->tile) {
00204               return;
00205        }
00206        srcx = x % gdImageSX(im->tile);
00207        srcy = y % gdImageSY(im->tile);
00208        p = gdImageGetPixel(im->tile, srcx, srcy);
00209        /* Allow for transparency */
00210        if (p != gdImageGetTransparent(im->tile)) {
00211               gdImageSetPixel(im, x, y,
00212                      im->tileColorMap[p]);
00213        }
00214 }             
00215 
00216 int gdImageGetPixel(gdImagePtr im, int x, int y)
00217 {
00218        if (gdImageBoundsSafe(im, x, y)) {
00219               return im->pixels[x][y];
00220        } else {
00221               return 0;
00222        }
00223 }
00224 
00225 /* Bresenham as presented in Foley & Van Dam */
00226 
00227 void gdImageLine(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
00228 {
00229        int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
00230        dx = abs(x2-x1);
00231        dy = abs(y2-y1);
00232        if (dy <= dx) {
00233               d = 2*dy - dx;
00234               incr1 = 2*dy;
00235               incr2 = 2 * (dy - dx);
00236               if (x1 > x2) {
00237                      x = x2;
00238                      y = y2;
00239                      ydirflag = (-1);
00240                      xend = x1;
00241               } else {
00242                      x = x1;
00243                      y = y1;
00244                      ydirflag = 1;
00245                      xend = x2;
00246               }
00247               gdImageSetPixel(im, x, y, color);
00248               if (((y2 - y1) * ydirflag) > 0) {
00249                      while (x < xend) {
00250                             x++;
00251                             if (d <0) {
00252                                    d+=incr1;
00253                             } else {
00254                                    y++;
00255                                    d+=incr2;
00256                             }
00257                             gdImageSetPixel(im, x, y, color);
00258                      }
00259               } else {
00260                      while (x < xend) {
00261                             x++;
00262                             if (d <0) {
00263                                    d+=incr1;
00264                             } else {
00265                                    y--;
00266                                    d+=incr2;
00267                             }
00268                             gdImageSetPixel(im, x, y, color);
00269                      }
00270               }             
00271        } else {
00272               d = 2*dx - dy;
00273               incr1 = 2*dx;
00274               incr2 = 2 * (dx - dy);
00275               if (y1 > y2) {
00276                      y = y2;
00277                      x = x2;
00278                      yend = y1;
00279                      xdirflag = (-1);
00280               } else {
00281                      y = y1;
00282                      x = x1;
00283                      yend = y2;
00284                      xdirflag = 1;
00285               }
00286               gdImageSetPixel(im, x, y, color);
00287               if (((x2 - x1) * xdirflag) > 0) {
00288                      while (y < yend) {
00289                             y++;
00290                             if (d <0) {
00291                                    d+=incr1;
00292                             } else {
00293                                    x++;
00294                                    d+=incr2;
00295                             }
00296                             gdImageSetPixel(im, x, y, color);
00297                      }
00298               } else {
00299                      while (y < yend) {
00300                             y++;
00301                             if (d <0) {
00302                                    d+=incr1;
00303                             } else {
00304                                    x--;
00305                                    d+=incr2;
00306                             }
00307                             gdImageSetPixel(im, x, y, color);
00308                      }
00309               }
00310        }
00311 }
00312 
00313 /* As above, plus dashing */
00314 
00315 #define dashedSet \
00316        { \
00317               dashStep++; \
00318               if (dashStep == gdDashSize) { \
00319                      dashStep = 0; \
00320                      on = !on; \
00321               } \
00322               if (on) { \
00323                      gdImageSetPixel(im, x, y, color); \
00324               } \
00325        }
00326 
00327 void gdImageDashedLine(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
00328 {
00329        int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
00330        int dashStep = 0;
00331        int on = 1;
00332        dx = abs(x2-x1);
00333        dy = abs(y2-y1);
00334        if (dy <= dx) {
00335               d = 2*dy - dx;
00336               incr1 = 2*dy;
00337               incr2 = 2 * (dy - dx);
00338               if (x1 > x2) {
00339                      x = x2;
00340                      y = y2;
00341                      ydirflag = (-1);
00342                      xend = x1;
00343               } else {
00344                      x = x1;
00345                      y = y1;
00346                      ydirflag = 1;
00347                      xend = x2;
00348               }
00349               dashedSet;
00350               if (((y2 - y1) * ydirflag) > 0) {
00351                      while (x < xend) {
00352                             x++;
00353                             if (d <0) {
00354                                    d+=incr1;
00355                             } else {
00356                                    y++;
00357                                    d+=incr2;
00358                             }
00359                             dashedSet;
00360                      }
00361               } else {
00362                      while (x < xend) {
00363                             x++;
00364                             if (d <0) {
00365                                    d+=incr1;
00366                             } else {
00367                                    y--;
00368                                    d+=incr2;
00369                             }
00370                             dashedSet;
00371                      }
00372               }             
00373        } else {
00374               d = 2*dx - dy;
00375               incr1 = 2*dx;
00376               incr2 = 2 * (dx - dy);
00377               if (y1 > y2) {
00378                      y = y2;
00379                      x = x2;
00380                      yend = y1;
00381                      xdirflag = (-1);
00382               } else {
00383                      y = y1;
00384                      x = x1;
00385                      yend = y2;
00386                      xdirflag = 1;
00387               }
00388               dashedSet;
00389               if (((x2 - x1) * xdirflag) > 0) {
00390                      while (y < yend) {
00391                             y++;
00392                             if (d <0) {
00393                                    d+=incr1;
00394                             } else {
00395                                    x++;
00396                                    d+=incr2;
00397                             }
00398                             dashedSet;
00399                      }
00400               } else {
00401                      while (y < yend) {
00402                             y++;
00403                             if (d <0) {
00404                                    d+=incr1;
00405                             } else {
00406                                    x--;
00407                                    d+=incr2;
00408                             }
00409                             dashedSet;
00410                      }
00411               }
00412        }
00413 }
00414 
00415 int gdImageBoundsSafe(gdImagePtr im, int x, int y)
00416 {
00417        return (!(((y < 0) || (y >= im->sy)) ||
00418               ((x < 0) || (x >= im->sx))));
00419 }
00420 
00421 void gdImageChar(gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
00422 {
00423        int cx, cy;
00424        int px, py;
00425        int fline;
00426        cx = 0;
00427        cy = 0;
00428        if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
00429               return;
00430        }
00431        fline = (c - f->offset) * f->h * f->w;
00432        for (py = y; (py < (y + f->h)); py++) {
00433               for (px = x; (px < (x + f->w)); px++) {
00434                      if (f->data[fline + cy * f->w + cx]) {
00435                             gdImageSetPixel(im, px, py, color);       
00436                      }
00437                      cx++;
00438               }
00439               cx = 0;
00440               cy++;
00441        }
00442 }
00443 
00444 void gdImageCharUp(gdImagePtr im, gdFontPtr f, int x, int y, char c, int color)
00445 {
00446        int cx, cy;
00447        int px, py;
00448        int fline;
00449        cx = 0;
00450        cy = 0;
00451        if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
00452               return;
00453        }
00454        fline = (c - f->offset) * f->h * f->w;
00455        for (py = y; (py > (y - f->w)); py--) {
00456               for (px = x; (px < (x + f->h)); px++) {
00457                      if (f->data[fline + cy * f->w + cx]) {
00458                             gdImageSetPixel(im, px, py, color);       
00459                      }
00460                      cy++;
00461               }
00462               cy = 0;
00463               cx++;
00464        }
00465 }
00466 
00467 void gdImageString(gdImagePtr im, gdFontPtr f, int x, int y, char *s, int color)
00468 {
00469        int i;
00470        int l;
00471        l = strlen(s);
00472        for (i=0; (i<l); i++) {
00473               gdImageChar(im, f, x, y, s[i], color);
00474               x += f->w;
00475        }
00476 }
00477 
00478 void gdImageStringUp(gdImagePtr im, gdFontPtr f, int x, int y, char *s, int color)
00479 {
00480        int i;
00481        int l;
00482        l = strlen(s);
00483        for (i=0; (i<l); i++) {
00484               gdImageCharUp(im, f, x, y, s[i], color);
00485               y -= f->w;
00486        }
00487 }
00488 
00489 /* s and e are integers modulo 360 (degrees), with 0 degrees
00490   being the rightmost extreme and degrees changing clockwise.
00491   cx and cy are the center in pixels; w and h are the horizontal 
00492   and vertical diameter in pixels. Nice interface, but slow, since
00493   I don't yet use Bresenham (I'm using an inefficient but
00494   simple solution with too much work going on in it; generalizing
00495   Bresenham to ellipses and partial arcs of ellipses is non-trivial,
00496   at least for me) and there are other inefficiencies (small circles
00497   do far too much work). */
00498 
00499 void gdImageArc(gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color)
00500 {
00501        int i;
00502        int lx = 0, ly = 0;
00503        int w2, h2;
00504        w2 = w/2;
00505        h2 = h/2;
00506        while (e < s) {
00507               e += 360;
00508        }
00509        for (i=s; (i <= e); i++) {
00510               int x, y;
00511               x = ((long)cost[i % 360] * (long)w2 / costScale) + cx; 
00512               y = ((long)sint[i % 360] * (long)h2 / sintScale) + cy;
00513               if (i != s) {
00514                      gdImageLine(im, lx, ly, x, y, color);     
00515               }
00516               lx = x;
00517               ly = y;
00518        }
00519 }
00520 
00521 
00522 #if 0
00523        /* Bresenham octant code, which I should use eventually */
00524        int x, y, d;
00525        x = 0;
00526        y = w;
00527        d = 3-2*w;
00528        while (x < y) {
00529               gdImageSetPixel(im, cx+x, cy+y, color);
00530               if (d < 0) {
00531                      d += 4 * x + 6;
00532               } else {
00533                      d += 4 * (x - y) + 10;
00534                      y--;
00535               }
00536               x++;
00537        }
00538        if (x == y) {
00539               gdImageSetPixel(im, cx+x, cy+y, color);
00540        }
00541 #endif
00542 
00543 void gdImageFillToBorder(gdImagePtr im, int x, int y, int border, int color)
00544 {
00545        int lastBorder;
00546        /* Seek left */
00547        int leftLimit, rightLimit;
00548        int i;
00549         /* XIAO: overboard */
00550         if(x<0 || y<0 || x>=im->sx || y>=im->sy) return;
00551        leftLimit = (-1);
00552        if (border < 0) {
00553               /* Refuse to fill to a non-solid border */
00554               return;
00555        }
00556        for (i = x; (i >= 0); i--) {
00557               if (gdImageGetPixel(im, i, y) == border) {
00558                      break;
00559               }
00560               gdImageSetPixel(im, i, y, color);
00561               leftLimit = i;
00562        }
00563        if (leftLimit == (-1)) {
00564               return;
00565        }
00566        /* Seek right */
00567        rightLimit = x;
00568        for (i = (x+1); (i < im->sx); i++) {      
00569               if (gdImageGetPixel(im, i, y) == border) {
00570                      break;
00571               }
00572               gdImageSetPixel(im, i, y, color);
00573               rightLimit = i;
00574        }
00575        /* Look at lines above and below and start paints */
00576        /* Above */
00577        if (y > 0) {
00578               lastBorder = 1;
00579               for (i = leftLimit; (i <= rightLimit); i++) {
00580                      int c;
00581                      c = gdImageGetPixel(im, i, y-1);
00582                      if (lastBorder) {
00583                             if ((c != border) && (c != color)) {      
00584                                    gdImageFillToBorder(im, i, y-1, 
00585                                           border, color);             
00586                                    lastBorder = 0;
00587                             }
00588                      } else if ((c == border) || (c == color)) {
00589                             lastBorder = 1;
00590                      }
00591               }
00592        }
00593        /* Below */
00594        if (y < ((im->sy) - 1)) {
00595               lastBorder = 1;
00596               for (i = leftLimit; (i <= rightLimit); i++) {
00597                      int c;
00598                      c = gdImageGetPixel(im, i, y+1);
00599                      if (lastBorder) {
00600                             if ((c != border) && (c != color)) {      
00601                                    gdImageFillToBorder(im, i, y+1, 
00602                                           border, color);             
00603                                    lastBorder = 0;
00604                             }
00605                      } else if ((c == border) || (c == color)) {
00606                             lastBorder = 1;
00607                      }
00608               }
00609        }
00610 }
00611 
00612 void gdImageFill(gdImagePtr im, int x, int y, int color)
00613 {
00614        int lastBorder;
00615        int old;
00616        int leftLimit, rightLimit;
00617        int i;
00618         /* XIAO: overboard */
00619         if(x<0 || y<0 || x>=im->sx || y>=im->sy) return;
00620        old = gdImageGetPixel(im, x, y);
00621        if (color == gdTiled) {
00622               /* Tile fill -- got to watch out! */
00623               int p, tileColor;    
00624               int srcx, srcy;
00625               if (!im->tile) {
00626                      return;
00627               }
00628               /* Refuse to flood-fill with a transparent pattern --
00629                      I can't do it without allocating another image */
00630               if (gdImageGetTransparent(im->tile) != (-1)) {
00631                      return;
00632               }      
00633               srcx = x % gdImageSX(im->tile);
00634               srcy = y % gdImageSY(im->tile);
00635               p = gdImageGetPixel(im->tile, srcx, srcy);
00636               tileColor = im->tileColorMap[p];
00637               if (old == tileColor) {
00638                      /* Nothing to be done */
00639                      return;
00640               }
00641        } else {
00642               if (old == color) {
00643                      /* Nothing to be done */
00644                      return;
00645               }
00646        }
00647        /* Seek left */
00648        leftLimit = (-1);
00649        for (i = x; (i >= 0); i--) {
00650               if (gdImageGetPixel(im, i, y) != old) {
00651                      break;
00652               }
00653               gdImageSetPixel(im, i, y, color);
00654               leftLimit = i;
00655        }
00656        if (leftLimit == (-1)) {
00657               return;
00658        }
00659        /* Seek right */
00660        rightLimit = x;
00661        for (i = (x+1); (i < im->sx); i++) {      
00662               if (gdImageGetPixel(im, i, y) != old) {
00663                      break;
00664               }
00665               gdImageSetPixel(im, i, y, color);
00666               rightLimit = i;
00667        }
00668        /* Look at lines above and below and start paints */
00669        /* Above */
00670        if (y > 0) {
00671               lastBorder = 1;
00672               for (i = leftLimit; (i <= rightLimit); i++) {
00673                      int c;
00674                      c = gdImageGetPixel(im, i, y-1);
00675                      if (lastBorder) {
00676                             if (c == old) {      
00677                                    gdImageFill(im, i, y-1, color);           
00678                                    lastBorder = 0;
00679                             }
00680                      } else if (c != old) {
00681                             lastBorder = 1;
00682                      }
00683               }
00684        }
00685        /* Below */
00686        if (y < ((im->sy) - 1)) {
00687               lastBorder = 1;
00688               for (i = leftLimit; (i <= rightLimit); i++) {
00689                      int c;
00690                      c = gdImageGetPixel(im, i, y+1);
00691                      if (lastBorder) {
00692                             if (c == old) {
00693                                    gdImageFill(im, i, y+1, color);           
00694                                    lastBorder = 0;
00695                             }
00696                      } else if (c != old) {
00697                             lastBorder = 1;
00698                      }
00699               }
00700        }
00701 }
00702        
00703 #ifdef TEST_CODE
00704 void gdImageDump(gdImagePtr im)
00705 {
00706        int i, j;
00707        for (i=0; (i < im->sy); i++) {
00708               for (j=0; (j < im->sx); j++) {
00709                      printf("%d", im->pixels[j][i]);
00710               }
00711               printf("\n");
00712        }
00713 }
00714 #endif
00715 
00716 /* Code drawn from ppmtogif.c, from the pbmplus package
00717 **
00718 ** Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>. A
00719 ** Lempel-Zim compression based on "compress".
00720 **
00721 ** Modified by Marcel Wijkstra <wijkstra@fwi.uva.nl>
00722 **
00723 ** Copyright (C) 1989 by Jef Poskanzer.
00724 **
00725 ** Permission to use, copy, modify, and distribute this software and its
00726 ** documentation for any purpose and without fee is hereby granted, provided
00727 ** that the above copyright notice appear in all copies and that both that
00728 ** copyright notice and this permission notice appear in supporting
00729 ** documentation.  This software is provided "as is" without express or
00730 ** implied warranty.
00731 **
00732 ** The Graphics Interchange Format(c) is the Copyright property of
00733 ** CompuServe Incorporated.  GIF(sm) is a Service Mark property of
00734 ** CompuServe Incorporated.
00735 */
00736 
00737 /*
00738  * a code_int must be able to hold 2**GIFBITS values of type int, and also -1
00739  */
00740 typedef int             code_int;
00741 
00742 #ifdef SIGNED_COMPARE_SLOW
00743 typedef unsigned long int count_int;
00744 typedef unsigned short int count_short;
00745 #else /*SIGNED_COMPARE_SLOW*/
00746 typedef long int          count_int;
00747 #endif /*SIGNED_COMPARE_SLOW*/
00748 
00749 static int colorstobpp(int colors);
00750 static void BumpPixel (void);
00751 static int GIFNextPixel (gdImagePtr im);
00752 static void GIFEncode (FILE *fp, int GWidth, int GHeight, int GInterlace, int Background, int Transparent, int BitsPerPixel, int *Red, int *Green, int *Blue, gdImagePtr im);
00753 static void Putword (int w, FILE *fp);
00754 static void compress (int init_bits, FILE *outfile, gdImagePtr im);
00755 static void output (code_int code);
00756 static void cl_block (void);
00757 static void cl_hash (register count_int hsize);
00758 static void char_init (void);
00759 static void char_out (int c);
00760 static void flush_char (void);
00761 /* Allows for reuse */
00762 static void init_statics(void);
00763 
00764 void gdImageGif(gdImagePtr im, FILE *out)
00765 {
00766        int interlace, transparent, BitsPerPixel;
00767        interlace = im->interlace;
00768        transparent = im->transparent;
00769 
00770        BitsPerPixel = colorstobpp(im->colorsTotal);
00771        /* Clear any old values in statics strewn through the GIF code */
00772        init_statics();
00773        /* All set, let's do it. */
00774        GIFEncode(
00775               out, im->sx, im->sy, interlace, 0, transparent, BitsPerPixel,
00776               im->red, im->green, im->blue, im);
00777 }
00778 
00779 static int
00780 colorstobpp(int colors)
00781 {
00782     int bpp = 0;
00783 
00784     if ( colors <= 2 )
00785         bpp = 1;
00786     else if ( colors <= 4 )
00787         bpp = 2;
00788     else if ( colors <= 8 )
00789         bpp = 3;
00790     else if ( colors <= 16 )
00791         bpp = 4;
00792     else if ( colors <= 32 )
00793         bpp = 5;
00794     else if ( colors <= 64 )
00795         bpp = 6;
00796     else if ( colors <= 128 )
00797         bpp = 7;
00798     else if ( colors <= 256 )
00799         bpp = 8;
00800     return bpp;
00801     }
00802 
00803 /*****************************************************************************
00804  *
00805  * GIFENCODE.C    - GIF Image compression interface
00806  *
00807  * GIFEncode( FName, GHeight, GWidth, GInterlace, Background, Transparent,
00808  *            BitsPerPixel, Red, Green, Blue, gdImagePtr )
00809  *
00810  *****************************************************************************/
00811 
00812 #define TRUE 1
00813 #define FALSE 0
00814 
00815 static int Width, Height;
00816 static int curx, cury;
00817 static long CountDown;
00818 static int Pass = 0;
00819 static int Interlace;
00820 
00821 /*
00822  * Bump the 'curx' and 'cury' to point to the next pixel
00823  */
00824 static void
00825 BumpPixel(void)
00826 {
00827         /*
00828          * Bump the current X position
00829          */
00830         ++curx;
00831 
00832         /*
00833          * If we are at the end of a scan line, set curx back to the beginning
00834          * If we are interlaced, bump the cury to the appropriate spot,
00835          * otherwise, just increment it.
00836          */
00837         if( curx == Width ) {
00838                 curx = 0;
00839 
00840                 if( !Interlace )
00841                         ++cury;
00842                 else {
00843                      switch( Pass ) {
00844 
00845                        case 0:
00846                           cury += 8;
00847                           if( cury >= Height ) {
00848                                 ++Pass;
00849                                 cury = 4;
00850                           }
00851                           break;
00852 
00853                        case 1:
00854                           cury += 8;
00855                           if( cury >= Height ) {
00856                                 ++Pass;
00857                                 cury = 2;
00858                           }
00859                           break;
00860 
00861                        case 2:
00862                           cury += 4;
00863                           if( cury >= Height ) {
00864                              ++Pass;
00865                              cury = 1;
00866                           }
00867                           break;
00868 
00869                        case 3:
00870                           cury += 2;
00871                           break;
00872                         }
00873                 }
00874         }
00875 }
00876 
00877 /*
00878  * Return the next pixel from the image
00879  */
00880 static int
00881 GIFNextPixel(gdImagePtr im)
00882 {
00883         int r;
00884 
00885         if( CountDown == 0 )
00886                 return EOF;
00887 
00888         --CountDown;
00889 
00890         r = gdImageGetPixel(im, curx, cury);
00891 
00892         BumpPixel();
00893 
00894         return r;
00895 }
00896 
00897 /* public */
00898 
00899 static void
00900 GIFEncode(FILE *fp, int GWidth, int GHeight, int GInterlace, int Background, int Transparent, int BitsPerPixel, int *Red, int *Green, int *Blue, gdImagePtr im)
00901 {
00902         int B;
00903         int RWidth, RHeight;
00904         int LeftOfs, TopOfs;
00905         int Resolution;
00906         int ColorMapSize;
00907         int InitCodeSize;
00908         int i;
00909 
00910         Interlace = GInterlace;
00911 
00912         ColorMapSize = 1 << BitsPerPixel;
00913 
00914         RWidth = Width = GWidth;
00915         RHeight = Height = GHeight;
00916         LeftOfs = TopOfs = 0;
00917 
00918         Resolution = BitsPerPixel;
00919 
00920         /*
00921          * Calculate number of bits we are expecting
00922          */
00923         CountDown = (long)Width * (long)Height;
00924 
00925         /*
00926          * Indicate which pass we are on (if interlace)
00927          */
00928         Pass = 0;
00929 
00930         /*
00931          * The initial code size
00932          */
00933         if( BitsPerPixel <= 1 )
00934                 InitCodeSize = 2;
00935         else
00936                 InitCodeSize = BitsPerPixel;
00937 
00938         /*
00939          * Set up the current x and y position
00940          */
00941         curx = cury = 0;
00942 
00943         /*
00944          * Write the Magic header
00945          */
00946         fwrite( Transparent < 0 ? "GIF87a" : "GIF89a", 1, 6, fp );
00947 
00948         /*
00949          * Write out the screen width and height
00950          */
00951         Putword( RWidth, fp );
00952         Putword( RHeight, fp );
00953 
00954         /*
00955          * Indicate that there is a global colour map
00956          */
00957         B = 0x80;       /* Yes, there is a color map */
00958 
00959         /*
00960          * OR in the resolution
00961          */
00962         B |= (Resolution - 1) << 5;
00963 
00964         /*
00965          * OR in the Bits per Pixel
00966          */
00967         B |= (BitsPerPixel - 1);
00968 
00969         /*
00970          * Write it out
00971          */
00972         fputc( B, fp );
00973 
00974         /*
00975          * Write out the Background colour
00976          */
00977         fputc( Background, fp );
00978 
00979         /*
00980          * Byte of 0's (future expansion)
00981          */
00982         fputc( 0, fp );
00983 
00984         /*
00985          * Write out the Global Colour Map
00986          */
00987         for( i=0; i<ColorMapSize; ++i ) {
00988                 fputc( Red[i], fp );
00989                 fputc( Green[i], fp );
00990                 fputc( Blue[i], fp );
00991         }
00992 
00993        /*
00994         * Write out extension for transparent colour index, if necessary.
00995         */
00996        if ( Transparent >= 0 ) {
00997            fputc( '!', fp );
00998            fputc( 0xf9, fp );
00999            fputc( 4, fp );
01000            fputc( 1, fp );
01001            fputc( 0, fp );
01002            fputc( 0, fp );
01003            fputc( (unsigned char) Transparent, fp );
01004            fputc( 0, fp );
01005        }
01006 
01007         /*
01008          * Write an Image separator
01009          */
01010         fputc( ',', fp );
01011 
01012         /*
01013          * Write the Image header
01014          */
01015 
01016         Putword( LeftOfs, fp );
01017         Putword( TopOfs, fp );
01018         Putword( Width, fp );
01019         Putword( Height, fp );
01020 
01021         /*
01022          * Write out whether or not the image is interlaced
01023          */
01024         if( Interlace )
01025                 fputc( 0x40, fp );
01026         else
01027                 fputc( 0x00, fp );
01028 
01029         /*
01030          * Write out the initial code size
01031          */
01032         fputc( InitCodeSize, fp );
01033 
01034         /*
01035          * Go and actually compress the data
01036          */
01037         compress( InitCodeSize+1, fp, im );
01038 
01039         /*
01040          * Write out a Zero-length packet (to end the series)
01041          */
01042         fputc( 0, fp );
01043 
01044         /*
01045          * Write the GIF file terminator
01046          */
01047         fputc( ';', fp );
01048 }
01049 
01050 /*
01051  * Write out a word to the GIF file
01052  */
01053 static void
01054 Putword(int w, FILE *fp)
01055 {
01056         fputc( w & 0xff, fp );
01057         fputc( (w / 256) & 0xff, fp );
01058 }
01059 
01060 
01061 /***************************************************************************
01062  *
01063  *  GIFCOMPR.C       - GIF Image compression routines
01064  *
01065  *  Lempel-Ziv compression based on 'compress'.  GIF modifications by
01066  *  David Rowley (mgardi@watdcsu.waterloo.edu)
01067  *
01068  ***************************************************************************/
01069 
01070 /*
01071  * General DEFINEs
01072  */
01073 
01074 #define GIFBITS    12
01075 
01076 #define HSIZE  5003            /* 80% occupancy */
01077 
01078 #ifdef NO_UCHAR
01079  typedef char   char_type;
01080 #else /*NO_UCHAR*/
01081  typedef        unsigned char   char_type;
01082 #endif /*NO_UCHAR*/
01083 
01084 /*
01085  *
01086  * GIF Image compression - modified 'compress'
01087  *
01088  * Based on: compress.c - File compression ala IEEE Computer, June 1984.
01089  *
01090  * By Authors:  Spencer W. Thomas       (decvax!harpo!utah-cs!utah-gr!thomas)
01091  *              Jim McKie               (decvax!mcvax!jim)
01092  *              Steve Davies            (decvax!vax135!petsd!peora!srd)
01093  *              Ken Turkowski           (decvax!decwrl!turtlevax!ken)
01094  *              James A. Woods          (decvax!ihnp4!ames!jaw)
01095  *              Joe Orost               (decvax!vax135!petsd!joe)
01096  *
01097  */
01098 #include <ctype.h>
01099 
01100 #define ARGVAL() (*++(*argv) || (--argc && *++argv))
01101 
01102 static int n_bits;                        /* number of bits/code */
01103 static int maxbits = GIFBITS;                /* user settable max # bits/code */
01104 static code_int maxcode;                  /* maximum code, given n_bits */
01105 static code_int maxmaxcode = (code_int)1 << GIFBITS; /* should NEVER generate this code */
01106 #ifdef COMPATIBLE               /* But wrong! */
01107 # define MAXCODE(n_bits)        ((code_int) 1 << (n_bits) - 1)
01108 #else /*COMPATIBLE*/
01109 # define MAXCODE(n_bits)        (((code_int) 1 << (n_bits)) - 1)
01110 #endif /*COMPATIBLE*/
01111 
01112 static count_int htab [HSIZE];
01113 static unsigned short codetab [HSIZE];
01114 #define HashTabOf(i)       htab[i]
01115 #define CodeTabOf(i)    codetab[i]
01116 
01117 static code_int hsize = HSIZE;                 /* for dynamic table sizing */
01118 
01119 /*
01120  * To save much memory, we overlay the table used by compress() with those
01121  * used by decompress().  The tab_prefix table is the same size and type
01122  * as the codetab.  The tab_suffix table needs 2**GIFBITS characters.  We
01123  * get this from the beginning of htab.  The output stack uses the rest
01124  * of htab, and contains characters.  There is plenty of room for any
01125  * possible stack (stack used to be 8000 characters).
01126  */
01127 
01128 #define tab_prefixof(i) CodeTabOf(i)
01129 #define tab_suffixof(i)        ((char_type*)(htab))[i]
01130 #define de_stack               ((char_type*)&tab_suffixof((code_int)1<<GIFBITS))
01131 
01132 static code_int free_ent = 0;                  /* first unused entry */
01133 
01134 /*
01135  * block compression parameters -- after all codes are used up,
01136  * and compression rate changes, start over.
01137  */
01138 static int clear_flg = 0;
01139 
01140 static int offset;
01141 static long int in_count = 1;            /* length of input */
01142 static long int out_count = 0;           /* # of codes output (for debugging) */
01143 
01144 /*
01145  * compress stdin to stdout
01146  *
01147  * Algorithm:  use open addressing double hashing (no chaining) on the
01148  * prefix code / next character combination.  We do a variant of Knuth's
01149  * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
01150  * secondary probe.  Here, the modular division first probe is gives way
01151  * to a faster exclusive-or manipulation.  Also do block compression with
01152  * an adaptive reset, whereby the code table is cleared when the compression
01153  * ratio decreases, but after the table fills.  The variable-length output
01154  * codes are re-sized at this point, and a special CLEAR code is generated
01155  * for the decompressor.  Late addition:  construct the table according to
01156  * file size for noticeable speed improvement on small files.  Please direct
01157  * questions about this implementation to ames!jaw.
01158  */
01159 
01160 static int g_init_bits;
01161 static FILE* g_outfile;
01162 
01163 static int ClearCode;
01164 static int EOFCode;
01165 
01166 static void
01167 compress(int init_bits, FILE *outfile, gdImagePtr im)
01168 {
01169     register long fcode;
01170     register code_int i /* = 0 */;
01171     register int c;
01172     register code_int ent;
01173     register code_int disp;
01174     register code_int hsize_reg;
01175     register int hshift;
01176 
01177     /*
01178      * Set up the globals:  g_init_bits - initial number of bits
01179      *                      g_outfile   - pointer to output file
01180      */
01181     g_init_bits = init_bits;
01182     g_outfile = outfile;
01183 
01184     /*
01185      * Set up the necessary values
01186      */
01187     offset = 0;
01188     out_count = 0;
01189     clear_flg = 0;
01190     in_count = 1;
01191     maxcode = MAXCODE(n_bits = g_init_bits);
01192 
01193     ClearCode = (1 << (init_bits - 1));
01194     EOFCode = ClearCode + 1;
01195     free_ent = ClearCode + 2;
01196 
01197     char_init();
01198 
01199     ent = GIFNextPixel( im );
01200 
01201     hshift = 0;
01202     for ( fcode = (long) hsize;  fcode < 65536L; fcode *= 2L )
01203         ++hshift;
01204     hshift = 8 - hshift;                /* set hash code range bound */
01205 
01206     hsize_reg = hsize;
01207     cl_hash( (count_int) hsize_reg);            /* clear hash table */
01208 
01209     output( (code_int)ClearCode );
01210 
01211 #ifdef SIGNED_COMPARE_SLOW
01212     while ( (c = GIFNextPixel( im )) != (unsigned) EOF ) {
01213 #else /*SIGNED_COMPARE_SLOW*/
01214     while ( (c = GIFNextPixel( im )) != EOF ) {  /* } */
01215 #endif /*SIGNED_COMPARE_SLOW*/
01216 
01217         ++in_count;
01218 
01219         fcode = (long) (((long) c << maxbits) + ent);
01220         i = (((code_int)c << hshift) ^ ent);    /* xor hashing */
01221 
01222         if ( HashTabOf (i) == fcode ) {
01223             ent = CodeTabOf (i);
01224             continue;
01225         } else if ( (long)HashTabOf (i) < 0 )      /* empty slot */
01226             goto nomatch;
01227         disp = hsize_reg - i;           /* secondary hash (after G. Knott) */
01228         if ( i == 0 )
01229             disp = 1;
01230 probe:
01231         if ( (i -= disp) < 0 )
01232             i += hsize_reg;
01233 
01234         if ( HashTabOf (i) == fcode ) {
01235             ent = CodeTabOf (i);
01236             continue;
01237         }
01238         if ( (long)HashTabOf (i) > 0 )
01239             goto probe;
01240 nomatch:
01241         output ( (code_int) ent );
01242         ++out_count;
01243         ent = c;
01244 #ifdef SIGNED_COMPARE_SLOW
01245         if ( (unsigned) free_ent < (unsigned) maxmaxcode) {
01246 #else /*SIGNED_COMPARE_SLOW*/
01247         if ( free_ent < maxmaxcode ) {  /* } */
01248 #endif /*SIGNED_COMPARE_SLOW*/
01249             CodeTabOf (i) = free_ent++; /* code -> hashtable */
01250             HashTabOf (i) = fcode;
01251         } else
01252                 cl_block();
01253     }
01254     /*
01255      * Put out the final code.
01256      */
01257     output( (code_int)ent );
01258     ++out_count;
01259     output( (code_int) EOFCode );
01260 }
01261 
01262 /*****************************************************************
01263  * TAG( output )
01264  *
01265  * Output the given code.
01266  * Inputs:
01267  *      code:   A n_bits-bit integer.  If == -1, then EOF.  This assumes
01268  *              that n_bits =< (long)wordsize - 1.
01269  * Outputs:
01270  *      Outputs code to the file.
01271  * Assumptions:
01272  *      Chars are 8 bits long.
01273  * Algorithm:
01274  *      Maintain a GIFBITS character long buffer (so that 8 codes will
01275  * fit in it exactly).  Use the VAX insv instruction to insert each
01276  * code in turn.  When the buffer fills up empty it and start over.
01277  */
01278 
01279 static unsigned long cur_accum = 0;
01280 static int cur_bits = 0;
01281 
01282 static unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
01283                                   0x001F, 0x003F, 0x007F, 0x00FF,
01284                                   0x01FF, 0x03FF, 0x07FF, 0x0FFF,
01285                                   0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
01286 
01287 static void
01288 output(code_int code)
01289 {
01290     cur_accum &= masks[ cur_bits ];
01291 
01292     if( cur_bits > 0 )
01293         cur_accum |= ((long)code << cur_bits);
01294     else
01295         cur_accum = code;
01296 
01297     cur_bits += n_bits;
01298 
01299     while( cur_bits >= 8 ) {
01300         char_out( (unsigned int)(cur_accum & 0xff) );
01301         cur_accum >>= 8;
01302         cur_bits -= 8;
01303     }
01304 
01305     /*
01306      * If the next entry is going to be too big for the code size,
01307      * then increase it, if possible.
01308      */
01309    if ( free_ent > maxcode || clear_flg ) {
01310 
01311             if( clear_flg ) {
01312 
01313                 maxcode = MAXCODE (n_bits = g_init_bits);
01314                 clear_flg = 0;
01315 
01316             } else {
01317 
01318                 ++n_bits;
01319                 if ( n_bits == maxbits )
01320                     maxcode = maxmaxcode;
01321                 else
01322                     maxcode = MAXCODE(n_bits);
01323             }
01324         }
01325 
01326     if( code == EOFCode ) {
01327         /*
01328          * At EOF, write the rest of the buffer.
01329          */
01330         while( cur_bits > 0 ) {
01331                 char_out( (unsigned int)(cur_accum & 0xff) );
01332                 cur_accum >>= 8;
01333                 cur_bits -= 8;
01334         }
01335 
01336         flush_char();
01337 
01338         fflush( g_outfile );
01339 
01340         if( ferror( g_outfile ) )
01341               return;
01342     }
01343 }
01344 
01345 /*
01346  * Clear out the hash table
01347  */
01348 static void
01349 cl_block (void)             /* table clear for block compress */
01350 {
01351 
01352         cl_hash ( (count_int) hsize );
01353         free_ent = ClearCode + 2;
01354         clear_flg = 1;
01355 
01356         output( (code_int)ClearCode );
01357 }
01358 
01359 static void
01360 cl_hash(register count_int hsize)          /* reset code table */
01361                          
01362 {
01363 
01364         register count_int *htab_p = htab+hsize;
01365 
01366         register long i;
01367         register long m1 = -1;
01368 
01369         i = hsize - 16;
01370         do {                            /* might use Sys V memset(3) here */
01371                 *(htab_p-16) = m1;
01372                 *(htab_p-15) = m1;
01373                 *(htab_p-14) = m1;
01374                 *(htab_p-13) = m1;
01375                 *(htab_p-12) = m1;
01376                 *(htab_p-11) = m1;
01377                 *(htab_p-10) = m1;
01378                 *(htab_p-9) = m1;
01379                 *(htab_p-8) = m1;
01380                 *(htab_p-7) = m1;
01381                 *(htab_p-6) = m1;
01382                 *(htab_p-5) = m1;
01383                 *(htab_p-4) = m1;
01384                 *(htab_p-3) = m1;
01385                 *(htab_p-2) = m1;
01386                 *(htab_p-1) = m1;
01387                 htab_p -= 16;
01388         } while ((i -= 16) >= 0);
01389 
01390         for ( i += 16; i > 0; --i )
01391                 *--htab_p = m1;
01392 }
01393 
01394 /******************************************************************************
01395  *
01396  * GIF Specific routines
01397  *
01398  ******************************************************************************/
01399 
01400 /*
01401  * Number of characters so far in this 'packet'
01402  */
01403 static int a_count;
01404 
01405 /*
01406  * Set up the 'byte output' routine
01407  */
01408 static void
01409 char_init(void)
01410 {
01411         a_count = 0;
01412 }
01413 
01414 /*
01415  * Define the storage for the packet accumulator
01416  */
01417 static char accum[ 256 ];
01418 
01419 /*
01420  * Add a character to the end of the current packet, and if it is 254
01421  * characters, flush the packet to disk.
01422  */
01423 static void
01424 char_out(int c)
01425 {
01426         accum[ a_count++ ] = c;
01427         if( a_count >= 254 )
01428                 flush_char();
01429 }
01430 
01431 /*
01432  * Flush the packet to disk, and reset the accumulator
01433  */
01434 static void
01435 flush_char(void)
01436 {
01437         if( a_count > 0 ) {
01438                 fputc( a_count, g_outfile );
01439                 fwrite( accum, 1, a_count, g_outfile );
01440                 a_count = 0;
01441         }
01442 }
01443 
01444 static void init_statics(void) {
01445        /* Some of these are properly initialized later. What I'm doing
01446               here is making sure code that depends on C's initialization
01447               of statics doesn't break when the code gets called more
01448               than once. */
01449        Width = 0;
01450        Height = 0;
01451        curx = 0;
01452        cury = 0;
01453        CountDown = 0;
01454        Pass = 0;
01455        Interlace = 0;
01456        a_count = 0;
01457        cur_accum = 0;
01458        cur_bits = 0;
01459        g_init_bits = 0;
01460        g_outfile = 0;
01461        ClearCode = 0;
01462        EOFCode = 0;
01463        free_ent = 0;
01464        clear_flg = 0;
01465        offset = 0;
01466        in_count = 1;
01467        out_count = 0;       
01468        hsize = HSIZE;
01469        n_bits = 0;
01470        maxbits = GIFBITS;
01471        maxcode = 0;
01472        maxmaxcode = (code_int)1 << GIFBITS;
01473 }
01474 
01475 
01476 /* +-------------------------------------------------------------------+ */
01477 /* | Copyright 1990, 1991, 1993, David Koblas.  (koblas@netcom.com)    | */
01478 /* |   Permission to use, copy, modify, and distribute this software   | */
01479 /* |   and its documentation for any purpose and without fee is hereby | */
01480 /* |   granted, provided that the above copyright notice appear in all | */
01481 /* |   copies and that both that copyright notice and this permission  | */
01482 /* |   notice appear in supporting documentation.  This software is    | */
01483 /* |   provided "as is" without express or implied warranty.           | */
01484 /* +-------------------------------------------------------------------+ */
01485 
01486 
01487 #define        MAXCOLORMAPSIZE         256
01488 
01489 #define        TRUE    1
01490 #define        FALSE   0
01491 
01492 #define CM_RED         0
01493 #define CM_GREEN       1
01494 #define CM_BLUE                2
01495 
01496 #define        MAX_LWZ_BITS            12
01497 
01498 #define INTERLACE              0x40
01499 #define LOCALCOLORMAP  0x80
01500 #define BitSet(byte, bit)      (((byte) & (bit)) == (bit))
01501 
01502 #define        ReadOK(file,buffer,len) (fread(buffer, len, 1, file) != 0)
01503 
01504 #define LM_to_uint(a,b)                        (((b)<<8)|(a))
01505 
01506 /* We may eventually want to use this information, but def it out for now */
01507 #if 0
01508 static struct {
01509        unsigned int    Width;
01510        unsigned int    Height;
01511        unsigned char   ColorMap[3][MAXCOLORMAPSIZE];
01512        unsigned int    BitPixel;
01513        unsigned int    ColorResolution;
01514        unsigned int    Background;
01515        unsigned int    AspectRatio;
01516 } GifScreen;
01517 #endif
01518 
01519 static struct {
01520        int     transparent;
01521        int     delayTime;
01522        int     inputFlag;
01523        int     disposal;
01524 } Gif89 = { -1, -1, -1, 0 };
01525 
01526 static int ReadColorMap (FILE *fd, int number, unsigned char (*buffer)[256]);
01527 static int DoExtension (FILE *fd, int label, int *Transparent);
01528 static int GetDataBlock (FILE *fd, unsigned char *buf);
01529 static int GetCode (FILE *fd, int code_size, int flag);
01530 static int LWZReadByte (FILE *fd, int flag, int input_code_size);
01531 static void ReadImage (gdImagePtr im, FILE *fd, int len, int height, unsigned char (*cmap)[256], int interlace, int ignore);
01532 
01533 int ZeroDataBlock;
01534 
01535 gdImagePtr
01536 gdImageCreateFromGif(FILE *fd)
01537 {
01538        int imageNumber;
01539        int BitPixel;
01540        int ColorResolution;
01541        int Background;
01542        int AspectRatio;
01543        int Transparent = (-1);
01544        unsigned char   buf[16];
01545        unsigned char   c;
01546        unsigned char   ColorMap[3][MAXCOLORMAPSIZE];
01547        unsigned char   localColorMap[3][MAXCOLORMAPSIZE];
01548        int             imw, imh;
01549        int             useGlobalColormap;
01550        int             bitPixel;
01551        int             imageCount = 0;
01552        char            version[4];
01553        gdImagePtr im = 0;
01554        ZeroDataBlock = FALSE;
01555 
01556        imageNumber = 1;
01557        if (! ReadOK(fd,buf,6)) {
01558               return 0;
01559        }
01560        if (strncmp((char *)buf,"GIF",3) != 0) {
01561               return 0;
01562        }
01563        strncpy(version, (char *)buf + 3, 3);
01564        version[3] = '\0';
01565 
01566        if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
01567               return 0;
01568        }
01569        if (! ReadOK(fd,buf,7)) {
01570               return 0;
01571        }
01572        BitPixel        = 2<<(buf[4]&0x07);
01573        ColorResolution = (int) (((buf[4]&0x70)>>3)+1);
01574        Background      = buf[5];
01575        AspectRatio     = buf[6];
01576 
01577        if (BitSet(buf[4], LOCALCOLORMAP)) {    /* Global Colormap */
01578                if (ReadColorMap(fd, BitPixel, ColorMap)) {
01579                      return 0;
01580               }
01581        }
01582        for (;;) {
01583                if (! ReadOK(fd,&c,1)) {
01584                        return 0;
01585                }
01586                if (c == ';') {         /* GIF terminator */
01587                        int i;
01588                        if (imageCount < imageNumber) {
01589                                return 0;
01590                        }
01591                        /* Terminator before any image was declared! */
01592                        if (!im) {
01593                               return 0;
01594                        }
01595                      /* Check for open colors at the end, so
01596                           we can reduce colorsTotal and ultimately
01597                           BitsPerPixel */
01598                        for (i=((im->colorsTotal-1)); (i>=0); i--) {
01599                                if (im->open[i]) {
01600                                        im->colorsTotal--;
01601                                } else {
01602                                        break;
01603                                }
01604                        } 
01605                        return im;
01606                }
01607 
01608                if (c == '!') {         /* Extension */
01609                        if (! ReadOK(fd,&c,1)) {
01610                                return 0;
01611                        }
01612                        DoExtension(fd, c, &Transparent);
01613                        continue;
01614                }
01615 
01616                if (c != ',') {         /* Not a valid start character */
01617                        continue;
01618                }
01619 
01620                ++imageCount;
01621 
01622                if (! ReadOK(fd,buf,9)) {
01623                       return 0;
01624                }
01625 
01626                useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP);
01627 
01628                bitPixel = 1<<((buf[8]&0x07)+1);
01629 
01630                imw = LM_to_uint(buf[4],buf[5]);
01631                imh = LM_to_uint(buf[6],buf[7]);
01632               if (!(im = gdImageCreate(imw, imh))) {
01633                       return 0;
01634               }
01635                im->interlace = BitSet(buf[8], INTERLACE);
01636                if (! useGlobalColormap) {
01637                        if (ReadColorMap(fd, bitPixel, localColorMap)) { 
01638                                  return 0;
01639                        }
01640                        ReadImage(im, fd, imw, imh, localColorMap, 
01641                                  BitSet(buf[8], INTERLACE), 
01642                                  imageCount != imageNumber);
01643                } else {
01644                        ReadImage(im, fd, imw, imh,
01645                                  ColorMap, 
01646                                  BitSet(buf[8], INTERLACE), 
01647                                  imageCount != imageNumber);
01648                }
01649                if (Transparent != (-1)) {
01650                        gdImageColorTransparent(im, Transparent);
01651                }        
01652        }
01653 }
01654 
01655 static int
01656 ReadColorMap(FILE *fd, int number, unsigned char (*buffer)[256])
01657 {
01658        int             i;
01659        unsigned char   rgb[3];
01660 
01661 
01662        for (i = 0; i < number; ++i) {
01663                if (! ReadOK(fd, rgb, sizeof(rgb))) {
01664                        return TRUE;
01665                }
01666                buffer[CM_RED][i] = rgb[0] ;
01667                buffer[CM_GREEN][i] = rgb[1] ;
01668                buffer[CM_BLUE][i] = rgb[2] ;
01669        }
01670 
01671 
01672        return FALSE;
01673 }
01674 
01675 static int
01676 DoExtension(FILE *fd, int label, int *Transparent)
01677 {
01678        static unsigned char     buf[256];
01679 
01680        switch (label) {
01681        case 0xf9:              /* Graphic Control Extension */
01682                (void) GetDataBlock(fd, (unsigned char*) buf);
01683                Gif89.disposal    = (buf[0] >> 2) & 0x7;
01684                Gif89.inputFlag   = (buf[0] >> 1) & 0x1;
01685                Gif89.delayTime   = LM_to_uint(buf[1],buf[2]);
01686                if ((buf[0] & 0x1) != 0)
01687                        *Transparent = buf[3];
01688 
01689                while (GetDataBlock(fd, (unsigned char*) buf) != 0)
01690                        ;
01691                return FALSE;
01692        default:
01693                break;
01694        }
01695        while (GetDataBlock(fd, (unsigned char*) buf) != 0)
01696                ;
01697 
01698        return FALSE;
01699 }
01700 
01701 static int
01702 GetDataBlock(FILE *fd, unsigned char *buf)
01703 {
01704        unsigned char   count;
01705 
01706        if (! ReadOK(fd,&count,1)) {
01707                return -1;
01708        }
01709 
01710        ZeroDataBlock = count == 0;
01711 
01712        if ((count != 0) && (! ReadOK(fd, buf, count))) {
01713                return -1;
01714        }
01715 
01716        return count;
01717 }
01718 
01719 static int
01720 GetCode(FILE *fd, int code_size, int flag)
01721 {
01722        static unsigned char    buf[280];
01723        static int              curbit, lastbit, done, last_byte;
01724        int                     i, j, ret;
01725        unsigned char           count;
01726 
01727        if (flag) {
01728                curbit = 0;
01729                lastbit = 0;
01730                done = FALSE;
01731                return 0;
01732        }
01733 
01734        if ( (curbit+code_size) >= lastbit) {
01735                if (done) {
01736                        if (curbit >= lastbit) {
01737                                 /* Oh well */
01738                        }                        
01739                        return -1;
01740                }
01741                buf[0] = buf[last_byte-2];
01742                buf[1] = buf[last_byte-1];
01743 
01744                if ((count = GetDataBlock(fd, &buf[2])) == 0)
01745                        done = TRUE;
01746 
01747                last_byte = 2 + count;
01748                curbit = (curbit - lastbit) + 16;
01749                lastbit = (2+count)*8 ;
01750        }
01751 
01752        ret = 0;
01753        for (i = curbit, j = 0; j < code_size; ++i, ++j)
01754                ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
01755 
01756        curbit += code_size;
01757 
01758        return ret;
01759 }
01760 
01761 static int
01762 LWZReadByte(FILE *fd, int flag, int input_code_size)
01763 {
01764        static int      fresh = FALSE;
01765        int             code, incode;
01766        static int      code_size, set_code_size;
01767        static int      max_code, max_code_size;
01768        static int      firstcode, oldcode;
01769        static int      clear_code, end_code;
01770        static int      table[2][(1<< MAX_LWZ_BITS)];
01771        static int      stack[(1<<(MAX_LWZ_BITS))*2], *sp;
01772        register int    i;
01773 
01774        if (flag) {
01775                set_code_size = input_code_size;
01776                code_size = set_code_size+1;
01777                clear_code = 1 << set_code_size ;
01778                end_code = clear_code + 1;
01779                max_code_size = 2*clear_code;
01780                max_code = clear_code+2;
01781 
01782                GetCode(fd, 0, TRUE);
01783                
01784                fresh = TRUE;
01785 
01786                for (i = 0; i < clear_code; ++i) {
01787                        table[0][i] = 0;
01788                        table[1][i] = i;
01789                }
01790                for (; i < (1<<MAX_LWZ_BITS); ++i)
01791                        table[0][i] = table[1][0] = 0;
01792 
01793                sp = stack;
01794 
01795                return 0;
01796        } else if (fresh) {
01797                fresh = FALSE;
01798                do {
01799                        firstcode = oldcode =
01800                                GetCode(fd, code_size, FALSE);
01801                } while (firstcode == clear_code);
01802                return firstcode;
01803        }
01804 
01805        if (sp > stack)
01806                return *--sp;
01807 
01808        while ((code = GetCode(fd, code_size, FALSE)) >= 0) {
01809                if (code == clear_code) {
01810                        for (i = 0; i < clear_code; ++i) {
01811                                table[0][i] = 0;
01812                                table[1][i] = i;
01813                        }
01814                        for (; i < (1<<MAX_LWZ_BITS); ++i)
01815                                table[0][i] = table[1][i] = 0;
01816                        code_size = set_code_size+1;
01817                        max_code_size = 2*clear_code;
01818                        max_code = clear_code+2;
01819                        sp = stack;
01820                        firstcode = oldcode =
01821                                        GetCode(fd, code_size, FALSE);
01822                        return firstcode;
01823                } else if (code == end_code) {
01824                        int             count;
01825                        unsigned char   buf[260];
01826 
01827                        if (ZeroDataBlock)
01828                                return -2;
01829 
01830                        while ((count = GetDataBlock(fd, buf)) > 0)
01831                                ;
01832 
01833                        if (count != 0)
01834                        return -2;
01835                }
01836 
01837                incode = code;
01838 
01839                if (code >= max_code) {
01840                        *sp++ = firstcode;
01841                        code = oldcode;
01842                }
01843 
01844                while (code >= clear_code) {
01845                        *sp++ = table[1][code];
01846                        if (code == table[0][code]) {
01847                                /* Oh well */
01848                        }
01849                        code = table[0][code];
01850                }
01851 
01852                *sp++ = firstcode = table[1][code];
01853 
01854                if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
01855                        table[0][code] = oldcode;
01856                        table[1][code] = firstcode;
01857                        ++max_code;
01858                        if ((max_code >= max_code_size) &&
01859                                (max_code_size < (1<<MAX_LWZ_BITS))) {
01860                                max_code_size *= 2;
01861                                ++code_size;
01862                        }
01863                }
01864 
01865                oldcode = incode;
01866 
01867                if (sp > stack)
01868                        return *--sp;
01869        }
01870        return code;
01871 }
01872 
01873 static void
01874 ReadImage(gdImagePtr im, FILE *fd, int len, int height, unsigned char (*cmap)[256], int interlace, int ignore)
01875 {
01876        unsigned char   c;      
01877        int             v;
01878        int             xpos = 0, ypos = 0, pass = 0;
01879        int i;
01880        /* Stash the color map into the image */
01881        for (i=0; (i<gdMaxColors); i++) {
01882                im->red[i] = cmap[CM_RED][i];     
01883                im->green[i] = cmap[CM_GREEN][i]; 
01884                im->blue[i] = cmap[CM_BLUE][i];   
01885                im->open[i] = 1;
01886        }
01887        /* Many (perhaps most) of these colors will remain marked open. */
01888        im->colorsTotal = gdMaxColors;
01889        /*
01890        **  Initialize the Compression routines
01891        */
01892        if (! ReadOK(fd,&c,1)) {
01893                return; 
01894        }
01895        if (LWZReadByte(fd, TRUE, c) < 0) {
01896                return;
01897        }
01898 
01899        /*
01900        **  If this is an "uninteresting picture" ignore it.
01901        */
01902        if (ignore) {
01903                while (LWZReadByte(fd, FALSE, c) >= 0)
01904                        ;
01905                return;
01906        }
01907 
01908        while ((v = LWZReadByte(fd,FALSE,c)) >= 0 ) {
01909                /* This how we recognize which colors are actually used. */
01910                if (im->open[v]) {
01911                        im->open[v] = 0;
01912                }
01913                gdImageSetPixel(im, xpos, ypos, v);
01914                ++xpos;
01915                if (xpos == len) {
01916                        xpos = 0;
01917                        if (interlace) {
01918                                switch (pass) {
01919                                case 0:
01920                                case 1:
01921                                        ypos += 8; break;
01922                                case 2:
01923                                        ypos += 4; break;
01924                                case 3:
01925                                        ypos += 2; break;
01926                                }
01927 
01928                                if (ypos >= height) {
01929                                        ++pass;
01930                                        switch (pass) {
01931                                        case 1:
01932                                                ypos = 4; break;
01933                                        case 2:
01934                                                ypos = 2; break;
01935                                        case 3:
01936                                                ypos = 1; break;
01937                                        default:
01938                                                goto fini;
01939                                        }
01940                                }
01941                        } else {
01942                                ++ypos;
01943                        }
01944                }
01945                if (ypos >= height)
01946                        break;
01947        }
01948 
01949 fini:
01950        if (LWZReadByte(fd,FALSE,c)>=0) {
01951                /* Ignore extra */
01952        }
01953 }
01954 
01955 void gdImageRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
01956 {
01957        gdImageLine(im, x1, y1, x2, y1, color);          
01958        gdImageLine(im, x1, y2, x2, y2, color);          
01959        gdImageLine(im, x1, y1, x1, y2, color);
01960        gdImageLine(im, x2, y1, x2, y2, color);
01961 }
01962 
01963 void gdImageFilledRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
01964 {
01965        int x, y;
01966        for (y=y1; (y<=y2); y++) {
01967               for (x=x1; (x<=x2); x++) {
01968                      gdImageSetPixel(im, x, y, color);
01969               }
01970        }
01971 }
01972 
01973 void gdImageCopy(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h)
01974 {
01975        int c;
01976        int x, y;
01977        int tox, toy;
01978        int i;
01979        int colorMap[gdMaxColors];
01980        for (i=0; (i<gdMaxColors); i++) {
01981               colorMap[i] = (-1);
01982        }
01983        toy = dstY;
01984        for (y=srcY; (y < (srcY + h)); y++) {
01985               tox = dstX;
01986               for (x=srcX; (x < (srcX + w)); x++) {
01987                      int nc;
01988                      c = gdImageGetPixel(src, x, y);
01989                      /* Added 7/24/95: support transparent copies */
01990                      if (gdImageGetTransparent(src) == c) {
01991                             tox++;
01992                             continue;
01993                      }
01994                      /* Have we established a mapping for this color? */
01995                      if (colorMap[c] == (-1)) {
01996                             /* If it's the same image, mapping is trivial */
01997                             if (dst == src) {
01998                                    nc = c;
01999                             } else { 
02000                                    /* First look for an exact match */
02001                                    nc = gdImageColorExact(dst,
02002                                           src->red[c], src->green[c],
02003                                           src->blue[c]);
02004                             }      
02005                             if (nc == (-1)) {
02006                                    /* No, so try to allocate it */
02007                                    nc = gdImageColorAllocate(dst,
02008                                           src->red[c], src->green[c],
02009                                           src->blue[c]);
02010                                    /* If we're out of colors, go for the
02011                                           closest color */
02012                                    if (nc == (-1)) {
02013                                           nc = gdImageColorClosest(dst,
02014                                                  src->red[c], src->green[c],
02015                                                  src->blue[c]);
02016                                    }
02017                             }
02018                             colorMap[c] = nc;
02019                      }
02020                      gdImageSetPixel(dst, tox, toy, colorMap[c]);
02021                      tox++;
02022               }
02023               toy++;
02024        }
02025 }                    
02026 
02027 void gdImageCopyResized(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
02028 {
02029        int c;
02030        int x, y;
02031        int tox, toy;
02032        int ydest;
02033        int i;
02034        int colorMap[gdMaxColors];
02035        /* Stretch vectors */
02036        int *stx;
02037        int *sty;
02038        /* We only need to use floating point to determine the correct
02039               stretch vector for one line's worth. */
02040        double accum;
02041        stx = (int *) malloc(sizeof(int) * srcW);
02042        sty = (int *) malloc(sizeof(int) * srcH);
02043        accum = 0;
02044        for (i=0; (i < srcW); i++) {
02045               int got;
02046               accum += (double)dstW/(double)srcW;
02047               got = floor(accum);
02048               stx[i] = got;
02049               accum -= got;
02050        }
02051        accum = 0;
02052        for (i=0; (i < srcH); i++) {
02053               int got;
02054               accum += (double)dstH/(double)srcH;
02055               got = floor(accum);
02056               sty[i] = got;
02057               accum -= got;
02058        }
02059        for (i=0; (i<gdMaxColors); i++) {
02060               colorMap[i] = (-1);
02061        }
02062        toy = dstY;
02063        for (y=srcY; (y < (srcY + srcH)); y++) {
02064               for (ydest=0; (ydest < sty[y-srcY]); ydest++) {
02065                      tox = dstX;
02066                      for (x=srcX; (x < (srcX + srcW)); x++) {
02067                             int nc;
02068                             if (!stx[x - srcX]) {
02069                                    continue;
02070                             }
02071                             c = gdImageGetPixel(src, x, y);
02072                             /* Added 7/24/95: support transparent copies */
02073                             if (gdImageGetTransparent(src) == c) {
02074                                    tox += stx[x-srcX];
02075                                    continue;
02076                             }
02077                             /* Have we established a mapping for this color? */
02078                             if (colorMap[c] == (-1)) {
02079                                    /* If it's the same image, mapping is trivial */
02080                                    if (dst == src) {
02081                                           nc = c;
02082                                    } else { 
02083                                           /* First look for an exact match */
02084                                           nc = gdImageColorExact(dst,
02085                                                  src->red[c], src->green[c],
02086                                                  src->blue[c]);
02087                                    }      
02088                                    if (nc == (-1)) {
02089                                           /* No, so try to allocate it */
02090                                           nc = gdImageColorAllocate(dst,
02091                                                  src->red[c], src->green[c],
02092                                                  src->blue[c]);
02093                                           /* If we're out of colors, go for the
02094                                                  closest color */
02095                                           if (nc == (-1)) {
02096                                                  nc = gdImageColorClosest(dst,
02097                                                         src->red[c], src->green[c],
02098                                                         src->blue[c]);
02099                                           }
02100                                    }
02101                                    colorMap[c] = nc;
02102                             }
02103                             for (i=0; (i < stx[x - srcX]); i++) {
02104                                    gdImageSetPixel(dst, tox, toy, colorMap[c]);
02105                                    tox++;
02106                             }
02107                      }
02108                      toy++;
02109               }
02110        }
02111        free(stx);
02112        free(sty);
02113 }
02114 
02115 int gdGetWord(int *result, FILE *in)
02116 {
02117        int r;
02118        r = getc(in);
02119        if (r == EOF) {
02120               return 0;
02121        }
02122        *result = r << 8;
02123        r = getc(in); 
02124        if (r == EOF) {
02125               return 0;
02126        }
02127        *result += r;
02128        return 1;
02129 }
02130 
02131 void gdPutWord(int w, FILE *out)
02132 {
02133        putc((unsigned char)(w >> 8), out);
02134        putc((unsigned char)(w & 0xFF), out);
02135 }
02136 
02137 int gdGetByte(int *result, FILE *in)
02138 {
02139        int r;
02140        r = getc(in);
02141        if (r == EOF) {
02142               return 0;
02143        }
02144        *result = r;
02145        return 1;
02146 }
02147 
02148 gdImagePtr gdImageCreateFromGd(FILE *in)
02149 {
02150        int sx, sy;
02151        int x, y;
02152        int i;
02153        gdImagePtr im;
02154        if (!gdGetWord(&sx, in)) {
02155               goto fail1;
02156        }
02157        if (!gdGetWord(&sy, in)) {
02158               goto fail1;
02159        }
02160        im = gdImageCreate(sx, sy);
02161        if (!gdGetByte(&im->colorsTotal, in)) {
02162               goto fail2;
02163        }
02164        if (!gdGetWord(&im->transparent, in)) {
02165               goto fail2;
02166        }
02167        if (im->transparent == 257) {
02168               im->transparent = (-1);
02169        }
02170        for (i=0; (i<gdMaxColors); i++) {
02171               if (!gdGetByte(&im->red[i], in)) {
02172                      goto fail2;
02173               }
02174               if (!gdGetByte(&im->green[i], in)) {
02175                      goto fail2;
02176               }
02177               if (!gdGetByte(&im->blue[i], in)) {
02178                      goto fail2;
02179               }
02180        }      
02181        for (y=0; (y<sy); y++) {
02182               for (x=0; (x<sx); x++) {    
02183                      int ch;
02184                      ch = getc(in);
02185                      if (ch == EOF) {
02186                             gdImageDestroy(im);
02187                             return 0;
02188                      }
02189                      im->pixels[x][y] = ch;
02190               }
02191        }
02192        return im;
02193 fail2:
02194        gdImageDestroy(im);
02195 fail1:
02196        return 0;
02197 }
02198        
02199 void gdImageGd(gdImagePtr im, FILE *out)
02200 {
02201        int x, y;
02202        int i;
02203        int trans;
02204        gdPutWord(im->sx, out);
02205        gdPutWord(im->sy, out);
02206        putc((unsigned char)im->colorsTotal, out);
02207        trans = im->transparent;
02208        if (trans == (-1)) {
02209               trans = 257;
02210        }      
02211        gdPutWord(trans, out);
02212        for (i=0; (i<gdMaxColors); i++) {
02213               putc((unsigned char)im->red[i], out);
02214               putc((unsigned char)im->green[i], out);   
02215               putc((unsigned char)im->blue[i], out);    
02216        }
02217        for (y=0; (y < im->sy); y++) {     
02218               for (x=0; (x < im->sx); x++) {     
02219                      putc((unsigned char)im->pixels[x][y], out);
02220               }
02221        }
02222 }
02223 
02224 gdImagePtr
02225 gdImageCreateFromXbm(FILE *fd)
02226 {
02227        gdImagePtr im;       
02228        int bit;
02229        int w, h;
02230        int bytes;
02231        int ch;
02232        int i, x, y;
02233        char *sp;
02234        char s[161];
02235        if (!fgets(s, 160, fd)) {
02236               return 0;
02237        }
02238        sp = &s[0];
02239        /* Skip #define */
02240        sp = strchr(sp, ' ');
02241        if (!sp) {
02242               return 0;
02243        }
02244        /* Skip width label */
02245        sp++;
02246        sp = strchr(sp, ' ');
02247        if (!sp) {
02248               return 0;
02249        }
02250        /* Get width */
02251        w = atoi(sp + 1);
02252        if (!w) {
02253               return 0;
02254        }
02255        if (!fgets(s, 160, fd)) {
02256               return 0;
02257        }
02258        sp = s;
02259        /* Skip #define */
02260        sp = strchr(sp, ' ');
02261        if (!sp) {
02262               return 0;
02263        }
02264        /* Skip height label */
02265        sp++;
02266        sp = strchr(sp, ' ');
02267        if (!sp) {
02268               return 0;
02269        }
02270        /* Get height */
02271        h = atoi(sp + 1);
02272        if (!h) {
02273               return 0;
02274        }
02275        /* Skip declaration line */
02276        if (!fgets(s, 160, fd)) {
02277               return 0;
02278        }
02279        bytes = (w * h / 8) + 1;
02280        im = gdImageCreate(w, h);
02281        gdImageColorAllocate(im, 255, 255, 255);
02282        gdImageColorAllocate(im, 0, 0, 0);
02283        x = 0;
02284        y = 0;
02285        for (i=0; (i < bytes); i++) {
02286               char h[3];
02287               int b;
02288               /* Skip spaces, commas, CRs, 0x */
02289               while(1) {
02290                      ch = getc(fd);
02291                      if (ch == EOF) {
02292                             goto fail;
02293                      }
02294                      if (ch == 'x') {
02295                             break;
02296                      }      
02297               }
02298               /* Get hex value */
02299               ch = getc(fd);
02300               if (ch == EOF) {
02301                      goto fail;
02302               }
02303               h[0] = ch;
02304               ch = getc(fd);
02305               if (ch == EOF) {
02306                      goto fail;
02307               }
02308               h[1] = ch;
02309               h[2] = '\0';
02310               sscanf(h, "%x", &b);        
02311               for (bit = 1; (bit <= 128); (bit = bit << 1)) {
02312                      gdImageSetPixel(im, x++, y, (b & bit) ? 1 : 0);  
02313                      if (x == im->sx) {
02314                             x = 0;
02315                             y++;
02316                             if (y == im->sy) {
02317                                    return im;
02318                             }
02319                             /* Fix 8/8/95 */
02320                             break;
02321                      }
02322               }
02323        }
02324        /* Shouldn't happen */
02325        fprintf(stderr, "Error: bug in gdImageCreateFromXbm!\n");
02326        return 0;
02327 fail:
02328        gdImageDestroy(im);
02329        return 0;
02330 }
02331 
02332 void gdImagePolygon(gdImagePtr im, gdPointPtr p, int n, int c)
02333 {
02334        int i;
02335        int lx, ly;
02336        if (!n) {
02337               return;
02338        }
02339        lx = p->x;
02340        ly = p->y;
02341        gdImageLine(im, lx, ly, p[n-1].x, p[n-1].y, c);
02342        for (i=1; (i < n); i++) {
02343               p++;
02344               gdImageLine(im, lx, ly, p->x, p->y, c);
02345               lx = p->x;
02346               ly = p->y;
02347        }
02348 }      
02349        
02350 int gdCompareInt(const void *a, const void *b);
02351        
02352 void gdImageFilledPolygon(gdImagePtr im, gdPointPtr p, int n, int c)
02353 {
02354        int i;
02355        int y;
02356        int y1, y2;
02357        int ints;
02358        if (!n) {
02359               return;
02360        }
02361        if (!im->polyAllocated) {
02362               im->polyInts = (int *) malloc(sizeof(int) * n);
02363               im->polyAllocated = n;
02364        }             
02365        if (im->polyAllocated < n) {
02366               while (im->polyAllocated < n) {
02367                      im->polyAllocated *= 2;
02368               }      
02369               im->polyInts = (int *) realloc(im->polyInts,
02370                      sizeof(int) * im->polyAllocated);
02371        }
02372        y1 = p[0].y;
02373        y2 = p[0].y;
02374        for (i=1; (i < n); i++) {
02375               if (p[i].y < y1) {
02376                      y1 = p[i].y;
02377               }
02378               if (p[i].y > y2) {
02379                      y2 = p[i].y;
02380               }
02381        }
02382        for (y=y1; (y <= y2); y++) {
02383               int interLast = 0;
02384               int dirLast = 0;
02385               int interFirst = 1;
02386               ints = 0;
02387               for (i=0; (i <= n); i++) {
02388                      int x1, x2;
02389                      int y1, y2;
02390                      int dir;
02391                      int ind1, ind2;
02392                      int lastInd1 = 0;
02393                      if ((i == n) || (!i)) {
02394                             ind1 = n-1;
02395                             ind2 = 0;
02396                      } else {
02397                             ind1 = i-1;
02398                             ind2 = i;
02399                      }
02400                      y1 = p[ind1].y;
02401                      y2 = p[ind2].y;
02402                      if (y1 < y2) {
02403                             y1 = p[ind1].y;
02404                             y2 = p[ind2].y;
02405                             x1 = p[ind1].x;
02406                             x2 = p[ind2].x;
02407                             dir = -1;
02408                      } else if (y1 > y2) {
02409                             y2 = p[ind1].y;
02410                             y1 = p[ind2].y;
02411                             x2 = p[ind1].x;
02412                             x1 = p[ind2].x;
02413                             dir = 1;
02414                      } else {
02415                             /* Horizontal; just draw it */
02416                             gdImageLine(im, 
02417                                    p[ind1].x, y1, 
02418                                    p[ind2].x, y1,
02419                                    c);
02420                             continue;
02421                      }
02422                      if ((y >= y1) && (y <= y2)) {
02423                             int inter = 
02424                                    (y-y1) * (x2-x1) / (y2-y1) + x1;
02425                             /* Only count intersections once
02426                                    except at maxima and minima. Also, 
02427                                    if two consecutive intersections are
02428                                    endpoints of the same horizontal line
02429                                    that is not at a maxima or minima, 
02430                                    discard the leftmost of the two. */
02431                             if (!interFirst) {
02432                                    if ((p[ind1].y == p[lastInd1].y) &&
02433                                           (p[ind1].x != p[lastInd1].x)) {
02434                                           if (dir == dirLast) {
02435                                                  if (inter > interLast) {
02436                                                         /* Replace the old one */
02437                                                         im->polyInts[ints] = inter;
02438                                                  } else {
02439                                                         /* Discard this one */
02440                                                  }      
02441                                                  continue;
02442                                           }
02443                                    }
02444                                    if (inter == interLast) {
02445                                           if (dir == dirLast) {
02446                                                  continue;
02447                                           }
02448                                    }
02449                             } 
02450                             if (i > 0) {
02451                                    im->polyInts[ints++] = inter;
02452                             }
02453                             lastInd1 = i;
02454                             dirLast = dir;
02455                             interLast = inter;
02456                             interFirst = 0;
02457                      }
02458               }
02459               qsort(im->polyInts, ints, sizeof(int), gdCompareInt);
02460               for (i=0; (i < (ints-1)); i+=2) {
02461                      gdImageLine(im, im->polyInts[i], y,
02462                             im->polyInts[i+1], y, c);
02463               }
02464        }
02465 }
02466        
02467 int gdCompareInt(const void *a, const void *b)
02468 {
02469        return (*(const int *)a) - (*(const int *)b);
02470 }
02471 
02472 void gdImageSetStyle(gdImagePtr im, int *style, int noOfPixels)
02473 {
02474        if (im->style) {
02475               free(im->style);
02476        }
02477        im->style = (int *) 
02478               malloc(sizeof(int) * noOfPixels);
02479        memcpy(im->style, style, sizeof(int) * noOfPixels);
02480        im->styleLength = noOfPixels;
02481        im->stylePos = 0;
02482 }
02483 
02484 void gdImageSetBrush(gdImagePtr im, gdImagePtr brush)
02485 {
02486        int i;
02487        im->brush = brush;
02488        for (i=0; (i < gdImageColorsTotal(brush)); i++) {
02489               int index;
02490               index = gdImageColorExact(im, 
02491                      gdImageRed(brush, i),
02492                      gdImageGreen(brush, i),
02493                      gdImageBlue(brush, i));
02494               if (index == (-1)) {
02495                      index = gdImageColorAllocate(im,
02496                             gdImageRed(brush, i),
02497                             gdImageGreen(brush, i),
02498                             gdImageBlue(brush, i));
02499                      if (index == (-1)) {
02500                             index = gdImageColorClosest(im,
02501                                    gdImageRed(brush, i),
02502                                    gdImageGreen(brush, i),
02503                                    gdImageBlue(brush, i));
02504                      }
02505               }
02506               im->brushColorMap[i] = index;
02507        }
02508 }
02509        
02510 void gdImageSetTile(gdImagePtr im, gdImagePtr tile)
02511 {
02512        int i;
02513        im->tile = tile;
02514        for (i=0; (i < gdImageColorsTotal(tile)); i++) {
02515               int index;
02516               index = gdImageColorExact(im, 
02517                      gdImageRed(tile, i),
02518                      gdImageGreen(tile, i),
02519                      gdImageBlue(tile, i));
02520               if (index == (-1)) {
02521                      index = gdImageColorAllocate(im,
02522                             gdImageRed(tile, i),
02523                             gdImageGreen(tile, i),
02524                             gdImageBlue(tile, i));
02525                      if (index == (-1)) {
02526                             index = gdImageColorClosest(im,
02527                                    gdImageRed(tile, i),
02528                                    gdImageGreen(tile, i),
02529                                    gdImageBlue(tile, i));
02530                      }
02531               }
02532               im->tileColorMap[i] = index;
02533        }
02534 }
02535 
02536 void gdImageInterlace(gdImagePtr im, int interlaceArg)
02537 {
02538        im->interlace = interlaceArg;
02539 }
02540