随笔-65  评论-68  文章-4  trackbacks-0

JPEG文件格式简单分析

作者:小爽

摘要:

这篇文章大体上介绍了JPEG文件的结构信息以及它的压缩算法和编码方式。使读者能够对JPEG文件格式有大体上的了解。为读者进一步进行学习JPEG文件压缩做好准备

 

关键字:十六进制,段格式,编码

 

一、    JPEG文件格式概述:

图像和动画的存储方式是一个很重要的问题。幸好我们有了数据压缩,有了JPEG等多种压缩存储图像的文件格式,我们今天才能够拿着小小的一个存储器,却存上许多张色彩鲜艳的图片。如果没有图像压缩算法,也许我们的多媒体时代就会晚到来许多年。

JPEG图像存储格式一个比较成熟的图像有损压缩格式,虽然一个图片经过转化为JPEG图像后,一些数据会丢失,但是,人眼是很不容易分辨出来这种差别的。也就是说,JPEG图像存储格式既满足了人眼对色彩和分辨率的要求,又适当的去除了图像中很难被人眼所分辨出的色彩,在图像的清晰与大小中JPEG找到了一个很好的平衡点。

虽然图像转化为JPEG格式会减小很多,但是并不是文件就变得简单了,相反,JPEG文件的格式是比较复杂的。不经过认真地分析,是不容易弄懂它的。

 

二、    JPEG文件的存储方式:

JPEG文件的格式是分为一个一个的段来存储的(但并不是全部都是段),段的多少和长度并不是一定的。只要包含了足够的信息,该JPEG文件就能够被打开,呈现给人们。JPEG文件的每个段都一定包含两部分一个是段的标识,它由两个字节构成:第一个字节是十六进制0xFF,第二个字节对于不同的段,这个值是不同的。紧接着的两个字节存放的是这个段的长度(除了前面的两个字节0xFF0xXXX表示不确定。他们是不算到段的长度中的)。注意:这个长度的表示方法是按照高位在前,低位在后的,与Intel的表示方法不同。比方说一个段的长度是0x12AB,那么它会按照0x120xAB的顺序存储。但是如果按照Intel的方式:高位在后,低位在前的方式会存储成0xAB0x12,而这样的存储方法对于JPEG是不对的。这样的话如果一个程序不认识JPEG文件某个段,它就可以读取后两个字节,得到这个段的长度,并跳过忽略它。

本人曾经编写过一个读取JPEG文件信息的程序,该程序能够读取JPEG文件中包含的段的信息并显示出来。下面是一个JPEG图片的信息片断:

 

SOI

        APP0    Length: 0x10

        DQT

                DQT [0]:

        8       6       5       8       12      20      26      31

        6       6       7       10      13      29      30      28

        7       7       8       12      20      29      35      60

        7       9       11      15      26      44      50      31

        9       11      19      28      34      56      52      0

        12      18      28      32      61      52      0       46

        25      32      39      57      52      0       60      0

        36      46      39      49      253     50      0       50

        Length: 0x43

        DQT

                DQT [1]:

        9       9       12      24      50      50      50      50

        9       11      13      33      50      50      50      50

        12      13      28      50      50      50      50      50

        24      33      50      50      50      50      50      50

        50      50      50      50      50      50      50      0

        50      50      50      50      50      50      0       50

        50      50      50      50      50      0       50      0

        50      50      50      50      253     50      0       50

        Length: 0x43

        SOF0

                Image Height: 173

                Image Width: 401

                Number of Frame(s): 3

                ****************

                Content ID: 1

                H Factor: 2

                V Factor: 2

                QT ID: 0

                ****************

                Content ID: 2

                H Factor: 1

                V Factor: 1

                QT ID: 1

                ****************

                Content ID: 3

                H Factor: 1

                V Factor: 1

                QT ID: 1

        Length: 0x11

        DHT

                Type: DC TABLE

                ID: 0

        Length: 0x1f

        DHT

                Type: AC TABLE

                ID: 0

        Length: 0xb5

        DHT

                Type: DC TABLE

                ID: 1

        Length: 0x1f

        DHT

                Type: AC TABLE

                ID: 1

        Length: 0xb5

        SOS     Length: 0xc     <-Will Not Process This Seg.

