Annotation of embedaddon/php/ext/gd/libgd/gd_gif_in.c, revision 1.1
1.1 ! misho 1: #include <stdio.h>
! 2: #include <math.h>
! 3: #include <string.h>
! 4: #include <stdlib.h>
! 5: #include "gd.h"
! 6:
! 7: #include "php.h"
! 8:
! 9: /* Used only when debugging GIF compression code */
! 10: /* #define DEBUGGING_ENVARS */
! 11:
! 12: #ifdef DEBUGGING_ENVARS
! 13:
! 14: static int verbose_set = 0;
! 15: static int verbose;
! 16: #define VERBOSE (verbose_set?verbose:set_verbose())
! 17:
! 18: static int set_verbose(void)
! 19: {
! 20: verbose = !!getenv("GIF_VERBOSE");
! 21: verbose_set = 1;
! 22: return(verbose);
! 23: }
! 24:
! 25: #else
! 26:
! 27: #define VERBOSE 0
! 28:
! 29: #endif
! 30:
! 31:
! 32: #define MAXCOLORMAPSIZE 256
! 33:
! 34: #define TRUE 1
! 35: #define FALSE 0
! 36:
! 37: #define CM_RED 0
! 38: #define CM_GREEN 1
! 39: #define CM_BLUE 2
! 40:
! 41: #define MAX_LWZ_BITS 12
! 42:
! 43: #define INTERLACE 0x40
! 44: #define LOCALCOLORMAP 0x80
! 45: #define BitSet(byte, bit) (((byte) & (bit)) == (bit))
! 46:
! 47: #define ReadOK(file,buffer,len) (gdGetBuf(buffer, len, file) > 0)
! 48:
! 49: #define LM_to_uint(a,b) (((b)<<8)|(a))
! 50:
! 51: /* We may eventually want to use this information, but def it out for now */
! 52: #if 0
! 53: static struct {
! 54: unsigned int Width;
! 55: unsigned int Height;
! 56: unsigned char ColorMap[3][MAXCOLORMAPSIZE];
! 57: unsigned int BitPixel;
! 58: unsigned int ColorResolution;
! 59: unsigned int Background;
! 60: unsigned int AspectRatio;
! 61: } GifScreen;
! 62: #endif
! 63:
! 64: #if 0
! 65: static struct {
! 66: int transparent;
! 67: int delayTime;
! 68: int inputFlag;
! 69: int disposal;
! 70: } Gif89 = { -1, -1, -1, 0 };
! 71: #endif
! 72:
! 73: #define STACK_SIZE ((1<<(MAX_LWZ_BITS))*2)
! 74:
! 75: typedef struct {
! 76: unsigned char buf[280];
! 77: int curbit, lastbit, done, last_byte;
! 78: } CODE_STATIC_DATA;
! 79:
! 80: typedef struct {
! 81: int fresh;
! 82: int code_size, set_code_size;
! 83: int max_code, max_code_size;
! 84: int firstcode, oldcode;
! 85: int clear_code, end_code;
! 86: int table[2][(1<< MAX_LWZ_BITS)];
! 87: int stack[STACK_SIZE], *sp;
! 88: CODE_STATIC_DATA scd;
! 89: } LZW_STATIC_DATA;
! 90:
! 91: static int ReadColorMap (gdIOCtx *fd, int number, unsigned char (*buffer)[256]);
! 92: static int DoExtension (gdIOCtx *fd, int label, int *Transparent, int *ZeroDataBlockP);
! 93: static int GetDataBlock (gdIOCtx *fd, unsigned char *buf, int *ZeroDataBlockP);
! 94: static int GetCode (gdIOCtx *fd, CODE_STATIC_DATA *scd, int code_size, int flag, int *ZeroDataBlockP);
! 95: static int LWZReadByte (gdIOCtx *fd, LZW_STATIC_DATA *sd, char flag, int input_code_size, int *ZeroDataBlockP);
! 96:
! 97: static void ReadImage (gdImagePtr im, gdIOCtx *fd, int len, int height, unsigned char (*cmap)[256], int interlace, int *ZeroDataBlockP); /*1.4//, int ignore); */
! 98:
! 99: gdImagePtr gdImageCreateFromGifSource(gdSourcePtr inSource) /* {{{ */
! 100: {
! 101: gdIOCtx *in = gdNewSSCtx(inSource, NULL);
! 102: gdImagePtr im;
! 103:
! 104: im = gdImageCreateFromGifCtx(in);
! 105:
! 106: in->gd_free(in);
! 107:
! 108: return im;
! 109: }
! 110: /* }}} */
! 111:
! 112: gdImagePtr gdImageCreateFromGif(FILE *fdFile) /* {{{ */
! 113: {
! 114: gdIOCtx *fd = gdNewFileCtx(fdFile);
! 115: gdImagePtr im = 0;
! 116:
! 117: im = gdImageCreateFromGifCtx(fd);
! 118:
! 119: fd->gd_free(fd);
! 120:
! 121: return im;
! 122: }
! 123: /* }}} */
! 124:
! 125: gdImagePtr gdImageCreateFromGifCtx(gdIOCtxPtr fd) /* {{{ */
! 126: {
! 127: int BitPixel;
! 128: #if 0
! 129: int ColorResolution;
! 130: int Background;
! 131: int AspectRatio;
! 132: #endif
! 133: int Transparent = (-1);
! 134: unsigned char buf[16];
! 135: unsigned char c;
! 136: unsigned char ColorMap[3][MAXCOLORMAPSIZE];
! 137: unsigned char localColorMap[3][MAXCOLORMAPSIZE];
! 138: int imw, imh, screen_width, screen_height;
! 139: int gif87a, useGlobalColormap;
! 140: int bitPixel;
! 141: int i;
! 142: /*1.4//int imageCount = 0; */
! 143:
! 144: int ZeroDataBlock = FALSE;
! 145: int haveGlobalColormap;
! 146: gdImagePtr im = 0;
! 147:
! 148: /*1.4//imageNumber = 1; */
! 149: if (! ReadOK(fd,buf,6)) {
! 150: return 0;
! 151: }
! 152: if (strncmp((char *)buf,"GIF",3) != 0) {
! 153: return 0;
! 154: }
! 155:
! 156: if (memcmp((char *)buf+3, "87a", 3) == 0) {
! 157: gif87a = 1;
! 158: } else if (memcmp((char *)buf+3, "89a", 3) == 0) {
! 159: gif87a = 0;
! 160: } else {
! 161: return 0;
! 162: }
! 163:
! 164: if (! ReadOK(fd,buf,7)) {
! 165: return 0;
! 166: }
! 167:
! 168: BitPixel = 2<<(buf[4]&0x07);
! 169: #if 0
! 170: ColorResolution = (int) (((buf[4]&0x70)>>3)+1);
! 171: Background = buf[5];
! 172: AspectRatio = buf[6];
! 173: #endif
! 174: screen_width = imw = LM_to_uint(buf[0],buf[1]);
! 175: screen_height = imh = LM_to_uint(buf[2],buf[3]);
! 176:
! 177: haveGlobalColormap = BitSet(buf[4], LOCALCOLORMAP); /* Global Colormap */
! 178: if (haveGlobalColormap) {
! 179: if (ReadColorMap(fd, BitPixel, ColorMap)) {
! 180: return 0;
! 181: }
! 182: }
! 183:
! 184: for (;;) {
! 185: int top, left;
! 186: int width, height;
! 187:
! 188: if (! ReadOK(fd,&c,1)) {
! 189: return 0;
! 190: }
! 191: if (c == ';') { /* GIF terminator */
! 192: goto terminated;
! 193: }
! 194:
! 195: if (c == '!') { /* Extension */
! 196: if (! ReadOK(fd,&c,1)) {
! 197: return 0;
! 198: }
! 199: DoExtension(fd, c, &Transparent, &ZeroDataBlock);
! 200: continue;
! 201: }
! 202:
! 203: if (c != ',') { /* Not a valid start character */
! 204: continue;
! 205: }
! 206:
! 207: /*1.4//++imageCount; */
! 208:
! 209: if (! ReadOK(fd,buf,9)) {
! 210: return 0;
! 211: }
! 212:
! 213: useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP);
! 214:
! 215: bitPixel = 1<<((buf[8]&0x07)+1);
! 216: left = LM_to_uint(buf[0], buf[1]);
! 217: top = LM_to_uint(buf[2], buf[3]);
! 218: width = LM_to_uint(buf[4], buf[5]);
! 219: height = LM_to_uint(buf[6], buf[7]);
! 220:
! 221: if (left + width > screen_width || top + height > screen_height) {
! 222: if (VERBOSE) {
! 223: printf("Frame is not confined to screen dimension.\n");
! 224: }
! 225: return 0;
! 226: }
! 227:
! 228: if (!(im = gdImageCreate(width, height))) {
! 229: return 0;
! 230: }
! 231: im->interlace = BitSet(buf[8], INTERLACE);
! 232: if (!useGlobalColormap) {
! 233: if (ReadColorMap(fd, bitPixel, localColorMap)) {
! 234: gdImageDestroy(im);
! 235: return 0;
! 236: }
! 237: ReadImage(im, fd, width, height, localColorMap,
! 238: BitSet(buf[8], INTERLACE), &ZeroDataBlock);
! 239: } else {
! 240: if (!haveGlobalColormap) {
! 241: gdImageDestroy(im);
! 242: return 0;
! 243: }
! 244: ReadImage(im, fd, width, height,
! 245: ColorMap,
! 246: BitSet(buf[8], INTERLACE), &ZeroDataBlock);
! 247: }
! 248: if (Transparent != (-1)) {
! 249: gdImageColorTransparent(im, Transparent);
! 250: }
! 251: goto terminated;
! 252: }
! 253:
! 254: terminated:
! 255: /* Terminator before any image was declared! */
! 256: if (!im) {
! 257: return 0;
! 258: }
! 259: if (!im->colorsTotal) {
! 260: gdImageDestroy(im);
! 261: return 0;
! 262: }
! 263: /* Check for open colors at the end, so
! 264: we can reduce colorsTotal and ultimately
! 265: BitsPerPixel */
! 266: for (i=((im->colorsTotal-1)); (i>=0); i--) {
! 267: if (im->open[i]) {
! 268: im->colorsTotal--;
! 269: } else {
! 270: break;
! 271: }
! 272: }
! 273: return im;
! 274: }
! 275: /* }}} */
! 276:
! 277: static int ReadColorMap(gdIOCtx *fd, int number, unsigned char (*buffer)[256]) /* {{{ */
! 278: {
! 279: int i;
! 280: unsigned char rgb[3];
! 281:
! 282:
! 283: for (i = 0; i < number; ++i) {
! 284: if (! ReadOK(fd, rgb, sizeof(rgb))) {
! 285: return TRUE;
! 286: }
! 287: buffer[CM_RED][i] = rgb[0] ;
! 288: buffer[CM_GREEN][i] = rgb[1] ;
! 289: buffer[CM_BLUE][i] = rgb[2] ;
! 290: }
! 291:
! 292:
! 293: return FALSE;
! 294: }
! 295: /* }}} */
! 296:
! 297: static int
! 298: DoExtension(gdIOCtx *fd, int label, int *Transparent, int *ZeroDataBlockP)
! 299: {
! 300: unsigned char buf[256];
! 301:
! 302: switch (label) {
! 303: case 0xf9: /* Graphic Control Extension */
! 304: memset(buf, 0, 4); /* initialize a few bytes in the case the next function fails */
! 305: (void) GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP);
! 306: #if 0
! 307: Gif89.disposal = (buf[0] >> 2) & 0x7;
! 308: Gif89.inputFlag = (buf[0] >> 1) & 0x1;
! 309: Gif89.delayTime = LM_to_uint(buf[1],buf[2]);
! 310: #endif
! 311: if ((buf[0] & 0x1) != 0)
! 312: *Transparent = buf[3];
! 313:
! 314: while (GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP) > 0);
! 315: return FALSE;
! 316: default:
! 317: break;
! 318: }
! 319: while (GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP) > 0)
! 320: ;
! 321:
! 322: return FALSE;
! 323: }
! 324: /* }}} */
! 325:
! 326: static int
! 327: GetDataBlock_(gdIOCtx *fd, unsigned char *buf, int *ZeroDataBlockP)
! 328: {
! 329: unsigned char count;
! 330:
! 331: if (! ReadOK(fd,&count,1)) {
! 332: return -1;
! 333: }
! 334:
! 335: *ZeroDataBlockP = count == 0;
! 336:
! 337: if ((count != 0) && (! ReadOK(fd, buf, count))) {
! 338: return -1;
! 339: }
! 340:
! 341: return count;
! 342: }
! 343: /* }}} */
! 344:
! 345: static int
! 346: GetDataBlock(gdIOCtx *fd, unsigned char *buf, int *ZeroDataBlockP)
! 347: {
! 348: int rv;
! 349: int i;
! 350:
! 351: rv = GetDataBlock_(fd,buf, ZeroDataBlockP);
! 352: if (VERBOSE) {
! 353: char *tmp = NULL;
! 354: if (rv > 0) {
! 355: tmp = safe_emalloc(3 * rv, sizeof(char), 1);
! 356: for (i=0;i<rv;i++) {
! 357: sprintf(&tmp[3*sizeof(char)*i], " %02x", buf[i]);
! 358: }
! 359: } else {
! 360: tmp = estrdup("");
! 361: }
! 362: php_gd_error_ex(E_NOTICE, "[GetDataBlock returning %d: %s]", rv, tmp);
! 363: efree(tmp);
! 364: }
! 365: return(rv);
! 366: }
! 367: /* }}} */
! 368:
! 369: static int
! 370: GetCode_(gdIOCtx *fd, CODE_STATIC_DATA *scd, int code_size, int flag, int *ZeroDataBlockP)
! 371: {
! 372: int i, j, ret;
! 373: unsigned char count;
! 374:
! 375: if (flag) {
! 376: scd->curbit = 0;
! 377: scd->lastbit = 0;
! 378: scd->last_byte = 0;
! 379: scd->done = FALSE;
! 380: return 0;
! 381: }
! 382:
! 383: if ( (scd->curbit + code_size) >= scd->lastbit) {
! 384: if (scd->done) {
! 385: if (scd->curbit >= scd->lastbit) {
! 386: /* Oh well */
! 387: }
! 388: return -1;
! 389: }
! 390: scd->buf[0] = scd->buf[scd->last_byte-2];
! 391: scd->buf[1] = scd->buf[scd->last_byte-1];
! 392:
! 393: if ((count = GetDataBlock(fd, &scd->buf[2], ZeroDataBlockP)) <= 0)
! 394: scd->done = TRUE;
! 395:
! 396: scd->last_byte = 2 + count;
! 397: scd->curbit = (scd->curbit - scd->lastbit) + 16;
! 398: scd->lastbit = (2+count)*8 ;
! 399: }
! 400:
! 401: ret = 0;
! 402: for (i = scd->curbit, j = 0; j < code_size; ++i, ++j)
! 403: ret |= ((scd->buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
! 404:
! 405: scd->curbit += code_size;
! 406: return ret;
! 407: }
! 408:
! 409: static int
! 410: GetCode(gdIOCtx *fd, CODE_STATIC_DATA *scd, int code_size, int flag, int *ZeroDataBlockP)
! 411: {
! 412: int rv;
! 413:
! 414: rv = GetCode_(fd, scd, code_size,flag, ZeroDataBlockP);
! 415: if (VERBOSE) printf("[GetCode(,%d,%d) returning %d]\n",code_size,flag,rv);
! 416: return(rv);
! 417: }
! 418: /* }}} */
! 419:
! 420: static int
! 421: LWZReadByte_(gdIOCtx *fd, LZW_STATIC_DATA *sd, char flag, int input_code_size, int *ZeroDataBlockP)
! 422: {
! 423: int code, incode, i;
! 424:
! 425: if (flag) {
! 426: sd->set_code_size = input_code_size;
! 427: sd->code_size = sd->set_code_size+1;
! 428: sd->clear_code = 1 << sd->set_code_size ;
! 429: sd->end_code = sd->clear_code + 1;
! 430: sd->max_code_size = 2*sd->clear_code;
! 431: sd->max_code = sd->clear_code+2;
! 432:
! 433: GetCode(fd, &sd->scd, 0, TRUE, ZeroDataBlockP);
! 434:
! 435: sd->fresh = TRUE;
! 436:
! 437: for (i = 0; i < sd->clear_code; ++i) {
! 438: sd->table[0][i] = 0;
! 439: sd->table[1][i] = i;
! 440: }
! 441: for (; i < (1<<MAX_LWZ_BITS); ++i)
! 442: sd->table[0][i] = sd->table[1][0] = 0;
! 443:
! 444: sd->sp = sd->stack;
! 445:
! 446: return 0;
! 447: } else if (sd->fresh) {
! 448: sd->fresh = FALSE;
! 449: do {
! 450: sd->firstcode = sd->oldcode =
! 451: GetCode(fd, &sd->scd, sd->code_size, FALSE, ZeroDataBlockP);
! 452: } while (sd->firstcode == sd->clear_code);
! 453: return sd->firstcode;
! 454: }
! 455:
! 456: if (sd->sp > sd->stack)
! 457: return *--sd->sp;
! 458:
! 459: while ((code = GetCode(fd, &sd->scd, sd->code_size, FALSE, ZeroDataBlockP)) >= 0) {
! 460: if (code == sd->clear_code) {
! 461: for (i = 0; i < sd->clear_code; ++i) {
! 462: sd->table[0][i] = 0;
! 463: sd->table[1][i] = i;
! 464: }
! 465: for (; i < (1<<MAX_LWZ_BITS); ++i)
! 466: sd->table[0][i] = sd->table[1][i] = 0;
! 467: sd->code_size = sd->set_code_size+1;
! 468: sd->max_code_size = 2*sd->clear_code;
! 469: sd->max_code = sd->clear_code+2;
! 470: sd->sp = sd->stack;
! 471: sd->firstcode = sd->oldcode =
! 472: GetCode(fd, &sd->scd, sd->code_size, FALSE, ZeroDataBlockP);
! 473: return sd->firstcode;
! 474: } else if (code == sd->end_code) {
! 475: int count;
! 476: unsigned char buf[260];
! 477:
! 478: if (*ZeroDataBlockP)
! 479: return -2;
! 480:
! 481: while ((count = GetDataBlock(fd, buf, ZeroDataBlockP)) > 0)
! 482: ;
! 483:
! 484: if (count != 0)
! 485: return -2;
! 486: }
! 487:
! 488: incode = code;
! 489:
! 490: if (sd->sp == (sd->stack + STACK_SIZE)) {
! 491: /* Bad compressed data stream */
! 492: return -1;
! 493: }
! 494:
! 495: if (code >= sd->max_code) {
! 496: *sd->sp++ = sd->firstcode;
! 497: code = sd->oldcode;
! 498: }
! 499:
! 500: while (code >= sd->clear_code) {
! 501: if (sd->sp == (sd->stack + STACK_SIZE)) {
! 502: /* Bad compressed data stream */
! 503: return -1;
! 504: }
! 505: *sd->sp++ = sd->table[1][code];
! 506: if (code == sd->table[0][code]) {
! 507: /* Oh well */
! 508: }
! 509: code = sd->table[0][code];
! 510: }
! 511:
! 512: *sd->sp++ = sd->firstcode = sd->table[1][code];
! 513:
! 514: if ((code = sd->max_code) <(1<<MAX_LWZ_BITS)) {
! 515: sd->table[0][code] = sd->oldcode;
! 516: sd->table[1][code] = sd->firstcode;
! 517: ++sd->max_code;
! 518: if ((sd->max_code >= sd->max_code_size) &&
! 519: (sd->max_code_size < (1<<MAX_LWZ_BITS))) {
! 520: sd->max_code_size *= 2;
! 521: ++sd->code_size;
! 522: }
! 523: }
! 524:
! 525: sd->oldcode = incode;
! 526:
! 527: if (sd->sp > sd->stack)
! 528: return *--sd->sp;
! 529: }
! 530: return code;
! 531: }
! 532: /* }}} */
! 533:
! 534: static int
! 535: LWZReadByte(gdIOCtx *fd, LZW_STATIC_DATA *sd, char flag, int input_code_size, int *ZeroDataBlockP)
! 536: {
! 537: int rv;
! 538:
! 539: rv = LWZReadByte_(fd, sd, flag, input_code_size, ZeroDataBlockP);
! 540: if (VERBOSE) printf("[LWZReadByte(,%d,%d) returning %d]\n",flag,input_code_size,rv);
! 541: return(rv);
! 542: }
! 543: /* }}} */
! 544:
! 545: static void
! 546: ReadImage(gdImagePtr im, gdIOCtx *fd, int len, int height, unsigned char (*cmap)[256], int interlace, int *ZeroDataBlockP) /*1.4//, int ignore) */
! 547: {
! 548: unsigned char c;
! 549: int v;
! 550: int xpos = 0, ypos = 0, pass = 0;
! 551: int i;
! 552: LZW_STATIC_DATA sd;
! 553:
! 554:
! 555: /*
! 556: ** Initialize the Compression routines
! 557: */
! 558: if (! ReadOK(fd,&c,1)) {
! 559: return;
! 560: }
! 561:
! 562: if (c > MAX_LWZ_BITS) {
! 563: return;
! 564: }
! 565:
! 566: /* Stash the color map into the image */
! 567: for (i=0; (i<gdMaxColors); i++) {
! 568: im->red[i] = cmap[CM_RED][i];
! 569: im->green[i] = cmap[CM_GREEN][i];
! 570: im->blue[i] = cmap[CM_BLUE][i];
! 571: im->open[i] = 1;
! 572: }
! 573: /* Many (perhaps most) of these colors will remain marked open. */
! 574: im->colorsTotal = gdMaxColors;
! 575: if (LWZReadByte(fd, &sd, TRUE, c, ZeroDataBlockP) < 0) {
! 576: return;
! 577: }
! 578:
! 579: /*
! 580: ** If this is an "uninteresting picture" ignore it.
! 581: ** REMOVED For 1.4
! 582: */
! 583: /*if (ignore) { */
! 584: /* while (LWZReadByte(fd, &sd, FALSE, c) >= 0) */
! 585: /* ; */
! 586: /* return; */
! 587: /*} */
! 588:
! 589: while ((v = LWZReadByte(fd, &sd, FALSE, c, ZeroDataBlockP)) >= 0) {
! 590: if (v >= gdMaxColors) {
! 591: v = 0;
! 592: }
! 593: /* This how we recognize which colors are actually used. */
! 594: if (im->open[v]) {
! 595: im->open[v] = 0;
! 596: }
! 597: gdImageSetPixel(im, xpos, ypos, v);
! 598: ++xpos;
! 599: if (xpos == len) {
! 600: xpos = 0;
! 601: if (interlace) {
! 602: switch (pass) {
! 603: case 0:
! 604: case 1:
! 605: ypos += 8; break;
! 606: case 2:
! 607: ypos += 4; break;
! 608: case 3:
! 609: ypos += 2; break;
! 610: }
! 611:
! 612: if (ypos >= height) {
! 613: ++pass;
! 614: switch (pass) {
! 615: case 1:
! 616: ypos = 4; break;
! 617: case 2:
! 618: ypos = 2; break;
! 619: case 3:
! 620: ypos = 1; break;
! 621: default:
! 622: goto fini;
! 623: }
! 624: }
! 625: } else {
! 626: ++ypos;
! 627: }
! 628: }
! 629: if (ypos >= height)
! 630: break;
! 631: }
! 632:
! 633: fini:
! 634: if (LWZReadByte(fd, &sd, FALSE, c, ZeroDataBlockP) >=0) {
! 635: /* Ignore extra */
! 636: }
! 637: }
! 638: /* }}} */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>