This is gifmerge.c in view mode; [Download] [Up]
/* * gifmerge.c * * Copyright (C) 1990,1991,1992,1993 by Mark Podlipec. * All rights reserved. * * This software may be freely copied, modified and redistributed * without fee provided that this copyright notice is preserved * intact on all copies and modified copies. * * There is no warranty or other guarantee of fitness of this software. * It is provided solely "as is". The author(s) disclaim(s) all * responsibility and liability with respect to this software's usage * or its effect upon hardware or computer systems. * */ /* * Description: * * This program reads a gif91(see XAnim docs) file and merges the listed * gif files into one gif file. * * Eventually, I'd like to have this program compare the current image * with the previous image and check to see if only a small section of * the screen changed from the previous image. Worth a shot. */ /* * Rev 1.00 23Jul91 Mark Podlipec * creation * Rev 1.01 08Jan92 Mark Podlipec * use all colormaps, not just 1st. * * Rev 1.2 20Dec95 Rene Mueller * command-line input (no longer txtfile needed) * * Rev 1.3 05Feb96 Rene Mueller (kiwi@iis.ee.ethz.ch) * GIF89a transparency, and "Netscape2.0" application extension (looping) * Rev 1.31 14May96 Rene Mueller (kiwi@iis.ee.ethz.ch) * disposal selectable * Rev 1.32 16Jul96 Rene Mueller (kiwi@iis.ee.ethz.ch) * logical position per image manipulating * Rev 1.33 22Jul96 Rene Mueller (kiwi@iis.ee.ethz.ch) * -notransp and -nopos added */ #define DA_REV 1.33 #include "gifmerge.h" #define MAXVAL 4100 /* maxval of lzw coding size */ #define MAXVALP 4200 int debug_flag = 0; /* make these options */ int verbose = 0; /* make these options */ int imagex = 0; int imagey = 0; int imagec = 0; GIF_Color gif_cmap[256]; ULONG GIF_Get_Code(); void GIF_Decompress(); void GIF_Get_Next_Entry(); void GIF_Add_To_Table(); void GIF_Send_Data(); void GIF_Clear_Table(); void GIF_Screen_Header(); void GIF_Image_Header(); void GIF_Read_File(); GIF_Screen_Hdr gifscrn; GIF_Image_Hdr gifimage; GIF_Table table[MAXVALP]; ULONG root_code_size,code_size,CLEAR,EOI,INCSIZE; ULONG nextab; ULONG gif_mask[16] = {1,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,0,0}; ULONG gif_ptwo[16] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,0,0}; UBYTE gif_buff[MAXVALP]; ULONG gif_block_size; int num_bits,bits; int pic_i; char gif_file_name[256]; int screen_was_last; int disposal = 2; int repeats = -1; int delay = 50; int transp = -1; int pos_set = 0; int xpos = 0, ypos = 0; void TheEnd() { exit(0); } void TheEnd1(p) char *p; { fprintf(stderr,"%s",p); TheEnd(); } Usage() { fprintf(stderr,"\nUsage:\ngifmerge [-<r>,<g>,<b>] [-<delay>] [-l<loops>] [-d<disp>] *.gif > anim.gif\n\n"); fprintf(stderr," -<r>,<g>,<b> set transparency, ie -192,192,192, default: no transparency\n"); fprintf(stderr," -notransp set transparency off (after you used -r,g,b before)\n"); fprintf(stderr," -<delay> set delay of between images in 1/100th secs, ie -100\n default 50 (0.5secs)\n"); fprintf(stderr," -l<loops> set loop counter, ie -l0 (ever) or -l1000, default no loops\n"); fprintf(stderr," -d<disposal> set disposal 0 = no action, 1 = no dispose,\n"); fprintf(stderr," 2 = restore background (default)\n"); fprintf(stderr," 3 = restore previous\n"); fprintf(stderr," -pos<x>,<y> set offset position for image\n"); fprintf(stderr," -nopos reset offset position (default)\n"); fprintf(stderr,"\n or look at http://www.iis.ee.ethz.ch/~kiwi/GIFMerge/\n\n"); exit(0); } main(argc,argv) int argc; char *argv[]; { int first, i; int num_of_files,num_of_frames; fprintf(stderr,"=== GIFMerge Rev %2.2f (C) 1991,1992 by Mark Podlipec\n Improvements by Rene K. Mueller 1996\n",DA_REV); if (argc < 2) Usage(); screen_was_last = FALSE; num_of_files = argc-1; /* Read files, save colormap of 1st one only */ first = 1; for(i=0; i<num_of_files; i++) { unsigned int r,g,b; if(sscanf(argv[i+1],"-%u,%u,%u",&r,&g,&b)==3) { transp = r|(g<<8)|(b<<16); fprintf(stderr,"Transparency: %d %d %d\n",r,g,b); } else if(!strcmp(argv[i+1],"-notransp")) transp = -1, fprintf(stderr,"NoTransparency\n"); else if(sscanf(argv[i+1],"-%u",&delay)==1) fprintf(stderr,"Delay: %d (%.2f secs)\n",delay,delay/100.); else if(sscanf(argv[i+1],"-l%d",&repeats)==1) fprintf(stderr,"Loops: %d\n",repeats); else if(sscanf(argv[i+1],"-d%d",&disposal)==1) fprintf(stderr,"DisposalMode: %d\n",disposal); else if(sscanf(argv[i+1],"-pos%d,%d",&xpos,&ypos)==2) fprintf(stderr,"Position: %d %d\n",xpos,ypos), pos_set = 1; else if(!strcmp(argv[i+1],"-nopos")) pos_set = 0, fprintf(stderr,"NoPositioning\n"); else if(argv[i+1][0]=='-') Usage(); else { strcpy(gif_file_name,argv[i+1]); fprintf(stderr,"Merging %s ...\n",gif_file_name); GIF_Read_File(gif_file_name,first); first = 0; } } fputc(';',stdout); /* image separator */ exit(0); } /* * Read a GIF file, outputting to fname as we go. * It would be faster to read and write the individual blocks, * but eventually we'd like to optimize based on changes from * previous images(ie only a small section of the image changed. */ void GIF_Read_File(fname,first_image) char *fname; int first_image; { FILE *fp; int ret,i,exit_flag; if ( (fp=fopen(fname,"r"))==0) { fprintf(stderr,"Can't open %s for reading.\n",fname); TheEnd(); } GIF_Screen_Header(fp,stdout,first_image); /*** read until , separator */ do { i=fgetc(fp); if ( (i<0) && feof(fp)) { fclose(fp); TheEnd1("GIF_Read_Header: Unexpected End of File\n"); } } while(i != ','); fputc(',',stdout); /* image separator */ GIF_Image_Header(fp,stdout,first_image); /*** Setup ACTION for IMAGE */ GIF_Decompress(fp,stdout,0); fputc(0,stdout); /* block count of zero */ fclose(fp); } void GIF_Decompress(fp,fout) FILE *fp,*fout; { register ULONG code,old; pic_i = 0; bits=0; num_bits=0; gif_block_size=0; /* starting code size of LZW */ root_code_size=(fgetc(fp) & 0xff); fputc(root_code_size,fout); GIF_Clear_Table(); /* clear decoding symbol table */ code=GIF_Get_Code(fp,fout); if (code==CLEAR) { GIF_Clear_Table(); code=GIF_Get_Code(fp,fout); } /* write code(or what it currently stands for) to file */ GIF_Send_Data(code); old=code; code=GIF_Get_Code(fp,fout); do { if (table[code].valid==1) /* if known code */ { /* send it's associated string to file */ GIF_Send_Data(code); GIF_Get_Next_Entry(fp); /* get next table entry (nextab) */ GIF_Add_To_Table(old,code,nextab); /* add old+code to table */ old=code; } else /* code doesn't exist */ { GIF_Add_To_Table(old,old,code); /* add old+old to table */ GIF_Send_Data(code); old=code; } code=GIF_Get_Code(fp,fout); if (code==CLEAR) { GIF_Clear_Table(); code=GIF_Get_Code(fp,fout); GIF_Send_Data(code); old=code; code=GIF_Get_Code(fp,fout); } } while(code!=EOI); } void GIF_Get_Next_Entry(fp) FILE *fp; { /* table walk to empty spot */ while( (table[nextab].valid==1) &&(nextab<MAXVAL) ) nextab++; /* * Ran out of space??!? Something's roached */ if (nextab>=MAXVAL) { fprintf(stderr,"Error: GetNext nextab=%ld\n",nextab); fclose(fp); TheEnd(); } if (nextab==INCSIZE) /* go to next table size (and LZW code size ) */ { /* fprintf(stderr,"GetNext INCSIZE was %ld ",nextab); */ code_size++; INCSIZE=(INCSIZE*2)+1; if (code_size>=12) code_size=12; /* fprintf(stderr,"<%ld>",INCSIZE); */ } } /* body is associated string next is code to add to that string to form associated string for index */ void GIF_Add_To_Table(body,next,index) register ULONG body,next,index; { if (index>MAXVAL) { fprintf(stderr,"Error index=%ld\n",index); } else { table[index].valid=1; table[index].data=table[next].first; table[index].first=table[body].first; table[index].last=body; } } void GIF_Send_Data(index) register int index; { register int i,j; i=0; do /* table walk to retrieve string associated with index */ { gif_buff[i]=table[index].data; i++; index=table[index].last; if (i>MAXVAL) { fprintf(stderr,"Error: Sending i=%ld index=%ld\n",i,index); TheEnd(); } } while(index>=0); /* now invert that string since we retreived it backwards */ i--; for(j=i;j>=0;j--) { /*pic[pic_i] = gif_buff[j] | gif_pix_offset;*/ pic_i++; } } /* * initialize string table */ void GIF_Init_Table() { register int maxi,i; if (debug_flag) fprintf(stderr,"Initing Table..."); maxi=gif_ptwo[root_code_size]; for(i=0; i<maxi; i++) { table[i].data=i; table[i].first=i; table[i].valid=1; table[i].last = -1; } CLEAR=maxi; EOI=maxi+1; nextab=maxi+2; INCSIZE = (2*maxi)-1; code_size=root_code_size+1; } /* * clear table */ void GIF_Clear_Table() { register int i; if (debug_flag) fprintf(stderr,"Clearing Table...\n"); for(i=0;i<MAXVAL;i++) table[i].valid=0; GIF_Init_Table(); } /*CODE*/ ULONG GIF_Get_Code(fp,fout) /* get code depending of current LZW code size */ FILE *fp,*fout; { ULONG code; register int tmp; while(num_bits < code_size) { /**** if at end of a block, start new block */ if (gif_block_size==0) { tmp = fgetc(fp); if (tmp >= 0 ) { fputc(tmp,fout); gif_block_size=(ULONG)(tmp); } else TheEnd1("EOF in data stream\n"); } tmp = fgetc(fp); gif_block_size--; if (tmp >= 0) { fputc(tmp,fout); bits |= ( ((ULONG)(tmp) & 0xff) << num_bits ); num_bits+=8; } else TheEnd1("EOF in data stream\n"); } code = bits & gif_mask[code_size]; bits >>= code_size; num_bits -= code_size; if (code>MAXVAL) { fprintf(stderr,"\nError! in stream=%lx \n",code); fprintf(stderr,"CLEAR=%lx INCSIZE=%lx EOI=%lx code_size=%lx \n", CLEAR,INCSIZE,EOI,code_size); code=EOI; } if (code==INCSIZE) { if (code_size<12) { code_size++; INCSIZE=(INCSIZE*2)+1; } else if (debug_flag) fprintf(stderr,"<13?>"); } return(code); } /* * read GIF header */ void GIF_Screen_Header(fp,fout,first_time) FILE *fp,*fout; int first_time; { int temp,i; for(i=0;i<6;i++) { temp = fgetc(fp); /* if (first_time==TRUE) fputc(temp,fout); */ } if(first_time) fputs("GIF89a",fout); gifscrn.width = GIF_Get_Short(fp,fout,first_time); gifscrn.height = GIF_Get_Short(fp,fout,first_time); temp=fgetc(fp); if (first_time==TRUE) fputc(temp,fout); gifscrn.m = temp & 0x80; gifscrn.cres = (temp & 0x70) >> 4; gifscrn.pixbits = temp & 0x07; gifscrn.bc = fgetc(fp); if (first_time==TRUE) fputc(gifscrn.bc,fout); temp=fgetc(fp); if (first_time==TRUE) fputc(temp,fout); imagec=gif_ptwo[(1+gifscrn.pixbits)]; if (verbose) fprintf(stderr,"Screen: %ldx%ldx%ld m=%ld cres=%ld bkgnd=%ld pix=%ld\n", gifscrn.width,gifscrn.height,imagec,gifscrn.m,gifscrn.cres, gifscrn.bc,gifscrn.pixbits); if (gifscrn.m) { for(i=0;i<imagec;i++) { gif_cmap[i].cmap.red = temp = fgetc(fp); if (first_time==TRUE) fputc(temp,fout); gif_cmap[i].cmap.green = temp = fgetc(fp); if (first_time==TRUE) fputc(temp,fout); gif_cmap[i].cmap.blue = temp = fgetc(fp); if (first_time==TRUE) fputc(temp,fout); } } screen_was_last = TRUE; if(gifscrn.m&&(transp>=0||delay>=0)) { int ix = 0, max_dist = 3*256; if(transp>=0) { for(i=0; i<imagec; i++) { int dist = abs(gif_cmap[i].cmap.red-(transp&255))+ abs(gif_cmap[i].cmap.green-((transp>>8)&255))+ abs(gif_cmap[i].cmap.blue-(transp>>16)); if(dist<max_dist) ix = i, max_dist = dist; } if(max_dist==0) /* info at http://www.iis.ee.ethz.ch/~kiwi/GIFMerge/gifspecs.txt */ ; /* fprintf(stderr,"Transparent color matched fully\n"); */ else fprintf(stderr,"Transparent not matched fully, col #%d (%d,%d,%d) used now\n",ix, gif_cmap[ix].cmap.red,gif_cmap[ix].cmap.green,gif_cmap[ix].cmap.blue); } fputc(0x21,fout); fputc(0xF9,fout); fputc(0x04,fout); fputc((transp>=0?0x01:0x00)|(disposal<<2),fout); fputc(delay&255,fout); fputc((unsigned)delay>>8,fout); fputc(ix,fout); fputc(0x00,fout); } if(first_time&&repeats>=0) { /* documentation look at */ fputc(0x21,fout); /* http://www.reiworld.com/royalef/gifabout.htm */ fputc(0xFF,fout); fputc(0x0B,fout); fputs("NETSCAPE2.0",fout); fputc(0x03,fout); fputc(0x01,fout); fputc(repeats&255,fout); fputc((unsigned)repeats>>8,fout); fputc(0x00,fout); } } void GIF_Image_Header(fp,fout,first_time) FILE *fp,*fout; int first_time; { int temp,tnum,i,tmp; tmp = GIF_Get_Short(fp,fout,0); if(!pos_set) xpos = tmp; gifimage.left = xpos; GIF_Put_Short(fout,xpos); tmp = GIF_Get_Short(fp,fout,0); if(!pos_set) ypos = tmp; gifimage.top = ypos; GIF_Put_Short(fout,ypos); gifimage.width = GIF_Get_Short(fp,fout,1); gifimage.height = GIF_Get_Short(fp,fout,1); temp=fgetc(fp); gifimage.m = temp & 0x80; gifimage.i = temp & 0x40; gifimage.pixbits = temp & 0x07; if (screen_was_last && (first_time==FALSE)) temp |= 0x80; temp &= 0xf8; temp |= gifscrn.pixbits; fputc(temp,fout); imagex=gifimage.width; imagey=gifimage.height; tnum=gif_ptwo[(1+gifimage.pixbits)]; if (verbose) fprintf(stderr,"Image: %ldx%ldx%ld m=%ld i=%ld pix=%ld \n", imagex,imagey,tnum,gifimage.m,gifimage.i,gifimage.pixbits); /* if there is an image cmap, then use it */ if (gifimage.m) { for(i=0;i<tnum;i++) { gif_cmap[i].cmap.red = temp = fgetc(fp); fputc(temp,fout); gif_cmap[i].cmap.green = temp = fgetc(fp); fputc(temp,fout); gif_cmap[i].cmap.blue = temp = fgetc(fp); fputc(temp,fout); } } /* else if screen was last not 1st time */ else if (screen_was_last && (first_time==FALSE)) { for(i=0;i<imagec;i++) { fputc(gif_cmap[i].cmap.red ,fout); fputc(gif_cmap[i].cmap.green,fout); fputc(gif_cmap[i].cmap.blue ,fout); } } screen_was_last = FALSE; } /* * */ int GIF_Get_Short(fp,fout,first_time) FILE *fp,*fout; int first_time; { register int temp,tmp1; temp=fgetc(fp); if (first_time==TRUE) fputc(temp,fout); tmp1=fgetc(fp); if (first_time==TRUE) fputc(tmp1,fout); return(temp|( (tmp1) << 8 )); } /* * */ int GIF_Put_Short(fout,data) FILE *fout; unsigned int data; { fputc((unsigned char)(data&255),fout); /* lo */ fputc((unsigned char)((data>>8)&255),fout); /* hi */ }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.