FATAL ERROR: File Structure Does NOT Support.

 

你首先会想到为什么最后会出现一个错误的信息呢?这是因为,在SOSStart Of Scan)段的后面,就是编码后的一行一行的图像信息。不再是段的结构了。在开始的SOIStart Of Image)不是一个段,它是文件的开始,它的值也是类似于0xFF0xXX的结构(SOI的具体数值清自己察看相关书籍,本文章中将不作重点介绍),但是后面没有段的长度。在文件的最后,有一个EOIEnd Of Image)的标识,它的结构和SOI是类似的。它标志着文件的结束。

在这中间,包含了APP0段,DQT段,SOF0段,DHT段,SOS段。有的段的个数是不唯一的,比方说DQT段。我们现在重点地介绍各个段的作用。

 

三、    JPEG文件中段的介绍:

APP0段中主要存储的是图片的识别信息(字符串”JFIF\0”)、一些分辨率的信息以及缩略图的信息。在我的实际测试中,发现并不是所有的JPEG文件都有APP0段的,有的仅是有APP2之类的其他段,但是每个文件中肯定是包含APPX的段(X可以取得的值可以查阅相关文档)。我个人估计,这些APPX的段的信息应该是大同小异。这个的验证还有待本人进一步的学习,目前只能说到这里。

DQT段的内容是量化表的信息。众所周知,一个颜色可以分为RGB(红、绿、兰)三个分量,这三色光组成了我们可以见到的所有色彩。但是,在JPEG文件中,RGB色彩格式需要先转化为YUV的格式。Y分量代表了亮度信息,UV分量代表了色差信息。相比之下,人眼对于Y分量更为敏感。量化表的作用就是对于一些不需要的量进行去除,这也是JPEG有损压缩损失数据的关键。上面的输出可以看到两个量化表,一个给Y分量,另一个给UV分量。其实,他们也可以共用一个量化表。一个量化的结果如下所示(摘自《JPEG压缩编码标准》):

15    0     -1    0     0     0     0     0

-2    -1    0     0     0     0     0     0

-1    -1    0     0     0     0     0     0

0     0     0     0     0     0     0     0

0     0     0     0     0     0     0     0

0     0     0     0     0     0     0     0

0     0     0     0     0     0     0     0

0     0     0     0     0     0     0     0

我们可以看到,量化后出现了大量的0,这种结果很有利于我们进行下一步的数据压缩的。至于为什么是8x8的大小,待会你就知道了。

SOF0段的内容是图像的大小信息,每个像素的位数信息,以及YUV每个分量分别得的采样信息(这部分如果读者想要进一步学习,请参考相应书籍和文档)。JPEG文件图像的编码是一个方块一个方块进行的,每块的大小为8x8大小(如果图像不是整数个方块的大小那么就对图像补齐为整数个大小)。简略地说采样信息,就是如何按组记录YUV的信息,即若干个Y方块,若干个U方块,若干个V方块经过量化的数据再次经过编码后组成一组记录,保存在SOS段结束后。

DHT段的内容是一个重头戏,如果没有它,JPEG压缩效率就不会那么高了。它内部定义的是一个Huffman表,不同的DHT段定义不同的Huffman表,有的是直流量的表,有的是交流量的表。什么是直流量,什么是交流量呢?待会我再作介绍。最多的Huffman表示几个呢?YUV各一个,直流交流各一个,因为YUV每个分量都有直流和交流,所以最多时,Huffman表有3x2个,也就是可以有6DHT段。该文件中有4DHT表,您可以大概猜出来是哪几个表么?Y的直流和交流各一个Huffman表,UV和起来直流和交流各一个Huffman表。这样说应该比较合理吧。

