JPEG格式研究——(2)JPEG文件格式

JPEG文件除了图像数据之外,还保存了与图片相关的各种信息,这些信息通过不同类型的TAG存储在文件中。

TAG

JPEG通过TAG标记压缩书记之外的信息。所有的TAG都包含一个TAG类型,TAG类型大小为两个字节,位于一个TAG的最前面。TAG类型的第一个字节一定为0xFF

以下是部分常见的TAG类型

TAG类型 数值 备注
SOF0 ~ SOF3
SOF5 ~ SOF7
SOF8 ~ SOF11
SOF13 ~ SOF15
FF C0 ~ FF C3
FF C5 ~ FF C7
FF C8 ~ FF CB
FF CD ~ FF CF
不同的编码模式对应不同的SOF,详见JPEG标准Table B.1。本文以常见的SOF0为研究对象
DHT FF C4 Define Huffman table(s),定义了解码所需的哈夫曼表
RSTm FF D0 ~ FF D7 遇到时重置DC系数,数字会递增,具体含义不清楚
SOI FF D8 Start of Image,表示图像文件的开始
EOI FF D9 End of Image,表示图像文件结束
SOS FF DA Start of scan,表示这一个TAG后就是压缩的图像数据,记录了DHT、DQT与图像不同部分的对应关系
DQT FF DB Define quantization table(s),定义了解码所需的量化表
APP0 ~ APP15 FF E0 ~ FF EF 应用保存的图片相关信息(如相机信息等)

压缩数据中也是存在TAG的,虽然大部分TAG都在文件开头,但是也有少部分是例外。如EOI就在文件的末尾,RSTm会出现在压缩数据当中。

那么问题来了,如果压缩数据中有一个字节本身就是0xFF怎么办?JPEG的做法是在0xFF后面再加一个字节0x00,用于表示这不是一个TAG。

因为不知道解码需要哪些TAG,我在尝试写JPEG解码器的时候耗费了大量的时间在研究TAG上。总结出对于常见的JPEG图片解码需要的TAG:

1.SOI和EOI:用于确定文件的开头和结尾

2.DQT和DHT:保存了解码时需要用到的哈夫曼表和量化表

3.SOS:保存了图片不同部分的需要用哪个哈夫曼表

4.SOF:图片的长和宽、采样精度等、使用哪个量化表都保存在SOF中

5.RST:部分图片存在RST,遇到RST时要重置DC系数才能得到正确的图像

哈夫曼表与量化表

这里有个小坑,我原先一直以为DQT和DHT都是一个TAG对应一个表,后来发现一个TAG可以不只一个表

哈夫曼表

哈夫曼表的存储格式如下:

名称 长度(bit) 备注
$Lh$ 16 表示这一个TAG的长度(包括TAG类型的两个字节)
$Tc$ 4 Table class,0=DC表,1=AC表
$Th$ 4 Huffman table destination identifier,表示该哈夫曼表的id
$L_i$ 8 表示这一长度的编码个数
$V_{i,j}$ 8 表示编码前的原始数据

一个DHT中的哈夫曼表个数可以通过长度Lh算出:

$$
Lh = 2 + \sum_{t=1}^{n} (17+m_t)
$$

其中

$$
m_t=\sum_{1}^{16} L_i
$$

除了TAG类型和Lh一个TAG只有一个外,其余的都是每个哈夫曼表都有的。

Th之后是一个长度为16字节的数组,分别对应长度从1bit到16bit的编码个数。

再之后存的是各个编码对应的原始数据(以字节为单位)。JPEG采用的范式哈夫曼编码,可以这些信息推导出数据编码前后的对应关系。

量化表

DQT的结构与DHT结构相似,比DHT还稍微简单一些

名称 长度(bit) 备注
Lq 16 与Lh意义相同,表示这一TAG的长度
Pq 4 量化表的精度,0=8bit,1=16bit
Pq 4 量化表的id
Qk 8 量化表中的数据

量化表大小固定为8x8,也就是一个表有64个数,DQT长度与量化表个数也有类似的关系:

$$
Pq = 2 + \sum_{t=1}^n (65 + 64 \times Pq(t))
$$

SOF

SOF(Start of Frame) TAG的结构如下:

名称 长度(bit) 备注
Lf 16 这一TAG的长度
P 8 采样精度
Y 16 图片的高度
X 16 图片的宽度
Nf 4 Component的个数

Component的结构如下:

名称 长度(bit) 备注
Ci 8 Compoenent的id
Hi 4 水平缩放因子
Vi 4 垂直缩放因子
Tqi 8 对应的量化表id

根据我的理解,这里的Component个数相当于色度分量的个数,比如RGB和YUV都是3,灰度图像则是1.

SOS

名称 长度(bit) 备注
Ls 16 这一TAG的长度
Ns 8 一个scan内的component数量
Ss 8 没用
Se 8 没用
Ah 4 没用
Al 4 没用

Scan中还描述了这一Scan内不同Component中哈夫曼表和量化表的对应关系:

名称 长度(bit) 备注
Csi 8 通过id选择Component
Tdi 4 通过id选择DC哈夫曼表
Tai 4 通过id选择AC哈夫曼表

到这里JPEG解码所需要的几个重要TAG的结构就介绍完了,接下来就做好准备工作就可以开始解码了。


参考资料

JPEG解码系列博客:多媒体-编解码 - 随笔分类 - OnlyTime_唯有时光 - 博客园 (cnblogs.com)

JPEG标准:Microsoft Word - T081E.DOC (w3.org)

一个Rust写的JPEG解码器:MROS/jpeg_tutorial: 跟我寫 JPEG 解碼器 (Write a JPEG decoder with me) (github.com)

友情链接

我学习过程中写的JPEG图片查看器:Ryan1202/my-tiny-jpeg-viewer: A Tiny Jpeg Viewer (github.com)