lzw压缩算法java实现文档格式.docx
- 文档编号:21738104
- 上传时间:2023-02-01
- 格式:DOCX
- 页数:10
- 大小:40.33KB
lzw压缩算法java实现文档格式.docx
《lzw压缩算法java实现文档格式.docx》由会员分享,可在线阅读,更多相关《lzw压缩算法java实现文档格式.docx(10页珍藏版)》请在冰豆网上搜索。
GIF文件在压缩时,不论图象色彩位数是多少,均要将颜色值按字节的单位放入代码流中,每个字节均表示一种颜色。
虽然在源图象文件中用一个字节表示16色、4色、2色时会出现4位或更多位的浪费(因为用一个字节中的4位就可以表示16色),但用LZW压缩法时可回收字节中的空闲位。
在压缩时,先从字符流中读取第一个字符作为当前前缀,再取第二个字符作为当前码,当前前缀与当前码构成第一个基本字符串(如当前前缀为A,当前码为B则此字符串即为AB),查串表,此时肯定不会找到同样字符串,则将此字符串写入串表,当前前缀写入前缀数组,当前码写入当前数组,并将当前前缀送入代码流,当前码放入当前前缀,接着读取下一个字符,该字符即为当前码了,此时又形成了一个新的基本字符串(若当前码为C,则此基本字符串为BC),查串表,若有此串,则丢弃当前前缀中的值,用该串在串表中的位置代码(即下标)作为当前前缀,再读取下一个字符作为当前码,形成新的基本字符串,直到整幅图象压缩完成。
由此可看出,在压缩时,前缀数组中的值就是代码流中的字符,大于色彩数目的代码肯定表示一个字符串,而小于或等于色彩数目的代码即为色彩本身。
3.3清除码
事实上压缩一幅图象时,常常要对串表进行多次初始化,往往一幅图象中出现的第一次出现的基本字符串个数会超过4096个,在压缩过程中只要字符串的长度超过了4096,就要将当前前缀和当前码输入代码流,并向代码流中加入一个清除码,初始化串表,继续按上述方法进行压缩。
3.4结束码
当所有压缩完成后,就向代码流中输出一个图象结束码,其值为色彩数加1,在256色文件中,结束码为257。
3.5字节空间回收
在GIF文件输出的代码流中的数据,除了以数据包的形式存放之外,所有的代码均按单位存贮,这样就有效的节省了存贮空间。
这如同4位彩色(16色)的图象,按字节存放时,只能利用其中的4位,另外的4位就浪费了,可按位存贮时,每个字节就可以存放两个颜色代码了。
事实上在GIF文件中,使用了一种可变数的存贮方法,由压缩过程可看出,串表前缀数组中各元素的值颁是有规律的,以256色的GIF文件中,第258-511元素中值的范围是0-510,正好可用9位的二进制数表示,第512-1023元素中值的范围是0-1022,正好可用10位的二进制数表示,第1024-2047元素中值的范围是0-2046,正好用11位的二进制数表示,第2048-4095元素中值的范围是0-4094,正好用12位的二进制数表示。
用可变位数存贮代码时,基础位数为图象色彩位数加1,随着代码数的增加,位数也在加大,直到位数超过为12(此时字符串表中的字符串个数正好为2的12次方,即4096个)。
其基本方法是:
每向代码流加入一个字符,就要判别此字符所在串在串表中的位置(即下标)是否超过2的当前位数次方,一旦超过,位数加1。
如在4位图象中,对于刚开始的代码按5位存贮,第一个字节的低5位放第一个代码,高三位为第二个代码的低3位,第二个字节的低2位放第二个代码的高两位,依次类推。
对于8位(256色)的图象,其基础位数就为9,一个代码最小要放在两个字节。
3.6压缩范围
以下为256色GIF文件编码实例,如果留心您会发现这是一种奇妙的编码方法,同时为什么在压缩完成后不再需要串表,而且还在解码时根据代码流信息能重新创建串表。
字符串:
1,2,1,1,1,1,2,3,4,1,2,3,4,5,9,…
当前码:
2,1,1,1,1,2,3,4,1,2,3,4,5,9,…
当前前缀:
1,2,1,1,260,1,258,3,4,1,258,262,4,5,…
当前数组:
2,1,1,1,3,4,1,4,5,9,…
数组下标:
258,259,260,261,262,263,264,265,266,267,…
代码流:
1,2,1,260,258,3,4,262,4,5,…
GIF文件作为一种重要的图形图象文件格式,尽管其编码规则极复杂,但其压缩效率是极高的,特别是对某些平滑过渡的图象的图形,压缩效果更好。
同时由于其在压缩过程中的对图象信息能够完整的保存,在目前流行的电子图片及电子图书中得到了广泛的应用。
四、LZW算法的简单示例
对原始数据ABCCAABCDDAACCDB进行LZW压缩,原始数据中,只包括4个字符(Character),A,B,C,D,四个字符可以用一个2bit的数表示,0-A,1-B,2-C,3-D,从最直观的角度看,原始字符串存在重复字符:
ABCCAABCDDAACCDB,用4代表AB,5代表CC,上面的字符串可以替代表示为:
45A4CDDAA5DB,这样是不是就比原数据短了一些呢!
五、LZW算法的适用范围
为了区别代表串的值(Code)和原来的单个的数据值(String),需要使它们的数值域不重合,上面用0-3来代表A-D,那么AB就必须用大于3的数值来代替,再举另外一个例子,原来的数值范围可以用8bit来表示,那么就认为原始的数的范围是0~255,压缩程序生成的标号的范围就不能为0~255(如果是0-255,就重复了)。
只能从256开始,但是这样一来就超过了8位的表示范围了,所以必须要扩展数据的位数,至少扩展一位,但是这样不是增加了1个字符占用的空间了么?
但是却可以用一个字符代表几个字符,比如原来255是8bit,但是现在用256来表示254,255两个数,还是划得来的。
从这个原理可以看出LZW算法的适用范围是原始数据串最好是有大量的子串多次重复出现,重复的越多,压缩效果越好。
反之则越差,可能真的不减反增了。
六、LZW算法中得特殊标记
随着新的串(string)不断被发现,标号也会不断地增长,如果原数据过大,生成的标号集(stringtable)会越来越大,这时候操作这个集合就会产生效率问题。
如何避免这个问题呢?
Gif在采用lzw算法的做法是当标号集足够大的时候,就不能增大了,干脆从头开始再来,在这个位置要插入一个标号,就是清除标志CLEAR,表示从这里我重新开始构造字典,以前的所有标记作废,开始使用新的标记。
这时候又有一个问题出现,足够大是多大?
这个标号集的大小为比较合适呢?
理论上是标号集大小越大,则压缩比率就越高,但开销也越高。
一般根据处理速度和内存空间连个因素来选定。
GIF规范规定的是12位,超过12位的表达范围就推倒重来,并且GIF为了提高压缩率,采用的是变长的字长。
比如说原始数据是8位,那么一开始,先加上一位再说,开始的字长就成了9位,然后开始加标号,当标号加到512时,也就是超过9为所能表达的最大数据时,也就意味着后面的标号要用10位字长才能表示了,那么从这里开始,后面的字长就是10位了。
依此类推,到了2^12也就是4096时,在这里插一个清除标志,从后面开始,从9位再来。
GIF规定的清除标志CLEAR的数值是原始数据字长表示的最大值加1,如果原始数据字长是8,那么清除标志就是256,如果原始数据字长为4那么就是16。
另外GIF还规定了一个结束标志END,它的值是清除标志CLEAR再加1。
由于GIF规定的位数有1位(单色图),4位(16色)和8位(256色),而1位的情况下如果只扩展1位,只能表示4种状态,那么加上一个清除标志和结束标志就用完了,所以1位的情况下就必须扩充到3位。
其它两种情况初始的字长就为5位和9位
七、LZW算法的伪代码实现
1STRING=getinputcharacter
2WHILEtherearestillinputcharactersDO
3CHARACTER=getinputcharacter
4IFSTRING+CHARACTERisinthestringtablethen
5STRING=STRING+character
6ELSE
7outputthecodeforSTRING
8addSTRING+CHARACTERtothestringtable
9STRING=CHARACTER
10ENDofIF
11ENDofWHILE
12outputthecodeforSTRING
13
八、LZW算法的流程图
九、LZW算法的Java模拟实现
packagecom.anywhere;
importjava.io.*;
publicclasslzwCode{
Dictionarydic=newDictionary();
intcount1=0,count2=0
BufferedInputStreamin;
BufferedOutputStreamout;
finalshortEND=4095;
/**theentryoftheclass,andchecktheargumentsfirst
@paramargsarrayofstringarguments
-csourceFile[targetFile]建立一个压缩文件
-dsourceFile[targetFile]解压缩一个文件
@returnNoreturnvalue
@exceptionNoecceptionsthrown*/
publicstaticvoidmain(String[]args){
if(args.length<
=1||args.length>
4){
System.out.println("
-csourceFile[targetFile][-dic]建立一个压
缩文件\n"
);
-dsourceFile[targetFile][-dic]解压缩一个
文件\n"
}
elseif(!
(args[0].equals(newString("
-c"
))||args[0].equals(new
String("
-d"
)))){
-csourceFile[targetFile]建立一个压缩文件\
n"
-dsourceFile[targetFile]解压缩一个文件\n"
elseif(args.length>
=2){
lzwCodea=newlzwCode(args);
a.run(args);
return;
publiclzwCode(String[]args){
try{
Stringf=newString();
in=newBufferedInputStream(
newFileInputStream(
newFile(args[1])));
if(args.length==3&
&
!
args[2].equals(newString("
-dic"
))){
f=args[2];
else{
inti=args[1].lastIndexOf(newString("
."
));
f=args[1].substring(0,i)+((args[0].equals("
)
)?
"
.lzw"
:
.dlzw"
out=newBufferedOutputStream(
newFileOutputStream(
newFile(f)));
}//try
catch(FileNotFoundExceptione){
System.err.println(e);
return;
catch(IOExceptione){
}}
publicvoidrun(Stringargs[]){
if(args[0].equals(newString("
))){
code(in,out);
else{
decode(in,out);
if(args[args.length-1].equals(newString("
)))
System.out.println(dic.toString());
publicvoidcode(BufferedInputStreamin,BufferedOutputStreamout)
{System.out.println("
coding...\n"
+"
.......\n"
//a:
thebufferbytereadfromtheinputfile,thentobeconvertedto
String
//buf:
thecodestreamtostoreinthecodefile
//prefix:
thepre_Stringofthedictory
//theindexbuf[]istheindexofdictionarytobeconvertedin
//thecodefile
//str:
thecurrentcharecterofthecharacterinputStream
bytea[]=newbyte[1],buf[]=newbyte[3];
Stringprefix="
cur="
;
bytei=0;
shortindexbuf[]=newshort[2];
Stringstr=null;
shortm=0;
while((a[0]=(byte)in.read())!
=-1){
cur=newString(a);
//beconverted
count1++;
//thenumberofbytesofinputfile
str=prefix;
str=str.concat(cur);
m=(short)dic.indexOf(str);
if(m!
=-1)//theprefixisinthedictionary,{
prefix=str;
else//{
if(i==0)//thefirstindexbuf,storeincodebuf[]{
indexbuf[0]=(short)dic.indexOf(prefix);
i=1;
else//nowhave2indexnumber,thenouputtothecodefile{
indexbuf[1]=(short)dic.indexOf(prefix);
zipOutput(out,indexbuf);
count2+=3;
//3bytesstoredtothecodefile
i=0;
dic.add(str);
prefix=cur;
}//else}//while
//System.out.println("
i="
+i);
if(i==(byte)1)//thisisthecasethatthe
//inputfilehasonlyoddindexnumbertostore{
indexbuf[1]=END;
//putaspecialindexnumber
//(themaxnumberofthedictionary)ENDtothe
codefile
in.close();
out.close();
ziprate:
+(float)count2*100/count1+"
%"
}catch(IOExceptione){
catch(OutDictionaryExceptione){
publicvoiddecode(BufferedInputStreamin,BufferedOutputStreamout){
decoding...\n"
+"
shortprecode=0,curcode=0;
Stringprefix=null;
shorti=0;
shortbufcode[]=newshort[2];
//2codereadfromthecodefile
booleanmore=true;
//indicatetheendofthefileorsomeerrorwhile
inputthefile
//DataOutputStreamout2=newDataOutputStream(out);
more=zipInput(in,bufcode);
//firstinput2code
if(more){
curcode=bufcode[0];
//out2.writeChars(dic.getString(curcode));
stringOut(out,dic.getString(curcode));
else
errorinthebeginning..."
while(more){
precode=curcode;
if(i==0){
curcode=bufcode[1];
}else
{more=zipInput(in,bufcode);
if(bufcode[1]==END){
stringOut(out,dic.getString(bufcode[0]));
break;
}
}if(curcode<
dic.length())//iftheprefixstringcanbefoundinthe
dictory{
prefix=dic.getString(precode);
prefix+=(dic.getString(curcode)).substring(0,1);
dic.add(prefix);
prefix+=prefix.substring(0,1);
//out2.writeChars(prefix);
stringOut(out,prefix);
catch(OutDictionaryExceptione){
}
catch(IOExceptione){
}}
privatevoidzipOutput(BufferedOutputStreamout,shortindex[]){
bytebuf[]=newbyte[3];
buf[1]=(byte)(index[0]<
<
4);
buf[0]=(byte)(index[0]>
>
buf[2]=(byte)index[1];
buf[1]+=(byte)(index[1]>
8);
out.write(buf,0,3);
//outputthedecoding
//System.out.println(index[0]+"
\t"
+index[1]+"
/*shortcodebuf[]=newshort[2];
//codebuf[0]=(short)(buf[0]<
codebuf[0]=toRight(buf[0],4);
codebuf[0]+=(short)(toRight(buf[1],0)>
//codebuf[1]=(short)buf[2];
codebuf[1]=toRight
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- lzw 压缩 算法 java 实现
![提示](https://static.bdocx.com/images/bang_tan.gif)