一、简介
(Joint Photographic Experts Group)是联合图像专家小组的英文缩写,负责制定静态数字图像的编码标准,JPEG/Exif是数码相机和其他图像捕获设备最常用的图像格式,JPEG / JFIF,它是在互联网上存储和传输摄影图像的最常见格式。大体上分为两部分:标记码(TAG)和压缩数据
二、压缩算法
1. 两种基本的压缩算法:
有损的离散余弦变换(Discrete Cosine Transform)DCT、无损的预测技术压缩
2. 两种数据编码方法:
哈夫曼编码、算术编码
3. 四种编码模式:
- 基于DCT顺序模式:编/解码通过一次扫描完成
- 基于DCT递进模式:编/解码需要多次扫描完成,扫描效果从粗糙到精细,逐级递进
- 无损模式:基于DPCM,保证解码后完全精确恢复到原图像采样值
- 层次模式:图像在多个空间多种分辨率进行编码,可以根据需要只对低分辨率数据作解码,放弃高分辨率信息
- 在实际应用中,JPEG图像使用的是离散余弦变换、哈夫曼编码、顺序模式。
三、标记码
标记名称 | Marker内容 | 说明 | |
---|---|---|---|
SOI | FF D8 | Start Of Image | 图像开始 |
SOF0 | FF C0 | Start Of Frame 0 | 第0帧图像开始 |
SOF2 | FF C2 | Start of Frame 2 | 第2帧图像开始 |
DHT | FF C4 | Define Huffman Table(s) | 定义哈夫曼表 |
DQT | FF DB | Define Quantization Table(s) | 定义量化表 |
DRI | FF DD | Define Restart Interva | 定义差分编码累计复位的间隔 |
SOS | FF DA | Start of Scan | 扫描开始 |
RST0~RST7 | FF D0 ~ FF D7 | Restart | 表示在压缩数据流中,每隔n个MCU 块就有一个RST标记 |
APP0~APP15 | FF E0 ~ FF EF | Application-sepcific | 应用程序保留标记,0为JFIF特有部分,1~15支持用户自定义 |
COM | FF FE | Comment | 评论、注释 |
EOI | FF D9 | End of Image | 图像结束 |
3.1 格式简介
1、JPEG文件都是以十六进制 'FF D8’开始,以’FF D9’结束
2、JPEG格式都是按段来存储的,分别为0xFF段开始(1字节)+段类型或者叫段标记码(1字节)+段长度(2字节)+段内容。有些段没有长度描述也没有内容,只有段标识,文件头和文件尾均属于这种段。
由于在JPEG文件中0xFF具有标志性的意思,所以在压缩数据流(真正的图像信息)中出现0xFF,就需要作特别处理,如下:
2.1 0x00,则表示0xFF是图像流的组成部分,需要进行译码;
2.2 0xD8,则与0xFF组成标记SOI,则图像流开始,同时图像文件开始;
2.3 0xD9,则与0xFF组成标记EOI,则图像流结束,同时图像文件结束;
2.4 0xD0~0xD7,组成RSTn标记,则要忽视整个RSTn标记,即不对当前0xFF和紧接的0xDn两个字节进行译码并按RST标记的规则调整译码变量;
2.5 0xFF,则忽视当前0xFF,对后一个0xFF再作判断;
2.6 其他数值,则忽视当前0xFF,并保留紧接的此数值用于译码。
2.7 段与段之间无论有多少FF都是合法的,这些FF称为“填充字节”,必须被忽略掉。
3、 JFIF格式的JPEG文件(*.jpg)的一般顺序:
SOI(0xFFD8)-->APP0(0xFFE0)-->[APPn(0xFFEn)]可选-->DQT(0xFFDB)-->SOF0(0xFFC0)-->DHT(0xFFC4)-->SOS(0xFFDA)-->data
-->EOI(0xFFD9)
4、 EXIF格式的JPEG文件(*.jpg)的一般顺序:
SOI(0xFFD8)-->APP1(0xFFE1)-->[APPn(0xFFEn)]可选-->DQT(0xFFDB)-->SOF(0xFFC0)-->DHT(0xFFC4)可选-->DRI(0xFF DD)可选
-->SOS(0xFFDA)-->data-->EOI(0xFFD9)
PS:开始(SOI)和结束(EIO)的格式不做详细解释
3.2 JFIF格式 APP0详解
3.2.1 二进制数据
APP0内容如图(蓝色部分):
3.2.2 APP0结构
名称 | 字节数 | 值 | 说明 |
---|---|---|---|
段标识 | 1 | FF | 段开始 |
段类型 | 1 | E0 | JFIF标识码,代表APP0标识段 |
段长度 | 2 | 00 10 | 如果有RGB缩略图就=16+3n |
交换格式 | 5 | 4A 46 49 46 00 | “JFIF”的ASCII码,以’\n’终止 |
版本号 | 2 | 01 01 | 第一个字节为主版本号,第二个字节为次版本号,图中代表1.01 |
密度单位 | 1 | 00 | 0=无单位;1=点数/英寸;2=点数/厘米 |
X像素密度 | 2 | 00 01 | 水平方向的密度,不得为0 |
Y像素密度 | 2 | 00 01 | 垂直方向的密度,不得为0 |
缩略图X像素 | 1 | 00 | 缩略图水平像素数目,可以为0 |
缩略图Y像素 | 1 | 00 | 缩略图垂直像素数目,可以为0 |
RGB缩略图 | 3×n | 如果“缩略图X像素”和“缩略图Y像素”的值均>0,才有RGB缩略图的数据,n=缩略图X像素×缩略图Y像素 |
3.3 EXIF格式 APP1详解
3.3.1 二进制数据
Exif 文件实际是JPEG文件的一种,遵从JPEG标准,只是在文件头信息中增加了有关拍摄信息的内容和索引图
3.3.2 APP1结构
名称 | 字节数 | 值 | 说明 |
---|---|---|---|
段标识 | 1 | FF | 段开始 |
段类型 | 1 | E1 | EXIF标识码,代表APP1标识段 |
段长度 | 2 | 15 FE | |
标识符 | 6 | 45 78 69 66 00 00 | “EXIF”的ASCII码,以空字节终止 |
TIFF头 | 8 | 49 49 2A 00 08 00 00 00 | TIFF头信息 |
IFD0 (main image) | 不固定 | ||
IFD1(thumbnail image) | 不固定 |
1、TIFF头:
1.1 共8个字节,头两个字节表示 Byte align(字节对齐):II表示数字存储遵循 intel 的字节序,即小端存储;MM表示数据存储遵循 Motorola 的字节序, 即大端存储。
1.2 中间两个字节表示 Tag Mark,是固定值:如果使用 Intel 字节序,则对应的存储值为 0x2a00;如果使用Motorola 的字节序,则存储值为
0x002a
1.3 最后四个字节表示到 IFD0(Image File Directory)的偏移:该偏移的起始位置为 TIFFHeader 的起始位置,APP1 Data段中的 IFD0,Exif
SubIFD,IFD1 中的偏移,也都是以 TIFFHeader的起始位置为基准
2、IFD main image
根据 TIFF Header 的后四个字节,我们可以找到第一个 IFD,数据结构如下表所示,IFD结构中存在多个Directory Entry,每个Entry记录着图片的一条属性信息,比如拍摄时间、拍摄机器、图片尺寸等等。
名称 | 字节数 | 值 | 说明 |
---|---|---|---|
目录条目数量 | 2 | 09 00 | 此APP1图中代表有9条目录,如上图0900到0000共九条,每条12字节 |
目录条目 | 108 | 不固定 | 参考下方2.1 |
下一个IFD的偏移 | 4 | 不固定 | |
Directory Entry data area | 不固定 | Directory的数据存储区,存储Entry的值 |
2.1 目录条目数量:
此APP1图中代表有9条目录,如上图0900到0000共九条,每条12字节。每条目录分为四个部分:
2.2 目录条目:
2.2.1 头两个字节对应的内容为 Exif Tag ,次两个字节对应的内容为 Directory Entry存储内容的类型(Component Type)
2.2.2 后面四个字节存储的是 Directory Entry 对应的Component的数量;
2.2.3 最后的四个字节,存储的可能是Entry对应的值,Entry对应的值的长度超过四个字节,那么存储的是对应的值的偏移地址(该偏移寻址的基址 也是TIFFHEADER的起始位置)。
3.4 DQT定义量化表详解
JPEG文件一般有2个DQT段,为Y值(亮度)定义1个, 为C值(色度)定义1个,一个DQT段可以包含多个QT, 每个都有自己的信息字节
DQT内容如图(蓝色部分):
名称 | 字节数 | 值 | 说明 |
---|---|---|---|
段标识 | 1 | FF | 段开始 |
段类型 | 1 | DB | 标识码,代表DQT标识段 |
段长度 | 2 | 00 43 | 其值=3+n(当只有一个QT时) |
下面的内容部分: | |||
QT信息 | 1 | 00 | 0-3位是QT号,4-7位QT精度,此处是0,所以精度是8bit,即1个字节。 |
QT量化表 | 这个的长度是根据QT信息确定的,上面QT精度为8bit,所以此处是64×1 = 64个字节 |
3.5 SOF图像信息详解
1、JPEG大都采用yCrCb色彩模型(y表示亮度,Cr红色分量,Cb表示蓝色分量),所以组件数量一般=3;
2、样本就是单个像素的颜色分量,也可理解为一个样本就是一个组件;
3、采样系数是实际采样方式与最高采样系数之比,而最高采样系数一般=0.5(分数表示为1/2)。比如说,垂直采样系数=2,那么2×0.5=1,表示实际采样方式是每个点采一个样,也就是逐点采样;如果垂直采样系数=1,那么:1×0.5=0.5(分数表示为1/2),表示每2个点采一个样
4、组件 ID、采样系数:1=Y, 2=Cb, 3=Cr; 4=I, 5=Q;0-3位:垂直采样系数,4-7位:水平采样系数;
名称 | 字节数 | 值 | 说明 |
---|---|---|---|
段标识 | 1 | FF | 段开始 |
段类型 | 1 | C0 | 标识码,代表SOF标识段 |
段长度 | 2 | 00 11 | 其值=8+组件数量×3,此处17 = 8 + 3*3,说明组件数量有3个 |
下面的时内容部分: | |||
样本精度 1 | 1 | 08 | 每个样本位数(大多数软件不支持12和16) |
图片高度 2 | 2 | 03 5F | |
图片宽度 2 | 2 | 05 00 | |
组件数量 | 1 | 03 | 1=灰度图,3=YCbCr/YIQ 彩色图,4=CMYK 彩色图 |
(以下每个组件占用3字节) | |||
组件 ID、采样系数、量化表号(Y组件) | 3 | 01 22 00 | Y组件,垂直采样系数和水平采样系数都是2,即逐点采样,量化表号是0 |
组件 ID、采样系数、量化表号(Cb组件) | 3 | 02 11 01 | Cb组件,垂直采样系数和水平采样系数都是1,即隔点采样,量化表号是1 |
组件 ID、采样系数、量化表号(Cr组件) | 3 | 03 11 01 | Cr组件,垂直采样系数和水平采样系数都是1,即隔点采样,量化表号是1 |
3.6 DHT定义huffman表
1、JPEG文件里有2类Haffman 表:一类用于DC(直流量),一类用于AC(交流量)。一般有4个表:亮度的DC和AC,色度的DC和AC。最多可有6个。 2、一个DHT 段可以包含多个HT表, 每个都有自己的信息字节 3、HT表是一个按递增次序代码长度排列的符号表。
名称 | 字节数 | 值 | 说明 |
---|---|---|---|
段标识 | 1 | FF | 段开始 |
段类型 | 1 | C4 | 标识码,代表DHT标识段 |
段长度 | 2 | 00 1F | 其值=19+n(当只有一个HT表时) |
下面的时内容部分: | |||
HT信息 | 1 | 00 | 0-3位:HT号;4位:HT类型, 0=DC表,1=AC表;5-7位:必须=0 |
HT位表 | 16 | 00 -00(B5上方) | 这16个数的和应该≤256 |
HT值表 | n | 00-0B |
4、段长度:此处1F(16进制)=31(10进制)=19(段长度2个字节+HT信息1个字节+HT位表16个字节) + 12(这个数代表HT值表有12个字节)
5、HT信息:此处一共有4个Haffman 表,亮度DC Haffman 表,亮度AC Haffman 表,色度DC Haffman 表,色度AC Haffman 表
6、HT位表:这16个数字值和小于等于256,此处加起来是12(此处和段长度是相匹配的),说明HT表有12个字节
3.7 SOS扫描行开始
名称 | 字节数 | 值 | 说明 |
---|---|---|---|
段标识 | 1 | FF | 段开始 |
段类型 | 1 | DA | 标识码,代表SOS标识段 |
段长度 | 2 | 00 0C | 其值=6+2×扫描行内组件数量 |
下面的时内容部分: | |||
扫描行内组件数量 | 1 | 03 | 必须≥1,≤4(否则错误),通常=3 |
组件ID、Huffman表号 | 2 | 01 00 | Y组件,AC表号是0,DC表号是0 |
组件ID、Huffman表号 | 2 | 02 11 | Cb组件,AC表号是1,DC表号是1 |
组件ID、Huffman表号 | 2 | 03 11 | Cr组件,AC表号是1,DC表号是1 |
后面的3字节不知道有什么作用 | 3 | 紧接着的F8是数据scanData部分,到FF D9结束 |
1、段长度:0C = 12 = 6(2个字节的扫描行开始头+1个字节扫描行内组件数量+3个字节的剩余位) + 2×3(扫描行内组件数量,每个组件2个字节)
2、组件ID:1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q
3、Huffman表号:0-3位:AC表号 (其值=0…3) 4-7位:DC表号(其值=0…3)
4、后面是数据scanData部分,到FF D9(EOI)结束
3.8 其他段
3.7.1 COM(注释)
名称 | 字节数 | 值 | 说明 |
---|---|---|---|
段标识 | 1 | FF | 段开始 |
段类型 | 1 | FE | 标识码,代表COM标识段 |
段长度 | 2 | 其值=注释字符的字节数+2 | |
内容 | 注释字符 |
说明:有的JPEG文件没有这个段
3.7.2 DRI(定义重新开始间隔)
名称 | 字节数 | 值 | 说明 |
---|---|---|---|
段标识 | 1 | FF | 段开始 |
段类型 | 1 | DD | 标识码,代表DRI标识段 |
段长度 | 2 | 4 | |
开始间隔 | 2 | n | 复位标记的间隔距离 |
1、开始间隔表示在压缩数据流中,每隔n个MCU 块就有一个RST标记,RST标记将Huffman 的解码数据流复位,DC也重新从0开始,因此,RST标记是一种复位标记 2、RST 标记是一种特殊的段,它只具有段标识和段类型(长度=2字节),但它不是独立的段,只能穿插在数据流中(文件头和文件尾段也只有段标识和段类型,却都是独立的段)。 3、RST标记共有8个(RST0-RST7),从RST0起开始使用,然后是RST1….直至RST7,再从RST0重复 4、RST标记的标识码是 FFD0-FFD7,对应 RST0-RST7 说明:这个不是必须段,很多JPEG都没有。