LZW压缩算法 C#源码
usingSystem; usingSystem.IO; namespaceGif.Components { publicclassLZWEncoder { privatestaticreadonlyintEOF=-1; privateintimgW,imgH; privatebyte[]pixAry; privateintinitCodeSize; privateintremaining; privateintcurPixel; //GIFCOMPR.C-GIFImagecompressionroutines // //Lempel-Zivcompressionbasedon'compress'.GIFmodificationsby //DavidRowley(mgardi@watdcsu.waterloo.edu) //GeneralDEFINEs staticreadonlyintBITS=12; staticreadonlyintHSIZE=5003;//80%occupancy //GIFImagecompression-modified'compress' // //Basedon:compress.c-FilecompressionalaIEEEComputer,June1984. // //ByAuthors:SpencerW.Thomas(decvax!harpo!utah-cs!utah-gr!thomas) //JimMcKie(decvax!mcvax!jim) //SteveDavies(decvax!vax135!petsd!peora!srd) //KenTurkowski(decvax!decwrl!turtlevax!ken) //JamesA.Woods(decvax!ihnp4!ames!jaw) //JoeOrost(decvax!vax135!petsd!joe) intn_bits;//numberofbits/code intmaxbits=BITS;//usersettablemax#bits/code intmaxcode;//maximumcode,givenn_bits intmaxmaxcode=1<<BITS;//shouldNEVERgeneratethiscode int[]htab=newint[HSIZE];//这个是放hash的筒子,在这里面可以很快的找到1个key int[]codetab=newint[HSIZE]; inthsize=HSIZE;//fordynamictablesizing intfree_ent=0;//firstunusedentry //blockcompressionparameters--afterallcodesareusedup, //andcompressionratechanges,startover. boolclear_flg=false; //Algorithm:useopenaddressingdoublehashing(nochaining)onthe //prefixcode/nextcharactercombination.WedoavariantofKnuth's //algorithmD(vol.3,sec.6.4)alongwithG.Knott'srelatively-prime //secondaryprobe.Here,themodulardivisionfirstprobeisgivesway //toafasterexclusive-ormanipulation.Alsodoblockcompressionwith //anadaptivereset,wherebythecodetableisclearedwhenthecompression //ratiodecreases,butafterthetablefills.Thevariable-lengthoutput //codesarere-sizedatthispoint,andaspecialCLEARcodeisgenerated //forthedecompressor.Lateaddition:constructthetableaccordingto //filesizefornoticeablespeedimprovementonsmallfiles.Pleasedirect //questionsaboutthisimplementationtoames!jaw. intg_init_bits; intClearCode; intEOFCode; //output // //Outputthegivencode. //Inputs: //code:An_bits-bitinteger.If==-1,thenEOF.Thisassumes //thatn_bits=<wordsize-1. //Outputs: //Outputscodetothefile. //Assumptions: //Charsare8bitslong. //Algorithm: //MaintainaBITScharacterlongbuffer(sothat8codeswill //fitinitexactly).UsetheVAXinsvinstructiontoinserteach //codeinturn.Whenthebufferfillsupemptyitandstartover. intcur_accum=0; intcur_bits=0; int[]masks= { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF}; //Numberofcharacterssofarinthis'packet' inta_count; //Definethestorageforthepacketaccumulator byte[]accum=newbyte[256]; //---------------------------------------------------------------------------- publicLZWEncoder(intwidth,intheight,byte[]pixels,intcolor_depth) { imgW=width; imgH=height; pixAry=pixels; initCodeSize=Math.Max(2,color_depth); } //Addacharactertotheendofthecurrentpacket,andifitis254 //characters,flushthepackettodisk. voidAdd(bytec,Streamouts) { accum[a_count++]=c; if(a_count>=254) Flush(outs); } //Clearoutthehashtable //tableclearforblockcompress voidClearTable(Streamouts) { ResetCodeTable(hsize); free_ent=ClearCode+2; clear_flg=true; Output(ClearCode,outs); } //resetcodetable //全部初始化为-1 voidResetCodeTable(inthsize) { for(inti=0;i<hsize;++i) htab[i]=-1; } voidCompress(intinit_bits,Streamouts) { intfcode; inti/*=0*/; intc; intent; intdisp; inthsize_reg; inthshift; //Setuptheglobals:g_init_bits-initialnumberofbits //原始数据的字长,在gif文件中,原始数据的字长可以为1(单色图),4(16色),和8(256色) //开始的时候先加上1 //但是当原始数据长度为1的时候,开始为3 //因此原始长度1->3,4->5,8->9 //?为何原始数据字长为1的时候,开始长度为3呢?? //如果+1=2,只能表示四种状态,加上clearcode和endcode就用完了。所以必须扩展到3 g_init_bits=init_bits; //Setupthenecessaryvalues //是否需要加清除标志 //GIF为了提高压缩率,采用的是变长的字长(VCL)。比如说原始数据是8位,那么开始先加上1位(8+1=9) //当标号到2^9=512的时候,超过了当前长度9所能表现的最大值,此时后面的标号就必须用10位来表示 //以此类推,当标号到2^12的时候,因为最大为12,不能继续扩展了,需要在2^12=4096的位置上插入一个ClearCode,表示从这往后,从9位重新再来了 clear_flg=false; n_bits=g_init_bits; //获得n位数能表述的最大值(gif图像中开始一般为3,5,9,故maxcode一般为7,31,511) maxcode=MaxCode(n_bits); //表示从这里我重新开始构造字典字典了,以前的所有标记作废, //开始使用新的标记。这个标号集的大小多少比较合适呢?据说理论上是越大压缩率越高(我个人感觉太大了也不见得就好), //不过处理的开销也呈指数增长 //gif规定,clearcode的值为原始数据最大字长所能表达的数值+1;比如原始数据长度为8,则clearcode=1<<(9-1)=256 ClearCode=1<<(init_bits-1); //结束标志为clearcode+1 EOFCode=ClearCode+1; //这个是解除结束的 free_ent=ClearCode+2; //清楚数量 a_count=0;//clearpacket //从图像中获得下一个像素 ent=NextPixel(); hshift=0; for(fcode=hsize;fcode<65536;fcode*=2) ++hshift; //设置hash码范围 hshift=8-hshift;//sethashcoderangebound hsize_reg=hsize; //清除固定大小的hash表,用于存储标记,这个相当于字典 ResetCodeTable(hsize_reg);//clearhashtable Output(ClearCode,outs); outer_loop:while((c=NextPixel())!=EOF) { fcode=(c<<maxbits)+ent; i=(c<<hshift)^ent;//xorhashing //嘿嘿,小样,又来了,我认识你 if(htab[i]==fcode) { ent=codetab[i]; continue; } //这小子,新来的 elseif(htab[i]>=0)//non-emptyslot { disp=hsize_reg-i;//secondaryhash(afterG.Knott) if(i==0) disp=1; do { if((i-=disp)<0) i+=hsize_reg; if(htab[i]==fcode) { ent=codetab[i]; gotoouter_loop; } }while(htab[i]>=0); } Output(ent,outs); //从这里可以看出,ent就是前缀(prefix),而当前正在处理的字符标志就是后缀(suffix) ent=c; //判断终止结束符是否超过当前位数所能表述的范围 if(free_ent<maxmaxcode) { //如果没有超 codetab[i]=free_ent++;//code->hashtable //hash表里面建立相应索引 htab[i]=fcode; } else //说明超过了当前所能表述的范围,清空字典,重新再来 ClearTable(outs); } //Putoutthefinalcode. Output(ent,outs); Output(EOFCode,outs); } //---------------------------------------------------------------------------- publicvoidEncode(Streamos) { os.WriteByte(Convert.ToByte(initCodeSize));//write"initialcodesize"byte //这个图像包含多少个像素 remaining=imgW*imgH;//resetnavigationvariables //当前处理的像素索引 curPixel=0; Compress(initCodeSize+1,os);//compressandwritethepixeldata os.WriteByte(0);//writeblockterminator } //Flushthepackettodisk,andresettheaccumulator voidFlush(Streamouts) { if(a_count>0) { outs.WriteByte(Convert.ToByte(a_count)); outs.Write(accum,0,a_count); a_count=0; } } ///<summary> ///获得n位数所能表达的最大数值 ///</summary> ///<paramname="n_bits">位数,一般情况下n_bits=9</param> ///<returns>最大值,例如n_bits=8,则返回值就为2^8-1=255</returns> intMaxCode(intn_bits) { return(1<<n_bits)-1; } //---------------------------------------------------------------------------- //Returnthenextpixelfromtheimage //---------------------------------------------------------------------------- ///<summary> ///从图像中获得下一个像素 ///</summary> ///<returns></returns> privateintNextPixel() { //还剩多少个像素没有处理 //如果没有了,返回结束标志 if(remaining==0) returnEOF; //否则处理下一个,并将未处理像素数目-1 --remaining; //当前处理的像素 inttemp=curPixel+1; //如果当前处理像素在像素范围之内 if(temp<pixAry.GetUpperBound(0)) { //下一个像素 bytepix=pixAry[curPixel++]; returnpix&0xff; } return0xff; } ///<summary> ///输出字到输出流 ///</summary> ///<paramname="code">要输出的字</param> ///<paramname="outs">输出流</param> voidOutput(intcode,Streamouts) { //得到当前标志位所能表示的最大标志值 cur_accum&=masks[cur_bits]; if(cur_bits>0) cur_accum|=(code<<cur_bits); else //如果标志位为0,就将当前标号为输入流 cur_accum=code; //当前能标志的最大字长度(9-10-11-12-9-10。。。。。。。) cur_bits+=n_bits; //如果当前最大长度大于8 while(cur_bits>=8) { //向流中输出一个字节 Add((byte)(cur_accum&0xff),outs); //将当前标号右移8位 cur_accum>>=8; cur_bits-=8; } //Ifthenextentryisgoingtobetoobigforthecodesize, //thenincreaseit,ifpossible. if(free_ent>maxcode||clear_flg) { if(clear_flg) { maxcode=MaxCode(n_bits=g_init_bits); clear_flg=false; } else { ++n_bits; if(n_bits==maxbits) maxcode=maxmaxcode; else maxcode=MaxCode(n_bits); } } if(code==EOFCode) { //AtEOF,writetherestofthebuffer. while(cur_bits>0) { Add((byte)(cur_accum&0xff),outs); cur_accum>>=8; cur_bits-=8; } Flush(outs); } } } }
以上就是本文的全部内容,希望能给大家一个参考,也希望大家多多支持毛票票。