摘要:之前做过一些Jpeg相关的需求,对Jpeg进行了一些了解但是不够系统,因此整理下Jpeg文件相关的内容。本文描述了Jpeg文件格式的详细构成以及JPEG/JFIF,JPEG/EXIF的区别。
关键字:JPEG,JFIF,EXIF
1 简介
JPEG(Joint Picture Expert Group)编解码标准是由国际标准化组织(ISO)和CCITT联合制定的静态图象有损压缩编码标准(标准也定义了无损压缩内容但是大多数系统都不支持)。JPEG是一种编解码标准不是一种文件格式,其对应的文件格式有JIF,JPEG/JFIF,JPEG/EXIF等。其中JIF(JPEG Interchange Format)是早期的JPEG文件格式,但是由于一些缺陷而没有大规模使用,JPEG/JFIF和JPEG/EXIF为在JIF的基础上的两种继任者(在JIF的基础上,去除JIF中部分字段,添加一些新的字段)。
JPEG图像文件通常可能的扩展名有.jpg,.jpeg,.jpe,.jif,jfif,jfi
,而其中三个字母的扩展名是因为早期的DOS系统采用8.3的文件格式,即仅仅支持三个字母的扩展名JPG vs. JPEG image formats。JPEG/JFIF和JPEG/EXIF无法通过扩展名区分,只能读取文件的metadata区分。
- JPEG:编解码标准;
- JIF(JPEG Interchange Format):JPEG标准中定义的一种文件格式但是按照标准难以实现且在色彩空间定义,像素宽高比定义等方面存在缺陷而没有大范围的被使用;
- JFIF(JPEG File Interchange Format):为了解决JIF存在的问题发展的标准文件格式之一,通常用于网络图像的传输;
- EXIF(Exchangeable image file format):JIF的另一"扩展",可以存储一些设备相关的元信息(照片拍摄的时间、厂商等)多用于摄像设备,比如智能机拍摄的图像格式通常就是EXIF。
JPEG图像的优劣:
- 优势:
- 兼容性:现如今的操作系统基本都支持JPEG图像格式;
- 尺寸:JPEG采用有损压缩,去除图像中人眼无法清晰分辨的部分信息以保证在不损失图像画质的前提下尽可能的压缩图像大小;
- 后处理:更容易后处理。
- 劣势:
- 画质:有损压缩图像在某些场景下容易出现比较明显的细节丢失。丢失如此多的数据可能会导致色调分离——颜色之间的平滑过渡丢失,使图像看起来更加块状和突兀。 它还可能导致出现伪影——边缘混叠、光晕或噪点——这会严重影响图像质量。 摄影师可以通过以原始格式保存照片来避免伪影和分色的潜在缺陷。
下面三张图像分别为图像质量为1,50,99的JPEG图像,能够看到其中质量为1时图像已经有比较明显的失真了。
JPEG质量用来控制JPEG图像画质和图像大小的参数,具体是根据JPEG中的DCT决定,一般值越大画质越好,文件越大。并且不同的实现方式效果可能不同。
据我所知,ffmpeg,windows和mac(Mac系统API写入的JPEG文件即便质量参数为0也不会有很明显的失真)的jpeg实现有差异。
质量1 | 质量50 | 质量99 |
---|---|---|
由于现如今JPEG主要是JPEG/JFIF和JPEG/EXIF两种格式,因此下面主要描述这两种格式(下面两张图都为10x10大小的jpeg图像)。
2 JFIF
JFIF存储格式以块为基础,每个块都有一个标识符来表示当前块的类型。每个块开头的两个字节表示当前块的类型,第一个字节是固定的0xFF
表示当前块的起始位置,后面的一个字节是当前块独一唯二的标识码(多个0xFF
等同于一个),紧跟在标识码后面的就是对应块的数据。所有块的存储结构都是定义好的,大部分块中都会字段描述当前块的大小。下面详细描述下JFIF支持的块的类型。
名称 | 标记码 | 说明 |
---|---|---|
SOI | D8 | 文件头 |
EOI | D9 | 文件尾 |
SOF0 | C0 | 帧开始(标准 JPEG) |
SOF1 | C1 | 同上 |
DHT | C4 | 定义 Huffman 表(霍夫曼表) |
SOS | DA | 扫描行开始 |
DQT | DB | 定义量化表 |
DRI | DD | 定义重新开始间隔 |
APP0 | E0 | 定义交换格式和图像识别信息 |
DNL | DC | 标记码 |
COM | FE | 注释 |
在JPEG中0xFF
具有标记的意思,所以在压缩数据流(真正的图像信息)中,如果出现了0XFF,就需要做特别处理了。方法是,如果在图像数据流中遇到0xFF
,应该检测其紧接着的字符,如果是:
0x00
,表示0xFF
是图像流的组成部分;需要进行译码;0xD9
,表示与0xFF
组成标记EOI,即,代表图像流的结束,同时,图像文件结束;0xD0--0xD7
,组成RSTn标记,需要忽视整个RSTn标记,即不对当前0xFF
和紧接着的0XDn两个字节进行译码,并按RST标记的规则调整译码变量;0xFF
,忽略当前0xFF
,对后一个0xFF
进行判断;- 其它数值,忽然当前0XFF,并保留紧接着此数值用于译码;
2.1 SOI
SOI(Start Of Image),图像的开始标记,标识符为0xFFD8
,只有两个字节。
2.2 APP0
APP0(Application 0)应用程序保留标记0,标识符为0xFFE0
,标识一个JFIF文件,存储图像流中的基本信息,一般紧跟在SOI后面。下图是APP0中各个字段的分布情况:
下面是一个JFIF文件的二进制数据。
1 00000000: ffd8 ffe0 0010 4a46 4946 0001 0100 0001 ......JFIF......
2 00000010: 0001 0000 ffdb 0043 0002 0101 0101 0102 .......C........
3 00000020: 0101 0102 0202 0202 0403 0202 0202 0504 ................
- length:APP0的大小不包含标识符包含当前长度字段。上面的图片的APP0大小是
0x10(16)
个字节; - identifier:当前文件的标识符,固定为
0x4a46494600
,末尾的0为字符串终结符; - version:版本号,第一个数字为主版本号,第二个数字为次版本号,这里是v1.1;
- units:像素密度单位,这里是1即每英寸像素:
- 0表示无单位;
- 1表示每英寸像素;
- 2表示每厘米像素;
- x density:水平方向的像素密度。示例为
0x01
即1(SAR); - y density:垂直方向的像素密度。示例为
0x01
即1; - x thumbnail:缩略图宽度,0表示没有缩略图;
- y thumbnail:缩略图的高度;
- 缩略图的RGB数据:未压缩的缩略图数据,存储顺序为 R 0 , G 0 , B 0 , . . . , R n , G n , B n R_0,G_0,B_0,...,R_n,G_n,B_n R0,G0,B0,...,Rn,Gn,Bn,其中 n = x t h u m b n a i l × y t h u m b n a i l n=xthumbnail\times ythumbnail n=xthumbnail×ythumbnail
2.3 APPn
APPn(Application n,)标识符为0xEn
,n可取1-e,包含两个字段:
- length:2字节,数据长度;
- user-data:根据具体的用户扩展而定义。
用户数据区完全和具体的用户定义有关,比如JFIF和Exif不同。
2.4 DQT
DQT(Define Quantization Table)量化表,标识符为0xFFDB
:
- 数据长度:2字节。这里长度为67个字节;
- 量化表描述:
- 精度及量化表ID:1个字节,高4位表示精度,只有两个可选值,0:8位;1:16位;低4位表示量化表ID,取值范围为0–3。这里可以看到图片给的位数为8bit,量化表id为0;
- 表项:64*(精度取值+1)个字节,例如,8位精度的量化表,其表项长度为64*(0+1)=64字节;
2 00000010: 0001 0000 ffdb 0043 0002 0101 0101 0102 .......C........
3 00000020: 0101 0102 0202 0202 0403 0202 0202 0504 ................
4 00000030: 0403 0406 0506 0606 0506 0606 0709 0806 ................
5 00000040: 0709 0706 0608 0b08 090a 0a0a 0a0a 0608 ................
6 00000050: 0b0c 0b0a 0c09 0a0a 0aff db00 4301 0202 ............C...
7 00000060: 0202 0202 0503 0305 0a07 0607 0a0a 0a0a ................
8 00000070: 0a0a 0a0a 0a0a 0a0a 0a0a 0a0a 0a0a 0a0a ................
9 00000080: 0a0a 0a0a 0a0a 0a0a 0a0a 0a0a 0a0a 0a0a ................
10 00000090: 0a0a 0a0a 0a0a 0a0a 0a0a 0a0a 0a0a ffc0 ................
从上面的二进制中能够看出当前表格有2个量化表,都是8bit的。
2.5 SOFO
SOFO(Start Of Frame),标识符为0xFFC0
,包含:
- 数据长度:2个字节,共6个字段的总长度;即,不包含标记代码,但包含本字段;
- 精度:1个字节,代表每个数据样本的位数;通常是8位;
- 图像高度:2个字节,表示以像素为单位的图像高度,如果不支持DNL就必须大于0;
- 图像宽度:2个字节,表示以像素为单位的图像宽度,如果不支持DNL就必须大于0;
- 颜色分量个数:1个字节,由于JPEG采用YCrCb颜色空间,这里恒定为3;
- 颜色分量信息:颜色分量个数*3个字节,这里通常为9个字节;并依此表示如下一些信息:
- 颜色分量ID: 1个字节;
- 水平/垂直采样因子:1个字节,高4位代表水平采样因子,低4位代表垂直采样因子;
- 量化表:1个字节,当前分量使用的量化表ID;
10 00000090: 0a0a 0a0a 0a0a 0a0a 0a0a 0a0a 0a0a ffc0 ................
11 000000a0: 0011 0800 0a00 0a03 0122 0002 1101 0311 ........."......
12 000000b0: 01ff c400 1f00 0001 0501 0101 0101 0100 ................
从上面的二进制中能够解析出,SOFO数据长度为17个字节,8bit采样,图像宽高为 10 × 10 10\times 10 10×10,采样模式为YUV。三个颜色分量的信息为:
- id1:水平和垂直采样模式均为2,使用的量化表ID为0;
- id2:水平和垂直采样模式均为1,使用的量化表id为1;
- id3:水平和垂直采样模式均为1,使用的量化表id为1。
2.6 DHT
DHT(Define Huffman Table)定义Huffman表,标记码为0xFFC4
:
- 数据长度,2个字节,总长度,不包含标记代码,但包含本字段;
- Huffman表:
- 表ID和表类型,1个字节,高4位表示表的类型,取值只有两个;0:DC直流;1:AC交流;低4位,Huffman表ID;需要提醒的是,DC表和AC表分开进行编码;
- 不同位数的码字数量,16个字节;
- 编码内容,16个不同位数的码字数量之和(字节);
12 000000b0: 01ff c400 1f00 0001 0501 0101 0101 0100 ................
13 000000c0: 0000 0000 0000 0001 0203 0405 0607 0809 ................
14 000000d0: 0a0b ffc4 00b5 1000 0201 0303 0204 0305 ................
15 000000e0: 0504 0400 0001 7d01 0203 0004 1105 1221 ......}........!
16 000000f0: 3141 0613 5161 0722 7114 3281 91a1 0823 1A..Qa."q.2....#
17 00000100: 42b1 c115 52d1 f024 3362 7282 090a 1617 B...R..$3br.....
18 00000110: 1819 1a25 2627 2829 2a34 3536 3738 393a ...%&'()*456789:
19 00000120: 4344 4546 4748 494a 5354 5556 5758 595a CDEFGHIJSTUVWXYZ
20 00000130: 6364 6566 6768 696a 7374 7576 7778 797a cdefghijstuvwxyz
21 00000140: 8384 8586 8788 898a 9293 9495 9697 9899 ................
22 00000150: 9aa2 a3a4 a5a6 a7a8 a9aa b2b3 b4b5 b6b7 ................
23 00000160: b8b9 bac2 c3c4 c5c6 c7c8 c9ca d2d3 d4d5 ................
24 00000170: d6d7 d8d9 dae1 e2e3 e4e5 e6e7 e8e9 eaf1 ................
25 00000180: f2f3 f4f5 f6f7 f8f9 faff c400 1f01 0003 ................
26 00000190: 0101 0101 0101 0101 0100 0000 0000 0001 ................
27 000001a0: 0203 0405 0607 0809 0a0b ffc4 00b5 1100 ................
28 000001b0: 0201 0204 0403 0407 0504 0400 0102 7700 ..............w.
29 000001c0: 0102 0311 0405 2131 0612 4151 0761 7113 ......!1..AQ.aq.
30 000001d0: 2232 8108 1442 91a1 b1c1 0923 3352 f015 "2...B.....#3R..
31 000001e0: 6272 d10a 1624 34e1 25f1 1718 191a 2627 br...$4.%.....&'
32 000001f0: 2829 2a35 3637 3839 3a43 4445 4647 4849 ()*56789:CDEFGHI
33 00000200: 4a53 5455 5657 5859 5a63 6465 6667 6869 JSTUVWXYZcdefghi
34 00000210: 6a73 7475 7677 7879 7a82 8384 8586 8788 jstuvwxyz.......
35 00000220: 898a 9293 9495 9697 9899 9aa2 a3a4 a5a6 ................
36 00000230: a7a8 a9aa b2b3 b4b5 b6b7 b8b9 bac2 c3c4 ................
37 00000240: c5c6 c7c8 c9ca d2d3 d4d5 d6d7 d8d9 dae2 ................
38 00000250: e3e4 e5e6 e7e8 e9ea f2f3 f4f5 f6f7 f8f9 ................
39 00000260: faff da00 0c03 0100 0211 0311 003f 0028 .............?.(
上面的图像中总共4个霍夫曼表,2个长度为0x1f
,及31字节的DC表,两个长度为0xb5
,即181个字节的AC表。
2.7 DRI
DRI(Define Restart Interval),定义差分编码累计复位的间隔,标记码为固定值0xFFDD
。
- 数据长度:2个字节,取值为固定值0X0004,总长度;即不包含标记代码,但包含本字段;
- MCU块的单元中重新开始间隔:2个字节,如果取值为n,就代表每n个MCU块就有一个RSTn标记;第一个标记是RST0,第二个是RST1,RST7之后再从RST0开始重复;如果没有本标记段,或者间隔值为0,就表示不存在重开始间隔和标记RST;
2.8 SOS
SOS(Start Of Scan,扫描开始;标记码为0xFFDA
,包含2个具体字段:
- 数据长度:2个字节,数据总长度;
- 颜色分量数目:1个字节,只有3个可选值,1:灰度图;3:YCrCb或YIQ;4:CMYK;
- 颜色分量信息:包括以下字段,
- 颜色分量ID:1个字节;
- 直流/交流系数表ID,1个字节,高4位表示直流分量的Huffman表的ID;低4位表示交流分量的Huffman表的ID;
- 压缩图像数据
- 谱选择开始:1个字节,固定值0X00;
- 谱选择结束:1个字节,固定值0X3F;
- 谱选择:1个字节,固定值0X00;
本标记段中,颜色分量信息应该重复出现,有多少个颜色分量,就重复出现几次;本段结束之后,就是真正的图像信息了;图像信息直到遇到EOI标记就结束了。
39 00000260: faff da00 0c03 0100 0211 0311 003f 0028 .............?.(
40 00000270: a28a 00ff d9
2.9 EOI
EOI(End Of Image),图像结束;标记代码为0xFFD9
。
3 Exif
可以看出两者基本上是一致的,最大的差异还是APP1与APP0。详细的信息可以参考Exif-App1
参考文献
-
Everything you need to know about JPEG files
-
jpeg.org
-
wc3-JPEG
-
the jpeg still picture compression standard
-
Exif
-
JPEG文件格式介绍
-
JPEG File Interchange Format
-
JPEG文件格式解析(一) Exif 与 JFIF