This is xanim_gif.c in view mode; [Download] [Up]
/* * xanim_gif.c * * Copyright (C) 1990,1991,1992,1993,1994 by Mark Podlipec. * All rights reserved. * * This software may be freely copied, modified and redistributed without * fee for non-commerical purposes 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. * */ #include "xanim_gif.h" ULONG GIF_Read_Anim(); GIF_FRAME *GIF_Read_File(); GIF_FRAME *GIF_Add_Frame(); LONG Is_GIF_File(); void GIF_Decompress(); void GIF_Get_Next_Entry(); void GIF_Add_To_Table(); void GIF_Send_Data(); void GIF_Init_Table(); void GIF_Clear_Table(); ULONG GIF_Get_Code(); void GIF_Screen_Header(); void GIF_Image_Header(); void GIF_Read_Extension(); XA_ACTION *ACT_Get_Action(); XA_CHDR *ACT_Get_CMAP(); void ACT_Setup_PIXMAP(); void ACT_Setup_IMAGE(); void ACT_Setup_CLIP(); void ACT_Setup_Mapped(); void ACT_Add_CHDR_To_Action(); LONG UTIL_Get_LSB_Short(); #define MAXVAL 4100 /* maxval of lzw coding size */ #define MAXVALP 4200 #define GIF_CMAP_SIZE 256 static GIF_Screen_Hdr gifscrn; static GIF_Image_Hdr gifimage; static ColorReg gif_cmap[GIF_CMAP_SIZE]; static XA_CHDR *gif_chdr_now; static GIF_Table table[MAXVALP]; static ULONG root_code_size,code_size,CLEAR,EOI,INCSIZE; static ULONG nextab; static ULONG gif_mask[16] = {1,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,0,0}; static ULONG gif_ptwo[16] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,0,0}; static UBYTE gif_buff[MAXVALP]; static ULONG gif_block_size; static LONG gif_bits,num_bits; static gif_lace_flag; static LONG gif_max_imagec,gif_max_imagex,gif_max_imagey,gif_max_imaged; static ULONG gif_imagex,gif_imagey,gif_imagec,gif_imaged; static ULONG gif_screenx,gif_screeny; static LONG pic_i,pic_size; /* GIF89a variables */ static LONG gif_anim_type; /* from GIF89 f9 extension */ static LONG gif_anim_time; /* from GIF89 f9 extension */ static LONG gif_anim_mask; /* from GIF89 f9 extension */ static GIF_FRAME *gif_frame_start,*gif_frame_cur; static ULONG gif_frame_cnt; GIF_FRAME *GIF_Add_Frame(time,act) ULONG time; XA_ACTION *act; { GIF_FRAME *gframe; gframe = (GIF_FRAME *) malloc(sizeof(GIF_FRAME)); if (gframe == 0) TheEnd1("GIF_Add_Frame: malloc err"); gframe->time = time; gframe->act = act; gframe->next = 0; if (gif_frame_start == 0) gif_frame_start = gframe; else gif_frame_cur->next = gframe; gif_frame_cur = gframe; gif_frame_cnt++; return(gframe); } void GIF_Free_Frame_List(gframes) GIF_FRAME *gframes; { GIF_FRAME *gtmp; while(gframes != 0) { gtmp = gframes; gframes = gframes->next; FREE(gtmp,0x3000); } } ULONG GIF_Read_Anim(fname,anim_hdr) char *fname; XA_ANIM_HDR *anim_hdr; { GIF_FRAME *glist,*gtmp; ULONG frame_cnt,i; glist = GIF_Read_File(fname,anim_hdr,&frame_cnt); if (glist==0) return(FALSE); anim_hdr->frame_lst = (XA_FRAME *)malloc(sizeof(XA_FRAME) * (frame_cnt+1)); if (anim_hdr->frame_lst == NULL) TheEnd1("GIF_Read_Anim: malloc err"); gtmp = glist; i = 0; while(gtmp != 0) { if (i >= frame_cnt) { fprintf(stderr,"GIF_Read_Anim: frame inconsistency %ld %ld\n", i,frame_cnt); break; } anim_hdr->frame_lst[i].time = gtmp->time; anim_hdr->frame_lst[i].act = gtmp->act; gtmp = gtmp->next; i++; } anim_hdr->frame_lst[i].time = 0; anim_hdr->frame_lst[i].act = 0; anim_hdr->loop_frame = 0; if (i > 0) anim_hdr->last_frame = i - 1; else i = 0; GIF_Free_Frame_List(glist); return(TRUE); } /* * */ GIF_FRAME *GIF_Read_File(fname,anim_hdr,frame_cnt) char *fname; XA_ANIM_HDR *anim_hdr; ULONG *frame_cnt; { FILE *fp; LONG i,exit_flag; XA_ACTION *act; gif_frame_cnt = 0; gif_frame_start = gif_frame_cur = 0; gif_imagex = gif_max_imagex = 0; gif_imagey = gif_max_imagey = 0; gif_imagec = gif_max_imagec = 0; gif_imaged = gif_max_imaged = 0; gif_screenx = 0; gif_screeny = 0; if ( (fp=fopen(fname,XA_OPEN_MODE))==0) { fprintf(stderr,"Can't open %s for reading.\n",fname); return(0); } gif_anim_type = 0; gif_anim_time = XA_GET_TIME(MS_PER_60HZ); gif_anim_mask = 0; GIF_Screen_Header(fp,anim_hdr); /*** read until , separator */ do { i=fgetc(fp); if ( (i<0) && feof(fp)) { fclose(fp); fprintf(stderr,"GIF_Read_Header: Unexpected EOF\n"); return(0); } if (i == '!') GIF_Read_Extension(fp); /* GIF extension */ } while(i != ','); exit_flag = 0; while(!exit_flag) { UBYTE *pic_ptr; /* Read Image Header */ GIF_Image_Header(fp,anim_hdr); /*** Setup ACTION for IMAGE or CLIP */ act = ACT_Get_Action(anim_hdr); pic_size = gif_imagex * gif_imagey; pic_ptr = (UBYTE *) malloc( XA_PIC_SIZE(pic_size) ); if (pic_ptr==0) TheEnd1("GIF_Read_File: could malloc of image\n"); pic_i=0; GIF_Decompress(fp,pic_ptr); if (gif_anim_type == 0x01) { ACT_Setup_Mapped(act, pic_ptr, gif_chdr_now, gifimage.left,gifimage.top,gif_imagex,gif_imagey, gif_screenx,gif_screeny,TRUE,gif_anim_mask, TRUE,FALSE,FALSE); } else { ACT_Setup_Mapped(act, pic_ptr, gif_chdr_now, gifimage.left,gifimage.top,gif_imagex,gif_imagey, gif_screenx,gif_screeny,FALSE,0,TRUE,FALSE,FALSE); } ACT_Add_CHDR_To_Action(act,gif_chdr_now); GIF_Add_Frame(gif_anim_time,act); /*** read until "," ";" or feof */ do { i=fgetc(fp); if ( (i<0) || (i == ';')) exit_flag = 1; else if (i == '!') GIF_Read_Extension(fp); /* extension */ } while( (i != ',') && (!exit_flag) ); } /*** end of while images */ fclose(fp); anim_hdr->imagex = gif_max_imagex; anim_hdr->imagey = gif_max_imagey; anim_hdr->imagec = gif_max_imagec; anim_hdr->imaged = gif_max_imaged; *frame_cnt = gif_frame_cnt; return(gif_frame_start); } void GIF_Decompress(fp,pic) FILE *fp; char *pic; { register ULONG code,old; gif_bits = 0; num_bits=0; gif_block_size=0; /* starting code size of LZW */ root_code_size=(fgetc(fp) & 0xff); DEBUG_LEVEL3 fprintf(stderr," root code size = %ld\n",root_code_size); GIF_Clear_Table(); /* clear decoding symbol table */ code=GIF_Get_Code(fp); if (code==CLEAR) { GIF_Clear_Table(); code=GIF_Get_Code(fp); } /* write code(or what it currently stands for) to file */ GIF_Send_Data(code,pic); old=code; code=GIF_Get_Code(fp); do { if (table[code].valid == 1) /* if known code */ { /* send it's associated string to file */ GIF_Send_Data(code,pic); 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,pic); old=code; } code=GIF_Get_Code(fp); if (code==CLEAR) { GIF_Clear_Table(); code=GIF_Get_Code(fp); GIF_Send_Data(code,pic); old=code; code=GIF_Get_Code(fp); } } 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 ) */ { DEBUG_LEVEL4 fprintf(stderr,"GetNext INCSIZE was %ld ",nextab); code_size++; INCSIZE=(INCSIZE*2)+1; if (code_size>=12) code_size=12; DEBUG_LEVEL4 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,pic) register LONG index; char *pic; { register LONG 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--) { if (pic_i < pic_size) pic[pic_i++] = gif_buff[j]; else fprintf(stderr,"GIF_Send: data beyond image size - ignored\n"); if (gif_lace_flag) { if ((pic_i % gif_imagex) == 0 ) { switch(gif_lace_flag) { case 1: pic_i += gif_imagex * 7; break; /* fill every 8th row */ case 2: pic_i += gif_imagex * 7; break; /* fill every 8th row */ case 3: pic_i += gif_imagex * 3; break; /* fill every 4th row */ case 4: pic_i += gif_imagex ; break; /* fill every other row */ } } if (pic_i >= pic_size) { gif_lace_flag++; switch(gif_lace_flag) { case 2: pic_i = gif_imagex << 2; break; /* start at 4th row */ case 3: pic_i = gif_imagex << 1; break; /* start at 2nd row */ case 4: pic_i = gif_imagex; break; /* start at 1st row */ default: gif_lace_flag = 0; pic_i = 0; break; } } } /*** end of if gif_lace_flag */ } /*** end of code expansion */ } /* * initialize string table */ void GIF_Init_Table() { register LONG maxi,i; DEBUG_LEVEL3 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; DEBUG_LEVEL3 fprintf(stderr,"done\n"); } /* * clear table */ void GIF_Clear_Table() { register LONG i; DEBUG_LEVEL3 fprintf(stderr," Clearing Table...\n"); for(i=0;i<MAXVAL;i++) table[i].valid=0; GIF_Init_Table(); } /*CODE*/ ULONG GIF_Get_Code(fp) /* get code depending of current LZW code size */ FILE *fp; { ULONG code; register LONG 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 ) gif_block_size=(ULONG)(tmp); else TheEnd1("EOF in data stream\n"); DEBUG_LEVEL3 fprintf(stderr,"New Block size=%ld\n",gif_block_size); } tmp = fgetc(fp); gif_block_size--; if (tmp >= 0) { gif_bits |= ( ((ULONG)(tmp) & (ULONG)(0xff)) << num_bits ); DEBUG_LEVEL3 fprintf(stderr,"tmp=%lx bits=%lx num_bits=%ld\n",tmp,gif_bits,num_bits); num_bits+=8; } else TheEnd1("EOF in data stream\n"); } code = gif_bits & gif_mask[code_size]; gif_bits >>= code_size; num_bits -= code_size; DEBUG_LEVEL3 fprintf(stderr,"code=%lx \n",code); 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) { DEBUG_LEVEL3 fprintf(stderr," code=INCSIZE(%ld)\n",INCSIZE); if (code_size<12) { code_size++; INCSIZE=(INCSIZE*2)+1; } else DEBUG_LEVEL3 fprintf(stderr," <13?>\n"); DEBUG_LEVEL3 fprintf(stderr," new size = %ld\n",code_size); } return(code); } /* * read GIF header */ void GIF_Screen_Header(fp,anim_hdr) FILE *fp; XA_ANIM_HDR *anim_hdr; { LONG temp,i; for(i=0;i<6;i++) fgetc(fp); /* read and toss GIF87a or GIF89? */ gif_screenx = gif_imagex = gifscrn.width = UTIL_Get_LSB_Short(fp); gif_screeny = gif_imagey = gifscrn.height = UTIL_Get_LSB_Short(fp); temp=fgetc(fp); gifscrn.m = temp & 0x80; gifscrn.cres = (temp & 0x70) >> 4; gifscrn.pixbits = temp & 0x07; gifscrn.bc = fgetc(fp); temp=fgetc(fp); gif_imaged = gifscrn.pixbits + 1; gif_imagec = gif_ptwo[gif_imaged]; if (gif_imagex > gif_max_imagex) gif_max_imagex = gif_imagex; if (gif_imagey > gif_max_imagey) gif_max_imagey = gif_imagey; if (gif_imagec > gif_max_imagec) gif_max_imagec = gif_imagec; if (gif_imaged > gif_max_imaged) gif_max_imaged = gif_imaged; if (xa_verbose == TRUE) fprintf(stderr," Screen: %ldx%ldx%ld m=%ld cres=%ld bkgnd=%ld pix=%ld\n", gifscrn.width,gifscrn.height,gif_imagec,gifscrn.m,gifscrn.cres, gifscrn.bc,gifscrn.pixbits); if ( (gif_imagec > x11_cmap_size) && (x11_cmap_flag == TRUE) && (x11_display_type & XA_X11_CMAP) ) { fprintf(stderr,"ERROR: Image has %ld colors, display can handle %ld\n", gif_imagec,x11_cmap_size); TheEnd(); } if (gifscrn.m) { for(i=0; i < gif_imagec; i++) { gif_cmap[i].red = fgetc(fp); gif_cmap[i].green = fgetc(fp); gif_cmap[i].blue = fgetc(fp); } gif_chdr_now = ACT_Get_CMAP(gif_cmap,gif_imagec,0,gif_imagec,0,8,8,8); } } /* end of function */ /* * */ void GIF_Image_Header(fp,anim_hdr) FILE *fp; XA_ANIM_HDR *anim_hdr; { LONG temp,i; gifimage.left = UTIL_Get_LSB_Short(fp); gifimage.top = UTIL_Get_LSB_Short(fp); gifimage.width = UTIL_Get_LSB_Short(fp); gifimage.height = UTIL_Get_LSB_Short(fp); temp=fgetc(fp); gifimage.m = temp & 0x80; gifimage.i = temp & 0x40; if (gifimage.i) gif_lace_flag = 1; else gif_lace_flag = 0; gifimage.pixbits = temp & 0x07; gif_imaged = gifimage.pixbits + 1; gif_imagex = gifimage.width; gif_imagey = gifimage.height; gif_imagec = gif_ptwo[gif_imaged]; if (gif_imagex > gif_max_imagex) gif_max_imagex = gif_imagex; if (gif_imagey > gif_max_imagey) gif_max_imagey = gif_imagey; if (gif_imagec > gif_max_imagec) gif_max_imagec = gif_imagec; if (gif_imaged > gif_max_imaged) gif_max_imaged = gif_imaged; DEBUG_LEVEL1 { fprintf(stderr," Image: %ldx%ldx%ld m=%ld i=%ld pix=%ld resvd=%lx", gif_imagex,gif_imagey,gif_imagec,gifimage.m,gifimage.i,gifimage.pixbits, gifimage.reserved ); fprintf(stderr,"Pos: %ldx%ld \n",gifimage.left,gifimage.top); } /* Read in Image CMAP if Image has one */ if (gifimage.m) { for(i=0; i < gif_imagec; i++) { gif_cmap[i].red = fgetc(fp); gif_cmap[i].green = fgetc(fp); gif_cmap[i].blue = fgetc(fp); } gif_chdr_now = ACT_Get_CMAP(gif_cmap,gif_imagec,0,gif_imagec,0,8,8,8); } } /* * */ LONG Is_GIF_File(filename) char *filename; { FILE *fp; ULONG firstword; if ( (fp=fopen(filename,XA_OPEN_MODE)) == 0) return(XA_NOFILE); /* by reading bytes we can ignore big/little endian problems */ firstword = (ULONG)(fgetc(fp) & 0xff) << 24; firstword |= (ULONG)(fgetc(fp) & 0xff) << 16; firstword |= (ULONG)(fgetc(fp) & 0xff) << 8; firstword |= (ULONG)(fgetc(fp) & 0xff); fclose(fp); if (firstword == 0x47494638) return((LONG)TRUE); return((LONG)FALSE); } void GIF_Read_Extension(fp) FILE *fp; { LONG block_size,code,tmp,i; code = fgetc(fp); DEBUG_LEVEL2 fprintf(stderr," GIF Extension: Code = %lx\n",code); if ( (code == 0xfe) && (xa_verbose==TRUE) ) fprintf(stderr," GIF COMMENT EXTENSION BLOCK\n"); block_size = fgetc(fp); if ( (code == 0xf9) && (block_size == 4)) { gif_anim_type = fgetc(fp); i = UTIL_Get_LSB_Short(fp); if (i < 0) i = 1; gif_anim_time = XA_GET_TIME(i * 10); gif_anim_mask = fgetc(fp); block_size = fgetc(fp); } while(block_size > 0) { for(i=0; i<block_size; i++) { tmp=fgetc(fp); if ( (code == 0xfe) && (xa_verbose==TRUE) ) fprintf(stderr,"%c",tmp); if (code == 0xf9) DEBUG_LEVEL1 fprintf(stderr,"%lx ",tmp); } block_size = fgetc(fp); if (code == 0xf9) DEBUG_LEVEL1 fprintf(stderr,"\n"); } }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.