理解JPEG文件头的格式

2023-11-09

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 代码:

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

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • 无法“安装”plpython3u - postgresql

    我正在尝试在 postgresql 中使用 python 语言 像这样的事情 create or replace function test a integer returns integer as if a 2 0 return even
  • 通过 Scrapy 抓取 Google Analytics

    我一直在尝试使用 Scrapy 从 Google Analytics 获取一些数据 尽管我是一个完全的 Python 新手 但我已经取得了一些进展 我现在可以通过 Scrapy 登录 Google Analytics 但我需要发出 AJAX
  • SQLAlchemy 通过关联对象声明式多对多自连接

    我有一个用户表和一个朋友表 它将用户映射到其他用户 因为每个用户可以有很多朋友 这个关系显然是对称的 如果用户A是用户B的朋友 那么用户B也是用户A的朋友 我只存储这个关系一次 除了两个用户 ID 之外 Friends 表还有其他字段 因此
  • 如何在flask中使用g.user全局

    据我了解 Flask 中的 g 变量 它应该为我提供一个全局位置来存储数据 例如登录后保存当前用户 它是否正确 我希望我的导航在登录后在整个网站上显示我的用户名 我的观点包含 from Flask import g among other
  • 测试 python Counter 是否包含在另一个 Counter 中

    如何测试是否是pythonCounter https docs python org 2 library collections html collections Counter is 包含在另一个中使用以下定义 柜台a包含在计数器中b当且
  • 基于代理的模拟:性能问题:Python vs NetLogo & Repast

    我正在 Python 3 中复制一小段 Sugarscape 代理模拟模型 我发现我的代码的性能比 NetLogo 慢约 3 倍 这可能是我的代码的问题 还是Python的固有限制 显然 这只是代码的一个片段 但 Python 却花费了三分
  • 以编程方式停止Python脚本的执行? [复制]

    这个问题在这里已经有答案了 是否可以使用命令在任意行停止执行 python 脚本 Like some code quit quit at this point some more code that s not executed sys e
  • Python 函数可以从作用域之外赋予新属性吗?

    我不知道你可以这样做 def tom print tom s locals locals def dick z print z name z name z guest Harry print z guest z guest print di
  • 绘制方程

    我正在尝试创建一个函数 它将绘制我告诉它的任何公式 import numpy as np import matplotlib pyplot as plt def graph formula x range x np array x rang
  • BeautifulSoup 中的嵌套标签 - Python

    我在网站和 stackoverflow 上查看了许多示例 但找不到解决我的问题的通用解决方案 我正在处理一个非常混乱的网站 我想抓取一些数据 标记看起来像这样 table tbody tr tr tr td td td table tr t
  • 添加不同形状的 numpy 数组

    我想添加两个不同形状的 numpy 数组 但不进行广播 而是将 缺失 值视为零 可能最简单的例子是 1 2 3 2 gt 3 2 3 or 1 2 3 2 1 gt 3 2 3 1 0 0 我事先不知道形状 我正在弄乱每个 np shape
  • Pandas:merge_asof() 对多行求和/不重复

    我正在处理两个数据集 每个数据集具有不同的关联日期 我想合并它们 但因为日期不完全匹配 我相信merge asof 是最好的方法 然而 有两件事发生merge asof 不理想的 数字重复 数字丢失 以下代码是一个示例 df a pd Da
  • Jupyter Notebook 内核一直很忙

    我已经安装了 anaconda 并且 python 在 Spyder IPython 等中工作正常 但是我无法运行 python 笔记本 内核被创建 它也连接 但它始终显示黑圈忙碌符号 防火墙或防病毒软件没有问题 我尝试过禁用两者 我也无法
  • 解释 Python 中的数字范围

    在 Pylons Web 应用程序中 我需要获取一个字符串 例如 关于如何做到这一点有什么建议吗 我是 Python 新手 我还没有找到任何可以帮助解决此类问题的东西 该列表将是 1 2 3 45 46 48 49 50 51 77 使用
  • 使用 Python 绘制 2D 核密度估计

    I would like to plot a 2D kernel density estimation I find the seaborn package very useful here However after searching
  • 使用其构造函数初始化 OrderedDict 以便保留初始数据的顺序的正确方法?

    初始化有序字典 OD 以使其保留初始数据的顺序的正确方法是什么 from collections import OrderedDict Obviously wrong because regular dict loses order d O
  • 发送用户注册密码,django-allauth

    我在 django 应用程序上使用 django alluth 进行身份验证 注册 我需要创建一个自定义注册表单 其中只有一个字段 电子邮件 密码将在服务器上生成 这是我创建的表格 from django import forms from
  • 在 Qt 中自动调整标签文本大小 - 奇怪的行为

    在 Qt 中 我有一个复合小部件 它由排列在 QBoxLayouts 内的多个 QLabels 组成 当小部件调整大小时 我希望标签文本缩放以填充标签区域 并且我已经在 resizeEvent 中实现了文本大小的调整 这可行 但似乎发生了某
  • Python Selenium:如何在文本文件中打印网站上的值?

    我正在尝试编写一个脚本 该脚本将从 tulsaspca org 网站获取以下 6 个值并将其打印在 txt 文件中 最终输出应该是 905 4896 7105 23194 1004 42000 放置的动物 的 HTML span class
  • 如何使用 Pycharm 安装 tkinter? [复制]

    这个问题在这里已经有答案了 I used sudo apt get install python3 6 tk而且效果很好 如果我在终端中打开 python Tkinter 就可以工作 但我无法将其安装在我的 Pycharm 项目上 pip

