gd.c

Go to the documentation of this file.
00001 #include <stdio.h>
00002 #include <math.h>
00003 #include <string.h>
00004 #include <stdlib.h>
00005 #include "gd.h"
00006 
00007 #include "../../../../libs/MALLOC/includes/MALLOC.h"
00008 #include "mtables.c"
00009 
00010 #define Min(x,y)        (((x)<(y))?(x):(y))
00011 #define Max(x,y)        (((x)>(y))?(x):(y))
00012 /* MONO returns total intensity of r,g,b components */
00013 #define MONO(rd,gn,bl) (((rd)*11 + (gn)*16 + (bl)*5) >> 5)  /*.33R+ .5G+ .17B*/
00014 
00015 static void gdImageBrushApply __PARAMS((gdImagePtr im, int x, int y));
00016 static void gdImageTileApply __PARAMS((gdImagePtr im, int x, int y));
00017 
00018 
00019 /*SG modified to add alu modes and clipping fiels */
00020 gdImagePtr gdImageCreate(sx, sy)
00021      int sx;
00022      int sy;
00023 {
00024         int i;
00025         gdImagePtr im;
00026         im = (gdImage *) MALLOC(sizeof(gdImage));
00027         /* NOW ROW-MAJOR IN GD 1.3 */
00028         im->pixels = (unsigned char **) MALLOC(sizeof(unsigned char *) * sy);
00029         im->polyInts = 0;
00030         im->polyAllocated = 0;
00031         im->brush = 0;
00032         im->tile = 0;
00033         im->style = 0;
00034         for (i=0; (i<sy); i++) {
00035                 /* NOW ROW-MAJOR IN GD 1.3 */
00036                 im->pixels[i] = (unsigned char *) CALLOC(
00037                         sx, sizeof(unsigned char));
00038         }       
00039         im->sx = sx;
00040         im->sy = sy;
00041         for (i=0;i<gdMaxColors;i++)
00042           im->open[i]=1;
00043         im->colorsTotal = 0;
00044         im->transparent = (-1);
00045         im->interlace = 0;
00046         /* modification to add alu and clipping */
00047         im->alu = 3;
00048         im->clipping = 0;
00049         im->cliprect[0] = 0; /* xmin */
00050         im->cliprect[1] = 0; /* ymin */
00051         im->cliprect[2] = sx; /* xmax */
00052         im->cliprect[3] = sy; /* ymax */
00053         return im;
00054 }
00055 
00056 void gdImageDestroy(im)
00057      gdImagePtr im;
00058 {
00059         int i;
00060         for (i=0; (i<im->sy); i++) {
00061                 FREE(im->pixels[i]);
00062         }       
00063         FREE(im->pixels);
00064         if (im->polyInts) {
00065                         FREE(im->polyInts);
00066         }
00067         if (im->style) {
00068                 FREE(im->style);
00069         }
00070         FREE(im);
00071 }
00072 
00073 int gdImageColorClosest(im, r, g, b)
00074      gdImagePtr im;
00075      int r;
00076      int g;
00077      int b;
00078 {
00079         int i;
00080         long rd, gd, bd;
00081         int ct = (-1);
00082         long mindist = 0;
00083         for (i=0; (i<(im->colorsTotal)); i++) {
00084                 long dist;
00085                 if (im->open[i]) {
00086                         continue;
00087                 }
00088                 rd = (im->red[i] - r);  
00089                 gd = (im->green[i] - g);
00090                 bd = (im->blue[i] - b);
00091                 dist = rd * rd + gd * gd + bd * bd;
00092                 if ((i == 0) || (dist < mindist)) {
00093                         mindist = dist; 
00094                         ct = i;
00095                 }
00096         }
00097         return ct;
00098 }
00099 
00100 int gdImageColorExact(im, r, g, b)
00101      gdImagePtr im;
00102      int r;
00103      int g;
00104      int b;
00105 {
00106         int i;
00107         for (i=0; (i<(im->colorsTotal)); i++) {
00108                 if (im->open[i]) {
00109                         continue;
00110                 }
00111                 if ((im->red[i] == r) && 
00112                         (im->green[i] == g) &&
00113                         (im->blue[i] == b)) {
00114                         return i;
00115                 }
00116         }
00117         return -1;
00118 }
00119 
00120 int gdImageColorAllocate(im, r, g, b)
00121      gdImagePtr im;
00122      int r;
00123      int g;
00124      int b;
00125 {
00126         int i;
00127         int ct = (-1);
00128         for (i=0; (i<(im->colorsTotal)); i++) {
00129                 if (im->open[i]) {
00130                         ct = i;
00131                         break;
00132                 }
00133         }       
00134         if (ct == (-1)) {
00135                 ct = im->colorsTotal;
00136                 if (ct == gdMaxColors) {
00137                         return -1;
00138                 }
00139                 im->colorsTotal++;
00140         }
00141         im->red[ct] = r;
00142         im->green[ct] = g;
00143         im->blue[ct] = b;
00144         im->open[ct] = 0;
00145         return ct;
00146 }
00147 
00148 void gdImageColorDeallocate(im, color)
00149      gdImagePtr im;
00150      int color;
00151 {
00152         /* Mark it open. */
00153         im->open[color] = 1;
00154 }
00155 
00156 void gdImageColorTransparent(im, color)
00157      gdImagePtr im;
00158      int color;
00159 {
00160         im->transparent = color;
00161 }
00162 
00163 /*SG gdSetClipping and gdUnsetClipping have been added to handle clipping */
00164 void gdSetClipping(im, xmin, ymin, xmax, ymax)
00165      gdImagePtr im;
00166      int xmin;
00167      int ymin;
00168      int xmax;
00169      int ymax;
00170 {
00171         im->clipping = 1;
00172         im->cliprect[0] = xmin; /* xmin */
00173         im->cliprect[1] = ymin; /* ymin */
00174         im->cliprect[2] = xmax; /* xmax */
00175         im->cliprect[3] = ymax; /* ymax */
00176 }
00177 
00178 void gdUnsetClipping(im)
00179      gdImagePtr im;
00180 {
00181         im->clipping = 0;
00182 }
00183 /*SG gdSetAlu and gdAluColor have been added to handle alu modes */
00184 void gdSetAlu(im, alu)
00185      gdImagePtr im;
00186      int alu;
00187 {
00188         im->alu = alu;
00189 }
00190 
00191 int gdAluColor(im, dst, src)
00192      gdImagePtr im;
00193      int dst;
00194      int src;
00195 {
00196 int new;
00197 unsigned char r, g, b, rd, gd, bd, rs, gs, bs;
00198 
00199  switch (im->alu) {
00200  case 0: /* clear */
00201    return 0;
00202  case 3: /* src */
00203    return src;
00204  case 5: /* dst */
00205    return dst;
00206  }
00207  rd =  ~(unsigned char)im->red[dst];
00208  gd  =  ~(unsigned char)im->green[dst];
00209  bd  =  ~(unsigned char)im->blue[dst];
00210 
00211  rs =  ~(unsigned char)im->red[src];
00212  gs  =  ~(unsigned char)im->green[src];
00213  bs  =  ~(unsigned char)im->blue[src];
00214 
00215  switch (im->alu) {
00216  case 1: /* src AND dst */
00217    r = rs & rd;
00218    g = gs & gd;
00219    b = bs & bd;
00220    break;
00221  case 2: /* src AND NOT dst */
00222    r = rs & ~rd;
00223    g = gs & ~gd;
00224    b = bs & ~bd;
00225    break;
00226  case 4: /* NOT src AND dst */
00227    r = ~rs & rd;
00228    g = ~gs & gd;
00229    b = ~bs & bd;
00230    break;
00231  case 5: /* dst */
00232    return dst;
00233  case 6: /* src XOR dst */
00234    r = rs ^ rd;
00235    g = gs ^ gd;
00236    b = bs ^ bd;
00237    break;
00238  case 7: /* src OR dst */
00239    r = rs | rd;
00240    g = gs | gd;
00241    b = bs | bd;
00242    break;
00243  case 8: /*NOT src AND NOT dst */
00244    r = ~rs &  ~rd;
00245    g = ~gs &  ~gd;
00246    b = ~bs &  ~bd;
00247    break;
00248  case 9: /*NOT src XOR dst */
00249    r = ~rs ^ rd;
00250    g = ~gs ^ gd;
00251    b = ~bs ^ bd;
00252    break;
00253  case 10: /* NOT dst */
00254    r =~rd;
00255    g =~gd;
00256    b =~bd;
00257    break;
00258  case 11: /*src OR NOT dst */
00259    r = rs | ~rd;
00260    g = gs | ~gd;
00261    b = bs | ~bd;
00262    break;
00263  case 12: /* NOT src */
00264    r = ~rs;
00265    g = ~gs ;
00266    b = ~bs; 
00267    break;
00268  case 13: /* NOT src OR dst */
00269    r = ~rs | rd;
00270    g = ~gs | gd;
00271    b = ~bs | bd;
00272    break;
00273  case 14: /* NOT src OR NOT dst */
00274    r = ~rs  | ~rd;
00275    g = ~gs | ~gd;
00276    b = ~bs | ~bd;
00277    break;
00278  case 15: /* 1 */
00279    r = 0;
00280    g = 0;
00281    b = 0;
00282    break;
00283  }
00284  r = ~r;
00285  g = ~g;
00286  b = ~b;
00287  new = gdImageColorExact(im, (int)r, (int)g, (int)b);
00288  if (new==-1) 
00289    new = gdImageColorAllocate(im, (int)r, (int)g, (int)b);
00290  if (new==-1) 
00291    new = gdImageColorClosest(im, (int)r, (int)g, (int)b);
00292  return new;
00293 }
00294 
00295 void gdSetBackground(im, background)
00296      gdImagePtr im;
00297      int background;
00298 {
00299         im->background = background;
00300 }
00301 /*SG gdImageSetPixel modified to handle alu modes */
00302 void gdImageSetPixel(im, x, y, color)
00303      gdImagePtr im;
00304      int x;
00305      int y;
00306      int color;
00307 {
00308         int p;
00309 
00310         switch(color) {
00311                 case gdStyled:
00312                 if (!im->style) {
00313                         /* Refuse to draw if no style is set. */
00314                         return;
00315                 } else {
00316                         p = im->style[im->stylePos++];
00317                 }
00318                 if (p != (gdTransparent)) {
00319                         gdImageSetPixel(im, x, y, p);
00320                 }
00321                 im->stylePos = im->stylePos %  im->styleLength;
00322                 break;
00323                 case gdStyledBrushed:
00324                 if (!im->style) {
00325                         /* Refuse to draw if no style is set. */
00326                         return;
00327                 }
00328                 p = im->style[im->stylePos++];
00329                 if ((p != gdTransparent) && (p != 0)) {
00330                         gdImageSetPixel(im, x, y, gdBrushed);
00331                 }
00332                 im->stylePos = im->stylePos %  im->styleLength;
00333                 break;
00334                 case gdBrushed:
00335                 gdImageBrushApply(im, x, y);
00336                 break;
00337                 case gdTiled:
00338                 gdImageTileApply(im, x, y);
00339                 break;
00340                 default:
00341                 if (gdImageBoundsSafe(im, x, y)) {
00342                   /* NOW ROW-MAJOR IN GD 1.3 */
00343                   /*SG modified here to handle alu modes */
00344                   im->pixels[y][x] = gdAluColor(im,im->pixels[y][x],color);
00345 
00346                 }
00347                 break;
00348         }
00349 }
00350 
00351 
00352 static void gdImageBrushApply(im, x, y)
00353      gdImagePtr im;
00354      int x;
00355      int y;
00356 {
00357         int lx, ly;
00358         int hy;
00359         int hx;
00360         int x1, y1, x2, y2;
00361         int srcx, srcy;
00362         if (!im->brush) {
00363                 return;
00364         }
00365         hy = gdImageSY(im->brush)/2;
00366         y1 = y - hy;
00367         y2 = y1 + gdImageSY(im->brush); 
00368         hx = gdImageSX(im->brush)/2;
00369         x1 = x - hx;
00370         x2 = x1 + gdImageSX(im->brush);
00371         srcy = 0;
00372         for (ly = y1; (ly < y2); ly++) {
00373                 srcx = 0;
00374                 for (lx = x1; (lx < x2); lx++) {
00375                         int p;
00376                         p = gdImageGetPixel(im->brush, srcx, srcy);
00377                         /* Allow for non-square brushes! */
00378                         if (p != gdImageGetTransparent(im->brush)) {
00379                                 gdImageSetPixel(im, lx, ly,
00380                                         im->brushColorMap[p]);
00381                         }
00382                         srcx++;
00383                 }
00384                 srcy++;
00385         }       
00386 }               
00387 
00388 static void gdImageTileApply(im, x, y)
00389      gdImagePtr im;
00390      int x;
00391      int y;
00392 {
00393         int srcx, srcy;
00394         int p;
00395         if (!im->tile) {
00396                 return;
00397         }
00398         srcx = x % gdImageSX(im->tile);
00399         srcy = y % gdImageSY(im->tile);
00400         p = gdImageGetPixel(im->tile, srcx, srcy);
00401         /* Allow for transparency */
00402         if (p != gdImageGetTransparent(im->tile)) {
00403                 gdImageSetPixel(im, x, y,
00404                         im->tileColorMap[p]);
00405         }
00406 }               
00407 
00408 int gdImageGetPixel(im, x, y)
00409      gdImagePtr im;
00410      int x;
00411      int y;
00412 {
00413         if (gdImageBoundsSafe(im, x, y)) {
00414                 /* NOW ROW-MAJOR IN GD 1.3 */
00415                 return im->pixels[y][x];
00416         } else {
00417                 return 0;
00418         }
00419 }
00420 
00421 /* Bresenham as presented in Foley & Van Dam */
00422 /*SG added function to handle Thick lines with alu modes */
00423 void gdImageThickLine(im, x1, y1, x2, y2, color, thick)
00424      gdImagePtr im;
00425      int x1;
00426      int y1;
00427      int x2;
00428      int y2;
00429      int color;
00430      int thick;
00431 {
00432   int  virtual, c, c1, x, y, oldcmap, mnx, mxx, mny, mxy;
00433   gdImagePtr imv, brush, oldbrush;
00434 
00435   virtual= (im->alu!=3 && im->alu!=0 && im->alu!=5);
00436   if (virtual) {
00437     mnx=Max(0,Min(x1,x2)-thick/2);
00438     mny=Max(0,Min(y1,y2)-thick/2);
00439     mxx=Min(im->sx,Max(x1,x2)+thick/2);
00440     mxy=Min(im->sy,Max(y1,y2)+thick/2);
00441 
00442     imv=gdImageCreate(im->sx, im->sy);
00443     for (y=mny; (y <= mxy ); y++) {     
00444       for (x=mnx; (x <= mxx); x++) {    
00445         imv->pixels[y][x]=0;
00446       }
00447     }
00448     c=1;
00449   }
00450   else {
00451     imv = im;
00452     c = color;
00453   }
00454 
00455   if (thick > 1 && color >= 0) { /* create a square brush */
00456     brush=gdImageCreate(thick, thick);
00457     for (y=0; (y < thick ); y++) {      
00458       for (x=0; (x < thick); x++) {     
00459         brush->pixels[y][x]=c;
00460       }
00461     }
00462     oldbrush = imv->brush;
00463     imv->brush = brush;
00464     oldcmap = imv->brushColorMap[c];
00465     imv->brushColorMap[c] = c;
00466     c1 = c;
00467     c = gdBrushed;
00468   }
00469     gdImageLine(imv,x1, y1, x2, y2, c);
00470 
00471   if (thick > 1 && color >= 0) { /* deallocate square brush */
00472     gdImageDestroy(brush);
00473     imv->brush = oldbrush;
00474     imv->brushColorMap[c1] = oldcmap;
00475   }
00476   if (virtual) {
00477     for (y=mny; (y <= mxy ); y++) {     
00478       for (x=mnx; (x <= mxx); x++) {    
00479         if (imv->pixels[y][x] == 1)
00480           gdImageSetPixel(im, x, y, color);
00481       }
00482     }
00483     gdImageDestroy(imv);
00484   }
00485 
00486 }
00487 
00488 void gdImageLine(im, x1, y1, x2, y2, color)
00489      gdImagePtr im;
00490      int x1;
00491      int y1;
00492      int x2;
00493      int y2;
00494      int color;
00495 {
00496         int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
00497         dx = abs(x2-x1);
00498         dy = abs(y2-y1);
00499         if (dy <= dx) {
00500                 d = 2*dy - dx;
00501                 incr1 = 2*dy;
00502                 incr2 = 2 * (dy - dx);
00503                 if (x1 > x2) {
00504                         x = x2;
00505                         y = y2;
00506                         ydirflag = (-1);
00507                         xend = x1;
00508                 } else {
00509                         x = x1;
00510                         y = y1;
00511                         ydirflag = 1;
00512                         xend = x2;
00513                 }
00514                 gdImageSetPixel(im, x, y, color);
00515                 if (((y2 - y1) * ydirflag) > 0) {
00516                         while (x < xend) {
00517                                 x++;
00518                                 if (d <0) {
00519                                         d+=incr1;
00520                                 } else {
00521                                         y++;
00522                                         d+=incr2;
00523                                 }
00524                                 gdImageSetPixel(im, x, y, color);
00525                         }
00526                 } else {
00527                         while (x < xend) {
00528                                 x++;
00529                                 if (d <0) {
00530                                         d+=incr1;
00531                                 } else {
00532                                         y--;
00533                                         d+=incr2;
00534                                 }
00535                                 gdImageSetPixel(im, x, y, color);
00536                         }
00537                 }               
00538         } else {
00539                 d = 2*dx - dy;
00540                 incr1 = 2*dx;
00541                 incr2 = 2 * (dx - dy);
00542                 if (y1 > y2) {
00543                         y = y2;
00544                         x = x2;
00545                         yend = y1;
00546                         xdirflag = (-1);
00547                 } else {
00548                         y = y1;
00549                         x = x1;
00550                         yend = y2;
00551                         xdirflag = 1;
00552                 }
00553                 gdImageSetPixel(im, x, y, color);
00554                 if (((x2 - x1) * xdirflag) > 0) {
00555                         while (y < yend) {
00556                                 y++;
00557                                 if (d <0) {
00558                                         d+=incr1;
00559                                 } else {
00560                                         x++;
00561                                         d+=incr2;
00562                                 }
00563                                 gdImageSetPixel(im, x, y, color);
00564                         }
00565                 } else {
00566                         while (y < yend) {
00567                                 y++;
00568                                 if (d <0) {
00569                                         d+=incr1;
00570                                 } else {
00571                                         x--;
00572                                         d+=incr2;
00573                                 }
00574                                 gdImageSetPixel(im, x, y, color);
00575                         }
00576                 }
00577         }
00578 }
00579 /*SG added to handle thick polylines along with alu mode */
00580 void gdImagePolyLine(im, X, Y, n, color, thick, close)
00581      gdImagePtr im;
00582      int *X;
00583      int *Y;
00584      int n;
00585      int color;
00586      int thick;
00587      int close;
00588 {
00589   int i;
00590   int x, y;
00591   int virtual, c, c1, mnx, mxx, mny, mxy, oldcmap1;
00592   gdImagePtr imv, brush, oldbrush;
00593   
00594 
00595   virtual= (im->alu!=3 && im->alu!=0 && im->alu!=5);
00596   if (virtual) {
00597     mnx=mxx=X[0];
00598     mny=mxy=Y[0];
00599     for (i=0;i<n;i++) {
00600       mnx=Min(mnx,X[i]);
00601       mny=Min(mny,Y[i]);
00602       mxx=Max(mxx,X[i]);
00603       mxy=Max(mxy,Y[i]);
00604     }
00605     mnx=Max(0,mnx-thick/2);
00606     mny=Max(0,mny-thick/2);
00607     mxx=Min(im->sx,mxx+thick/2);
00608     mxy=Min(im->sy,mxy+thick/2);
00609 
00610     imv=gdImageCreate(im->sx, im->sy);
00611     for (y=mny; (y <= mxy ); y++) {     
00612       for (x=mnx; (x <= mxx); x++) {    
00613         imv->pixels[y][x]=0;
00614       }
00615     }
00616     c=1;
00617   }
00618   else {
00619     imv = im;
00620     c = color;
00621   }
00622 
00623   if (thick > 1 && color >= 0) { /* create a square brush */
00624     brush=gdImageCreate(thick, thick);
00625     for (y=0; (y < thick ); y++) {      
00626       for (x=0; (x < thick); x++) {     
00627         brush->pixels[y][x]=c;
00628       }
00629     }
00630     oldbrush = imv->brush;
00631     imv->brush = brush;
00632     oldcmap1 = imv->brushColorMap[c];
00633     imv->brushColorMap[c] = c;
00634     c1 = c;
00635     c = gdBrushed;
00636   }
00637   for (i=0;i<n-1;i++) 
00638     gdImageLine(imv,X[i],Y[i],X[i+1],Y[i+1],c);
00639 
00640     
00641   if (close) 
00642     gdImageLine(imv,X[n-1],Y[n-1],X[0],Y[0],c);
00643 
00644 
00645   if (thick > 1 && color >= 0) { /* deallocate square brush */
00646     gdImageDestroy(brush);
00647     imv->brush = oldbrush;
00648     imv->brushColorMap[c1] = oldcmap1;
00649   }
00650 
00651   if (virtual) {
00652     for (y=mny; (y <= mxy ); y++) {     
00653       for (x=mnx; (x <= mxx); x++) {    
00654         if (imv->pixels[y][x] == 1)
00655           gdImageSetPixel(im, x, y, color);
00656       }
00657     }
00658     gdImageDestroy(imv);
00659   }
00660 }
00661         
00662 /*SG modified to add clipping region */
00663 int gdImageBoundsSafe(im, x, y)
00664      gdImagePtr im;
00665      int x;
00666      int y;
00667 {
00668   int bounds;
00669 
00670   bounds= (!(((y < 0) || (y >= im->sy)) ||
00671              ((x < 0) || (x >= im->sx))));
00672   /* next lines added to handle clipping region */
00673   if (im->clipping == 1) {
00674 
00675     bounds = bounds & 
00676       (!(((y < im->cliprect[1]) || (y > im->cliprect[3])) ||
00677          ((x < im->cliprect[0]) || (x > im->cliprect[2]))));
00678   }
00679   return bounds;
00680 }
00681 
00682 /*SG gdImageChar has been modified to handle variable width fonts; 
00683    it now returns the position of beginning of the next character */
00684 int gdImageChar(im, f, x, y, c, color)
00685      gdImagePtr im;
00686      gdFontPtr f;
00687      int x;
00688      int y;
00689      int c;
00690      int color;
00691 {
00692         int cx, cy;
00693         int px, py;
00694         int fline;
00695         int mx;
00696         cx = 0;
00697         cy = 0;
00698         mx = x;
00699         if (c == 32)  /* a q & d way to solve bug 1113 (bruno 7 dec 2004) */
00700           return((f->w-2)/3);
00701 
00702         if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
00703                 return(0);
00704         }
00705         fline = (c - f->offset) * f->h * f->w;
00706         for (py = y; (py < (y + f->h)); py++) {
00707                 for (px = x; (px < (x + f->w)); px++) {
00708                         if (f->data[fline + cy * f->w + cx]) {
00709                                 gdImageSetPixel(im, px, py, color);     
00710                                 mx = Max(mx,px+1);
00711                         }
00712                         cx++;
00713                 }
00714                 cx = 0;
00715                 cy++;
00716         }
00717         if (f->fixed) 
00718           return(f->w-2);
00719         else
00720           return(mx-x+1);
00721 }
00722 
00723 /*SG gdCharWidth has been added to compute the effective width of a character */
00724 int gdCharWidth(f, c)
00725      gdFontPtr f;
00726      int c; 
00727 {
00728         int cx, cy;
00729         int px, py;
00730         int fline;
00731         int mx;
00732 
00733         cx = 0;
00734         cy = 0;
00735 
00736         mx = 0;
00737         if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
00738                 return(0);
00739         }
00740         fline = (c - f->offset) * f->h * f->w;
00741         for (py = 0; (py < ( f->h)); py++) {
00742                 for (px = 0; (px < (f->w)); px++) {
00743                         if (f->data[fline + cy * f->w + cx]) {
00744                                 mx = Max(mx,px+1);
00745                         }
00746                         cx++;
00747                 }
00748                 cx = 0;
00749                 cy++;
00750         }
00751         if (f->fixed) 
00752           return(f->w-2);
00753         else
00754           return(mx+1);
00755 }
00756 
00757 /*SG gdImageSymb added for centered symbols */
00758 int gdImageSymb(im, f, x, y, c, color)
00759      gdImagePtr im;
00760      gdFontPtr f;
00761      int x;
00762      int y;
00763      int c;
00764      int color;
00765 {
00766         int cx, cy,xx,yy;
00767         int px, py;
00768         int fline;
00769         int mx;
00770         int w;
00771         if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
00772                 return(0);
00773         }
00774 
00775 
00776         cx = 0;
00777         cy = 0;
00778         mx = x;
00779 
00780         w = gdCharWidth(f,c);
00781         xx=x-w/2;yy=y-f->h/2;
00782         fline = (c - f->offset) * f->h * f->w;
00783         for (py = yy; (py < (yy + f->h)); py++) {
00784                 for (px = xx; (px < (xx + f->w)); px++) {
00785                         if (f->data[fline + cy * f->w + cx]) {
00786                                 gdImageSetPixel(im, px, py, color);     
00787                                 mx = Max(mx,px+1);
00788                         }
00789                         cx++;
00790                 }
00791                 cx = 0;
00792                 cy++;
00793         }
00794         return(1); /* Correction Warning missing return statement at end of non-void function */
00795 }
00796 
00797 
00798 void gdImageCharUp(im, f, x, y, c, color)
00799      gdImagePtr im;
00800      gdFontPtr f;
00801      int x;
00802      int y;
00803      int c;
00804      int color;
00805 {
00806         int cx, cy;
00807         int px, py;
00808         int fline;
00809         int mx;
00810         cx = 0;
00811         cy = 0;
00812         mx = x;
00813         if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
00814                 return;
00815         }
00816         fline = (c - f->offset) * f->h * f->w;
00817         for (py = y; (py > (y - f->w)); py--) {
00818                 for (px = x; (px < (x + f->h)); px++) {
00819                         if (f->data[fline + cy * f->w + cx]) {
00820                                 gdImageSetPixel(im, px, py, color);     
00821                                 mx = Max(mx,px+1);
00822                         }
00823                         cy++;
00824                 }
00825                 cy = 0;
00826                 cx++;
00827         }
00828 }
00829 /*SG gdImageString has been modified to handle variable width fonts */
00830 void gdImageString(im, f, x, y, s, color)
00831      gdImagePtr im;
00832      gdFontPtr f;
00833      int x;
00834      int y;
00835      unsigned char *s;
00836      int color;
00837 {
00838         int i;
00839         int l,dx;
00840         l = strlen((unsigned char *)s);
00841         for (i=0; (i<l); i++) {
00842                 dx = gdImageChar(im, f, x, y, s[i], color);
00843                 /*              x += f->w;*/
00844                 x += dx;
00845         }
00846 }
00847 
00848 void gdImageStringUp(im, f, x, y, s, color)
00849      gdImagePtr im;
00850      gdFontPtr f;
00851      int x;
00852      int y;
00853      unsigned char *s;
00854      int color;
00855 {
00856         int i;
00857         int l;
00858         l = strlen((unsigned char *)s);
00859         for (i=0; (i<l); i++) {
00860                 gdImageCharUp(im, f, x, y, s[i], color);
00861                 y -= f->w;
00862         }
00863 }
00864 
00865 static int strlen16();
00866 
00867 void gdImageString16(im, f, x, y, s, color)
00868      gdImagePtr im;
00869      gdFontPtr f;
00870      int x;
00871      int y;
00872      short unsigned int *s;
00873      int color;
00874 {
00875         int i;
00876         int l;
00877         l = strlen16(s);
00878         for (i=0; (i<l); i++) {
00879                 gdImageChar(im, f, x, y, s[i], color);
00880                 x += f->w;
00881         }
00882 }
00883 
00884 void gdImageStringUp16(im, f, x, y, s, color)
00885      gdImagePtr im;
00886      gdFontPtr f;
00887      int x;
00888      int y;
00889      short unsigned int *s;
00890      int color;
00891 {
00892         int i;
00893         int l;
00894         l = strlen16(s);
00895         for (i=0; (i<l); i++) {
00896                 gdImageCharUp(im, f, x, y, s[i], color);
00897                 y -= f->w;
00898         }
00899 }
00900 
00901 static int strlen16(s)
00902      short unsigned int *s;
00903 {
00904         int len = 0;
00905         while (*s) {
00906                 s++;
00907                 len++;
00908         }
00909         return len;
00910 }
00911 
00912 /* s and e are integers modulo 360 (degrees), with 0 degrees
00913   being the rightmost extreme and degrees changing clockwise.
00914   cx and cy are the center in pixels; w and h are the horizontal 
00915   and vertical diameter in pixels. Nice interface, but slow, since
00916   I don't yet use Bresenham (I'm using an inefficient but
00917   simple solution with too much work going on in it; generalizing
00918   Bresenham to ellipses and partial arcs of ellipses is non-trivial,
00919   at least for me) and there are other inefficiencies (small circles
00920   do far too much work). */
00921 
00922 void gdImageArc(im, cx, cy, w, h, s, e, color)
00923      gdImagePtr im;
00924      int cx;
00925      int cy;
00926      int w;
00927      int h;
00928      int s;
00929      int e;
00930      int color;
00931 {
00932         int i;
00933         int lx = 0, ly = 0;
00934         int w2, h2;
00935         w2 = w/2;
00936         h2 = h/2;
00937         while (e < s) {
00938                 e += 360;
00939         }
00940         for (i=s; (i <= e); i++) {
00941                 int x, y;
00942                 x = ((long)cost[i % 360] * (long)w2 / costScale) + cx; 
00943                 y = ((long)sint[i % 360] * (long)h2 / sintScale) + cy;
00944                 if (i != s) {
00945                         gdImageLine(im, lx, ly, x, y, color);   
00946                 }
00947                 lx = x;
00948                 ly = y;
00949         }
00950 }
00951 
00952 
00953 #if 0
00954         /* Bresenham octant code, which I should use eventually */
00955         int x, y, d;
00956         x = 0;
00957         y = w;
00958         d = 3-2*w;
00959         while (x < y) {
00960                 gdImageSetPixel(im, cx+x, cy+y, color);
00961                 if (d < 0) {
00962                         d += 4 * x + 6;
00963                 } else {
00964                         d += 4 * (x - y) + 10;
00965                         y--;
00966                 }
00967                 x++;
00968         }
00969         if (x == y) {
00970                 gdImageSetPixel(im, cx+x, cy+y, color);
00971         }
00972 #endif
00973 
00974 void gdImageFillToBorder(im, x, y, border, color)
00975      gdImagePtr im;
00976      int x;
00977      int y;
00978      int border;
00979      int color;
00980 {
00981         int lastBorder;
00982         /* Seek left */
00983         int leftLimit, rightLimit;
00984         int i;
00985         leftLimit = (-1);
00986         if (border < 0) {
00987                 /* Refuse to fill to a non-solid border */
00988                 return;
00989         }
00990         for (i = x; (i >= 0); i--) {
00991                 if (gdImageGetPixel(im, i, y) == border) {
00992                         break;
00993                 }
00994                 gdImageSetPixel(im, i, y, color);
00995                 leftLimit = i;
00996         }
00997         if (leftLimit == (-1)) {
00998                 return;
00999         }
01000         /* Seek right */
01001         rightLimit = x;
01002         for (i = (x+1); (i < im->sx); i++) {    
01003                 if (gdImageGetPixel(im, i, y) == border) {
01004                         break;
01005                 }
01006                 gdImageSetPixel(im, i, y, color);
01007                 rightLimit = i;
01008         }
01009         /* Look at lines above and below and start paints */
01010         /* Above */
01011         if (y > 0) {
01012                 lastBorder = 1;
01013                 for (i = leftLimit; (i <= rightLimit); i++) {
01014                         int c;
01015                         c = gdImageGetPixel(im, i, y-1);
01016                         if (lastBorder) {
01017                                 if ((c != border) && (c != color)) {    
01018                                         gdImageFillToBorder(im, i, y-1, 
01019                                                 border, color);         
01020                                         lastBorder = 0;
01021                                 }
01022                         } else if ((c == border) || (c == color)) {
01023                                 lastBorder = 1;
01024                         }
01025                 }
01026         }
01027         /* Below */
01028         if (y < ((im->sy) - 1)) {
01029                 lastBorder = 1;
01030                 for (i = leftLimit; (i <= rightLimit); i++) {
01031                         int c;
01032                         c = gdImageGetPixel(im, i, y+1);
01033                         if (lastBorder) {
01034                                 if ((c != border) && (c != color)) {    
01035                                         gdImageFillToBorder(im, i, y+1, 
01036                                                 border, color);         
01037                                         lastBorder = 0;
01038                                 }
01039                         } else if ((c == border) || (c == color)) {
01040                                 lastBorder = 1;
01041                         }
01042                 }
01043         }
01044 }
01045 
01046 void gdImageFill(im, x, y, color)
01047      gdImagePtr im;
01048      int x;
01049      int y;
01050      int color;
01051 {
01052         int lastBorder;
01053         int old;
01054         int leftLimit, rightLimit;
01055         int i;
01056         old = gdImageGetPixel(im, x, y);
01057         if (color == gdTiled) {
01058                 /* Tile fill -- got to watch out! */
01059                 int p, tileColor;       
01060                 int srcx, srcy;
01061                 if (!im->tile) {
01062                         return;
01063                 }
01064                 /* Refuse to flood-fill with a transparent pattern --
01065                         I can't do it without allocating another image */
01066                 if (gdImageGetTransparent(im->tile) != (-1)) {
01067                         return;
01068                 }       
01069                 srcx = x % gdImageSX(im->tile);
01070                 srcy = y % gdImageSY(im->tile);
01071                 p = gdImageGetPixel(im->tile, srcx, srcy);
01072                 tileColor = im->tileColorMap[p];
01073                 if (old == tileColor) {
01074                         /* Nothing to be done */
01075                         return;
01076                 }
01077         } else {
01078                 if (old == color) {
01079                         /* Nothing to be done */
01080                         return;
01081                 }
01082         }
01083         /* Seek left */
01084         leftLimit = (-1);
01085         for (i = x; (i >= 0); i--) {
01086                 if (gdImageGetPixel(im, i, y) != old) {
01087                         break;
01088                 }
01089                 gdImageSetPixel(im, i, y, color);
01090                 leftLimit = i;
01091         }
01092         if (leftLimit == (-1)) {
01093                 return;
01094         }
01095         /* Seek right */
01096         rightLimit = x;
01097         for (i = (x+1); (i < im->sx); i++) {    
01098                 if (gdImageGetPixel(im, i, y) != old) {
01099                         break;
01100                 }
01101                 gdImageSetPixel(im, i, y, color);
01102                 rightLimit = i;
01103         }
01104         /* Look at lines above and below and start paints */
01105         /* Above */
01106         if (y > 0) {
01107                 lastBorder = 1;
01108                 for (i = leftLimit; (i <= rightLimit); i++) {
01109                         int c;
01110                         c = gdImageGetPixel(im, i, y-1);
01111                         if (lastBorder) {
01112                                 if (c == old) { 
01113                                         gdImageFill(im, i, y-1, color);         
01114                                         lastBorder = 0;
01115                                 }
01116                         } else if (c != old) {
01117                                 lastBorder = 1;
01118                         }
01119                 }
01120         }
01121         /* Below */
01122         if (y < ((im->sy) - 1)) {
01123                 lastBorder = 1;
01124                 for (i = leftLimit; (i <= rightLimit); i++) {
01125                         int c;
01126                         c = gdImageGetPixel(im, i, y+1);
01127                         if (lastBorder) {
01128                                 if (c == old) {
01129                                         gdImageFill(im, i, y+1, color);         
01130                                         lastBorder = 0;
01131                                 }
01132                         } else if (c != old) {
01133                                 lastBorder = 1;
01134                         }
01135                 }
01136         }
01137 }
01138         
01139 /* Code drawn from ppmtogif.c, from the pbmplus package
01140 **
01141 ** Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>. A
01142 ** Lempel-Zim compression based on "compress".
01143 **
01144 ** Modified by Marcel Wijkstra <wijkstra@fwi.uva.nl>
01145 **
01146 ** Copyright (C) 1989 by Jef Poskanzer.
01147 **
01148 ** Permission to use, copy, modify, and distribute this software and its
01149 ** documentation for any purpose and without fee is hereby granted, provided
01150 ** that the above copyright notice appear in all copies and that both that
01151 ** copyright notice and this permission notice appear in supporting
01152 ** documentation.  This software is provided "as is" without express or
01153 ** implied warranty.
01154 **
01155 ** The Graphics Interchange Format(c) is the Copyright property of
01156 ** CompuServe Incorporated.  GIF(sm) is a Service Mark property of
01157 ** CompuServe Incorporated.
01158 *
01159 *  Heavily modified by Mouse, 1998-02-12.  
01160 *  Remove LZW compression.
01161 *  Added miGIF run length compression.
01162 *
01163 */
01164 
01165 /*
01166  * a code_int must be able to hold 2**GIFBITS values of type int, and also -1
01167  */
01168 typedef int code_int;
01169 
01170 static int colorstobpp();
01171 static void BumpPixel ();
01172 static int GIFNextPixel ();
01173 static void GIFEncode ();
01174 static void Putword ();
01175 static void compress ();
01176 static void output ();
01177 static void char_init ();
01178 static void char_out ();
01179 /* Allows for reuse */
01180 static void init_statics();
01181 
01182 void gdImageGif(im, out)
01183      gdImagePtr im;
01184      FILE *out;
01185 {
01186         int interlace, transparent, background, BitsPerPixel;
01187         interlace = im->interlace;
01188         transparent = im->transparent;
01189         background = im->background;
01190         BitsPerPixel = colorstobpp(im->colorsTotal);
01191         /* Clear any old values in statics strewn through the GIF code */
01192         init_statics();
01193         /* All set, let's do it. */
01194         GIFEncode(
01195                 out, im->sx, im->sy, interlace, background, transparent, 
01196                 BitsPerPixel, im->red, im->green, im->blue, im);
01197 }
01198 
01199 static int
01200 colorstobpp(colors)
01201      int colors;
01202 {
01203     int bpp = 0;
01204 
01205     if ( colors <= 2 )
01206         bpp = 1;
01207     else if ( colors <= 4 )
01208         bpp = 2;
01209     else if ( colors <= 8 )
01210         bpp = 3;
01211     else if ( colors <= 16 )
01212         bpp = 4;
01213     else if ( colors <= 32 )
01214         bpp = 5;
01215     else if ( colors <= 64 )
01216         bpp = 6;
01217     else if ( colors <= 128 )
01218         bpp = 7;
01219     else if ( colors <= 256 )
01220         bpp = 8;
01221     return bpp;
01222     }
01223 
01224 /*****************************************************************************
01225  *
01226  * GIFENCODE.C    - GIF Image compression interface
01227  *
01228  * GIFEncode( FName, GHeight, GWidth, GInterlace, Background, Transparent,
01229  *            BitsPerPixel, Red, Green, Blue, gdImagePtr )
01230  *
01231  *****************************************************************************/
01232 
01233 #define TRUE 1
01234 #define FALSE 0
01235 
01236 static int Width, Height;
01237 static int curx, cury;
01238 static long CountDown;
01239 static int Pass = 0;
01240 static int Interlace;
01241 
01242 /*
01243  * Bump the 'curx' and 'cury' to point to the next pixel
01244  */
01245 static void
01246 BumpPixel()
01247 {
01248         /*
01249          * Bump the current X position
01250          */
01251         ++curx;
01252 
01253         /*
01254          * If we are at the end of a scan line, set curx back to the beginning
01255          * If we are interlaced, bump the cury to the appropriate spot,
01256          * otherwise, just increment it.
01257          */
01258         if( curx == Width ) {
01259                 curx = 0;
01260 
01261                 if( !Interlace )
01262                         ++cury;
01263                 else {
01264                      switch( Pass ) {
01265 
01266                        case 0:
01267                           cury += 8;
01268                           if( cury >= Height ) {
01269                                 ++Pass;
01270                                 cury = 4;
01271                           }
01272                           break;
01273 
01274                        case 1:
01275                           cury += 8;
01276                           if( cury >= Height ) {
01277                                 ++Pass;
01278                                 cury = 2;
01279                           }
01280                           break;
01281 
01282                        case 2:
01283                           cury += 4;
01284                           if( cury >= Height ) {
01285                              ++Pass;
01286                              cury = 1;
01287                           }
01288                           break;
01289 
01290                        case 3:
01291                           cury += 2;
01292                           break;
01293                         }
01294                 }
01295         }
01296 }
01297 
01298 /*
01299  * Return the next pixel from the image
01300  */
01301 static int
01302 GIFNextPixel(im)
01303      gdImagePtr im;
01304 {
01305         int r;
01306 
01307         if( CountDown == 0 )
01308                 return EOF;
01309 
01310         --CountDown;
01311 
01312         r = gdImageGetPixel(im, curx, cury);
01313 
01314         BumpPixel();
01315 
01316         return r;
01317 }
01318 
01319 /* public */
01320 
01321 static void
01322 GIFEncode(fp, GWidth, GHeight, GInterlace, Background, Transparent, BitsPerPixel, Red, Green, Blue, im)
01323      FILE *fp;
01324      int GWidth;
01325      int GHeight;
01326      int GInterlace;
01327      int Background;
01328      int Transparent;
01329      int BitsPerPixel;
01330      int *Red;
01331      int *Green;
01332      int *Blue;
01333      gdImagePtr im;
01334 {
01335         int B;
01336         int RWidth, RHeight;
01337         int LeftOfs, TopOfs;
01338         int Resolution;
01339         int ColorMapSize;
01340         int InitCodeSize;
01341         int i;
01342 
01343         Interlace = GInterlace;
01344 
01345         ColorMapSize = 1 << BitsPerPixel;
01346 
01347         RWidth = Width = GWidth;
01348         RHeight = Height = GHeight;
01349         LeftOfs = TopOfs = 0;
01350 
01351         Resolution = BitsPerPixel;
01352 
01353         /*
01354          * Calculate number of bits we are expecting
01355          */
01356         CountDown = (long)Width * (long)Height;
01357         /*
01358          * Indicate which pass we are on (if interlace)
01359          */
01360         Pass = 0;
01361 
01362         /*
01363          * The initial code size
01364          */
01365         if( BitsPerPixel <= 1 )
01366                 InitCodeSize = 2;
01367         else
01368                 InitCodeSize = BitsPerPixel;
01369 
01370         /*
01371          * Set up the current x and y position
01372          */
01373         curx = cury = 0;
01374 
01375         /*
01376          * Write the Magic header
01377          */
01378         fwrite( Transparent < 0 ? "GIF87a" : "GIF89a", 1, 6, fp );
01379 
01380         /*
01381          * Write out the screen width and height
01382          */
01383         Putword( RWidth, fp );
01384         Putword( RHeight, fp );
01385 
01386         /*
01387          * Indicate that there is a global colour map
01388          */
01389         B = 0x80;       /* Yes, there is a color map */
01390 
01391         /*
01392          * OR in the resolution
01393          */
01394         B |= (Resolution - 1) << 4;
01395 
01396         /*
01397          * OR in the Bits per Pixel
01398          */
01399         B |= (BitsPerPixel - 1);
01400 
01401         /*
01402          * Write it out
01403          */
01404         fputc( B, fp );
01405 
01406         /*
01407          * Write out the Background colour
01408          */
01409         fputc( Background, fp );
01410 
01411         /*
01412          * Byte of 0's (future expansion)
01413          */
01414         fputc( 0, fp );
01415 
01416         /*
01417          * Write out the Global Colour Map
01418          */
01419         for( i=0; i<ColorMapSize; ++i ) {
01420                 fputc( Red[i], fp );
01421                 fputc( Green[i], fp );
01422                 fputc( Blue[i], fp );
01423         }
01424 
01425         /*
01426          * Write out extension for transparent colour index, if necessary.
01427          */
01428         if ( Transparent >= 0 ) {
01429             fputc( '!', fp );
01430             fputc( 0xf9, fp );
01431             fputc( 4, fp );
01432             fputc( 1, fp );
01433             fputc( 0, fp );
01434             fputc( 0, fp );
01435             fputc( (unsigned char) Transparent, fp );
01436             fputc( 0, fp );
01437         }
01438 
01439         /*
01440          * Write an Image separator
01441          */
01442         fputc( ',', fp );
01443 
01444         /*
01445          * Write the Image header
01446          */
01447 
01448         Putword( LeftOfs, fp );
01449         Putword( TopOfs, fp );
01450         Putword( Width, fp );
01451         Putword( Height, fp );
01452 
01453         /*
01454          * Write out whether or not the image is interlaced
01455          */
01456         if( Interlace )
01457                 fputc( 0x40, fp );
01458         else
01459                 fputc( 0x00, fp );
01460         /*
01461          * Write out the initial code size
01462          */
01463         fputc( InitCodeSize, fp );
01464 
01465         /*
01466          * Go and actually compress the data
01467          */
01468         compress( InitCodeSize+1, fp, im, Background );
01469 
01470         /*
01471          * Write out a Zero-length packet (to end the series)
01472          */
01473         fputc( 0, fp );
01474 
01475         /*
01476          * Write the GIF file terminator
01477          */
01478         fputc( ';', fp );
01479 }
01480 
01481 /*
01482  * Write out a word to the GIF file
01483  */
01484 static void
01485 Putword(w, fp)
01486      int w;
01487      FILE *fp;
01488 {
01489         fputc( w & 0xff, fp );
01490         fputc( (w / 256) & 0xff, fp );
01491 }
01492 
01493 #define GIFBITS 12
01494 
01495 /*-----------------------------------------------------------------------
01496  *
01497  * miGIF Compression - mouse and ivo's GIF-compatible compression
01498  *
01499  *          -run length encoding compression routines-
01500  *
01501  * Copyright (C) 1998 Hutchison Avenue Software Corporation
01502  *               http://www.hasc.com
01503  *               info@hasc.com
01504  *
01505  * Permission to use, copy, modify, and distribute this software and its
01506  * documentation for any purpose and without fee is hereby granted, provided
01507  * that the above copyright notice appear in all copies and that both that
01508  * copyright notice and this permission notice appear in supporting
01509  * documentation.  This software is provided "AS IS." The Hutchison Avenue 
01510  * Software Corporation disclaims all warranties, either express or implied, 
01511  * including but not limited to implied warranties of merchantability and 
01512  * fitness for a particular purpose, with respect to this code and accompanying
01513  * documentation. 
01514  * 
01515  * The miGIF compression routines do not, strictly speaking, generate files 
01516  * conforming to the GIF spec, since the image data is not LZW-compressed 
01517  * (this is the point: in order to avoid transgression of the Unisys patent 
01518  * on the LZW algorithm.)  However, miGIF generates data streams that any 
01519  * reasonably sane LZW decompresser will decompress to what we want.
01520  *
01521  * miGIF compression uses run length encoding. It compresses horizontal runs 
01522  * of pixels of the same color. This type of compression gives good results
01523  * on images with many runs, for example images with lines, text and solid 
01524  * shapes on a solid-colored background. It gives little or no compression 
01525  * on images with few runs, for example digital or scanned photos.
01526  *
01527  *                               der Mouse
01528  *                      mouse@rodents.montreal.qc.ca
01529  *            7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B
01530  *
01531  *                             ivo@hasc.com
01532  *
01533  * The Graphics Interchange Format(c) is the Copyright property of
01534  * CompuServe Incorporated.  GIF(sm) is a Service Mark property of
01535  * CompuServe Incorporated.
01536  *
01537  */
01538 
01539 static int rl_pixel;
01540 static int rl_basecode;
01541 static int rl_count;
01542 static int rl_table_pixel;
01543 static int rl_table_max;
01544 static int just_cleared;
01545 static int out_bits;
01546 static int out_bits_init;
01547 static int out_count;
01548 static int out_bump;
01549 static int out_bump_init;
01550 static int out_clear;
01551 static int out_clear_init;
01552 static int max_ocodes;
01553 static int code_clear;
01554 static int code_eof;
01555 static unsigned int obuf;
01556 static int obits;
01557 static FILE *ofile;
01558 static unsigned char oblock[256];
01559 static int oblen;
01560 
01561 /* Used only when debugging GIF compression code */
01562 /* #define DEBUGGING_ENVARS */
01563 
01564 #ifdef DEBUGGING_ENVARS
01565 
01566 static int verbose_set = 0;
01567 static int verbose;
01568 #define VERBOSE (verbose_set?verbose:set_verbose())
01569 
01570 static int set_verbose(void)
01571 {
01572  verbose = !!getenv("GIF_VERBOSE");
01573  verbose_set = 1;
01574  return(verbose);
01575 }
01576 
01577 #else
01578 
01579 #define VERBOSE 0
01580 
01581 #endif
01582 
01583 #ifdef __STDC__
01584 static const char *binformat(unsigned int v, int nbits)
01585 #else
01586 static char *binformat(v, nbits)
01587      unsigned int v;
01588      int nbits;
01589 #endif
01590 {
01591  static char bufs[8][64];
01592  static int bhand = 0;
01593  unsigned int bit;
01594  int bno;
01595  char *bp;
01596 
01597  bhand --;
01598  if (bhand < 0) bhand = (sizeof(bufs)/sizeof(bufs[0]))-1;
01599  bp = &bufs[bhand][0];
01600  for (bno=nbits-1,bit=(unsigned int)1<<bno;bno>=0;bno--,bit>>=1)
01601   { *bp++ = (v & bit) ? '1' : '0';
01602     if (((bno&3) == 0) && (bno != 0)) *bp++ = '.';
01603   }
01604  *bp = '\0';
01605  return(&bufs[bhand][0]);
01606 }
01607 
01608 static void write_block()
01609 {
01610  int i;
01611 
01612  if (VERBOSE)
01613   { printf("write_block %d:",oblen);
01614     for (i=0;i<oblen;i++) printf(" %02x",oblock[i]);
01615     printf("\n");
01616   }
01617  fputc(oblen,ofile);
01618  fwrite(&oblock[0],1,oblen,ofile);
01619  oblen = 0;
01620 }
01621 
01622 static void block_out(c)
01623      unsigned char c;
01624 {
01625  if (VERBOSE) printf("block_out %s\n",binformat(c,8));
01626  oblock[oblen++] = c;
01627  if (oblen >= 255) write_block();
01628 }
01629 
01630 static void block_flush()
01631 {
01632  if (VERBOSE) printf("block_flush\n");
01633  if (oblen > 0) write_block();
01634 }
01635 
01636 static void output(val)
01637      int val;
01638 {
01639  if (VERBOSE) printf("output %s [%s %d %d]\n",binformat(val,out_bits),binformat(obuf,obits),obits,out_bits);
01640  obuf |= val << obits;
01641  obits += out_bits;
01642  while (obits >= 8)
01643   { block_out(obuf&0xff);
01644     obuf >>= 8;
01645     obits -= 8;
01646   }
01647  if (VERBOSE) printf("output leaving [%s %d]\n",binformat(obuf,obits),obits);
01648 }
01649 
01650 static void output_flush()
01651 {
01652  if (VERBOSE) printf("output_flush\n");
01653  if (obits > 0) block_out(obuf);
01654  block_flush();
01655 }
01656 
01657 static void did_clear()
01658 {
01659  if (VERBOSE) printf("did_clear\n");
01660  out_bits = out_bits_init;
01661  out_bump = out_bump_init;
01662  out_clear = out_clear_init;
01663  out_count = 0;
01664  rl_table_max = 0;
01665  just_cleared = 1;
01666 }
01667 
01668 static void output_plain(c)
01669      int c;
01670 {
01671  if (VERBOSE) printf("output_plain %s\n",binformat(c,out_bits));
01672  just_cleared = 0;
01673  output(c);
01674  out_count ++;
01675  if (out_count >= out_bump)
01676   { out_bits ++;
01677     out_bump += 1 << (out_bits - 1);
01678   }
01679  if (out_count >= out_clear)
01680   { output(code_clear);
01681     did_clear();
01682   }
01683 }
01684 
01685 static unsigned int isqrt(x)
01686      unsigned int x;
01687 {
01688  unsigned int r;
01689  unsigned int v;
01690 
01691  if (x < 2) return(x);
01692  for (v=x,r=1;v;v>>=2,r<<=1) ;
01693  while (1)
01694   { v = ((x / r) + r) / 2;
01695     if ((v == r) || (v == r+1)) return(r);
01696     r = v;
01697   }
01698 }
01699 
01700 static unsigned int compute_triangle_count(count, nrepcodes)
01701      unsigned int count;
01702      unsigned int nrepcodes;
01703 {
01704  unsigned int perrep;
01705  unsigned int lcost;
01706 
01707  lcost = 0;
01708  perrep = (nrepcodes * (nrepcodes+1)) / 2;
01709  while (count >= perrep)
01710   { lcost += nrepcodes;
01711     count -= perrep;
01712   }
01713  if (count > 0)
01714   { unsigned int n;
01715     n = isqrt(count);
01716     while ((n*(n+1)) >= 2*count) n --;
01717     while ((n*(n+1)) < 2*count) n ++;
01718     lcost += n;
01719   }
01720  return(lcost);
01721 }
01722 
01723 static void max_out_clear()
01724 {
01725  out_clear = max_ocodes;
01726 }
01727 
01728 static void reset_out_clear()
01729 {
01730  out_clear = out_clear_init;
01731  if (out_count >= out_clear)
01732   { output(code_clear);
01733     did_clear();
01734   }
01735 }
01736 
01737 static void rl_flush_fromclear(count)
01738      int count;
01739 {
01740  int n;
01741 
01742  if (VERBOSE) printf("rl_flush_fromclear %d\n",count);
01743  max_out_clear();
01744  rl_table_pixel = rl_pixel;
01745  n = 1;
01746  while (count > 0)
01747   { if (n == 1)
01748      { rl_table_max = 1;
01749        output_plain(rl_pixel);
01750        count --;
01751      }
01752     else if (count >= n)
01753      { rl_table_max = n;
01754        output_plain(rl_basecode+n-2);
01755        count -= n;
01756      }
01757     else if (count == 1)
01758      { rl_table_max ++;
01759        output_plain(rl_pixel);
01760        count = 0;
01761      }
01762     else
01763      { rl_table_max ++;
01764        output_plain(rl_basecode+count-2);
01765        count = 0;
01766      }
01767     if (out_count == 0) n = 1; else n ++;
01768   }
01769  reset_out_clear();
01770  if (VERBOSE) printf("rl_flush_fromclear leaving table_max=%d\n",rl_table_max);
01771 }
01772 
01773 static void rl_flush_clearorrep(count)
01774      int count;
01775 {
01776  int withclr;
01777 
01778  if (VERBOSE) printf("rl_flush_clearorrep %d\n",count);
01779  withclr = 1 + (int)compute_triangle_count(count,max_ocodes);
01780  if (withclr < count)
01781   { output(code_clear);
01782     did_clear();
01783     rl_flush_fromclear(count);
01784   }
01785  else
01786   { for (;count>0;count--) output_plain(rl_pixel);
01787   }
01788 }
01789 
01790 static void rl_flush_withtable(count)
01791      int count;
01792 {
01793  int repmax;
01794  int repleft;
01795  int leftover;
01796 
01797  if (VERBOSE) printf("rl_flush_withtable %d\n",count);
01798  repmax = count / rl_table_max;
01799  leftover = count % rl_table_max;
01800  repleft = (leftover ? 1 : 0);
01801  if (out_count+repmax+repleft > max_ocodes)
01802   { repmax = max_ocodes - out_count;
01803     leftover = count - (repmax * rl_table_max);
01804     repleft = 1 + compute_triangle_count(leftover,max_ocodes);
01805   }
01806  if (VERBOSE) printf("rl_flush_withtable repmax=%d leftover=%d repleft=%d\n",repmax,leftover,repleft);
01807  if ( (int) (1+compute_triangle_count(count,max_ocodes)) < repmax+repleft)
01808   { output(code_clear);
01809     did_clear();
01810     rl_flush_fromclear(count);
01811     return;
01812   }
01813  max_out_clear();
01814  for (;repmax>0;repmax--) output_plain(rl_basecode+rl_table_max-2);
01815  if (leftover)
01816   { if (just_cleared)
01817      { rl_flush_fromclear(leftover);
01818      }
01819     else if (leftover == 1)
01820      { output_plain(rl_pixel);
01821      }
01822     else
01823      { output_plain(rl_basecode+leftover-2);
01824      }
01825   }
01826  reset_out_clear();
01827 }
01828 
01829 static void rl_flush()
01830 {
01831  if (VERBOSE) printf("rl_flush [ %d %d\n",rl_count,rl_pixel);
01832  if (rl_count == 1)
01833   { output_plain(rl_pixel);
01834     rl_count = 0;
01835     if (VERBOSE) printf("rl_flush ]\n");
01836     return;
01837   }
01838  if (just_cleared)
01839   { rl_flush_fromclear(rl_count);
01840   }
01841  else if ((rl_table_max < 2) || (rl_table_pixel != rl_pixel))
01842   { rl_flush_clearorrep(rl_count);
01843   }
01844  else
01845   { rl_flush_withtable(rl_count);
01846   }
01847  if (VERBOSE) printf("rl_flush ]\n");
01848  rl_count = 0;
01849 }
01850 
01851 static void compress(init_bits, outfile, im, background)
01852      int init_bits;
01853      FILE *outfile;
01854      gdImagePtr im;
01855      int background;
01856 {
01857  int c;
01858 
01859  ofile = outfile;
01860  obuf = 0;
01861  obits = 0;
01862  oblen = 0;
01863  code_clear = 1 << (init_bits - 1);
01864  code_eof = code_clear + 1;
01865  rl_basecode = code_eof + 1;
01866  out_bump_init = (1 << (init_bits - 1)) - 1;
01867  /* for images with a lot of runs, making out_clear_init larger will
01868     give better compression. */ 
01869  out_clear_init = (init_bits <= 3) ? 9 : (out_bump_init-1);
01870 
01871 #ifdef DEBUGGING_ENVARS
01872   { const char *ocienv;
01873     ocienv = getenv("GIF_OUT_CLEAR_INIT");
01874     if (ocienv)
01875      { out_clear_init = atoi(ocienv);
01876        if (VERBOSE) printf("[overriding out_clear_init to %d]\n",out_clear_init);
01877      }
01878   }
01879 #endif
01880 
01881  out_bits_init = init_bits;
01882 
01883  max_ocodes = (1 << GIFBITS) - ((1 << (out_bits_init - 1)) + 3);
01884  did_clear();
01885  output(code_clear);
01886  rl_count = 0;
01887  while (1)
01888   { c = GIFNextPixel(im);
01889     if ((rl_count > 0) && (c != rl_pixel)) rl_flush();
01890     if (c == EOF) break;
01891     if (rl_pixel == c)
01892      { rl_count ++;
01893      }
01894     else
01895      { rl_pixel = c;
01896        rl_count = 1;
01897      }
01898   }
01899  output(code_eof);
01900  output_flush();
01901 }
01902 
01903 /*-----------------------------------------------------------------------
01904  *
01905  * End of miGIF section  - See copyright notice at start of section.
01906  *
01907  *-----------------------------------------------------------------------*/
01908 
01909 
01910 /******************************************************************************
01911  *
01912  * GIF Specific routines
01913  *
01914  ******************************************************************************/
01915 
01916 /*
01917  * Number of characters so far in this 'packet'
01918  */
01919 static int a_count;
01920 
01921 /*
01922  * Set up the 'byte output' routine
01923  */
01924 static void
01925 char_init()
01926 {
01927         a_count = 0;
01928 }
01929 
01930 /*
01931  * Define the storage for the packet accumulator
01932  */
01933 static char accum[ 256 ];
01934 
01935 static void init_statics()
01936  {
01937         /* Some of these are properly initialized later. What I'm doing
01938                 here is making sure code that depends on C's initialization
01939                 of statics doesn't break when the code gets called more
01940                 than once. */
01941         Width = 0;
01942         Height = 0;
01943         curx = 0;
01944         cury = 0;
01945         CountDown = 0;
01946         Pass = 0;
01947         Interlace = 0;
01948         a_count = 0;
01949 }
01950 
01951 
01952 /* +-------------------------------------------------------------------+ */
01953 /* | Copyright 1990, 1991, 1993, David Koblas.  (koblas@netcom.com)    | */
01954 /* |   Permission to use, copy, modify, and distribute this software   | */
01955 /* |   and its documentation for any purpose and without fee is hereby | */
01956 /* |   granted, provided that the above copyright notice appear in all | */
01957 /* |   copies and that both that copyright notice and this permission  | */
01958 /* |   notice appear in supporting documentation.  This software is    | */
01959 /* |   provided "as is" without express or implied warranty.           | */
01960 /* +-------------------------------------------------------------------+ */
01961 
01962 
01963 #define        MAXCOLORMAPSIZE         256
01964 
01965 #define        TRUE    1
01966 #define        FALSE   0
01967 
01968 #define CM_RED         0
01969 #define CM_GREEN       1
01970 #define CM_BLUE                2
01971 
01972 #define        MAX_LWZ_BITS            12
01973 
01974 #define INTERLACE              0x40
01975 #define LOCALCOLORMAP  0x80
01976 #define BitSet(byte, bit)      (((byte) & (bit)) == (bit))
01977 
01978 #define        ReadOK(file,buffer,len) (fread(buffer, len, 1, file) != 0)
01979 
01980 #define LM_to_uint(a,b)                        (((b)<<8)|(a))
01981 
01982 /* We may eventually want to use this information, but def it out for now */
01983 #if 0
01984 static struct {
01985        unsigned int    Width;
01986        unsigned int    Height;
01987        unsigned char   ColorMap[3][MAXCOLORMAPSIZE];
01988        unsigned int    BitPixel;
01989        unsigned int    ColorResolution;
01990        unsigned int    Background;
01991        unsigned int    AspectRatio;
01992 } GifScreen;
01993 #endif
01994 
01995 static struct {
01996        int     transparent;
01997        int     delayTime;
01998        int     inputFlag;
01999        int     disposal;
02000 } Gif89 = { -1, -1, -1, 0 };
02001 
02002 static int ReadColorMap ();
02003 static int DoExtension ();
02004 static int GetDataBlock ();
02005 static int GetCode ();
02006 static int LWZReadByte ();
02007 static void ReadImage ();
02008 
02009 int ZeroDataBlock;
02010 
02011 gdImagePtr
02012 gdImageCreateFromGif(fd)
02013      FILE *fd;
02014 {
02015        int imageNumber;
02016        int BitPixel;
02017        int ColorResolution;
02018        int Background;
02019        int AspectRatio;
02020        int Transparent = (-1);
02021        unsigned char   buf[16];
02022        unsigned char   c;
02023        unsigned char   ColorMap[3][MAXCOLORMAPSIZE];
02024        unsigned char   localColorMap[3][MAXCOLORMAPSIZE];
02025        int             imw, imh;
02026        int             useGlobalColormap;
02027        int             bitPixel;
02028        int             imageCount = 0;
02029        char            version[4];
02030        gdImagePtr im = 0;
02031        ZeroDataBlock = FALSE;
02032 
02033        imageNumber = 1;
02034        if (! ReadOK(fd,buf,6)) {
02035                 return 0;
02036         }
02037        if (strncmp((char *)buf,"GIF",3) != 0) {
02038                 return 0;
02039         }
02040        strncpy(version, (char *)buf + 3, 3);
02041        version[3] = '\0';
02042 
02043        if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
02044                 return 0;
02045         }
02046        if (! ReadOK(fd,buf,7)) {
02047                 return 0;
02048         }
02049        BitPixel        = 2<<(buf[4]&0x07);
02050        ColorResolution = (int) (((buf[4]&0x70)>>3)+1);
02051        Background      = buf[5];
02052        AspectRatio     = buf[6];
02053 
02054        if (BitSet(buf[4], LOCALCOLORMAP)) {    /* Global Colormap */
02055                if (ReadColorMap(fd, BitPixel, ColorMap)) {
02056                         return 0;
02057                 }
02058        }
02059        for (;;) {
02060                if (! ReadOK(fd,&c,1)) {
02061                        return 0;
02062                }
02063                if (c == ';') {         /* GIF terminator */
02064                        int i;
02065                        if (imageCount < imageNumber) {
02066                                return 0;
02067                        }
02068                        /* Terminator before any image was declared! */
02069                        if (!im) {
02070                               return 0;
02071                        }
02072                        /* Check for open colors at the end, so
02073                           we can reduce colorsTotal and ultimately
02074                           BitsPerPixel */
02075                        for (i=((im->colorsTotal-1)); (i>=0); i--) {
02076                                if (im->open[i]) {
02077                                        im->colorsTotal--;
02078                                } else {
02079                                        break;
02080                                }
02081                        } 
02082                        return im;
02083                }
02084 
02085                if (c == '!') {         /* Extension */
02086                        if (! ReadOK(fd,&c,1)) {
02087                                return 0;
02088                        }
02089                        DoExtension(fd, c, &Transparent);
02090                        continue;
02091                }
02092 
02093                if (c != ',') {         /* Not a valid start character */
02094                        continue;
02095                }
02096 
02097                ++imageCount;
02098 
02099                if (! ReadOK(fd,buf,9)) {
02100                        return 0;
02101                }
02102 
02103                useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP);
02104 
02105                bitPixel = 1<<((buf[8]&0x07)+1);
02106 
02107                imw = LM_to_uint(buf[4],buf[5]);
02108                imh = LM_to_uint(buf[6],buf[7]);
02109                if (!(im = gdImageCreate(imw, imh))) {
02110                          return 0;
02111                }
02112                im->interlace = BitSet(buf[8], INTERLACE);
02113                if (! useGlobalColormap) {
02114                        if (ReadColorMap(fd, bitPixel, localColorMap)) { 
02115                                  return 0;
02116                        }
02117                        ReadImage(im, fd, imw, imh, localColorMap, 
02118                                  BitSet(buf[8], INTERLACE), 
02119                                  imageCount != imageNumber);
02120                } else {
02121                        ReadImage(im, fd, imw, imh,
02122                                  ColorMap, 
02123                                  BitSet(buf[8], INTERLACE), 
02124                                  imageCount != imageNumber);
02125                }
02126                if (Transparent != (-1)) {
02127                        gdImageColorTransparent(im, Transparent);
02128                }           
02129        }
02130 }
02131 
02132 static int
02133 ReadColorMap(fd, number, buffer)
02134      FILE *fd;
02135      int number;
02136      unsigned char (*buffer)[256];
02137 {
02138        int             i;
02139        unsigned char   rgb[3];
02140 
02141 
02142        for (i = 0; i < number; ++i) {
02143                if (! ReadOK(fd, rgb, sizeof(rgb))) {
02144                        return TRUE;
02145                }
02146                buffer[CM_RED][i] = rgb[0] ;
02147                buffer[CM_GREEN][i] = rgb[1] ;
02148                buffer[CM_BLUE][i] = rgb[2] ;
02149        }
02150 
02151 
02152        return FALSE;
02153 }
02154 
02155 static int
02156 DoExtension(fd, label, Transparent)
02157      FILE *fd;
02158      int label;
02159      int *Transparent;
02160 {
02161        static unsigned char     buf[256];
02162 
02163        switch (label) {
02164        case 0xf9:              /* Graphic Control Extension */
02165                (void) GetDataBlock(fd, (unsigned char*) buf);
02166                Gif89.disposal    = (buf[0] >> 2) & 0x7;
02167                Gif89.inputFlag   = (buf[0] >> 1) & 0x1;
02168                Gif89.delayTime   = LM_to_uint(buf[1],buf[2]);
02169                if ((buf[0] & 0x1) != 0)
02170                        *Transparent = buf[3];
02171 
02172                while (GetDataBlock(fd, (unsigned char*) buf) != 0)
02173                        ;
02174                return FALSE;
02175        default:
02176                break;
02177        }
02178        while (GetDataBlock(fd, (unsigned char*) buf) != 0)
02179                ;
02180 
02181        return FALSE;
02182 }
02183 
02184 static int
02185 GetDataBlock_(fd, buf)
02186      FILE *fd;
02187      unsigned char *buf;
02188 {
02189        unsigned char   count;
02190 
02191        if (! ReadOK(fd,&count,1)) {
02192                return -1;
02193        }
02194 
02195        ZeroDataBlock = count == 0;
02196 
02197        if ((count != 0) && (! ReadOK(fd, buf, count))) {
02198                return -1;
02199        }
02200 
02201        return count;
02202 }
02203 
02204 static int
02205 GetDataBlock(fd, buf)
02206      FILE *fd;
02207      unsigned char *buf;
02208 {
02209  int rv;
02210  int i;
02211 
02212  rv = GetDataBlock_(fd,buf);
02213  if (VERBOSE)
02214   { printf("[GetDataBlock returning %d",rv);
02215     if (rv > 0)
02216      { printf(":");
02217        for (i=0;i<rv;i++) printf(" %02x",buf[i]);
02218      }
02219     printf("]\n");
02220   }
02221  return(rv);
02222 }
02223 
02224 static int
02225 GetCode_(fd, code_size, flag)
02226      FILE *fd;
02227      int code_size;
02228      int flag;
02229 {
02230        static unsigned char    buf[280];
02231        static int              curbit, lastbit, done, last_byte;
02232        int                     i, j, ret;
02233        unsigned char           count;
02234 
02235        if (flag) {
02236                curbit = 0;
02237                lastbit = 0;
02238                done = FALSE;
02239                return 0;
02240        }
02241 
02242        if ( (curbit+code_size) >= lastbit) {
02243                if (done) {
02244                        if (curbit >= lastbit) {
02245                                 /* Oh well */
02246                        }                        
02247                        return -1;
02248                }
02249                buf[0] = buf[last_byte-2];
02250                buf[1] = buf[last_byte-1];
02251 
02252                if ((count = GetDataBlock(fd, &buf[2])) == 0)
02253                        done = TRUE;
02254 
02255                last_byte = 2 + count;
02256                curbit = (curbit - lastbit) + 16;
02257                lastbit = (2+count)*8 ;
02258        }
02259 
02260        ret = 0;
02261        for (i = curbit, j = 0; j < code_size; ++i, ++j)
02262                ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
02263 
02264        curbit += code_size;
02265        return ret;
02266 }
02267 
02268 static int
02269 GetCode(fd, code_size, flag)
02270      FILE *fd;
02271      int code_size;
02272      int flag;
02273 {
02274  int rv;
02275 
02276  rv = GetCode_(fd,code_size,flag);
02277  if (VERBOSE) printf("[GetCode(,%d,%d) returning %d]\n",code_size,flag,rv);
02278  return(rv);
02279 }
02280 
02281 static int
02282 LWZReadByte_(fd, flag, input_code_size)
02283      FILE *fd;
02284      int flag;
02285      int input_code_size;
02286 {
02287        static int      fresh = FALSE;
02288        int             code, incode;
02289        static int      code_size, set_code_size;
02290        static int      max_code, max_code_size;
02291        static int      firstcode, oldcode;
02292        static int      clear_code, end_code;
02293        static int      table[2][(1<< MAX_LWZ_BITS)];
02294        static int      stack[(1<<(MAX_LWZ_BITS))*2], *sp;
02295        register int    i;
02296 
02297        if (flag) {
02298                set_code_size = input_code_size;
02299                code_size = set_code_size+1;
02300                clear_code = 1 << set_code_size ;
02301                end_code = clear_code + 1;
02302                max_code_size = 2*clear_code;
02303                max_code = clear_code+2;
02304 
02305                GetCode(fd, 0, TRUE);
02306                
02307                fresh = TRUE;
02308 
02309                for (i = 0; i < clear_code; ++i) {
02310                        table[0][i] = 0;
02311                        table[1][i] = i;
02312                }
02313                for (; i < (1<<MAX_LWZ_BITS); ++i)
02314                        table[0][i] = table[1][0] = 0;
02315 
02316                sp = stack;
02317 
02318                return 0;
02319        } else if (fresh) {
02320                fresh = FALSE;
02321                do {
02322                        firstcode = oldcode =
02323                                GetCode(fd, code_size, FALSE);
02324                } while (firstcode == clear_code);
02325                return firstcode;
02326        }
02327 
02328        if (sp > stack)
02329                return *--sp;
02330 
02331        while ((code = GetCode(fd, code_size, FALSE)) >= 0) {
02332                if (code == clear_code) {
02333                        for (i = 0; i < clear_code; ++i) {
02334                                table[0][i] = 0;
02335                                table[1][i] = i;
02336                        }
02337                        for (; i < (1<<MAX_LWZ_BITS); ++i)
02338                                table[0][i] = table[1][i] = 0;
02339                        code_size = set_code_size+1;
02340                        max_code_size = 2*clear_code;
02341                        max_code = clear_code+2;
02342                        sp = stack;
02343                        firstcode = oldcode =
02344                                        GetCode(fd, code_size, FALSE);
02345                        return firstcode;
02346                } else if (code == end_code) {
02347                        int             count;
02348                        unsigned char   buf[260];
02349 
02350                        if (ZeroDataBlock)
02351                                return -2;
02352 
02353                        while ((count = GetDataBlock(fd, buf)) > 0)
02354                                ;
02355 
02356                        if (count != 0)
02357                        return -2;
02358                }
02359 
02360                incode = code;
02361 
02362                if (code >= max_code) {
02363                        *sp++ = firstcode;
02364                        code = oldcode;
02365                }
02366 
02367                while (code >= clear_code) {
02368                        *sp++ = table[1][code];
02369                        if (code == table[0][code]) {
02370                                /* Oh well */
02371                        }
02372                        code = table[0][code];
02373                }
02374 
02375                *sp++ = firstcode = table[1][code];
02376 
02377                if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
02378                        table[0][code] = oldcode;
02379                        table[1][code] = firstcode;
02380                        ++max_code;
02381                        if ((max_code >= max_code_size) &&
02382                                (max_code_size < (1<<MAX_LWZ_BITS))) {
02383                                max_code_size *= 2;
02384                                ++code_size;
02385                        }
02386                }
02387 
02388                oldcode = incode;
02389 
02390                if (sp > stack)
02391                        return *--sp;
02392        }
02393        return code;
02394 }
02395 
02396 static int
02397 LWZReadByte(fd, flag, input_code_size)
02398      FILE *fd;
02399      int flag;
02400      int input_code_size;
02401 {
02402  int rv;
02403 
02404  rv = LWZReadByte_(fd,flag,input_code_size);
02405  if (VERBOSE) printf("[LWZReadByte(,%d,%d) returning %d]\n",flag,input_code_size,rv);
02406  return(rv);
02407 }
02408 
02409 static void
02410 ReadImage(im, fd, len, height, cmap, interlace, ignore)
02411      gdImagePtr im;
02412      FILE *fd;
02413      int len;
02414      int height;
02415      unsigned char (*cmap)[256];
02416      int interlace;
02417      int ignore;
02418 {
02419        unsigned char   c;      
02420        int             v;
02421        int             xpos = 0, ypos = 0, pass = 0;
02422        int i;
02423        /* Stash the color map into the image */
02424        for (i=0; (i<gdMaxColors); i++) {
02425                im->red[i] = cmap[CM_RED][i];    
02426                im->green[i] = cmap[CM_GREEN][i];        
02427                im->blue[i] = cmap[CM_BLUE][i];  
02428                im->open[i] = 1;
02429        }
02430        /* Many (perhaps most) of these colors will remain marked open. */
02431        im->colorsTotal = gdMaxColors;
02432        /*
02433        **  Initialize the Compression routines
02434        */
02435        if (! ReadOK(fd,&c,1)) {
02436                return; 
02437        }
02438        if (LWZReadByte(fd, TRUE, c) < 0) {
02439                return;
02440        }
02441 
02442        /*
02443        **  If this is an "uninteresting picture" ignore it.
02444        */
02445        if (ignore) {
02446                while (LWZReadByte(fd, FALSE, c) >= 0)
02447                        ;
02448                return;
02449        }
02450 
02451        while ((v = LWZReadByte(fd,FALSE,c)) >= 0 ) {
02452                /* This how we recognize which colors are actually used. */
02453                if (im->open[v]) {
02454                        im->open[v] = 0;
02455                }
02456                gdImageSetPixel(im, xpos, ypos, v);
02457                ++xpos;
02458                if (xpos == len) {
02459                        xpos = 0;
02460                        if (interlace) {
02461                                switch (pass) {
02462                                case 0:
02463                                case 1:
02464                                        ypos += 8; break;
02465                                case 2:
02466                                        ypos += 4; break;
02467                                case 3:
02468                                        ypos += 2; break;
02469                                }
02470 
02471                                if (ypos >= height) {
02472                                        ++pass;
02473                                        switch (pass) {
02474                                        case 1:
02475                                                ypos = 4; break;
02476                                        case 2:
02477                                                ypos = 2; break;
02478                                        case 3:
02479                                                ypos = 1; break;
02480                                        default:
02481                                                goto fini;
02482                                        }
02483                                }
02484                        } else {
02485                                ++ypos;
02486                        }
02487                }
02488                if (ypos >= height)
02489                        break;
02490        }
02491 
02492 fini:
02493        if (LWZReadByte(fd,FALSE,c)>=0) {
02494                /* Ignore extra */
02495        }
02496 }
02497 
02498 void gdImageRectangle(im, x1, y1, x2, y2, color)
02499      gdImagePtr im;
02500      int x1;
02501      int y1;
02502      int x2;
02503      int y2;
02504      int color;
02505 {
02506         gdImageLine(im, x1, y1, x2, y1, color);         
02507         gdImageLine(im, x1, y2, x2, y2, color);         
02508         gdImageLine(im, x1, y1, x1, y2, color);
02509         gdImageLine(im, x2, y1, x2, y2, color);
02510 }
02511 void gdImageThickRectangle(im, x1, y1, x2, y2, color, thick)
02512      gdImagePtr im;
02513      int x1;
02514      int y1;
02515      int x2;
02516      int y2;
02517      int color;
02518      int thick;
02519 {
02520         gdImageThickLine(im, x1, y1, x2, y1, color, thick);             
02521         gdImageThickLine(im, x1, y2, x2, y2, color, thick);             
02522         gdImageThickLine(im, x1, y1, x1, y2, color, thick);
02523         gdImageThickLine(im, x2, y1, x2, y2, color, thick);
02524 }
02525 
02526 void gdImageFilledRectangle(im, x1, y1, x2, y2, color)
02527      gdImagePtr im;
02528      int x1;
02529      int y1;
02530      int x2;
02531      int y2;
02532      int color;
02533 {
02534         int x, y;
02535         for (y=y1; (y<=y2); y++) {
02536                 for (x=x1; (x<=x2); x++) {
02537                         gdImageSetPixel(im, x, y, color);
02538                 }
02539         }
02540 }
02541 
02542 void gdImageCopy(dst, src, dstX, dstY, srcX, srcY, w, h)
02543      gdImagePtr dst;
02544      gdImagePtr src;
02545      int dstX;
02546      int dstY;
02547      int srcX;
02548      int srcY;
02549      int w;
02550      int h;
02551 {
02552         int c;
02553         int x, y;
02554         int tox, toy;
02555         int i;
02556         int colorMap[gdMaxColors];
02557         for (i=0; (i<gdMaxColors); i++) {
02558                 colorMap[i] = (-1);
02559         }
02560         toy = dstY;
02561         for (y=srcY; (y < (srcY + h)); y++) {
02562                 tox = dstX;
02563                 for (x=srcX; (x < (srcX + w)); x++) {
02564                         int nc;
02565                         c = gdImageGetPixel(src, x, y);
02566                         /* Added 7/24/95: support transparent copies */
02567                         if (gdImageGetTransparent(src) == c) {
02568                                 tox++;
02569                                 continue;
02570                         }
02571                         /* Have we established a mapping for this color? */
02572                         if (colorMap[c] == (-1)) {
02573                                 /* If it's the same image, mapping is trivial */
02574                                 if (dst == src) {
02575                                         nc = c;
02576                                 } else { 
02577                                         /* First look for an exact match */
02578                                         nc = gdImageColorExact(dst,
02579                                                 src->red[c], src->green[c],
02580                                                 src->blue[c]);
02581                                 }       
02582                                 if (nc == (-1)) {
02583                                         /* No, so try to allocate it */
02584                                         nc = gdImageColorAllocate(dst,
02585                                                 src->red[c], src->green[c],
02586                                                 src->blue[c]);
02587                                         /* If we're out of colors, go for the
02588                                                 closest color */
02589                                         if (nc == (-1)) {
02590                                                 nc = gdImageColorClosest(dst,
02591                                                         src->red[c], src->green[c],
02592                                                         src->blue[c]);
02593                                         }
02594                                 }
02595                                 colorMap[c] = nc;
02596                         }
02597                         gdImageSetPixel(dst, tox, toy, colorMap[c]);
02598                         tox++;
02599                 }
02600                 toy++;
02601         }
02602 }                       
02603 
02604 void gdImageCopyResized(dst, src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH)
02605      gdImagePtr dst;
02606      gdImagePtr src;
02607      int dstX;
02608      int dstY;
02609      int srcX;
02610      int srcY;
02611      int dstW;
02612      int dstH;
02613      int srcW;
02614      int srcH;
02615 {
02616         int c;
02617         int x, y;
02618         int tox, toy;
02619         int ydest;
02620         int i;
02621         int colorMap[gdMaxColors];
02622         /* Stretch vectors */
02623         int *stx;
02624         int *sty;
02625         /* We only need to use floating point to determine the correct
02626                 stretch vector for one line's worth. */
02627         double accum;
02628         stx = (int *) MALLOC(sizeof(int) * srcW);
02629         sty = (int *) MALLOC(sizeof(int) * srcH);
02630         accum = 0;
02631         for (i=0; (i < srcW); i++) {
02632                 int got;
02633                 accum += (double)dstW/(double)srcW;
02634                 got = (int)floor(accum);
02635                 stx[i] = got;
02636                 accum -= got;
02637         }
02638         accum = 0;
02639         for (i=0; (i < srcH); i++) {
02640                 int got;
02641                 accum += (double)dstH/(double)srcH;
02642                 got = (int)floor(accum);
02643                 sty[i] = got;
02644                 accum -= got;
02645         }
02646         for (i=0; (i<gdMaxColors); i++) {
02647                 colorMap[i] = (-1);
02648         }
02649         toy = dstY;
02650         for (y=srcY; (y < (srcY + srcH)); y++) {
02651                 for (ydest=0; (ydest < sty[y-srcY]); ydest++) {
02652                         tox = dstX;
02653                         for (x=srcX; (x < (srcX + srcW)); x++) {
02654                                 int nc;
02655                                 if (!stx[x - srcX]) {
02656                                         continue;
02657                                 }
02658                                 c = gdImageGetPixel(src, x, y);
02659                                 /* Added 7/24/95: support transparent copies */
02660                                 if (gdImageGetTransparent(src) == c) {
02661                                         tox += stx[x-srcX];
02662                                         continue;
02663                                 }
02664                                 /* Have we established a mapping for this color? */
02665                                 if (colorMap[c] == (-1)) {
02666                                         /* If it's the same image, mapping is trivial */
02667                                         if (dst == src) {
02668                                                 nc = c;
02669                                         } else { 
02670                                                 /* First look for an exact match */
02671                                                 nc = gdImageColorExact(dst,
02672                                                         src->red[c], src->green[c],
02673                                                         src->blue[c]);
02674                                         }       
02675                                         if (nc == (-1)) {
02676                                                 /* No, so try to allocate it */
02677                                                 nc = gdImageColorAllocate(dst,
02678                                                         src->red[c], src->green[c],
02679                                                         src->blue[c]);
02680                                                 /* If we're out of colors, go for the
02681                                                         closest color */
02682                                                 if (nc == (-1)) {
02683                                                         nc = gdImageColorClosest(dst,
02684                                                                 src->red[c], src->green[c],
02685                                                                 src->blue[c]);
02686                                                 }
02687                                         }
02688                                         colorMap[c] = nc;
02689                                 }
02690                                 for (i=0; (i < stx[x - srcX]); i++) {
02691                                         gdImageSetPixel(dst, tox, toy, colorMap[c]);
02692                                         tox++;
02693                                 }
02694                         }
02695                         toy++;
02696                 }
02697         }
02698         FREE(stx);
02699         FREE(sty);
02700 }
02701 
02702 int gdGetWord(result, in)
02703      int *result;
02704      FILE *in;
02705 {
02706         int r;
02707         r = getc(in);
02708         if (r == EOF) {
02709                 return 0;
02710         }
02711         *result = r << 8;
02712         r = getc(in);   
02713         if (r == EOF) {
02714                 return 0;
02715         }
02716         *result += r;
02717         return 1;
02718 }
02719 
02720 void gdPutWord(w, out)
02721      int w;
02722      FILE *out;
02723 {
02724         putc((unsigned char)(w >> 8), out);
02725         putc((unsigned char)(w & 0xFF), out);
02726 }
02727 
02728 int gdGetByte(result, in)
02729      int *result;
02730      FILE *in;
02731 {
02732         int r;
02733         r = getc(in);
02734         if (r == EOF) {
02735                 return 0;
02736         }
02737         *result = r;
02738         return 1;
02739 }
02740 
02741 gdImagePtr gdImageCreateFromGd(in)
02742      FILE *in;
02743 {
02744         int sx, sy;
02745         int x, y;
02746         int i;
02747         gdImagePtr im;
02748         if (!gdGetWord(&sx, in)) {
02749                 goto fail1;
02750         }
02751         if (!gdGetWord(&sy, in)) {
02752                 goto fail1;
02753         }
02754         im = gdImageCreate(sx, sy);
02755         if (!gdGetByte(&im->colorsTotal, in)) {
02756                 goto fail2;
02757         }
02758         if (!gdGetWord(&im->transparent, in)) {
02759                 goto fail2;
02760         }
02761         if (im->transparent == 257) {
02762                 im->transparent = (-1);
02763         }
02764         for (i=0; (i<gdMaxColors); i++) {
02765                 if (!gdGetByte(&im->red[i], in)) {
02766                         goto fail2;
02767                 }
02768                 if (!gdGetByte(&im->green[i], in)) {
02769                         goto fail2;
02770                 }
02771                 if (!gdGetByte(&im->blue[i], in)) {
02772                         goto fail2;
02773                 }
02774         }       
02775         for (y=0; (y<sy); y++) {
02776                 for (x=0; (x<sx); x++) {        
02777                         int ch;
02778                         ch = getc(in);
02779                         if (ch == EOF) {
02780                                 gdImageDestroy(im);
02781                                 return 0;
02782                         }
02783                         /* ROW-MAJOR IN GD 1.3 */
02784                         im->pixels[y][x] = ch;
02785                 }
02786         }
02787         return im;
02788 fail2:
02789         gdImageDestroy(im);
02790 fail1:
02791         return 0;
02792 }
02793         
02794 void gdImageGd(im, out)
02795      gdImagePtr im;
02796      FILE *out;
02797 {
02798         int x, y;
02799         int i;
02800         int trans;
02801         gdPutWord(im->sx, out);
02802         gdPutWord(im->sy, out);
02803         putc((unsigned char)im->colorsTotal, out);
02804         trans = im->transparent;
02805         if (trans == (-1)) {
02806                 trans = 257;
02807         }       
02808         gdPutWord(trans, out);
02809         for (i=0; (i<gdMaxColors); i++) {
02810                 putc((unsigned char)im->red[i], out);
02811                 putc((unsigned char)im->green[i], out); 
02812                 putc((unsigned char)im->blue[i], out);  
02813         }
02814         for (y=0; (y < im->sy); y++) {  
02815                 for (x=0; (x < im->sx); x++) {  
02816                         /* ROW-MAJOR IN GD 1.3 */
02817                         putc((unsigned char)im->pixels[y][x], out);
02818                 }
02819         }
02820 }
02821 
02822 gdImagePtr
02823 gdImageCreateFromXbm(fd)
02824      FILE *fd;
02825 {
02826         gdImagePtr im;  
02827         int bit;
02828         int w, h;
02829         int bytes;
02830         int ch;
02831         int i, x, y;
02832         char *sp;
02833         char s[161];
02834         if (!fgets(s, 160, fd)) {
02835                 return 0;
02836         }
02837         sp = &s[0];
02838         /* Skip #define */
02839         sp = strchr(sp, ' ');
02840         if (!sp) {
02841                 return 0;
02842         }
02843         /* Skip width label */
02844         sp++;
02845         sp = strchr(sp, ' ');
02846         if (!sp) {
02847                 return 0;
02848         }
02849         /* Get width */
02850         w = atoi(sp + 1);
02851         if (!w) {
02852                 return 0;
02853         }
02854         if (!fgets(s, 160, fd)) {
02855                 return 0;
02856         }
02857         sp = s;
02858         /* Skip #define */
02859         sp = strchr(sp, ' ');
02860         if (!sp) {
02861                 return 0;
02862         }
02863         /* Skip height label */
02864         sp++;
02865         sp = strchr(sp, ' ');
02866         if (!sp) {
02867                 return 0;
02868         }
02869         /* Get height */
02870         h = atoi(sp + 1);
02871         if (!h) {
02872                 return 0;
02873         }
02874         /* Skip declaration line */
02875         if (!fgets(s, 160, fd)) {
02876                 return 0;
02877         }
02878         bytes = ((w * h) / 8) + 1;
02879         im = gdImageCreate(w, h);
02880         gdImageColorAllocate(im, 255, 255, 255);
02881         gdImageColorAllocate(im, 0, 0, 0);
02882         x = 0;
02883         y = 0;
02884         for (i=0; (i < bytes); i++) {
02885                 char h[3];
02886                 int b;
02887                 /* Skip spaces, commas, CRs, 0x */
02888                 while(1) {
02889                         ch = getc(fd);
02890                         if (ch == EOF) {
02891                                 goto fail;
02892                         }
02893                         if (ch == 'x') {
02894                                 break;
02895                         }       
02896                 }
02897                 /* Get hex value */
02898                 ch = getc(fd);
02899                 if (ch == EOF) {
02900                         goto fail;
02901                 }
02902                 h[0] = ch;
02903                 ch = getc(fd);
02904                 if (ch == EOF) {
02905                         goto fail;
02906                 }
02907                 h[1] = ch;
02908                 h[2] = '\0';
02909                 sscanf(h, "%x", &b);            
02910                 for (bit = 1; (bit <= 128); (bit = bit << 1)) {
02911                         gdImageSetPixel(im, x++, y, (b & bit) ? 1 : 0); 
02912                         if (x == im->sx) {
02913                                 x = 0;
02914                                 y++;
02915                                 if (y == im->sy) {
02916                                         return im;
02917                                 }
02918                                 /* Fix 8/8/95 */
02919                                 break;
02920                         }
02921                 }
02922         }
02923         /* Shouldn't happen */
02924         /*      fprintf(stderr, "Error: bug in gdImageCreateFromXbm x=%d,sx=%d,y=%dsy=%d!\n",x,im->sx,y,im->sy);*/
02925         return im;
02926 fail:
02927         gdImageDestroy(im);
02928         return 0;
02929 }
02930 
02931 void gdImagePolygon(im, p, n, c)
02932      gdImagePtr im;
02933      gdPointPtr p;
02934      int n;
02935      int c;
02936 {
02937         int i;
02938         int lx, ly;
02939         if (!n) {
02940                 return;
02941         }
02942         lx = p->x;
02943         ly = p->y;
02944         gdImageLine(im, lx, ly, p[n-1].x, p[n-1].y, c);
02945         for (i=1; (i < n); i++) {
02946                 p++;
02947                 gdImageLine(im, lx, ly, p->x, p->y, c);
02948                 lx = p->x;
02949                 ly = p->y;
02950         }
02951 }       
02952         
02953 int gdCompareInt();
02954 void gdImageFilledPolygon(im,p,n,c)
02955      gdImagePtr im; gdPointPtr p; int n; int c;
02956 {
02957         int i;
02958         int y;
02959         int miny, maxy;
02960         int x1, y1;
02961         int x2, y2;
02962         int ind1, ind2;
02963         int ints;
02964         if (!n) {
02965                 return;
02966         }
02967         if (!im->polyAllocated) {
02968                 im->polyInts = (int *) MALLOC(sizeof(int) * n);
02969                 im->polyAllocated = n;
02970         }               
02971         if (im->polyAllocated < n) {
02972                 while (im->polyAllocated < n) {
02973                         im->polyAllocated *= 2;
02974                 }       
02975                 im->polyInts = (int *) REALLOC(im->polyInts,
02976                         sizeof(int) * im->polyAllocated);
02977         }
02978         miny = p[0].y;
02979         maxy = p[0].y;
02980         for (i=1; (i < n); i++) {
02981                 if (p[i].y < miny) {
02982                         miny = p[i].y;
02983                 }
02984                 if (p[i].y > maxy) {
02985                         maxy = p[i].y;
02986                 }
02987         }
02988         /* Fix in 1.3: count a vertex only once */
02989         for (y=miny; (y <= maxy); y++) {
02990 /*1.4           int interLast = 0; */
02991 /*              int dirLast = 0; */
02992 /*              int interFirst = 1; */
02993                 ints = 0;
02994                 for (i=0; (i < n); i++) {
02995                         if (!i) {
02996                                 ind1 = n-1;
02997                                 ind2 = 0;
02998                         } else {
02999                                 ind1 = i-1;
03000                                 ind2 = i;
03001                         }
03002                         y1 = p[ind1].y;
03003                         y2 = p[ind2].y;
03004                         if (y1 < y2) {
03005                                 x1 = p[ind1].x;
03006                                 x2 = p[ind2].x;
03007                         } else if (y1 > y2) {
03008                                 y2 = p[ind1].y;
03009                                 y1 = p[ind2].y;
03010                                 x2 = p[ind1].x;
03011                                 x1 = p[ind2].x;
03012                         } else {
03013                                 continue;
03014                         }
03015                         if ((y >= y1) && (y < y2)) {
03016                                 im->polyInts[ints++] = (y-y1) * (x2-x1) / (y2-y1) + x1;
03017                         } else if ((y == maxy) && (y > y1) && (y <= y2)) {
03018                                 im->polyInts[ints++] = (y-y1) * (x2-x1) / (y2-y1) + x1;
03019                         }
03020                 }
03021                 qsort(im->polyInts, ints, sizeof(int), gdCompareInt);
03022 
03023                 for (i=0; (i < (ints)); i+=2) {
03024                         gdImageLine(im, im->polyInts[i], y,
03025                                 im->polyInts[i+1], y, c);
03026                 }
03027         }
03028 }
03029 int gdCompareInt(a, b)
03030      /*     const void *a;
03031             const void *b; */
03032   void *a;
03033   void *b; 
03034 {
03035   /*    return (*(const int *)a) - (*(const int *)b); */
03036         return (*(int *)a) - (*(int *)b);
03037 }
03038 
03039 void gdImageSetStyle(im, style, noOfPixels)
03040      gdImagePtr im;
03041      int *style;
03042      int noOfPixels;
03043 {
03044         if (im->style) {
03045                 FREE(im->style);
03046         }
03047         im->style = (int *) 
03048                 MALLOC(sizeof(int) * noOfPixels);
03049         memcpy(im->style, style, sizeof(int) * noOfPixels);
03050         im->styleLength = noOfPixels;
03051         im->stylePos = 0;
03052 }
03053 
03054 void gdImageSetBrush(im, brush)
03055      gdImagePtr im;
03056      gdImagePtr brush;
03057 {
03058         int i;
03059         im->brush = brush;
03060         for (i=0; (i < gdImageColorsTotal(brush)); i++) {
03061                 int index;
03062                 index = gdImageColorExact(im, 
03063                         gdImageRed(brush, i),
03064                         gdImageGreen(brush, i),
03065                         gdImageBlue(brush, i));
03066                 if (index == (-1)) {
03067                         index = gdImageColorAllocate(im,
03068                                 gdImageRed(brush, i),
03069                                 gdImageGreen(brush, i),
03070                                 gdImageBlue(brush, i));
03071                         if (index == (-1)) {
03072                                 index = gdImageColorClosest(im,
03073                                         gdImageRed(brush, i),
03074                                         gdImageGreen(brush, i),
03075                                         gdImageBlue(brush, i));
03076                         }
03077                 }
03078                 im->brushColorMap[i] = index;
03079         }
03080 }
03081         
03082 void gdImageSetTile(im, tile)
03083      gdImagePtr im;
03084      gdImagePtr tile;
03085 {
03086         int i;
03087         im->tile = tile;
03088         for (i=0; (i < gdImageColorsTotal(tile)); i++) {
03089                 int index;
03090                 index = gdImageColorExact(im, 
03091                         gdImageRed(tile, i),
03092                         gdImageGreen(tile, i),
03093                         gdImageBlue(tile, i));
03094                 if (index == (-1)) {
03095                         index = gdImageColorAllocate(im,
03096                                 gdImageRed(tile, i),
03097                                 gdImageGreen(tile, i),
03098                                 gdImageBlue(tile, i));
03099                         if (index == (-1)) {
03100                                 index = gdImageColorClosest(im,
03101                                         gdImageRed(tile, i),
03102                                         gdImageGreen(tile, i),
03103                                         gdImageBlue(tile, i));
03104                         }
03105                 }
03106                 im->tileColorMap[i] = index;
03107         }
03108 }
03109 
03110 void gdImageInterlace(im, interlaceArg)
03111      gdImagePtr im;
03112      int interlaceArg;
03113 {
03114         im->interlace = interlaceArg;
03115 }
03116 
03117 /*SG added function to change a given color with another */
03118 void gdImageChangeColor(im, old, new)
03119      gdImagePtr im;
03120      int old;
03121      int new;
03122 {
03123   int x, y,mx=0,mn=0;
03124   for (y=0; (y < im->sy); y++) {        
03125     for (x=0; (x < im->sx); x++) {      
03126       if (im->pixels[y][x]==old) 
03127         im->pixels[y][x]=new;
03128 
03129     }
03130   }
03131 }
03132 void gdImagePPM(im, out)
03133      gdImagePtr im;
03134      FILE *out;
03135 {
03136   int x,y,k;
03137   int interlace, transparent, background, BitsPerPixel;
03138   interlace = im->interlace;
03139   transparent = im->transparent;
03140   background = im->background;
03141   BitsPerPixel = colorstobpp(im->colorsTotal);
03142 
03143                
03144   /*    Write the 'header' information  */
03145   fprintf(out,"P6\n%d %d\n255\n",im->sx,im->sy);
03146   for (y=0; (y < im->sy); y++) {        
03147     for (x=0; (x < im->sx); x++) {      
03148       k=im->pixels[y][x];
03149       putc(im->red[k],out);
03150       putc(im->green[k],out);
03151       putc(im->blue[k],out);
03152     }
03153   }
03154 }
03155 
03156 

Generated on Sun Mar 4 15:03:54 2007 for Scilab [trunk] by  doxygen 1.5.1