#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xproto.h>
#define MAKE_ONE_GIF 2
#define GET_GLOBAL_CMAP 1
#define FIRST_ANI_GIF 3
#define NEXT_ANI_GIF 4
#define BLOKLEN 255
#define BUFLEN 1000
#define TERMIN 'T'
#define LOOKUP 'L'
#define SEARCH 'S'
#define noOfArrays 20
/* defines the amount of memory set aside in the encoding for the
* LOOKUP type nodes; for a 256 color GIF, the number of LOOKUP
* nodes will be <= noOfArrays, for a 128 color GIF the number of
* LOOKUP nodes will be <= 2 * noOfArrays, etc. */
#define GifPutShort(i, fout) {fputc(i&0xff, fout); fputc(i>>8, fout);}
typedef struct GifTree {
char typ; /* terminating, lookup, or search */
int code; /* the code to be output */
unsigned char ix; /* the color map index */
struct GifTree **node, *nxt, *alt;
} GifTree;
char *AddCodeToBuffer(int, short, char *);
void ClearTree(int, GifTree *);
int GifEncode();
unsigned int debugFlag;
int UseGlobalMap=0;
int GifFrameDelay=5,GifFrameLoop=1000;
int chainlen = 0, maxchainlen = 0, nodecount = 0, lookuptypes = 0, nbits;
short need = 8;
GifTree *empty[256], GifRoot = {LOOKUP, 0, 0, empty, NULL, NULL},
*topNode, *baseNode, **nodeArray, **lastArray;
extern Display *display;
typedef struct {
unsigned char r,g,b;
} GIFCOL;
GIFCOL gifcol[256];
GIFCOL gifGcol[256];
int NGlobalColors=0;
set_global_map(int flag)
{
if(NGlobalColors==0){ /* Cant use it if it aint there */
UseGlobalMap=0;
return;
}
UseGlobalMap=flag;
}
int ppmtopix(unsigned char r,unsigned char g, unsigned char b,int *n)
{
int i,nc=*n;
if(UseGlobalMap==1){
for(i=0;i<NGlobalColors;i++){
if(r==gifGcol[i].r&&g==gifGcol[i].g&&b==gifGcol[i].b)
return i;
}
return -1;
}
for(i=0;i<nc;i++)
if(r==gifcol[i].r&&g==gifcol[i].g&&b==gifcol[i].b)
return i;
if(nc>255){
printf("Too many colors \n");
return -1;
}
gifcol[nc].r=r;
gifcol[nc].g=g;
gifcol[nc].b=b;
nc++;
*n=nc;
return nc-1;
}
end_ani_gif(FILE *fp)
{
fputc(';',fp);
}
add_ani_gif(Window win,FILE *fp,int count)
{
printf("Frame %d \n",count);
if(count==0)
gif_stuff(win,fp,FIRST_ANI_GIF);
else
gif_stuff(win,fp,NEXT_ANI_GIF);
}
screen_to_gif(Window win, FILE *fp)
{
gif_stuff(win,fp,MAKE_ONE_GIF);
}
get_global_colormap(Window win)
{
FILE *junk;
gif_stuff(win,junk,GET_GLOBAL_CMAP);
}
local_to_global()
{
int i;
for(i=0;i<256;i++){
gifcol[i].r=gifGcol[i].r;
gifcol[i].g=gifGcol[i].g;
gifcol[i].b=gifGcol[i].b;
}
}
int use_global_map(unsigned char *pixels,unsigned char *ppm,int h, int w)
{
unsigned char r,g,b;
int i,j,k=0,l=0;
int pix,nc;
for(i=0;i<h;i++){
for(j=0;j<w;j++){
r=ppm[k];
g=ppm[k+1];
b=ppm[k+2];
pix=ppmtopix(r,g,b,&nc);
if(pix<0)return(0);
pixels[l]=pix;
k+=3;
l++;
}
}
return(1);
}
int make_local_map(unsigned char *pixels,unsigned char *ppm,int h, int w)
{
unsigned char r,g,b;
int i,j,k=0,l=0;
int pix,ncol=0;
for(i=0;i<h;i++){
for(j=0;j<w;j++){
r=ppm[k];
g=ppm[k+1];
b=ppm[k+2];
k+=3;
pix=ppmtopix(r,g,b,&ncol);
if(pix<0)pix=255;
pixels[l]=pix;
l++;
}
}
printf("Got %d colors\n",ncol);
for(i=ncol;i<256;i++){
gifcol[i].r=255;
gifcol[i].g=255;
gifcol[i].b=255;
}
return ncol;
}
gif_stuff(Window win,FILE *fp,int task)
{
Window root;
unsigned int h,w,bw,d;
int x0,y0;
unsigned char *ppm;
unsigned char *pixels;
int i,j,k=0,l=0;
int ncol=0;
int locflag=1;
int ok;
/* printf("stog !! \n");*/
XGetGeometry(display,win,&root,&x0,&y0,&w,&h,&bw,&d);
ppm=(unsigned char *)malloc(w*h*3);
pixels=(unsigned char *)malloc(h*w);
/* printf(" h=%d w=%d \n",h,w);*/
getppmbits(win,&w,&h,ppm);
switch(task){
case GET_GLOBAL_CMAP:
ncol=make_local_map(pixels,ppm,h,w);
for(i=0;i<256;i++){
gifGcol[i].r=gifcol[i].r;
gifGcol[i].g=gifcol[i].g;
gifGcol[i].b=gifcol[i].b;
}
NGlobalColors=ncol;
break;
case MAKE_ONE_GIF: /* don't need global map! */
ncol=make_local_map(pixels,ppm,h,w);
make_gif(pixels,w,h,fp);
break;
case FIRST_ANI_GIF:
if(UseGlobalMap)
{
ok=use_global_map(pixels,ppm,h,w);
if(ok==1)
{
local_to_global();
write_global_header(w,h,fp);
write_local_header(w,h,fp,0,GifFrameDelay);
GifEncode(fp,pixels,8,w*h);
}
else /* first map cant be encoded */
{
UseGlobalMap=0;
local_to_global();
write_global_header(w,h,fp); /* write global header */
make_local_map(pixels,ppm,h,w);
write_local_header(w,h,fp,1,GifFrameDelay);
GifEncode(fp,pixels,8,w*h);
UseGlobalMap=1;
}
}
else
{
make_local_map(pixels,ppm,h,w);
write_global_header(w,h,fp);
write_local_header(w,h,fp,0,GifFrameDelay);
GifEncode(fp,pixels,8,w*h);
}
break;
case NEXT_ANI_GIF:
if(UseGlobalMap)
{
ok=use_global_map(pixels,ppm,h,w);
if(ok==1)
{
write_local_header(w,h,fp,0,GifFrameDelay);
GifEncode(fp,pixels,8,w*h);
}
else
{
UseGlobalMap=0;
make_local_map(pixels,ppm,h,w);
write_local_header(w,h,fp,1,GifFrameDelay);
GifEncode(fp,pixels,8,w*h);
UseGlobalMap=1;
}
}
else
{
make_local_map(pixels,ppm,h,w);
write_local_header(w,h,fp,1,GifFrameDelay);
GifEncode(fp,pixels,8,w*h);
}
break;
}
free(pixels);
free(ppm);
}
write_global_header(int cols,int rows, FILE *dst)
{
int i,depth=8;
char *pos,*buffer;
buffer = (char *)malloc((BUFLEN+1)*sizeof(char))+1;
pos = buffer;
*pos++ = 'G';
*pos++ = 'I';
*pos++ = 'F';
*pos++ = '8';
*pos++ = '9';
*pos++ = 'a';
*pos++ = 0xff & cols;
*pos++ = (0xff00 & cols)/0x100;
*pos++ = 0xff & rows;
*pos++ = (0xff00 & rows)/0x100;
*pos++ = 0x87;
*pos++ = 0xff;
*pos++ = 0x0;
for(i=0;i<256;i++) {
*pos++ = 0xff & gifcol[i].r;
*pos++ = 0xff & gifcol[i].g;
*pos++ = 0xff & gifcol[i].b;
}
fwrite(buffer,pos-buffer,1,dst);
free(buffer-1);
GifLoop(dst,GifFrameLoop);
}
GifLoop(FILE *fout, unsigned int repeats)
{
fputc(0x21, fout);
fputc(0xFF, fout);
fputc(0x0B, fout);
fputs("NETSCAPE2.0", fout);
fputc(0x03, fout);
fputc(0x01, fout);
GifPutShort(repeats, fout); /* repeat count */
fputc(0x00, fout); /* terminator */
}
write_local_header(int cols,int rows, FILE *fout,int colflag,int delay)
{
int i;
fputc(0x21, fout);
fputc(0xF9, fout);
fputc(0x04, fout);
fputc(0x80, fout); /* flag ??? */
GifPutShort(delay,fout);
fputc(0x00, fout);
fputc(0x00,fout);
fputc(',',fout); /* image separator */
GifPutShort(0,fout);
GifPutShort(0,fout);
GifPutShort(cols,fout);
GifPutShort(rows,fout);
if(colflag)
fputc(0x87,fout);
else
fputc(0x07,fout);
if(colflag){
for(i=0;i<256;i++){
fputc(0xff&gifcol[i].r,fout);
fputc(0xff&gifcol[i].g,fout);
fputc(0xff&gifcol[i].b,fout);
}
}
}
make_gif(unsigned char *pixels,int cols,int rows,FILE *dst)
{
int i,j,depth=8;
char *pos,*buffer;
buffer = (char *)malloc((BUFLEN+1)*sizeof(char))+1;
pos = buffer;
*pos++ = 'G';
*pos++ = 'I';
*pos++ = 'F';
*pos++ = '8';
*pos++ = '7';
*pos++ = 'a';
*pos++ = 0xff & cols;
*pos++ = (0xff00 & cols)/0x100;
*pos++ = 0xff & rows;
*pos++ = (0xff00 & rows)/0x100;
*pos++ = 0xf0 | (0x7&(depth-1));
*pos++ = 0xff;
*pos++ = 0x0;
for(i=0;i<256;i++) {
*pos++ = 0xff & gifcol[i].r;
*pos++ = 0xff & gifcol[i].g;
*pos++ = 0xff & gifcol[i].b;
}
*pos++ = 0x2c;
*pos++ = 0x00;
*pos++ = 0x00;
*pos++ = 0x00;
*pos++ = 0x00;
*pos++ = 0xff & cols;
*pos++ = (0xff00 & cols)/0x100;
*pos++ = 0xff & rows;
*pos++ = (0xff00 & rows)/0x100;
*pos++ = 0x7&(depth-1);
/* *pos++ = (depth==1)?2:depth; */
fwrite(buffer,pos-buffer,1,dst);
/* header info done */
GifEncode(dst,pixels,depth,rows*cols);
fputc(';',dst);
free(buffer-1);
}
int GifEncode(FILE *fout, unsigned char *pixels, int depth, int siz)
{
GifTree *first = &GifRoot, *newNode, *curNode;
unsigned char *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 )
return 0;
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 )
return 0;
if (( nodeArray = first->node = (GifTree **)malloc(256*sizeof(GifTree *)*noOfArrays)) == NULL )
return 0;
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; pixel# = %d; nodecount = %d\n", 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;
pos = AddCodeToBuffer(0x0,8,pos);
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 1;
}
void ClearTree(int cc, GifTree *root)
{
int i;
GifTree *newNode, **xx;
if (debugFlag>1) fprintf(stderr, "Clear Tree cc= %d\n", cc);
if (debugFlag>1) fprintf(stderr, "nodeCount = %d lookup nodes = %d\n", nodecount, lookuptypes);
maxchainlen=0; lookuptypes = 1;
nodecount = 0;
nodeArray = root->node;
xx= nodeArray;
for (i = 0; i < noOfArrays; i++ ) {
memmove (xx, empty, 256*sizeof(GifTree **));
xx += 256;
}
topNode = baseNode;
for(i=0; i<cc; i++) {
root->node[i] = newNode = ++topNode;
newNode->nxt = NULL;
newNode->alt = NULL;
newNode->code = i;
newNode->ix = i;
newNode->typ = TERMIN;
newNode->node = empty;
nodecount++;
}
}
char *AddCodeToBuffer(int code, short n, char *buf)
{
int mask;
if(n<0) {
if(need<8) {
buf++;
*buf = 0x0;
}
need = 8;
return buf;
}
while(n>=need) {
mask = (1<<need)-1;
*buf += (mask&code)<<(8-need);
buf++;
*buf = 0x0;
code = code>>need;
n -= need;
need = 8;
}
if(n) {
mask = (1<<n)-1;
*buf += (mask&code)<<(8-need);
need -= n;
}
return buf;
}
syntax highlighted by Code2HTML, v. 0.9.1