随机推荐

  • Inception V1 V2 V3 V4

    最开始卷积的层数不断增加 后来开始修改卷积核的形式 一 二Inception V1 同一层级进行多尺度卷积 扩展了宽度 同时加强对小目标的检测能力 A 引入1 1的卷积是为了降维 降低通道维度 B 在中间层加入辅助损失 辅助损失只用于训练
  • fastCGI的安装和使用

    一 安装 1 先安装2个包 spawn fcgi 1 6 4 tar gz fcgi 2 4 1 SNAP 0910052249 安装 fcgi 2 4 1 SNAP 0910052249 报错 fcgio cpp In destructo
  • Git合并不同url的项目

    本文由云 社区发表 作者 工程师小熊 摘要 为了让项目能实现Git Gerrit Jenkin的持续集成 我们把项目从Git上迁移到了Gerrit上 发现有的同事在老Git提交代码 因为Gerrit做了同步 在Gerrit上有新提交的时候就
  • json文件格式详解

    json文件格式详解 JSON JavaScript Object Notation 是一种轻量级的数据交换格式 易于人阅读和编写 同时也易于机器解析和生成 它基于JavaScript Programming Language Standa
  • Latex排列图片:自由定义N行M列的排列方式

    首先导包 usepackage graphicx usepackage float usepackage subfigure 图片排成一行 begin figure htbp centering subfigure 图1 begin min
  • 【解决weditor报错】Local server not started, start with

    前言 大家在使用weditor查找元素的时候 经常会遇到 Local server not started start with 这个错误 下面是我个人的一些解决方法 供大家参考 原因1 浏览器问题导致 浏览器的原因导致的界面未刷新 我的就
  • 解决从GitHub下载文件时缓慢的问题

    我们知道 访问GitHub在国内的速度还算过得去 但是从GitHub上下载文件的速度就非常慢了 以下方法就是为了解决下载速度缓慢的 截止2019 9 5前测试有效 1 用记事本打开hosts文件 路径为C Windows System32
  • Mysql 实践(一):部署和安装

    1 目标 卸载centos自带的mysql 安装mysql 5 6 33 2 步骤 1 下载mysql 下载地址 http dev mysql com downloads mysql 5 6 html downloads 我们下载 这些包
  • 基于SSM框架的实验室开放管理系统

    系统功能结构设计 在分析并得出使用者对程序的功能要求时 就可以进行程序设计了 管理员功能结构图 管理员主要负责填充图书和其类别信息 并对已填充的数据进行维护 包括修改与删除 管理员也需要审核老师注册信息 发布公告信息 管理自助租房信息等 用
  • flutter初学之悬浮按钮

    期望 想实现一个悬浮在整个页面的悬浮按钮 实现1 用FloatingActionButton实现 新增悬浮按钮 Widget createFixedAddWidget ProductEntryState state Dispatch dis
  • linux环境下查看因内存占用过大被杀掉的进程

    文章目录 前言 查询方法 通过系统日志查找 通过dmesg命令查找 进程被杀的原因 总结 前言 最近发生两次游戏服务器进程突然消失的事件 查询日志上下文没有找到有用的信息 日志显示运行到某处戛然而止 此处代码逻辑简单 排除异常逻辑导致的服务
  • data_support/utlist(关于编译器的一些宏宏设置)

    ifndef UTLIST H tlist 权限查看程序 define UTLIST H define UTLIST VERSION 1 9 8 include
  • 灰度图像直方图均衡化公式及实现

    图像的直方图 直方图是图像中像素强度分布的图形表达方式 它统计了每一个强度值所具有的像素个数 直方图均衡化 是通过拉伸像素强度分布范围来增强图像对比度的一种方法 是图像处理领域中利用图像直方图对对比度进行调整的方法 均衡化指的是把一个分布
  • 华为手机发展史

    一 成立手机业务部 大家好 我是小码哥 今天我们来聊一下华为手机的发展史 作为国内乃至世界技术成熟大型互联网企业 已经成为国内市场不可缺失的一部分 华为由任正非在1987年创办的 至今已有34年 华为最初是做交换机起家 随着互联网的发展 华
  • 对象数组(初学)

    目录 一 什么是对象数组 二 定义对象数组 三 对象数组初始化 四 访问对象数组元素 五 new和对象数组 一 什么是对象数组 所谓对象数组 指每一个数组元素都是对象的数组 即若一个类有若干个对象 把这一系列的对象用一个数组来存放 对象数组
  • 关闭httpclient4.5控制台日志输出

    httpclient4 5每次执行的时候都会在控制台输出大量日志 一般情况下并不需要 去官方看了 没找到去掉日志的方法 囧 官网链接 https hc apache org httpcomponents client 4 5 x loggi
  • 2020-09-07

    使 mqtt fx连阿 云时 直提 MQTTException 最近在搞一个Mqtt项目 在用mqtt fx工具做测试时怎么都连接不上阿里云 直提 MQTTException 记得之前也都是可能的 操作好像都是按照官方的文档来操作的 密码也
  • RX8025T RTC读写与秒中断

    目录 一 精度 二 读写时序 三 写RTC对其内部ms计数的影响 四 在FPGA中用GPS校正RTC 五 ms维护 六 IIC防锁死计数清零 七 日期计算星期公式 一 精度 二 读写时序 接口为IIC 读写时序如下图 注意 1 写操作 写从
  • PHP常见问题总结

    1 为什么会出现这种情况 端口什么的都设置正确了 解决方法 请将本机的IIS服务关闭 开启Apache服务 IIS服务的关闭方法可参见 https jingyan baidu com article 0f5fb099e0d7216d8334
  • 理解JPEG文件头的格式

    1 JPEG 1 why jpeg jpeg作为图片传输格式使用最为普遍 压缩比最高 每天我们都会产出和传输大量的jpeg格式数据 手机拍出来的格式默认是jpeg 朋友圈各种分享 磁盘上积累了大量的jpeg 因此本人一直对jpeg头部数据非