Back to index

tetex-bin  3.0
gd_gif_in.c
Go to the documentation of this file.
00001 #include <stdio.h>
00002 #include <math.h>
00003 #include <string.h>
00004 #include <stdlib.h>
00005 #include "gd.h"
00006 
00007 /* Used only when debugging GIF compression code */
00008 /* #define DEBUGGING_ENVARS */
00009 
00010 #ifdef DEBUGGING_ENVARS
00011 
00012 static int verbose_set = 0;
00013 static int verbose;
00014 #define VERBOSE (verbose_set?verbose:set_verbose())
00015 
00016 static int set_verbose(void)
00017 {
00018  verbose = !!getenv("GIF_VERBOSE");
00019  verbose_set = 1;
00020  return(verbose);
00021 }
00022 
00023 #else
00024 
00025 #define VERBOSE 0
00026 
00027 #endif
00028 
00029 
00030 #define        MAXCOLORMAPSIZE         256
00031 
00032 #define        TRUE    1
00033 #define        FALSE   0
00034 
00035 #define CM_RED         0
00036 #define CM_GREEN       1
00037 #define CM_BLUE                2
00038 
00039 #define        MAX_LWZ_BITS            12
00040 
00041 #define INTERLACE              0x40
00042 #define LOCALCOLORMAP  0x80
00043 #define BitSet(byte, bit)      (((byte) & (bit)) == (bit))
00044 
00045 #define        ReadOK(file,buffer,len) (gdGetBuf(buffer, len, file) != 0)
00046 
00047 #define LM_to_uint(a,b)                        (((b)<<8)|(a))
00048 
00049 /* We may eventually want to use this information, but def it out for now */
00050 #if 0
00051 static struct {
00052        unsigned int    Width;
00053        unsigned int    Height;
00054        unsigned char   ColorMap[3][MAXCOLORMAPSIZE];
00055        unsigned int    BitPixel;
00056        unsigned int    ColorResolution;
00057        unsigned int    Background;
00058        unsigned int    AspectRatio;
00059 } GifScreen;
00060 #endif
00061 
00062 #if 0
00063 static struct {
00064        int     transparent;
00065        int     delayTime;
00066        int     inputFlag;
00067        int     disposal;
00068 } Gif89 = { -1, -1, -1, 0 };
00069 #endif
00070 
00071 static int ReadColorMap (gdIOCtx *fd, int number, unsigned char (*buffer)[256]);
00072 static int DoExtension (gdIOCtx *fd, int label, int *Transparent, int *ZeroDataBlockP);
00073 static int GetDataBlock (gdIOCtx *fd, unsigned char *buf, int *ZeroDataBlockP);
00074 static int GetCode (gdIOCtx *fd, int code_size, int flag, int *ZeroDataBlockP);
00075 static int LWZReadByte (gdIOCtx *fd, int flag, int input_code_size, int *ZeroDataBlockP);
00076 
00077 static void ReadImage (gdImagePtr im, gdIOCtx *fd, int len, int height, unsigned char (*cmap)[256], int interlace, int *ZeroDataBlockP); /*1.4//, int ignore); */
00078 
00079 BGD_DECLARE(gdImagePtr) gdImageCreateFromGif(FILE *fdFile)
00080 {
00081         gdIOCtx             *fd = gdNewFileCtx(fdFile);
00082         gdImagePtr          im = 0;
00083 
00084         im = gdImageCreateFromGifCtx(fd);
00085 
00086         fd->gd_free(fd);
00087 
00088         return im;
00089 }
00090 
00091 BGD_DECLARE(gdImagePtr) gdImageCreateFromGifPtr (int size, void *data)
00092 {
00093   gdImagePtr im;
00094   gdIOCtx *in = gdNewDynamicCtxEx (size, data, 0);
00095   im = gdImageCreateFromGifCtx (in);
00096   in->gd_free (in);
00097   return im;
00098 }
00099 
00100 BGD_DECLARE(gdImagePtr) gdImageCreateFromGifCtx(gdIOCtxPtr fd)
00101 {
00102        int BitPixel;
00103 #if 0
00104        int ColorResolution;
00105        int Background;
00106        int AspectRatio;
00107 #endif
00108        int Transparent = (-1);
00109        unsigned char   buf[16];
00110        unsigned char   c;
00111        unsigned char   ColorMap[3][MAXCOLORMAPSIZE];
00112        unsigned char   localColorMap[3][MAXCOLORMAPSIZE];
00113        int             imw, imh;
00114        int             useGlobalColormap;
00115        int             bitPixel;
00116        int           i;
00117        /*1.4//int             imageCount = 0; */
00118        char            version[4];
00119        /* 2.0.28: threadsafe storage */
00120        int ZeroDataBlock = FALSE;
00121 
00122        gdImagePtr im = 0;
00123        if (! ReadOK(fd,buf,6)) {
00124               return 0;
00125        }
00126        if (strncmp((char *)buf,"GIF",3) != 0) {
00127               return 0;
00128        }
00129        strncpy(version, (char *)buf + 3, 3);
00130        version[3] = '\0';
00131 
00132        if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
00133               return 0;
00134        }
00135        if (! ReadOK(fd,buf,7)) {
00136               return 0;
00137        }
00138        BitPixel        = 2<<(buf[4]&0x07);
00139 #if 0
00140        ColorResolution = (int) (((buf[4]&0x70)>>3)+1);
00141        Background      = buf[5];
00142        AspectRatio     = buf[6];
00143 #endif
00144 
00145        if (BitSet(buf[4], LOCALCOLORMAP)) {    /* Global Colormap */
00146                if (ReadColorMap(fd, BitPixel, ColorMap)) {
00147                      return 0;
00148               }
00149        }
00150        for (;;) {
00151                if (! ReadOK(fd,&c,1)) {
00152                        return 0;
00153                }
00154                if (c == ';') {         /* GIF terminator */
00155                      goto terminated;
00156               }
00157 
00158                if (c == '!') {         /* Extension */
00159                        if (! ReadOK(fd,&c,1)) {
00160                                return 0;
00161                        }
00162                        DoExtension(fd, c, &Transparent, &ZeroDataBlock);
00163                        continue;
00164                }
00165 
00166                if (c != ',') {         /* Not a valid start character */
00167                        continue;
00168                }
00169 
00170                /*1.4//++imageCount; */
00171 
00172                if (! ReadOK(fd,buf,9)) {
00173                       return 0;
00174                }
00175 
00176                useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP);
00177 
00178                bitPixel = 1<<((buf[8]&0x07)+1);
00179 
00180                imw = LM_to_uint(buf[4],buf[5]);
00181                imh = LM_to_uint(buf[6],buf[7]);
00182               if (!(im = gdImageCreate(imw, imh))) {
00183                       return 0;
00184               }
00185                im->interlace = BitSet(buf[8], INTERLACE);
00186                if (! useGlobalColormap) {
00187                        if (ReadColorMap(fd, bitPixel, localColorMap)) { 
00188                                  return 0;
00189                        }
00190                        ReadImage(im, fd, imw, imh, localColorMap, 
00191                                  BitSet(buf[8], INTERLACE), &ZeroDataBlock); 
00192                } else {
00193                        ReadImage(im, fd, imw, imh,
00194                                  ColorMap, 
00195                                  BitSet(buf[8], INTERLACE), &ZeroDataBlock);
00196                }
00197                if (Transparent != (-1)) {
00198                        gdImageColorTransparent(im, Transparent);
00199                }        
00200               goto terminated;
00201        }
00202 
00203 terminated:
00204        /* Terminator before any image was declared! */
00205        if (!im) {
00206               return 0;
00207        }
00208        /* Check for open colors at the end, so
00209           we can reduce colorsTotal and ultimately
00210           BitsPerPixel */
00211        for (i=((im->colorsTotal-1)); (i>=0); i--) {
00212               if (im->open[i]) {
00213                      im->colorsTotal--;
00214                 } else {
00215                      break;
00216                 }
00217        } 
00218        return im;
00219 }
00220 
00221 static int
00222 ReadColorMap(gdIOCtx *fd, int number, unsigned char (*buffer)[256])
00223 {
00224        int             i;
00225        unsigned char   rgb[3];
00226 
00227 
00228        for (i = 0; i < number; ++i) {
00229                if (! ReadOK(fd, rgb, sizeof(rgb))) {
00230                        return TRUE;
00231                }
00232                buffer[CM_RED][i] = rgb[0] ;
00233                buffer[CM_GREEN][i] = rgb[1] ;
00234                buffer[CM_BLUE][i] = rgb[2] ;
00235        }
00236 
00237 
00238        return FALSE;
00239 }
00240 
00241 static int
00242 DoExtension(gdIOCtx *fd, int label, int *Transparent, int *ZeroDataBlockP)
00243 {
00244        static unsigned char     buf[256];
00245 
00246        switch (label) {
00247        case 0xf9:              /* Graphic Control Extension */
00248                (void) GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP);
00249 #if 0
00250                Gif89.disposal    = (buf[0] >> 2) & 0x7;
00251                Gif89.inputFlag   = (buf[0] >> 1) & 0x1;
00252                Gif89.delayTime   = LM_to_uint(buf[1],buf[2]);
00253 #endif
00254                if ((buf[0] & 0x1) != 0)
00255                        *Transparent = buf[3];
00256 
00257                while (GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP) != 0)
00258                        ;
00259                return FALSE;
00260        default:
00261                break;
00262        }
00263        while (GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP) != 0)
00264                ;
00265 
00266        return FALSE;
00267 }
00268 
00269 static int
00270 GetDataBlock_(gdIOCtx *fd, unsigned char *buf, int *ZeroDataBlockP)
00271 {
00272        unsigned char   count;
00273 
00274        if (! ReadOK(fd,&count,1)) {
00275                return -1;
00276        }
00277 
00278        *ZeroDataBlockP = count == 0;
00279 
00280        if ((count != 0) && (! ReadOK(fd, buf, count))) {
00281                return -1;
00282        }
00283 
00284        return count;
00285 }
00286 
00287 static int
00288 GetDataBlock(gdIOCtx *fd, unsigned char *buf, int *ZeroDataBlockP)
00289 {
00290  int rv;
00291  int i;
00292 
00293  rv = GetDataBlock_(fd,buf, ZeroDataBlockP);
00294  if (VERBOSE)
00295   { printf("[GetDataBlock returning %d",rv);
00296     if (rv > 0)
00297      { printf(":");
00298        for (i=0;i<rv;i++) printf(" %02x",buf[i]);
00299      }
00300     printf("]\n");
00301   }
00302  return(rv);
00303 }
00304 
00305 static int
00306 GetCode_(gdIOCtx *fd, int code_size, int flag, int *ZeroDataBlockP)
00307 {
00308        static unsigned char    buf[280];
00309        static int              curbit, lastbit, done, last_byte;
00310        int                     i, j, ret;
00311        unsigned char           count;
00312 
00313        if (flag) {
00314                curbit = 0;
00315                lastbit = 0;
00316                done = FALSE;
00317                return 0;
00318        }
00319 
00320        if ( (curbit+code_size) >= lastbit) {
00321                if (done) {
00322                        if (curbit >= lastbit) {
00323                                 /* Oh well */
00324                        }                        
00325                        return -1;
00326                }
00327                buf[0] = buf[last_byte-2];
00328                buf[1] = buf[last_byte-1];
00329 
00330                if ((count = GetDataBlock(fd, &buf[2], ZeroDataBlockP)) == 0)
00331                        done = TRUE;
00332 
00333                last_byte = 2 + count;
00334                curbit = (curbit - lastbit) + 16;
00335                lastbit = (2+count)*8 ;
00336        }
00337 
00338        ret = 0;
00339        for (i = curbit, j = 0; j < code_size; ++i, ++j)
00340                ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
00341 
00342        curbit += code_size;
00343        return ret;
00344 }
00345 
00346 static int
00347 GetCode(gdIOCtx *fd, int code_size, int flag, int *ZeroDataBlockP)
00348 {
00349  int rv;
00350 
00351  rv = GetCode_(fd,code_size,flag, ZeroDataBlockP);
00352  if (VERBOSE) printf("[GetCode(,%d,%d) returning %d]\n",code_size,flag,rv);
00353  return(rv);
00354 }
00355 
00356 #define STACK_SIZE ((1<<(MAX_LWZ_BITS))*2)
00357 static int
00358 LWZReadByte_(gdIOCtx *fd, int flag, int input_code_size, int *ZeroDataBlockP)
00359 {
00360        static int      fresh = FALSE;
00361        int             code, incode;
00362        static int      code_size, set_code_size;
00363        static int      max_code, max_code_size;
00364        static int      firstcode, oldcode;
00365        static int      clear_code, end_code;
00366        static int      table[2][(1<< MAX_LWZ_BITS)];
00367        static int      stack[STACK_SIZE], *sp;
00368        register int    i;
00369 
00370        if (flag) {
00371                set_code_size = input_code_size;
00372                code_size = set_code_size+1;
00373                clear_code = 1 << set_code_size ;
00374                end_code = clear_code + 1;
00375                max_code_size = 2*clear_code;
00376                max_code = clear_code+2;
00377 
00378                GetCode(fd, 0, TRUE, ZeroDataBlockP);
00379                
00380                fresh = TRUE;
00381 
00382                for (i = 0; i < clear_code; ++i) {
00383                        table[0][i] = 0;
00384                        table[1][i] = i;
00385                }
00386                for (; i < (1<<MAX_LWZ_BITS); ++i)
00387                        table[0][i] = table[1][0] = 0;
00388 
00389                sp = stack;
00390 
00391                return 0;
00392        } else if (fresh) {
00393                fresh = FALSE;
00394                do {
00395                        firstcode = oldcode =
00396                                GetCode(fd, code_size, FALSE, ZeroDataBlockP);
00397                } while (firstcode == clear_code);
00398                return firstcode;
00399        }
00400 
00401        if (sp > stack)
00402                return *--sp;
00403 
00404        while ((code = GetCode(fd, code_size, FALSE, ZeroDataBlockP)) >= 0) {
00405                if (code == clear_code) {
00406                        for (i = 0; i < clear_code; ++i) {
00407                                table[0][i] = 0;
00408                                table[1][i] = i;
00409                        }
00410                        for (; i < (1<<MAX_LWZ_BITS); ++i)
00411                                table[0][i] = table[1][i] = 0;
00412                        code_size = set_code_size+1;
00413                        max_code_size = 2*clear_code;
00414                        max_code = clear_code+2;
00415                        sp = stack;
00416                        firstcode = oldcode =
00417                                        GetCode(fd, code_size, FALSE, ZeroDataBlockP);
00418                        return firstcode;
00419                } else if (code == end_code) {
00420                        int             count;
00421                        unsigned char   buf[260];
00422 
00423                        if (*ZeroDataBlockP)
00424                                return -2;
00425 
00426                        while ((count = GetDataBlock(fd, buf, ZeroDataBlockP)) > 0)
00427                                ;
00428 
00429                        if (count != 0)
00430                        return -2;
00431                }
00432 
00433                incode = code;
00434 
00435               if (sp == (stack + STACK_SIZE)) {
00436                      /* Bad compressed data stream */
00437                      return -1;
00438               }
00439 
00440                if (code >= max_code) {
00441                        *sp++ = firstcode;
00442                        code = oldcode;
00443                }
00444 
00445                while (code >= clear_code) {
00446                      if (sp == (stack + STACK_SIZE)) {
00447                             /* Bad compressed data stream */
00448                             return -1;
00449                      }
00450                        *sp++ = table[1][code];
00451                        if (code == table[0][code]) {
00452                                /* Oh well */
00453                        }
00454                        code = table[0][code];
00455                }
00456 
00457                *sp++ = firstcode = table[1][code];
00458 
00459                if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
00460                        table[0][code] = oldcode;
00461                        table[1][code] = firstcode;
00462                        ++max_code;
00463                        if ((max_code >= max_code_size) &&
00464                                (max_code_size < (1<<MAX_LWZ_BITS))) {
00465                                max_code_size *= 2;
00466                                ++code_size;
00467                        }
00468                }
00469 
00470                oldcode = incode;
00471 
00472                if (sp > stack)
00473                        return *--sp;
00474        }
00475        return code;
00476 }
00477 
00478 static int
00479 LWZReadByte(gdIOCtx *fd, int flag, int input_code_size, int *ZeroDataBlockP)
00480 {
00481  int rv;
00482 
00483  rv = LWZReadByte_(fd,flag,input_code_size, ZeroDataBlockP);
00484  if (VERBOSE) printf("[LWZReadByte(,%d,%d) returning %d]\n",flag,input_code_size,rv);
00485  return(rv);
00486 }
00487 
00488 static void
00489 ReadImage(gdImagePtr im, gdIOCtx *fd, int len, int height, unsigned char (*cmap)[256], int interlace, int *ZeroDataBlockP) /*1.4//, int ignore) */
00490 {
00491        unsigned char   c;      
00492        int             v;
00493        int             xpos = 0, ypos = 0, pass = 0;
00494        int i;
00495        /* Stash the color map into the image */
00496        for (i=0; (i<gdMaxColors); i++) {
00497                im->red[i] = cmap[CM_RED][i];     
00498                im->green[i] = cmap[CM_GREEN][i]; 
00499                im->blue[i] = cmap[CM_BLUE][i];   
00500                im->open[i] = 1;
00501        }
00502        /* Many (perhaps most) of these colors will remain marked open. */
00503        im->colorsTotal = gdMaxColors;
00504        /*
00505        **  Initialize the Compression routines
00506        */
00507        if (! ReadOK(fd,&c,1)) {
00508                return; 
00509        }
00510        if (LWZReadByte(fd, TRUE, c, ZeroDataBlockP) < 0) {
00511                return;
00512        }
00513 
00514        /*
00515        **  If this is an "uninteresting picture" ignore it.
00516        **  REMOVED For 1.4
00517        */
00518        /*if (ignore) { */
00519        /*        while (LWZReadByte(fd, FALSE, c) >= 0) */
00520        /*                ; */
00521        /*        return; */
00522        /*} */
00523 
00524        while ((v = LWZReadByte(fd,FALSE,c, ZeroDataBlockP)) >= 0 ) {
00525                /* This how we recognize which colors are actually used. */
00526                if (im->open[v]) {
00527                        im->open[v] = 0;
00528                }
00529                gdImageSetPixel(im, xpos, ypos, v);
00530                ++xpos;
00531                if (xpos == len) {
00532                        xpos = 0;
00533                        if (interlace) {
00534                                switch (pass) {
00535                                case 0:
00536                                case 1:
00537                                        ypos += 8; break;
00538                                case 2:
00539                                        ypos += 4; break;
00540                                case 3:
00541                                        ypos += 2; break;
00542                                }
00543 
00544                                if (ypos >= height) {
00545                                        ++pass;
00546                                        switch (pass) {
00547                                        case 1:
00548                                                ypos = 4; break;
00549                                        case 2:
00550                                                ypos = 2; break;
00551                                        case 3:
00552                                                ypos = 1; break;
00553                                        default:
00554                                                goto fini;
00555                                        }
00556                                }
00557                        } else {
00558                                ++ypos;
00559                        }
00560                }
00561                if (ypos >= height)
00562                        break;
00563        }
00564 
00565 fini:
00566        if (LWZReadByte(fd,FALSE,c, ZeroDataBlockP)>=0) {
00567                /* Ignore extra */
00568        }
00569 }
00570 
00571