理解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段:

图-1

蓝色框内为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 代码:

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

时间: 2024-10-04 06:39:44

理解JPEG文件头的格式的相关文章

Eclipse中java文件头注释格式设置

Eclipse中java文件头注释格式设置 Eclipse中java文件头注释格式设置 windows->preferences->java->Code Templates->comments->Type->edit Eclipse注释规范模版总结 新建类文件 /** * @ClassName:     ${file_name} * @Description:   ${todo}(用一句话描述该文件做什么) * * @author          ${user} * 

myeclipse中java文件头注释格式设置

windows->preferences->java->Code Templates->comments->Type->edit Eclipse注释规范模版总结 新建类文件 /** * @ClassName:     ${file_name} * @Description:   ${todo}(用一句话描述该文件做什么) * * @author         ${user} * @version        V1.0 * @Date           ${date

根据文件头判断图片格式

测试代码 byte[] imgb; using (FileStream fs = new FileStream(@"D:\favicon.ico", FileMode.Open)) { imgb = new byte[fs.Length]; fs.Read(imgb, 0, (int)fs.Length); } string imgtype = imgb.GetImageType(); 扩展方法实现 public static string GetImageType(this byte

[转]文件头格式

JPEG (jpg), 文件头:FFD8FF 文件尾:FFD9 PNG (png), 文件头:89504E47 文件尾:AE426082GIF (gif),           文件头:47494638 文件尾:003B ZIP Archive (zip), 文件头:504B0304 文件尾:504BTIFF (tif),   文件头:49492A00  Windows Bitmap (bmp), 文件头:424D  CAD (dwg),  文件头:41433130  Adobe Photosh

【CTF杂项】常见文件文件头文件尾格式总结及各类文件头

文件头文件尾总结 JPEG (jpg), 文件头:FFD8FF 文件尾:FF D9PNG (png), 文件头:89504E47 文件尾:AE 42 60 82GIF (gif), 文件头:47494638 文件尾:00 3B ZIP Archive (zip), 文件头:504B0304 文件尾:50 4B TIFF (tif), 文件头:49492A00 文件尾:Windows Bitmap (bmp), 文件头:424D 文件尾:CAD (dwg), 文件头:41433130 文件尾:Ad

【表空间支持的最大数据文件大小的算法】【数据库限制】【数据文件文件头保留数据块数】

本地管理表空间中设置不同大小的db_block_size时数据文件头保留空间相应例如以下:--?? db_block_size=2KB,文件头保留32个数据块,即64KB. db_block_size=4KB.文件头保留16个数据块,即64KB. db_block_size=8KB,文件头保留8个数据块,即64KB. db_block_size=16KB,文件头保留4个数据块.即64KB. db_block_size=32KB,文件头保留4个数据块.即128KB. --为什么不是64kb? 默认

利用文件头来实现的一些文件类型的方法封装

package com.opslab.util.algorithmImpl; import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.util.HashMap;import java.util.Iterator;import java.util.Map; /** * 利用文件头来实现的一些文件类型的方法封装 */publ

常见文件的文件头

JPEG (jpg),文件头:FFD8FF PNG (png),文件头:89504E47 GIF (gif),文件头:47494638 TIFF (tif),文件头:49492A00 Windows Bitmap (bmp),文件头:424D CAD (dwg),文件头:41433130 Adobe Photoshop (psd),文件头:38425053 Rich Text Format (rtf),文件头:7B5C727466 XML (xml),文件头:3C3F786D6C HTML (h

oracle特殊恢复-bbed修改某个数据文件头

数据文件头中的scn要与控制文件中的scn一致,数据库才可以open,在open过程中我们可以通过bbed来修改某个数据文件头的scn,来欺骗oracle,来open库. 1.环境如下 使用Oracle 11gR2进行测试,具体版本为11.2.0.4 [email protected] SQL>select file#,name,checkpoint_change#,checkpoint_time from v$datafile;      FILE# NAME