好了,现在我们应该弄明白什么是交流量,什么是直流量了。还举上面那个有许多个08x8的表的例子说,所谓交流量,是经过量化后的块内部除了左上角15那个值的其余值。实际上,块与块之间左上角那个值是用直流Huffman表来单独编码的。不与块内部一同编码。虽然不同的编码,但是要注意的事,不同的编码方式并不意味着它们是不在一起的,具体的存储编码后的数据的时候,还是按照若干个Y方块,若干个U方块,若干个V方块经过量化的数据再次经过编码后组成一组记录来存储的。

SOS段的内容是关于YUV每个分量的直流和交流各使用那个Huffman表来编码的。

      

四、    JPEG文件十六进制代码解析

我觉得,如果想要的了解JPEG,对十六进制代码的观察是必不可少的。不要认为这样有多难,我会让你知道这是很简单的。目前我们只需要了解我们能够了解的东西就可以了。要记住,每个段的开始是0xFF0xXX,紧接着两个字节是长度信息。

可以看到,上图被选定的标记是SOI标记。

上图被选定的段是APP0段。

 

紧接着的段是DQT段,这个JPEG文件有两个DQT段。这里需要强调一点的是,包括量化表在内8x8的块的值是按照Z形来保存量化表8x8的数据的。而不是按照一行一行的保存的。这样做的好处是,能够让实际上相邻的像素点保存后也排列得比较近,便于压缩和编码。如下图所示:

(摘自《JPEG压缩编码标准》)

 

 

上图标记的段是DHT段,一共有4DHT段。

 

这个段是SOS段,在这个段的后面就是所有压缩后的数据。

每段的具体信息在这里我就不详细介绍了,网上有很多相关的文章,如果有兴趣的话,可以去查找阅读。

 

五、    图像数据块内的编码方式

其实,图像数据块的编码是比较麻烦的,它涉及到了行程编码,Huffman编码等编码方式。这部分很多文档说得都不是很清楚,我力求去除内部比较麻烦的部分,再通过简单的语言让大家明白原理,这样大家如果有兴趣进行下一步的研究,也会比较容易上手的。

