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
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
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
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
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
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
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
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
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
00222 return im->pixels[y][x];
00223 } else {
00224 return 0;
00225 }
00226 }
00227
00228
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
00540
00541
00542
00543
00544
00545
00546
00547
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
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
00597 int leftLimit, rightLimit;
00598 int i;
00599 leftLimit = (-1);
00600 if (border < 0) {
00601
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
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
00624
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
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
00669 int p, tileColor;
00670 int srcx, srcy;
00671 if (!im->tile) {
00672 return;
00673 }
00674
00675
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
00685 return;
00686 }
00687 } else {
00688 if (old == color) {
00689
00690 return;
00691 }
00692 }
00693
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
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
00715
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
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
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
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
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
00800 init_statics();
00801
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
00834
00835
00836
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
00851
00852 static void
00853 BumpPixel(void)
00854 {
00855
00856
00857
00858 ++curx;
00859
00860
00861
00862
00863
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
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
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
00950
00951 CountDown = (long)Width * (long)Height;
00952
00953
00954
00955
00956 Pass = 0;
00957
00958
00959
00960
00961 if( BitsPerPixel <= 1 )
00962 InitCodeSize = 2;
00963 else
00964 InitCodeSize = BitsPerPixel;
00965
00966
00967
00968
00969 curx = cury = 0;
00970
00971
00972
00973
00974 fwrite( Transparent < 0 ? "GIF87a" : "GIF89a", 1, 6, fp );
00975
00976
00977
00978
00979 Putword( RWidth, fp );
00980 Putword( RHeight, fp );
00981
00982
00983
00984
00985 B = 0x80;
00986
00987
00988
00989
00990 B |= (Resolution - 1) << 4;
00991
00992
00993
00994
00995 B |= (BitsPerPixel - 1);
00996
00997
00998
00999
01000 fputc( B, fp );
01001
01002
01003
01004
01005 fputc( Background, fp );
01006
01007
01008
01009
01010 fputc( 0, fp );
01011
01012
01013
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
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
01037
01038 fputc( ',', fp );
01039
01040
01041
01042
01043
01044 Putword( LeftOfs, fp );
01045 Putword( TopOfs, fp );
01046 Putword( Width, fp );
01047 Putword( Height, fp );
01048
01049
01050
01051
01052 if( Interlace )
01053 fputc( 0x40, fp );
01054 else
01055 fputc( 0x00, fp );
01056
01057
01058
01059
01060 fputc( InitCodeSize, fp );
01061
01062
01063
01064
01065 compress( InitCodeSize+1, fp, im, Background );
01066
01067
01068
01069
01070 fputc( 0, fp );
01071
01072
01073
01074
01075 fputc( ';', fp );
01076 }
01077
01078
01079
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
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
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
01157
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
01449
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
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497 static int a_count;
01498
01499
01500
01501
01502 static void
01503 char_init(void)
01504 {
01505 a_count = 0;
01506 }
01507
01508
01509
01510
01511 static char accum[ 256 ];
01512
01513 static void init_statics(void) {
01514
01515
01516
01517
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
01531
01532
01533
01534
01535
01536
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
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)) {
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 == ';') {
01640 int i;
01641 if (imageCount < imageNumber) {
01642 return 0;
01643 }
01644
01645 if (!im) {
01646 return 0;
01647 }
01648
01649
01650
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 == '!') {
01662 if (! ReadOK(fd,&c,1)) {
01663 return 0;
01664 }
01665 DoExtension(fd, c, &Transparent);
01666 continue;
01667 }
01668
01669 if (c != ',') {
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:
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
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
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
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
01978 im->colorsTotal = gdMaxColors;
01979
01980
01981
01982 if (! ReadOK(fd,&c,1)) {
01983 return;
01984 }
01985 if (LWZReadByte(fd, TRUE, c) < 0) {
01986 return;
01987 }
01988
01989
01990
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
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
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
02080 if (gdImageGetTransparent(src) == c) {
02081 tox++;
02082 continue;
02083 }
02084
02085 if (colorMap[c] == (-1)) {
02086
02087 if (dst == src) {
02088 nc = c;
02089 } else {
02090
02091 nc = gdImageColorExact(dst,
02092 src->red[c], src->green[c],
02093 src->blue[c]);
02094 }
02095 if (nc == (-1)) {
02096
02097 nc = gdImageColorAllocate(dst,
02098 src->red[c], src->green[c],
02099 src->blue[c]);
02100
02101
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
02126 int *stx;
02127 int *sty;
02128
02129
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
02163 if (gdImageGetTransparent(src) == c) {
02164 tox += stx[x-srcX];
02165 continue;
02166 }
02167
02168 if (colorMap[c] == (-1)) {
02169
02170 if (dst == src) {
02171 nc = c;
02172 } else {
02173
02174 nc = gdImageColorExact(dst,
02175 src->red[c], src->green[c],
02176 src->blue[c]);
02177 }
02178 if (nc == (-1)) {
02179
02180 nc = gdImageColorAllocate(dst,
02181 src->red[c], src->green[c],
02182 src->blue[c]);
02183
02184
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
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
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
02332 sp = strchr(sp, ' ');
02333 if (!sp) {
02334 return 0;
02335 }
02336
02337 sp++;
02338 sp = strchr(sp, ' ');
02339 if (!sp) {
02340 return 0;
02341 }
02342
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
02352 sp = strchr(sp, ' ');
02353 if (!sp) {
02354 return 0;
02355 }
02356
02357 sp++;
02358 sp = strchr(sp, ' ');
02359 if (!sp) {
02360 return 0;
02361 }
02362
02363 h = atoi(sp + 1);
02364 if (!h) {
02365 return 0;
02366 }
02367
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
02381 while(1) {
02382 ch = getc(fd);
02383 if (ch == EOF) {
02384 goto fail;
02385 }
02386 if (ch == 'x') {
02387 break;
02388 }
02389 }
02390
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
02412 break;
02413 }
02414 }
02415 }
02416
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
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
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
02519
02520
02521
02522
02523
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
02530 im->polyInts[ints] = inter;
02531 } else {
02532
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 }