摘要:之前做过一些Jpeg相关的需求,对Jpeg进行了一些了解但是不够系统,因此整理下Jpeg文件相关的内容。本文描述了Jpeg文件格式的详细构成以及JPEG/JFIF,JPEG/EXIF的区别。
关键字:JPEG,JFIF,EXIF
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图像的优劣:
下面三张图像分别为图像质量为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图像)。
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
进行判断; SOI(Start Of Image),图像的开始标记,标识符为0xFFD8
,只有两个字节。
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 ................
0x10(16)
个字节;0x4a46494600
,末尾的0为字符串终结符;0x01
即1(SAR);0x01
即1; APPn(Application n,)标识符为0xEn
,n可取1-e,包含两个字段:
用户数据区完全和具体的用户定义有关,比如JFIF和Exif不同。
DQT(Define Quantization Table)量化表,标识符为0xFFDB
:
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的。
SOFO(Start Of Frame),标识符为0xFFC0
,包含:
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。三个颜色分量的信息为:
DHT(Define Huffman Table)定义Huffman表,标记码为0xFFC4
:
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表。
DRI(Define Restart Interval),定义差分编码累计复位的间隔,标记码为固定值0xFFDD
。
SOS(Start Of Scan,扫描开始;标记码为0xFFDA
,包含2个具体字段:
本标记段中,颜色分量信息应该重复出现,有多少个颜色分量,就重复出现几次;本段结束之后,就是真正的图像信息了;图像信息直到遇到EOI标记就结束了。
39 00000260: faff da00 0c03 0100 0211 0311 003f 0028 .............?.(
40 00000270: a28a 00ff d9
EOI(End Of Image),图像结束;标记代码为0xFFD9
。
可以看出两者基本上是一致的,最大的差异还是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