略微加速

略速 - 互联网笔记

理解JPEG文件头的格式

2020-04-22 leiting (2922阅读)

标签 开发编程

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的结构类似。

FFE1APP1 Marker
SSSSAPP1 DataAPP1 Data Size
45786966 0000Exif Header
49492A00 08000000TIFF Header
XXXX. . . .IFD0 (main image)Directory
LLLLLLLLLink to IFD1
XXXX. . . .Data area of IFD0
XXXX. . . .Exif SubIFDDirectory
00000000End of Link
XXXX. . . .Data area of Exif SubIFD
XXXX. . . .IFD1(thumbnail image)Directory
00000000End of Link
XXXX. . . .Data area of IFD1
FFD8XXXX. . . XXXXFFD9Thumbnail 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 代码:

https://github.com/dizuo/read_books/blob/master/algorithm_playground/algorithm_playground/jpeg/jpeg_exif_2.7.6_ok.py

解析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 d8: SOI (start of image) – JPEG files always start with this
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
Bytes 0-1 = 4d 4d = "MM" Big Endian Order"
Bytes 2-3 = 00 2a = 42 = Id as TIFF File
Bytes 4-7 = 8 = offset in bytes of 0th IFD 

0C + offset 开始读取IFD数据==>
0th IFD (1st IFD) (2 bytes long)
14:  00 08 
Bytes 0-1 = Number of entries = 8,一共8个IFD索引。
1st Tag in 0th IFD (12 bytes long)
16: 01 0f 00 02 00 00 00 04 48 54 43 00
Bytes 0-1 (Tag ID) = 01 0f = 271 = Make
Bytes 2-3 (Tag Type) = 00 02 = 2 = Ascii
Bytes 4-7 (Count) = 00 00 00 04 = 4 = 4 Characters
Bytes 8-11 (Value) = 48 54 43 00 = "HTC\0" – tag value is here (not offset)
2nd Tag in 0th IFD (12 bytes long)
22: 01 10 00 02 00 00 00 0a 00 00 00 6e 
Bytes 0-1 (Tag ID) = 01 10 = 272 = Model
Bytes 2-3 (Tag Type) = 00 02 = 2 = Ascii
Bytes 4-7 (Count) = 00 00 00 0a = 10 = 10 Characters
Bytes 8-11 (Value) = 00 00 00 6e = Offset = 6e = 110 Bytes
- This means the value is an Ascii string (length 10 starting at 122 Bytes = 0x78)
78: 44 65 73 69 72 65 29 48 44 00 = "Desire HD\0"
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

————————————————

原文链接:https://blog.csdn.net/ryfdizuo/article/details/41250775


北京半月雨文化科技有限公司.版权所有 京ICP备12026184号-3