我们还是使用那刚才那个包含很多0的量化后的8x8的数据块来说明。我们把块内剩余的63个数据用行程编码来编码。经过行程编码后的数据的格式是:(x,y)。x表示的是从当前位置开始有多少个连续的零,y表示这些连续的0的后面的第一个非零的数是多少。但是为了解决存储的问题和进行进一步的压缩。最后的压缩格式变为:(x,yzxy占有一个字节的长度。z的长度不固定,需要根据y的值来判断。x仍代表从当前位置开始有几个连续的零,但是因为x只能占有四位的长度,也就是它的最大值是15,所以,当多于16个连续的零的时候。会用一个字节的(15,0)来代替前面的160,然后继续编码(注意:这时候没有z部分)。当块结束或者当前块后面剩余的都是零的时候,就用(0,0)即EOB代替(同样也是没有z部分)。前面说到z的长度不固定,需要根据y的值来判断,这是为什么呢?简单的来说,z的长度是不一定的,在1~15的范围内。Y的作用简单的来说表示的是z的二进制位数(1~15),也正好是4位二进制的值能够表示的。然后,把xy合成的一个字节单独提取出来,利用DHT里面的Huffman表来进行编码。这样,编码的长度又能够被压缩了。

 

六、    总结

叙述了这么多,相信大家对于JPEG已经有了一个大概的了解了吧,如果你通过阅读这篇文章,对JPEG文件的结构和算法有了一个大体上的认识,那么这篇文章的目的也就达到了。下一步进行具体研究就不会有太大问题了。祝愿大家能够在数据压缩的路上走好。

 

参考文献:

1.             JPEG压缩编码标准》

2.             JPEG格式》

3.             JPEG简易文档》        作者:风云

posted on 2005-07-01 15:09 小爽 阅读(48330) 评论(19)  编辑  收藏 所属分类: 我的经验

评论:
# re: JPEG文件格式简单分析 2006-12-28 14:14 | 李运博
基本对该编码有一定的认识了,谢谢  回复  更多评论
  
# re: JPEG文件格式简单分析 2007-01-15 14:41 | ysm
有没有JPEG文件格式解析编码给一个,yangsm318@126.com 谢谢!  回复  更多评论
  
# re: JPEG文件格式简单分析 2007-07-26 14:09 | wyz

谢谢你的文章

如何从网络上读取jpeg信息,并实时的显示出来?(即不能全部读到本地之后再显示), 能告知吗? 谢谢,

wangyuanzhenghf@163.com  回复  更多评论
  
# re: JPEG文件格式简单分析[未登录] 2007-08-03 17:20 | 过客
不错的文章,谢谢你,辛苦了!  回复  更多评论
  
# re: JPEG文件格式简单分析 2007-08-06 20:22 | 畅达
通俗易懂!谢谢你的文章!  回复  更多评论
  
# re: JPEG文件格式简单分析 2007-08-06 20:24 | 畅达
作者是否编写过c++程序来处理JPEG图像?
我的邮箱xuzhengnan@163.com
期待您的指导!  回复  更多评论
  
# re: JPEG文件格式简单分析 2007-10-30 02:34 | Wilson
我编写过,但是因为现在在美国学习,所以没有办法给你发送一份拷贝,不好意思了@畅达
  回复  更多评论
  
# re: JPEG文件格式简单分析[未登录] 2008-01-05 11:55 | xiaoxin
首先非常感谢你的文章,辛苦了!
不好意思我是新手,我想知道通过什么软件或编辑器能知道一图像的格式信息的?像你上面显示出的图片那样,谢谢!
还有请问你知道如何读取jp2格式文件信息吗?知道的话能方便告知吗?不胜感激!
我的邮箱是chenmo1013@126.com  回复  更多评论
  
# re: JPEG文件格式简单分析[未登录] 2008-03-29 19:31 | 学习者
谢谢你
你的图我觉得是比较好地
十分感谢  回复  更多评论
  
# re: JPEG文件格式简单分析 2008-04-07 09:38 | t
很有收获
顺便问一下jp2和渐进式jpeg怎么分辨?  回复  更多评论
  
# re: JPEG文件格式简单分析[未登录] 2008-04-23 22:32 | xiaoxiao
很急 楼主有没有将接受到的数据转换成JPEG的VC软件程序或C软件方面的资料,cxml84@163.com 谢谢  回复  更多评论
  
# re: JPEG文件格式简单分析[未登录] 2008-05-15 13:39 | wolf
good  回复  更多评论
  
# re: JPEG文件格式简单分析 2008-08-05 10:02 | Sandwi
非常好,感谢分享。  回复  更多评论
  
# re: JPEG文件格式简单分析 2008-09-23 16:44 | 年建杰
HI,小爽你好
能把你那个读取并显示JPEG文件的程序发给我吗? 我现在正在做这个文件的解析和显示,比较迷茫。谢谢了  回复  更多评论
  
# re: JPEG文件格式简单分析 2008-09-23 16:49 | 年建杰
HI,小爽你好
能把你那个读取并显示JPEG文件的程序发给我吗? 我现在正在做这个文件的解析和显示,比较迷茫。谢谢了
我的MSN:nianjianjie@hotmail.com  回复  更多评论
  
# re: JPEG文件格式简单分析 2009-01-16 08:51 | 理标电子
详细  回复  更多评论
  
# re: JPEG文件格式简单分析 2009-03-24 08:35 | 小陈
非常感谢你的文章!  回复  更多评论
  
# re: JPEG文件格式简单分析 2009-08-24 08:50 | 敏敏
不错,多谢分享!

文中提到“JPEG文件图像的编码是一个方块一个方块进行的,每块的大小为8x8大小(如果图像不是整数个方块的大小那么就对图像补齐为整数个大小)”,很疑惑当图像不是整数个方块的大小如何将图像补齐为整数个大小,例如一个大小为10(行)×7(列)像素大小的图像(记为A11、A12、…A17,A21、A22、…,A71、A72、A73、…A77)该如何补成8x8的块呢?  回复  更多评论
  
# re: JPEG文件格式简单分析[未登录] 2010-01-17 00:07 | dboy
不错,学习了  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: