jindak@surfside.sgi.com (Chris Schoeneman) (06/12/90)
>I've been using togiff and fromgif but have never heard of gifview. Can >someone tell me where I can get a hold of this little goodie? The reason you haven't heard of it is because it's less than a week old. I didn't know about 'togif' or 'fromgif' so I wrote a simple viewer; the source code is below. I would like to thank Kevin (krk@cs.purdue.edu) for his favorable review. But Paul Haeberli just posted the source for a viewer too; I haven't run it, but the source code definitely looks cleaner. You should look into it. Chris Schoeneman | I was neat, clean, shaved and sober, jindak@surfside.esd.sgi.com | and I didn't care who knew it. Silicon Graphics, Inc. | -Raymond Chandler Mountain View, CA | (The Big Sleep) ---- Cut here ---- #define CMAP_START 1024 #include <gl.h> #include <stdio.h> typedef struct { int dx,dy; /* size */ int colors,bits,cr; /* num colors, bits/pixel, color resolution */ char gcm, /* global color map flag */ bgnd; /* background color */ } screen_dscrp; typedef struct { int x,y,dx,dy, /* position, size */ colors,bits; /* num colors, bits/pixel */ char gcm,order; /* use global cm, seq. or interlaced */ } image_dscrp; char g_colors[256][3]; /* Global color map */ int bits_left,byte_count, /* bits in last_char, bytes left */ mask[14]={0,1,3,7,0xf,0x1f,0x3f,0x7f,0xff, 0x1ff,0x3ff,0x7ff,0xfff,0x1fff}, code_size,countsize,countdown, dy_table[4]={8,8,4,2},offset_table[4]={0,4,2,1}, last_char,bit_mask,least_bits; short pixel_row[4096],code_table[4096][2],cmap; FILE *stream_source; /* file for input */ screen_dscrp si; /* global screen descriptor */ /***************************************************** * Input routines * *****************************************************/ int mscanf(FILE *infile, char *parse) { char *scan; int dx,dy; for (scan=parse;*scan;scan++) if (getc(infile)!=(int)*scan) return(0); return(!0); } /* read Screen Descriptor */ int scan_SD(FILE *infile, screen_dscrp *sd) { char data; data=(char)getc(infile); sd->dx=data+((char)getc(infile)<<8); data=(char)getc(infile); sd->dy=data+((char)getc(infile)<<8); data=getc(infile); if (data&8) return(0); sd->gcm=data&0x80; sd->cr=(data&0x70)>>4; sd->bits=(data&7)+1; sd->colors=1<<sd->bits; sd->bgnd=getc(infile); if (getc(infile)!=0) return(0); return(!0); } /* skip past an extension block */ void skip_EB(FILE *infile) { int count,garbage[256]; getc(infile); /* get function */ while (count=getc(infile)) fread(garbage,1,count,infile); } /* read Image Descriptor */ int scan_ID(FILE *infile, image_dscrp *id) { char data; /* wait for ',' or ';' or '!' EOF */ do { data=(char)getc(infile); if (data==';') return(1); if (feof(infile)) return(0); if (data==0x21) skip_EB(infile); } while (data!=0x2c); data=(char)getc(infile); id->x=data+((char)getc(infile)<<8); data=(char)getc(infile); id->y=data+((char)getc(infile)<<8); data=(char)getc(infile); id->dx=data+((char)getc(infile)<<8); data=(char)getc(infile); id->dy=data+((char)getc(infile)<<8); data=(char)getc(infile); id->gcm=data&0x80; id->order=data&0x40; id->bits=(data&7)+1; id->colors=1<<id->bits; return(2); } /* read Color Map */ void scan_CM(FILE *infile, int colors, char *cm) { char *scan; int i; for (scan=cm,i=3*colors;i>0;i--) *scan++=(char)getc(infile); } /* reset code stuff */ void reset_codes(void) { code_size=least_bits+1; if (code_size<=2) code_size=3; countsize=1<<code_size; countdown=countsize-(1<<least_bits)-2; bit_mask=(long)mask[code_size]; } /* clear bitstream */ void clear_stream(FILE *infile, int bits) { getc(infile); /* skip minimum bit size */ byte_count=0; last_char=0; bits_left=0; least_bits=bits; stream_source=infile; reset_codes(); } /* read next code and adjust code width */ short get_code(void) { static char flag=0; short code; int new; if (byte_count==0) byte_count=getc(stream_source); if (bits_left<code_size) { new=(int)getc(stream_source); byte_count--; if (bits_left+8<code_size) { if (byte_count==0) byte_count=getc(stream_source); byte_count--; new|=((int)getc(stream_source)<<8); code=16; } else code=8; if (bits_left) new<<=bits_left; last_char|=new; bits_left+=code; } code=(short)(last_char&bit_mask); last_char>>=code_size; bits_left-=code_size; if (flag) { flag=0; reset_codes(); } else if (--countdown==0) { countdown=countsize; countsize<<=1; if (++code_size==13) { flag=1; code_size--; } else bit_mask=(int)mask[code_size]; } return(code); } /***************************************************** * Other routines * *****************************************************/ void install_cmap(int colors, char *cm) { char *scan; int i; for (scan=cm,i=cmap;colors>0;scan+=3,i++,colors--) mapcolor(i,(short)*scan,(short)*(scan+1),(short)*(scan+2)); } void setup_codes(int colors) { int i; for (i=0;i<colors;i++) code_table[i][0]=code_table[i][1]=i; } void read_interlaced(image_dscrp *id) { int table_ptr,row_count,dy,y,pass,end_code,clear_code; short prefix,suffix,save,stack[4096],*stack_ptr,*pixel=pixel_row; row_count=id->dx; clear_code=id->colors; end_code=clear_code+1; while ((prefix=get_code())==clear_code); reset_codes(); table_ptr=clear_code+2; for (pass=0;pass<4;pass++) { y=id->y+id->dy-1-offset_table[pass]; dy=dy_table[pass]; while (y>=0 && (save=suffix=get_code())!=end_code) { if (suffix==clear_code) { reset_codes(); while ((save=get_code())==clear_code); reset_codes(); table_ptr=clear_code+1; } else { code_table[table_ptr][0]=prefix; if (suffix==table_ptr) code_table[table_ptr][1]=code_table[prefix][1]; else { while (suffix>=id->colors) suffix=code_table[suffix][0]; code_table[table_ptr][1]=suffix; } } suffix=1; stack_ptr=stack; while (prefix>=id->colors) { *stack_ptr++=code_table[prefix][1]; prefix=code_table[prefix][0]; suffix++; } *stack_ptr=prefix; for (;suffix>0;stack_ptr--,suffix--) { *pixel++ = cmap+*stack_ptr; if (--row_count==0) { row_count=id->dx; pixel=pixel_row; rectwrite(id->x,y,id->x+id->dx-1,y,pixel_row); y-=dy; } } table_ptr++; prefix=save; } } } void read_sequential(image_dscrp *id) { int table_ptr,row_count,y,end_code,clear_code; short *pixel=pixel_row,prefix,suffix,save,stack[4096],*stack_ptr; y=id->y+id->dy-1; row_count=id->dx; clear_code=id->colors; end_code=clear_code+1; while ((prefix=get_code())==clear_code); reset_codes(); table_ptr=clear_code+2; while ((save=suffix=get_code())!=end_code) { if (suffix==clear_code) { reset_codes(); while ((save=get_code())==clear_code); reset_codes(); table_ptr=clear_code+1; } else { code_table[table_ptr][0]=prefix; if (suffix==table_ptr) code_table[table_ptr][1]=code_table[prefix][1]; else { while (suffix>=id->colors) suffix=code_table[suffix][0]; code_table[table_ptr][1]=suffix; } } suffix=1; stack_ptr=stack; while (prefix>=id->colors) { *stack_ptr++=code_table[prefix][1]; prefix=code_table[prefix][0]; suffix++; } *stack_ptr=prefix; for (;suffix>0;stack_ptr--,suffix--) { *pixel++ = cmap+*stack_ptr; if (--row_count==0) { row_count=id->dx; pixel=pixel_row; rectwrite(id->x,y,id->x+id->dx-1,y,pixel_row); y--; } } table_ptr++; prefix=save; } } int draw_image(FILE *infile) { char lcm[256][3]; int flag; image_dscrp id; /* get image descriptor and setup colors */ flag=scan_ID(infile,&id); if (flag==0) { printf("unexpected eof.\n"); exit(3); } if (flag==1) return(0); if (id.gcm) { scan_CM(infile,id.colors,lcm); install_cmap(id.colors,lcm); } else { install_cmap(si.colors,g_colors); id.colors=si.colors; id.bits=si.bits; } /* draw image */ if (id.bits==1) { /* Need extra bit for 2 color pic. */ id.bits=2; id.colors=4; } clear_stream(infile,id.bits); setup_codes(id.colors); color(si.bgnd+CMAP_START); clear(); if (id.order) read_interlaced(&id); else read_sequential(&id); return(!0); } void main(int argc, char **argv) { FILE *gif_data; int name_arg=1,map=0; /* open file */ if (argc<2 || argc>3) { printf("usage: %s [-map#] <filename>\n",argv[0]); exit(1); } if (argv[1][0]=='-') { name_arg=2; if (isdigit(argv[1][1])) map=argv[1][1]-'0'; if (map<0 || map>7) printf("%d out of range (0-7).\n"); } cmap=CMAP_START+(map<<8); gif_data=fopen(argv[name_arg],"r"); if (gif_data==NULL) { printf("can't open %s.\n",argv[name_arg]); exit(1); } if (!mscanf(gif_data,"GIF87a")) { printf("%s not a gif file.\n",argv[name_arg]); exit(2); } /* get global info */ if (!scan_SD(gif_data,&si)) { printf("data format error.\n"); exit(3); } printf("File %s:\n resolution: %dx%d\n colors: %d\n", argv[name_arg],si.dx,si.dy,si.colors); /* get global colors */ if (si.gcm) scan_CM(gif_data,si.colors,g_colors); /* open window */ prefsize(si.dx,si.dy); maxsize(si.dx,si.dy); minsize(si.dx,si.dy); winopen(argv[name_arg]); /* setup colormap mode */ cmode(); onemap(); gconfig(); while (draw_image(gif_data)); fclose(gif_data); for (;;) sleep(1000); }