理解JPEG文件头的格式
1. JPEG
1)why jpeg?
jpeg作为图片传输格式使用最为普遍,压缩比最高。每天我们都会产出和传输大量的jpeg格式数据。手机拍出来的格式默认是jpeg,朋友圈各种分享。。。磁盘上积累了大量的jpeg。。。
因此本人一直对jpeg头部数据非常好奇,想着有时间深入一下jpeg格式,看看头部到底存储了哪些数据?记得研究生时有专门的信息隐藏专业,基本原理可能是保持jpeg现有格式框架下插入一些自己的二进制数据。。。
本人只是对jpeg头部尝试做一些解释,至于jpeg核心的压缩技术涉及DCT、哈夫曼编码,过于深奥理解起来有难度。。。下面这些内容,都是最近两天查了各种资料以后的一些综合认识,先全部写出来,讲解和示例代码都比较粗糙,后续有时间再继续完善。
2)怎么决定文件是否是jpeg格式?
二进制形式打开文件,文件开始字节为FF D8,文件结束两字节为FF D9。则初步判定文件为jpeg。
jpeg的SOI(start of image) 为ff d8,EOD(end of image)为ff d9
3)文件头采用何种格式存储?
The marker 0xFFE0~0xFFEF is named "Application Marker", not necessary for decoding JPEG image. They are used by user application. For example, older olympus/canon/casio/agfa digicams use JFIF(JPEG File Interchange Format) for storing images. JFIF uses APP0(0xFFE0) Marker for inserting digicam configuration data and thumbnail image.
Also Exif uses an Application Marker for inserting data, but Exif uses APP1(0xFFE1) Marker to avoid a conflict with JFIF format. Every Exif file formats starts from this format;
大概意思是:老式相机采用JFIF格式,即以FF E0开始,头部含有 .. JFIF...信息。现在Exif更加流行,Exif以FF E1字节开始。
不管JFIF还是Exif格式都类似:
0xFF + Marker Number(1 byte) + Data size(2 bytes) + Data(n bytes)
JFIF的marker为E0,Exif的marker为E1,maker后面两个字节是长度(包含长度两个字节),长度后面是数据(数据的为长度为长度-2)。
找了一张在照相馆拍的一寸照,邮件打开里面同时有JFIF段和Exif段:
蓝色框内为JFIF段,长度字节流为00 10 = 16,后面14个字节为内容。4A 46 49 46是JFIF的asci码。后面10个字节不清楚。直接通过JFIF长度跳过即可。
红色箭头开始位置为Exif段,头部的10个字节含义如下:
FF E1开始,
16 6F = 24096,约24k的数据,信息量还是相当丰富的,
45 78 69 66 为Exif的asci码流,
00 00 未使用
4)Exif的数据部分如何组织?
数据部分采用TIFF格式,TIFF格式参见refer[2],IFD(Image File Directory)
TIFF主要包含IFD0和IFD1两部分,IFD0有两部分组成:IFD的目录部分,以及Link to LFD1的部包(一个32bit的偏移量)。IFD的目录的每个记录指向一个IFD entry,每个IFD内部可能嵌套包含一系列IFD。。IFD1的结构类似。
FFE1 | APP1 Marker | ||
SSSS | APP1 Data | APP1 Data Size | |
45786966 0000 | Exif Header | ||
49492A00 08000000 | TIFF Header | ||
XXXX. . . . | IFD0 (main image) | Directory | |
LLLLLLLL | Link to IFD1 | ||
XXXX. . . . | Data area of IFD0 | ||
XXXX. . . . | Exif SubIFD | Directory | |
00000000 | End of Link | ||
XXXX. . . . | Data area of Exif SubIFD | ||
XXXX. . . . | IFD1(thumbnail image) | Directory | |
00000000 | End of Link | ||
XXXX. . . . | Data area of IFD1 | ||
FFD8XXXX. . . XXXXFFD9 | Thumbnail image |
图-2
图-2为TIFF的格式框架图,对应图1中,49 49 2A 00 08 00 00 00 为TIFF的头部,4949表示II小端存储,2A 00 为约定的常量数值,08 00 00 00 为TIFF数据相对TIFF开始位置的offset,头部为8个字节所以这个值一般为8,该offset用4字节表示,理论上可以是文件任何地方。
接下来0A 00 为IFD数据开始位置(也可以通过TIFF的头部开始位置加上offset of 0th IFD),两个字节0A 00,小端模式下为10,即Number of Directory Entries = 10。
每个IFD Entry(索引)有12个字节组成,图-2右子图,
- tag[0:2], tag是一些预定的标签
- type[2:4], type表示数据类型,1是BYTE,2是ASCII,3是SHORT等
- count[4:8], count是长度
- value[8:12],当count<=4时候,value里面存储的就是内容,否则value是一个offset值,指向内容的位置,结合count和type解析得到内容(这里的内容有可能是IFD Entry数组,即嵌套包含了IFD)。
示例解析IFD0,IFD1 https://github.com/dizuo/read_books/blob/master/algorithm_playground/algorithm_playground/jpeg/jpg_3.4_no_embedded_ifd.py
输出结果,只是简单对asci码字符串进行了解析:
IFD0有10个IFD索引,从8-1232,只处理了Asci类型的IFD entry,有相机属性,拍摄日期等。
IFD1共6个IFD索引,每个count都为1,信息十分有限。
length = 5743
exif = b'Exif\x00\x00'
b'Exif'
b'II'
tiff_tag = 42, tiff_off = 8
number of directory entries = 10
==> OFFSET 8 - 1232
tag=271,type=2,count=6,value=134
actual_data = Canon
tag=272,type=2,count=16,value=140
actual_data = Canon EOS 1100D
tag=274,type=3,count=1,value=1
tag=282,type=5,count=1,value=156
tag=283,type=5,count=1,value=164
tag=296,type=3,count=1,value=2
tag=305,type=2,count=27,value=172
actual_data = Adobe Photoshop CS Windows
tag=306,type=2,count=20,value=199
actual_data = 2013:06:05 17:25:16
tag=531,type=3,count=1,value=2
tag=34665,type=4,count=1,value=220
number of directory entries = 6
==> OFFSET 1232 - 0
tag=259,type=3,count=1,value=6
tag=282,type=5,count=1,value=1310
tag=283,type=5,count=1,value=1318
tag=296,type=3,count=1,value=2
tag=513,type=4,count=1,value=1326
tag=514,type=4,count=1,value=4409
-------------------------------------
网上较全面的解析jpeg Exif的python 代码:
解析jpeg的Exif信息没有问题, 但解析其他部分有错误。注意python版本号。
2. 示例
00: ff d8 ff e1 02 62 45 78 69 66 00 00 4d 4d 00 2a
10: 00 00 00 08 00 08 01 0f 00 02 00 00 00 04 48 54
20: 43 00 01 10 00 02 00 00 00 0a 00 00 00 6e 01 1a
30: 00 05 00 00 00 01 00 00 00 78 01 1b 00 05 00 00
40: 00 01 00 00 00 80 01 28 00 03 00 00 00 01 00 02
50: 00 00 02 13 00 03 00 00 00 01 00 01 00 00 87 69
60: 00 04 00 00 00 01 00 00 00 88 88 25 00 04 00 00
70: 00 01 00 00 01 60 00 00 00 00 44 65 73 69 72 65
80: 20 48 44 00 00 00 00 48 00 00 00 01 00 00 00 48
90: 00 00 00 01 00 0b 88 27 00 03 00 00 00 01 00 88
a0: 00 00 90 00 00 07 00 00 00 04 30 32 32 30 90 03
b0: 00 02 00 00 00 14 00 00 01 12 90 04 00 02 00 00
c0: 00 14 00 00 01 26 91 01 00 07 00 00 00 04 01 02
d0: 03 00 92 0a 00 05 00 00 00 01 00 00 01 3a a0 00
e0: 00 07 00 00 00 04 30 31 30 30 a0 01 00 03 00 00
f0: 00 01 00 01 00 00 a0 02 00 04 00 00 00 01 00 00
00: ff d8 ff e1 02 62 45 78 69 66 00 00 ff e1 Exif头部开始标志, 02 62:Exif数据长度,2*256+6*16+2 = 610 45 78 69 66 :Exif字符串的asci码 00 00 两个字节保留
Exif数据部分采用TIFF格式存储,参考refer[3],TIFF数据的开始于0C即第12个字节位置。 TIFF Image File Header –8 bytes 0C: 4d 4d 00 2a 00 00 00 08
0C + offset 开始读取IFD数据==> 0th IFD (1st IFD) (2 bytes long) 1st Tag in 0th IFD (12 bytes long) 2nd Tag in 0th IFD (12 bytes long) 122的偏移是这么算出来的:0C + 110 = 122 = 0x78 |
3. refer
1. Exif 文件格式:http://www.media.mit.edu/pia/Research/deepview/exif.html
2. TIFF6的格式标准:http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf
3. Anatomy of a jpg image:http://www.itbrigadeinc.com/post/2012/03/06/Anatomy-of-a-JPG-image.aspx
更多推荐
所有评论(0)