void GifEncode(FILE *fout, UBYTE *pixels, int depth, int siz) { GifTree *first = &GifRoot, *newNode, *curNode; UBYTE *end; int cc, eoi, next, tel=0; short cLength; char *pos, *buffer; empty[0] = NULL; need = 8; nodeArray = empty; memmove(++nodeArray, empty, 255*sizeof(GifTree **)); if (( buffer = (char *)malloc((BUFLEN+1)*sizeof(char))) == NULL ) TheEnd1("No memory for writing"); buffer++; pos = buffer; buffer[0] = 0x0; cc = (depth == 1) ? 0x4 : 1<<depth; fputc((depth == 1) ? 2 : depth, fout); eoi = cc+1; next = cc+2; cLength = (depth == 1) ? 3 : depth+1; if (( topNode = baseNode = (GifTree *)malloc(sizeof(GifTree)*4094)) == NULL ) TheEnd1("No memory for GIF-code tree"); if (( nodeArray = first->node = (GifTree **)malloc(256*sizeof(GifTree *)*noOfArrays)) == NULL ) TheEnd1("No memory for search nodes"); lastArray = nodeArray + ( 256*noOfArrays - cc); ClearTree(cc, first); pos = AddCodeToBuffer(cc, cLength, pos); end = pixels+siz; curNode = first; while(pixels < end) { if ( curNode->node[*pixels] != NULL ) { curNode = curNode->node[*pixels]; tel++; pixels++; chainlen++; continue; } else if ( curNode->typ == SEARCH ) { newNode = curNode->nxt; while ( newNode->alt != NULL ) { if ( newNode->ix == *pixels ) break; newNode = newNode->alt; } if (newNode->ix == *pixels ) { tel++; pixels++; chainlen++; curNode = newNode; continue; } } /* ****************************************************** * If there is no more thread to follow, we create a new node. If the * current node is terminating, it will become a SEARCH node. If it is * a SEARCH node, and if we still have room, it will be converted to a * LOOKUP node. */ newNode = ++topNode; switch (curNode->typ ) { case LOOKUP: newNode->nxt = NULL; newNode->alt = NULL, curNode->node[*pixels] = newNode; break; case SEARCH: if ( nodeArray != lastArray ) { nodeArray += cc; curNode->node = nodeArray; curNode->typ = LOOKUP; curNode->node[*pixels] = newNode; curNode->node[(curNode->nxt)->ix] = curNode->nxt; lookuptypes++; newNode->nxt = NULL; newNode->alt = NULL, curNode->nxt = NULL; break; } /* otherwise do as we do with a TERMIN node */ case TERMIN: newNode->alt = curNode->nxt; newNode->nxt = NULL, curNode->nxt = newNode; curNode->typ = SEARCH; break; default: fprintf(stderr, "Silly node type: %d\n", curNode->typ); } newNode->code = next; newNode->ix = *pixels; newNode->typ = TERMIN; newNode->node = empty; nodecount++; /* * End of node creation * ****************************************************** */ if (debugFlag) { if (curNode == newNode) fprintf(stderr, "Wrong choice of node\n"); if ( curNode->typ == LOOKUP && curNode->node[*pixels] != newNode ) fprintf(stderr, "Wrong pixel coding\n"); if ( curNode->typ == TERMIN ) fprintf(stderr, "Wrong Type coding; frame no = %d; pixel# = %d; nodecount = %d\n", count, tel, nodecount); } pos = AddCodeToBuffer(curNode->code, cLength, pos); if ( chainlen > maxchainlen ) maxchainlen = chainlen; chainlen = 0; if(pos-buffer>BLOKLEN) { buffer[-1] = BLOKLEN; fwrite(buffer-1, 1, BLOKLEN+1, fout); buffer[0] = buffer[BLOKLEN]; buffer[1] = buffer[BLOKLEN+1]; buffer[2] = buffer[BLOKLEN+2]; buffer[3] = buffer[BLOKLEN+3]; pos -= BLOKLEN; } curNode = first; if(next == (1<<cLength)) cLength++; next++; if(next == 0xfff) { ClearTree(cc,first); pos = AddCodeToBuffer(cc, cLength, pos); if(pos-buffer>BLOKLEN) { buffer[-1] = BLOKLEN; fwrite(buffer-1, 1, BLOKLEN+1, fout); buffer[0] = buffer[BLOKLEN]; buffer[1] = buffer[BLOKLEN+1]; buffer[2] = buffer[BLOKLEN+2]; buffer[3] = buffer[BLOKLEN+3]; pos -= BLOKLEN; } next = cc+2; cLength = (depth == 1)?3:depth+1; } } pos = AddCodeToBuffer(curNode->code, cLength, pos); if(pos-buffer>BLOKLEN-3) { buffer[-1] = BLOKLEN-3; fwrite(buffer-1, 1, BLOKLEN-2, fout); buffer[0] = buffer[BLOKLEN-3]; buffer[1] = buffer[BLOKLEN-2]; buffer[2] = buffer[BLOKLEN-1]; buffer[3] = buffer[BLOKLEN]; buffer[4] = buffer[BLOKLEN+1]; pos -= BLOKLEN-3; } pos = AddCodeToBuffer(eoi, cLength, pos); pos = AddCodeToBuffer(0x0, -1, pos); buffer[-1] = pos-buffer; fwrite(buffer-1, pos-buffer+1, 1, fout); free(buffer-1); free(first->node); free(baseNode); if (debugFlag) fprintf(stderr, "pixel count = %d; nodeCount = %d lookup nodes = %d\n", tel, nodecount, lookuptypes); return; }
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); }