Annotation of embedaddon/php/ext/gd/libgd/gd_gif_in.c, revision 1.1.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>