LZW压缩和解压.docx
- 文档编号:2102372
- 上传时间:2022-10-26
- 格式:DOCX
- 页数:12
- 大小:47.34KB
LZW压缩和解压.docx
《LZW压缩和解压.docx》由会员分享,可在线阅读,更多相关《LZW压缩和解压.docx(12页珍藏版)》请在冰豆网上搜索。
LZW压缩和解压
LZW压缩和解压
黄陂一中盘龙校区张兴才
LZW压缩是由Lemple、Zip和Welch共同创造,用他们的名字命名的压缩方法。
下面结合C语言的实现方法,介绍LZW压缩和解压的原理。
一、码表
被压缩的字符系列称为数据流,压缩后的代码称为编码流,将数据流压缩成编码流要依据码表。
什么是码表?
我们先看看码表的结构和初始化吧。
typedefstruct
{
charused;
UINTprev;//typedefUINTunsignedint
BYTEc;
}ENTRY;
voidInitTable()
{
inti;
for(i=0;i<4096;i++)
{
string_tab[i].used=FALSE;//#defineFALSE0
string_tab[i].prev=NO_PREV;//#defineNO_PREV0xFFFF表示没有前缀
string_tab[i].c=0;
for(i=0;i<258;i++)
{
string_tab[i].used=TRUE;//#defineTRUE!
FALSE
string_tab[i].c=i;
}
}
从上面的代码可知,码表共有4096行,每行有3列。
used表示该行是否被使用,使用了其值为TRUE,否则为FALSE。
prev表示前缀,主要存储的是该码表的索引值(行号),用以指示该表的不同行,取值范围是0——4095。
c表示后缀,存储一个字符。
该码表的0——257行的prev域被初始化,其中的值表示的意义是:
0—255用来表示单个字符,256表示开始新的码表,257表示压缩结束。
二、压缩过程
以下程序段将infp中的字符系列压缩到outfp中。
putcode(outfp,CC);
//outfp是存储编码流的文件,CC的值为256,表示开始新的码表,outfp是存放编码流的文件,以上函数表示将码表开始代码放在outfp文件的开始位置
InitTable();
c=readc(infp);
//从输入文件读取一个字符,infp表示输入文件,c是后缀变量
prevcode=QueryTable(NO_PREV,c);
//在码表中查询前缀为“NO_PREV”,后缀为“c”(即刚刚读入的字符)的行,并将行号赋给前缀变量prevcode,其实相当于prevcode=c;
++total;
while(UEOF!
=(c=readc(infp)))
//UEOF为文件结束标志
{
++total;
if(NOT_FIND!
=(localcode=QueryTable(prevcode,c)))
//NOT_FIND表示在码表中查询指定的前缀和后缀对,没有找到
{
prevcode=localcode;
//找到指定的前缀后缀对后,将找到行的行号赋给前缀变量,接着从输入文件读入下一个字符作为后缀,进行下一轮的查询
continue;
}
putcode(outfp,prevcode);
//指定的前缀和后缀对没有找到,则将前缀变量prevcode的值输出到存储编码流的输出文件outfp中
if(count)//count为码表中空白行的行数
{
UpdateTable(prevcode,c);
//将指定的前缀和后缀分别填入码表的第一个空白行的相应位置
--count;//码表的空白行减1
}
if(count==0)//如果码表没有空白行了,则重新建一个码表,并在编码流中放入代码CC(256),表示开始新的码表。
{
count=4096-258;
currentpos=258;
InitTable();
putcode(outfp,CC);//CC表示开始新的码表
}
prevcode=QueryTable(NO_PREV,c);//其实是将c的值赋给prevcode
}
putcode(outfp,prevcode);
putcode(outfp,CEND);//CEND是编码压缩结束标志
if(tempcode!
=EMPTY)
outputbuf[oupindex++]=(tempcode&0x0F0);//关键!
!
!
!
flushout(outfp);//将输出缓存区剩余的编码写入文件中
return0;
}
LZW压缩算法流程
三、.解压过程
这是LZW解码的主要代码:
prevcode=0;
while((prevcode=getcode(inputfd))!
=CC)
{
if(prevcode==UEOF)
return0;
}
InitTable();
prevcode=getcode(inputfd);
count=GetChars(prevcode,curstr,TAB_SIZE);//#defineTAB_SIZE4096
memcpy(outbuf,curstr,count);
oupindex+=count;
total=0;
while(UEOF!
=(local=getcode(inputfd)))
{
if(local==CC)
{
space=TAB_SIZE-INIT_SIZE;//#defineINIT_SIZE258
currentpos=INIT_SIZE;
InitTable();
prevcode=getcode(inputfd);
count=GetChars(prevcode,curstr,TAB_SIZE);
if(oupindex+count>TAB_SIZE)
{
printf(".");
fwrite(outbuf,sizeof(char),oupindex,outputfd);
total+=oupindex;
oupindex=0;
}
memcpy(&outbuf[oupindex],curstr,count);
oupindex+=count;
continue;
}
if(local>currentpos)
{
printf("\nerror,local>currentpos:
%d,%d",local,currentpos);
fwrite(outbuf,sizeof(char),oupindex,outputfd);
return-1;
}
if(string_tab[local].used)
{
count=GetChars(local,curstr,TAB_SIZE);
}
else
{
count=GetChars(prevcode,curstr,TAB_SIZE);
curstr[count]=curstr[0];
curstr[++count]='\0';
}
if(space)
{
temp=UpdateTable(prevcode,curstr[0]);
--space;
}
elseif(space==0)
{
printf("space=0");
}
prevcode=local;
if(oupindex+count>TAB_SIZE)
{
printf(".");
fwrite(outbuf,sizeof(char),oupindex,outputfd);
total+=oupindex;
oupindex=0;
}
memcpy(&outbuf[oupindex],curstr,count);
oupindex+=count;
}
fwrite(outbuf,sizeof(char),oupindex,outputfd);
total+=oupindex;
printf("\nsucessfulsize=%d\n",total);
return0;
}
在解码的过程中要注意以下两点:
1.假设码表的每一行在压缩或解码后都有内容,我们来看看码表,我们发现,码表的每一行都是链表的一个结点,结点的前缀就是指向其他行(结点)的指针,若该指针的值为NO_PREV表明该结点是某链表的最后一个结点,因此从任何一行开始都是一个链表,整个码表有4096个链表。
每个链表开始结点的行号,就是要被解压的代码,将这个链表中的后缀字符依次排列,得到一个字符串,这个字符串就是要被解压的代码的解码值。
2.在开始解码时,码表从258行开始的以后各行都是空的,那么这些空的部分的值在解码的过程中是怎样被填写的呢?
首先读入要解码的第一个代码到前缀变量prevcode中,接着对以后的每一个代码依次做以下工作就可以填写码表:
(1)读入代码,并将其解码;
(2)把解码所得的字符串的第一个字符和prevcode的值填入码表的第一个空白行;(3)将该代码值赋给prevcode,形成新的prevcode值,好进行下一轮的循环。
四、以上代码中用到的函数,供参考
#defineBUF_SIZE0x10000
#defineEMPTY0xFFFFFFFF
#defineUEOF0xFFFF
#defineNOT_FIND0xFFFF
voidInitTable();
UINTUpdateTable(UINTprevcode,BYTEc);
UINTQueryTable(UINTcode,BYTEc);
UINTreadc(FILE*fp);
voidputcode(FILE*fp,UINTcode);
voidflushout(FILE*fp);
#include"commfunc.h"
UINTcurrentpos=INIT_SIZE;
externENTRYstring_tab[TAB_SIZE];
BYTEinputbuf[BUF_SIZE];
intinpindex=EMPTY,limit;
BYTEoutputbuf[BUF_SIZE];
intoupindex=0,tempcode=EMPTY;
voidInitTable()
{
inti;
for(i=0;i string_tab[i].used=FALSE,string_tab[i].prev=NO_PREV,string_tab[i].c=0; for(i=0;i { string_tab[i].used=TRUE; string_tab[i].c=i; } } UINTUpdateTable(UINTprevcode,BYTEc)
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- LZW 压缩 解压