void GifDecode(FILE *fp, UBYTE *pix, GifImageHdr gifimage) { UBYTE *chPos, firstCodeOut = 0, charBuff[256]; ULONG CLEAR, EOI, bits = 0, code = 0, codeFeched, buffCount = 0; int need = 0; interlaced = gifimage.i; imgwidth = gifimage.width; imgheight = gifimage.height; imgsize = imgwidth * imgheight; picture = pix; pass = picI = 0; if ( debugFlag > 1 ) fprintf(stderr, "(interlaced,imgwidth,imgheight,imgsize)=(%d,%d,%d,%d)\n", interlaced, imgwidth, imgheight, imgsize); rootCodeSize = Xgetc(fp); CLEAR = 1 << rootCodeSize; EOI = CLEAR + 1; GifClearTable(); if ( (buffCount = Xgetc(fp)) == 0 ) { sprintf(charBuff, "End of image # %d before it began!\n", count); TheEnd1(charBuff); } while(buffCount > 0) { if ( fread(charBuff, 1, buffCount, fp) != buffCount ) { sprintf(charBuff, "Premature end of file; Image # %d\n", count); TheEnd1(charBuff); } for(chPos = charBuff; buffCount-- > 0; chPos++) { need += (int) *chPos << bits; bits += 8; while (bits >= codeSize) { code = need & mask; need >>= codeSize; bits -= codeSize; if(code > expected) TheEnd1("Neither LZW nor RunLength (new code != expected)\n"); if (code == EOI) { if (debugFlag > 1) fprintf(stderr, "Image # %d ends; buffCount=%d\n", count, buffCount); goto skipRest; } if(code == CLEAR) { GifClearTable(); continue; } if(old == MAXVAL) { /* i.e. first code after clear table */ pix = GifSendData(pix, 1, &last[code]); firstCodeOut = last[code]; old = code; continue; } codeFeched = code; if(code == expected) { *topGifBuff++ = firstCodeOut; code = old; } while(code > CLEAR) { *topGifBuff++ = last[code]; code = first[code]; } *topGifBuff++ = firstCodeOut = last[code]; first[expected] = old; last[expected] = firstCodeOut; if(expected < MAXVAL) expected++; if(((expected & mask) == 0) && (expected < MAXVAL)) { codeSize++; mask += expected; } old = codeFeched; pix = GifSendData(pix, topGifBuff - gifBuff, gifBuff); topGifBuff = gifBuff; } /* end of extracting codes */ } /* end of reading a block of data */ if ( (buffCount = Xgetc(fp)) == 0 ) { sprintf(charBuff, "End of image # %d without EOI\n", count); TheEnd1(charBuff); } } skipRest: if (debugFlag) fprintf(stderr, "Ending GifDecode, written: %d=%d\n", interlaced && (pix-picture == 0) ? imgsize : pix - picture, imgsize); return ; }
/* * Read a Gif file. */ void animate_gif(FILE *fout,char *fname,int firstImage,int Xoff,int Yoff, int delay_time,int loop_val) /* time in 100th of seconds */ { FILE *fp; UBYTE *pix; int i; if ( (fp = fopen(fname, REABIN)) == 0) { fprintf(stderr, "Can't open %s for reading.\n", fname); TheEnd(); } global.trans.type = TRANS_NONE; global.trans.valid = 0; global.time = delay_time; global.disposal = DEFAULT_DISPOSAL; global.left = Xoff; global.top = Yoff; loop=loop_val; /* loop = TRUE; */ /* loopcount = 0; */ /*global.left = global.top = 0;*/ GifScreenHeader(fp, fout, firstImage); /* read until , separator */ do { switch ( i = Xgetc(fp)) { case ',': case '\0': break; case '!': Xgetc(fp); /* the extension code */ for ( i = Xgetc(fp); i > 0; i-- ) Xgetc(fp); while ( ( i = Xgetc(fp) ) > 0 ) { for ( i = i ; i > 0; i-- ) Xgetc(fp); } break; default: fclose(fp); if ( feof(fp) || i == ';' ) TheEnd1("GifReadHeader: Unexpected End of File\n"); TheEnd1("GifReadHeader: Unknown block type\n"); } } while(i != ','); if(firstImage) { globscrn.m = gifscrn.m; globscrn.pixbits = gifscrn.pixbits; globscrn.bc = gifscrn.bc; if ( globscrn.m ) { for (i = gifMask[1+globscrn.pixbits]; i >= 0; i--) { gifGmap[i].cmap.red = gifCmap[i].cmap.red; gifGmap[i].cmap.green = gifCmap[i].cmap.green; gifGmap[i].cmap.blue = gifCmap[i].cmap.blue; } } if(loop) GifLoop(fout, loopcount); } ReadImageHeader(fp); /*** ACTION for IMAGE */ if ( ( gifimage.m != 0 && globmap !=0 ) || minimize !=0 ) { UBYTE translator[256], *p, *po; int left, right=0, top, bot=0, i, j, k, l, hi, wi; long dsquare, dsquare1; hi = gifimage.height; wi = gifimage.width; if (( pix = (UBYTE *)malloc(wi * hi * sizeof(UBYTE)) ) == NULL ) TheEnd1("No memory for image\n"); if (debugFlag) fprintf(stderr, " decoding picture no %d\n", count); GifDecode(fp, pix, gifimage); gifimage.i = 0; k = gifMask[1+globscrn.pixbits]; l = gifMask[1+gifscrn.pixbits]; for (j = 0; j <= l; j++) { dsquare = 256*256*3; for (i = 0; i <= k; i++) { dsquare1 = sq(gifGmap[i].cmap.red, gifCmap[j].cmap.red) + sq(gifGmap[i].cmap.green, gifCmap[j].cmap.green) + sq(gifGmap[i].cmap.blue, gifCmap[j].cmap.blue); if ( dsquare1 < dsquare ) { dsquare = dsquare1; translator[j]=i; if ( dsquare == 0 ) break; } } } gifimage.m = 0; gifscrn.pixbits = globscrn.pixbits; if (debugFlag) fprintf(stderr, " translating picture no %d\n", count); for (i = wi * hi -1; i>=0; i--) pix[i]=translator[pix[i]]; if ( minimize != 0 && pixold != NULL && hi == gifimageold.height && wi == gifimageold.width && gifimage.top == gifimageold.top && gifimage.left == gifimageold.left ) { gifimageold = gifimage; /* First test from left to right, top to bottom */ p = pix; po = pixold; for (i = 0; i < hi; i++ ) { for (j = 0; j < wi; j++ ) { if ( *p++ != *po++ ) { left = j; top=i; goto done; } } } if (FALSE) { done: /* i.e. a preliminary left and top found */ ; } else goto alike; /* writes full image, should we drop it ? */ /* Then test from right to left, bottom to top */ k=hi*wi-1; p = &pix[k]; po = &pixold[k]; for (i = hi-1; i >= top; i-- ) { for (j = wi -1; j >= 0; j-- ) { if ( *p-- != *po-- ) { right = j; bot=i; goto botfound; } } } botfound: /* The form of the differing area (not rectangle) may be slanted */ if ( right < left ) { i = right; right = left; left = i; } /* Now test between top and bottom at the left hand side */ for (i = top+1; i <= bot; i++ ) { k= i * wi; p = &pix[k]; po = &pixold[k]; for (j = 0; j < left; j++ ) { if ( *p++ != *po++ ) { left = j; break; } } } /* Finally test between bottom and top at the right hand side */ for (i = bot-1; i >= top; i-- ) { k= (i+1) * wi-1; p = &pix[k]; po = &pixold[k]; for (j = wi-1; j > right; j-- ) { if ( *p-- != *po-- ) { right = j; break; } } } gifimage.left += left; gifimage.top += top; gifimage.width = right-left+1; gifimage.height = bot-top+1; WriteImageHeader(fout); /* The rectangle containing diffs is transferred to the mem area of pixold */ po = pixold; for (i = top; i <= bot; i++ ) { p = &pix[i * wi+left]; for (j = left; j <= right; j++ ) { *po++ = *p++; } } GifEncode(fout, pixold, gifscrn.pixbits+1, gifimage.height * gifimage.width); if (debugFlag) fprintf(stderr, " encoded: width= %d, height = %d, left = %d, top = %d\n", gifimage.width, gifimage.height, gifimage.left, gifimage.top); } else { alike: WriteImageHeader(fout); gifimageold = gifimage; GifEncode(fout, pix, gifscrn.pixbits+1, gifimage.height * gifimage.width); if (debugFlag) fprintf(stderr, " picture re-encoded\n"); } free(pixold); pixold = pix; fputc(0, fout); /* block count of zero */ } else { WriteImageHeader(fout); i = Xgetc(fp); fputc(i, fout); /* the LZW code size */ while ( ( gifBlockSize = Xgetc(fp) ) > 0 ) { fputc(gifBlockSize, fout); while ( gifBlockSize-- > 0 ) fputc(Xgetc(fp),fout); } if ( gifBlockSize == 0 ) fputc(gifBlockSize, fout); else TheEnd1("GifPassing: Unexpected End of File\n"); } fclose(fp); }