📄 readgif.c
字号:
/* zgv 5.4 - GIF, JPEG and PBM/PGM/PPM viewer, for VGA PCs running Linux. * Copyright (C) 1993-2001 Russell Marks. See README for license details. * * readgif.c - GIF reader. */#include <stdio.h>#include <string.h>#include <unistd.h>#include <stdlib.h>#include "zgv.h"#include "readgif.h"/* XXX should make this allocate on the fly rather than inflicting * arbitrary values on people... :-) */#define MAX_GIF_IMAGES 256static byte *image;static hffunc howfar;static FILE *global_gif_infile; /* only used for error cleanup */typedef struct { int left,top; int width,height; int numcols; int misc,delay,transparent_col,gcb_control; unsigned char *cmap,*image; } gif_image;/* the GIF is read into these */static unsigned char *global_cmap;static int swidth,sheight; /* screen width/height (for multi-image) */static int imagecount;static gif_image *images[MAX_GIF_IMAGES];/* these are global to save going through multiple hoops :-) */int gif_delaycount;int *gif_delay=NULL; /* array of delays after each image */static int imagex,imagey,stopoutput;static int dc_cc,dc_eoi; /* the CC and EOI codes */static int passnum,passyloc,passstep; /* for interlaced GIFs */static int interlaced,width,height,bpp,numcols,gnumcols,lnumcols;static int global_colour_map,local_colour_map;static int transparent_col,delay,gcb_control;/* now this is for the string table. * the st_ptr array stores which pos to back reference to, * each string is [...]+ end char, [...] is traced back through * the 'pointer' (index really), then back through the next, etc. * a 'null pointer' is = to UNUSED. * the st_chr array gives the end char for each. * an unoccupied slot is = to UNUSED. */#define UNUSED 32767#define MAXSTR 4096static int st_ptr[MAXSTR],st_chr[MAXSTR],st_last;static int st_ptr1st[MAXSTR];/* this is for the byte -> bits mangler: * dc_bitbox holds the bits, dc_bitsleft is number of bits left in dc_bitbox, * blocksize is how many bytes of an image sub-block we have left. */static int dc_bitbox,dc_bitsleft,blocksize;struct { char sig[6]; /* should be GIF87a or GIF89a */ byte wide_lo,wide_hi; /* NUXI Problem Avoidance System (tm) */ byte high_lo,high_hi; /* these are 'screen size', BTW */ byte misc; /* misc, and bpp */ byte back; /* background index */ byte zero; /* if this ain't zero, problem */ } gifhed; /* BTW, the NUXI thing above is because most of this code is reused from * a GIF viewer I did for Tektronix 4200 series terminals. If you want a copy, * mail me, but I figure not many people use them. * (at least, not from Linux PCs :-)) */ struct { byte left_lo,left_hi; /* usually zero - ignore */ byte top_lo,top_hi; byte wide_lo,wide_hi; /* this is 'image size', often the same as screen */ byte high_lo,high_hi; byte misc; } imagehed;void outputchr(int code){if(!stopoutput) { *(image+(interlaced?passyloc:imagey)*width+imagex)=code; imagex++; if(imagex>=width) { imagex=0; imagey++; if(interlaced) { passyloc+=passstep; while(passyloc>=height && passnum<4) { passnum++; passyloc=(1<<(4-passnum)); passstep=(1<<(5-passnum)); } } if(howfar) howfar(imagey,height); if(imagey==height) stopoutput=1; } }}/* This used to be recursive, but a broken GIF could cause problems * that way. This version should be unhangable. :-) */void outputstring(int code){static int buf[MAXSTR];int *ptr=buf;while(st_ptr[code]!=UNUSED && ptr<buf+MAXSTR) { *ptr++=st_chr[code]; code=st_ptr[code]; }outputchr(st_chr[code]);while(ptr>buf) outputchr(*--ptr);}int findfirstchr(int code){if(st_ptr[code]!=UNUSED) /* not first? then use brand new st_ptr1st! */ code=st_ptr1st[code]; /* now with no artificial colouring */return(st_chr[code]);}int readgifhed(FILE *in){fread(&gifhed,sizeof(gifhed),1,in);if(strncmp(gifhed.sig,"GIF",3)) return(_PICERR_BADMAGIC);global_colour_map=(gifhed.misc&128)?1:0;bpp=(gifhed.misc&7)+1;gnumcols=numcols=(1<<bpp);return(_PIC_OK);}void readcolmap(FILE *in,byte *palette,int numcols){int f;for(f=0;f<numcols;f++) { palette[ f]=(byte)fgetc(in); palette[256+f]=(byte)fgetc(in); palette[512+f]=(byte)fgetc(in); }}int readimagehed(FILE *in){int c,f;gcb_control=0;delay=0;transparent_col=0;c=fgetc(in);while(c=='!') /* oh damn it, they've put an ext. block in, ditch it */ { c=fgetc(in); /* function code */ switch(c) { case 0xf9: /* graphics control block, specifies transparency etc. */ if((c=fgetc(in))==4) { gcb_control=fgetc(in); delay=fgetc(in); delay+=fgetc(in)*256; transparent_col=fgetc(in); c=fgetc(in); break; /* avoid fall-through required by `else' below */ } else { /* not 4 bytes, must be corrupt - try ditching the block. */ ungetc(c,in); } /* FALLS THROUGH */ default: /* other block types are ignored */ c=fgetc(in); while(c) { /* well then, c = number of bytes, so ignore that many */ for(f=0;f<c;f++) fgetc(in); c=fgetc(in); } } c=fgetc(in); /* test for image again */ }if(c==';') return(_PICERR_NOMORE); /* no more images */if(c!=',') return(_PICERR_NOIMAGE);fread(&imagehed,sizeof(imagehed),1,in);local_colour_map=(imagehed.misc&128)?1:0;if((imagehed.misc&64)!=0) { interlaced=1; passnum=1; passyloc=0; passstep=8; }else interlaced=0;width=(imagehed.wide_lo+256*imagehed.wide_hi);height=(imagehed.high_lo+256*imagehed.high_hi);lnumcols=0;if(local_colour_map) lnumcols=(1<<((imagehed.misc&7)+1));return(_PIC_OK);}void inittable(int orgcsize){int f;int numcols=(1<<(orgcsize-1));for(f=0;f<MAXSTR;f++) { st_chr[f]=UNUSED; st_ptr[f]=UNUSED; }for(f=0;f<numcols+2;f++) { st_ptr[f]=UNUSED; /* these are root values... no back pointer */ st_chr[f]=f; /* for numcols and numcols+1, doesn't matter */ }st_last=numcols+1; /* last occupied slot */dc_cc=numcols;dc_eoi=numcols+1;if(numcols==2) { st_chr[2]=st_chr[3]=UNUSED; dc_cc=4; dc_eoi=5; st_chr[dc_cc]=dc_cc; st_chr[dc_eoi]=dc_eoi; st_last=5; }}/* add a string specified by oldstring + chr to string table */int addstring(int oldcode,int chr){st_last++;if((st_last&4096)) { st_last=4095; return(1); /* not too clear it should die or not... */ }while(st_chr[st_last]!=UNUSED) { st_last++; if((st_last&4096)) { st_last=4095; return(1); } }st_chr[st_last]=chr;if(st_last==oldcode) return(0); /* corrupt GIF - can cause hangs without this */st_ptr[st_last]=oldcode;if(st_ptr[oldcode]==UNUSED) /* if we're pointing to a root... */ st_ptr1st[st_last]=oldcode; /* then that holds the first char */else /* otherwise... */ st_ptr1st[st_last]=st_ptr1st[oldcode]; /* use their pointer to first */return(1);}/* read a code of bitlength numbits from in file */int readcode(int *newcode,int numbits,FILE *in){int bitsfilled,got;bitsfilled=got=0;(*newcode)=0;while(bitsfilled<numbits) { if(dc_bitsleft==0) /* have we run out of bits? */ { if(blocksize<=0) /* end of block? */ blocksize=fgetc(in); /* start new block, blocksize = num of bytes */ blocksize--; dc_bitbox=fgetc(in); /* read eight more bits */ if(feof(in)) return(0); dc_bitsleft=8; } if(dc_bitsleft<(numbits-bitsfilled)) got=dc_bitsleft; else got=numbits-bitsfilled; (*newcode)|=((dc_bitbox&((1<<got)-1))<<bitsfilled); dc_bitbox>>=got; dc_bitsleft-=got; bitsfilled+=got; }if((*newcode)<0 || (*newcode)>MAXSTR-1) return(0);return(1);}/* 'image' is used directly for speed; * otherwise it'd need to use twice as many parameters in a recursive * routine (outputstring) */int decompress(FILE *in){int csize,orgcsize;int newcode,oldcode,k;int first=1;csize=fgetc(in)+1;orgcsize=csize;inittable(orgcsize);oldcode=newcode=0;while(newcode!=dc_eoi) { if(!readcode(&newcode,csize,in)) return(_PICERR_CORRUPT); if(newcode!=dc_eoi) { if(newcode==dc_cc) { /* don't redo it if it's the first code */ if(!first) inittable(orgcsize); csize=orgcsize; if(!readcode(&newcode,csize,in)) return(_PICERR_CORRUPT); oldcode=newcode; outputstring(newcode); } else { if(st_chr[newcode]!=UNUSED) { outputstring(newcode); k=findfirstchr(newcode);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -