CSDN博客

img ftofficer

GIF图像格式(一)——基础算法(上)

发表于2004/10/3 15:36:00  3270人阅读

首先道个歉:昨天写着写着突然熄灯,以至于写了80%的这篇文章不得不灰飞烟灭,我可怜的电脑也被裸关一次,没有办法,校有校规啊,所以只好今天从头开始再写一遍。
言归正传。

写着篇文章之前,我县假定你已经对于什么是GIF很清楚了,如果你不清楚的话,建议你到网上搜索一下“GIF文件简介”看看。

GIF作为一种面向网络的图像格式,他的种种设计都是以“便于在网络上使用”为原则的。网络使用的第一个原则就是文件大小。如何使用有效的压缩算法使文件的大小得以减小,是GIF文件要解决的首要问题。对于这个问题,GIF采用的是压缩效率很好的LZW压缩算法。这个算法的压缩效率、压缩比都是极高的,但是有一点不好:它是有版权的。

因此我的第一部分,是介绍LZW算法,与GIF文件格式的内容无关,只是一种算法,但是它是LZW-GIF压缩算法(GIF使用的压缩算法)的基础。

1、概述
LZW算法的基本思想很简单:在一个输入的未压缩的字节流中,一定有很多的重复出现的字符串,那么用一个字节来表示这个字符串,不就起到了压缩的作用了吗?

下面我们先看几个概念,这几个概念将会在下面的介绍中反复出现,因此请记住他们。

Char Stream(未编码的字节流):作为编码的输入和解码的输出,使未经压缩的字节流,我们要处理的对象。
Code Stream(已编码的流):我没有写作字节流,因为不一定输出的是字节,事实上大多数时候也不是字节。
String Table(编码表):作为编码和解码的字典,它的格式是一个index对应一个string,在初始化的时候,从0开始的index依次对应字符集中的相应的字符。LZW的编码表有一个很大的优势就是他不需要很大的存储空间,它是在编码、解码的过程中动态生成的,而生成他指需要一个变量:初始的根项的数目。
Root Item(编码表根项):生成编码表时初始的只有一个字符的那些项,他们有一系列的特点,我在算法描述的时候再详述。

好了,概念说完了。现在开始介绍编码的算法:

2、编码算法
首先是算法的伪码描述:
initial_string_table(root_number);                                   
current_prefix = '' ;             //空字符串                          
while (能够从Char Stream中取出一个Char c) {                            
    current_string = current_prefix+c ;                              
    if (current_string在string_table中存在) {                         
        current_prefix = current_string;                             
    } else {                                                         
        把current_string加入到string_table的末端;                      
        向Code Stream中输出current_prefix在string_table中对应的index;  
        current_prefix = c;                                          
    }                                                                
}                                                                    
向Code Stream中输出current_prefix在string_table中对应的index;          
// 编码结束                                                          
现在我们看看每一步是怎么做的:

第一步:初始化我们的编码表。刚才说了,初始化编码表只需要一个参数:root_number,也就是根项的数目。其实他就是我们要编码的Char Stream中的字符集的数目。初始化也很简单:根据一个事先的约定对所有的Char进行排序,然后从零开始对其编上一个index,形成一个item,再把这些items从小到大排列好,就形成了初始的编码表。

第二步:初始化一些局部变量:主要是current_prefix和current_string,把他们都设为空字符串。

第三步:开始循环编码,方法如下:
从Char Stream中读出一个Char c,然后把它接到current_prefix的后面形成current_string。
在string_table中进行查找,看有没有这个current_string。
有:说明这个current_string是“老的”,于是什么都不做,仅仅把current_string赋给current_prefix;
无:说明这个current_string是“新的”,因此第一步把它变成“老的”,也就是把它插入到string_table的末端;紧接着输出current_prefix在string_table中的index到Code Stream;最后重新开始找重复的字符串,也就是把c赋给current_prefix。

这样循环结束,最后肯定还余下一个prefix,输出它的index即可。

举个例子吧。

假设我们的Code Stream是BBBCBBA,字符集是{A,B,C},我们约定排列方式是ASCII升序。
初始化的string_table如下: 
-----------------------
index            string
00                'A'
01                'B'
02                'C'
-----------------------
这三项就是所谓的Root Items。
然后开始编码:简单期间,我只是列出各个量的值,并作简单说明。
Step        Prefix    Char c        CurrentString            Exist?       Operation            Code Stream(OUT)
01            []            B            []B=B                      yes              no                             X
02            [B]           B            [B]B=BB                  no            insert BB                index(B) = 01
03            [B]           B            [B]B=BB                  yes               no                            X
04            [BB]         C            [BB]C=BBC                no            insert BBC            index(BB)=03
05            [C]           B            [C]B=CB                   no            insert CB             index(C)=02
06            [B]           B            [B]B=BB                  yes               no                            X
07            [BB]         A            [BB]A=BBA                no            insert BBA            index(BB)=03
08            [A]          no
Output [A]'s index: index(A)=00
这样,编码结束了,Code Stream为:01 03 02 03 00
最终的编码表如下:
-------------------------
index            string
00                'A'
01                'B'
02                'C'
03                'BB'
04                'BBC'
05                'CB'
06                'BBA'
-------------------------
由此可见,编码压缩率的大小,取决于其中重复字符串的多少。
编码就讲到这里,下面是解码。

(To be continue...)

阅读全文
0 0

相关文章推荐

img
取 消
img