gd.cpp

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

Generated on Sat Dec 15 00:00:57 2007 for BulmaGes by  doxygen 1.5.1