PicScrub logoPicScrub
返回格式列表

JPEG

泄密最狠的一个

JPEG 文件把元数据放在文件头和图像数据之间的 APPn 段里。下面就是各部分都住着什么,以及 PicScrub 分别会怎么处理。

色彩配置文件,你想留就留
SOI开头
APP0JFIF
APP1EXIF
APP1XMP
APP2ICC
APP13IPTC
COM注释
SOS …你真正的照片,一点没动
EOI结尾
GPS 和相机信息藏在这,已删除
逐字节完全一致

会被清除的东西

  • EXIF GPS 坐标、相机品牌和型号、拍摄时间、曝光参数
  • XMP 编辑历史、用过的软件、评分
  • IPTC / Photoshop 图注、署名、关键词
  • 注释和内嵌缩略图 原图的一个微缩副本,可能在你裁剪、修图之后还活着

你可以保留的东西

  • 图像数据 永远不动,绝不重新编码
  • ICC 色彩配置文件 可选,让颜色保持准确
  • 方向信息 可选,让竖拍照片不歪
  • 版权声明 可选,给想署名又不想暴露坐标的摄影师

文件结构概览

如果你用十六进制编辑器打开过 JPEG,就会发现它是由一个个被标记分隔开的段组成的。每个标记都以 0xFF 开头,后面跟一个字节,说明这是什么类型的段。这个设计让 JPEG 相对好解析: 只要扫描 FF 字节,再看看它后面跟着什么就行。

对隐私来说有意思的地方在于,所有元数据(EXIF、GPS、拍摄时间)都住在这些段里, 和真正的图像数据完全分开。所以我们才能清除元数据,而不碰任何像素、不做任何重新压缩。

JPEG 文件结构

SOI
APP0-15
DQT
SOF
DHT
SOS + Data
EOI
SOI
2 字节
图像开始(FF D8)
APP0-15
100 字节
应用标记段(元数据)
DQT
130 字节
量化表
SOF
20 字节
帧开始
DHT
420 字节
霍夫曼表
SOS + Data
长度可变
扫描数据(图像本身)
EOI
2 字节
图像结束(FF D9)

JPEG 文件头示例

SOI(图像开始)
APP0 标记
APP0 长度
JFIF 标识符
JFIF 数据
APP1 标记
APP1 长度
Exif 标识符
OffsetHexASCII
0000
FFD8FFE000104A464946000101000048
......JFIF.....H
0010
00480000FFE112344578696600000000
.H.....4Exif..

标记的结构

  • FF xx:标记(xx 表示类型)
  • LL LL:长度(2 字节,大端序,把自己也算进去)
  • Data...:段数据(长度 - 2 字节)

JPEG 标记完整速查表

标记名称说明
FF D8SOI图像开始
FF D9EOI图像结束
FF C0SOF0帧开始(基线 DCT)
FF C2SOF2帧开始(渐进式 DCT)
FF C4DHT定义霍夫曼表
FF DBDQT定义量化表
FF DDDRI定义重启间隔
FF DASOS扫描开始(后面就是图像数据)
FF FECOM注释(元数据)
FF E0APP0JFIF 标记
FF E1APP1EXIF / XMP 标记
FF E2APP2ICC 配置文件 / MPF
FF EDAPP13IPTC / Photoshop
FF EEAPP14Adobe 色彩变换

金色 = 元数据(会被清除),无底色 = 必需的结构

JFIF 与 EXIF

有件事让很多人犯迷糊:JPEG 文件里常常同时装着两套不同的元数据标准。 JFIF 出现得更早,管的是分辨率之类的基础信息。后来相机开始往里塞 EXIF 数据, 记录详细的拍摄参数。今天大多数 JPEG 两套都有,所以你会在文件开头附近同时看到 APP0 和 APP1 标记。

APP0:JFIF

JPEG File Interchange Format,记录图片的基础信息。

  • • 版本号
  • • 像素密度(DPI)
  • • 宽高比
  • • 可选的缩略图

APP1:EXIF

Exchangeable Image File Format,相机写入的元数据。

  • • 相机品牌和型号
  • • GPS 坐标
  • • 时间戳
  • • 曝光参数

APP 标记详解

JPEG 规范预留了 16 个“应用”标记(APP0 到 APP15),让厂商自由发挥。 这些年下来,不同的组织各自占了不同的标记来放自己的元数据格式。 结果自然有点乱,但好在是一团有文档可查的乱。

麻烦之处在于,同一个标记根据内容不同,含义也不同。比如 APP1 既可能装 EXIF, 也可能装 XMP,你得看看里面的标识符字符串,才知道自己面对的是哪一种。

APP0 (0xFFE0):JFIF

标识符:JFIF\0。包含版本、密度单位、X/Y 密度, 以及可选的内嵌缩略图。一般保留它是安全的。

APP1 (0xFFE1):EXIF

标识符:Exif\0\0。里面是一套完整的 TIFF 结构, 用 IFD 条目存放相机信息、GPS 数据、时间戳、缩略图和 maker notes。 隐私上最需要提防的部分。

APP1 (0xFFE1):XMP

标识符: http://ns.adobe.com/xap/1.0/\0。Adobe 制定的基于 XML 的 元数据标准,可能包含编辑历史、软件信息和扩展的 EXIF 数据。

XMP 命名空间
xmp: http://ns.adobe.com/xap/1.0/
xmpMM: http://ns.adobe.com/xap/1.0/mm/
dc: http://purl.org/dc/elements/1.1/
photoshop: http://ns.adobe.com/photoshop/1.0/
tiff: http://ns.adobe.com/tiff/1.0/
exif: http://ns.adobe.com/exif/1.0/

APP1 (0xFFE1):扩展 XMP

标识符: http://ns.adobe.com/xmp/extension/\0。当 XMP 数据超过 65KB 时, 会被拆到多个 APP1 段里。

APP2 (0xFFE2):MPF

标识符:MPF\0。Multi-Picture Format,用于立体图像和全景图。

APP2 (0xFFE2):ICC 配置文件

标识符:ICC_PROFILE\0。色彩管理数据,可能被切分到多个 APP2 标记里。 通常保留它是安全的。

APP13 (0xFFED):IPTC/Photoshop

标识符:Photoshop 3.0\0。存放 IPTC-IIM 数据, 包括图注、关键词、版权和创作者信息,可能带有作者身份。

APP14 (0xFFEE):Adobe

标识符:Adobe\0。存放色彩变换标志(RGB/CMYK), 对颜色能否正确渲染很重要。

EXIF 的结构

有意思(也有点怪)的地方来了:EXIF 数据其实是一个嵌在 JPEG 里的微型 TIFF 文件。 是的,真的。它有自己的文件头、自己的字节序,并用 TIFF 的 IFD(Image File Directory) 结构来存放标签。

在“Exif”标识符之后,你首先看到的是 TIFF 文件头,它说明数据是小端序(Intel,“II”) 还是大端序(Motorola,“MM”)。这一步弄错,后面所有数字都会变成垃圾, 所以任何解析器都会先检查它。

TIFF 文件头(8 字节)

字节序(II = 小端序)
魔数(42)
IFD0 偏移量
OffsetHexASCII
0000
49492A0008000000
II*.....

II = Intel(小端序),MM = Motorola(大端序)

IFD 条目的结构(12 字节)

标签 ID类型数量值/偏移量
2 字节2 字节4 字节4 字节

主要的 IFD 条目

0x010F:Make
0x0110:Model
0x0132:DateTime
0x8769:ExifIFDPointer
0x8825:GPSInfoIFDPointer
0x927C:MakerNote

PicScrub 如何处理 JPEG

思路相当直接:我们一个标记一个标记地读完整个文件,保留显示图像必需的那些, 跳过装着元数据的那些。因为压缩过的图像数据我们从来不碰,所以画质零损失。

关键在于 JPEG 基于标记的结构让这件事变得简单。我们不需要理解 DCT 系数, 也不需要看懂霍夫曼表,只要分清哪些段是元数据、哪些不是就够了。

1

校验文件头

确认文件开头有 SOI 标记(FF D8)

2

解析标记

按顺序读取每个标记,取出类型和长度

3

识别元数据

检查 APP 段里的标识符(EXIF、XMP、IPTC 等)

4

选择性复制

把非元数据的段复制到输出里,跳过元数据段

会保留什么

  • • SOI/EOI 标记(必需)
  • • DQT(量化表)
  • • SOF(帧头)
  • • DHT(霍夫曼表)
  • • SOS 和扫描数据(图像本身)
  • • 可选:ICC 色彩配置文件(可配置)

会清除什么

  • • APP1 EXIF(相机、GPS、时间戳)
  • • APP1 XMP(编辑元数据)
  • • APP13 IPTC(图注、作者)
  • • COM 标记(注释)
  • • EXIF 缩略图

EXIF 标签速查表

就隐私而言,EXIF 标签并不是一视同仁的。有些标签(比如曝光参数)相当无害, 另一些(比如序列号和机主姓名)却能唯一地指认出你或你的器材。 下面这些是我们认定的高风险标签:

标签 ID名称隐私风险
0x9003DateTimeOriginal高
0x9004DateTimeDigitized高
0x9010OffsetTime中
0x9286UserComment高
0x927CMakerNote高
0xA420ImageUniqueID高
0xA430CameraOwnerName高
0xA431BodySerialNumber高
0xA434LensModel中
0xA435LensSerialNumber高
0xFDE8OwnerName高
0xFDE9SerialNumber高
查看所有相机参数标签(不涉及身份)
0x829A ExposureTime
0x829D FNumber
0x8822 ExposureProgram
0x8827 ISOSpeedRatings
0x9201 ShutterSpeedValue
0x9202 ApertureValue
0x9203 BrightnessValue
0x9204 ExposureBiasValue
0x9207 MeteringMode
0x9208 LightSource
0x9209 Flash
0x920A FocalLength
0xA001 ColorSpace
0xA002 PixelXDimension
0xA003 PixelYDimension
0xA402 ExposureMode
0xA403 WhiteBalance
0xA405 FocalLengthIn35mmFilm
0xA406 SceneCaptureType

GPS 标签速查表

GPS 数据住在自己的子 IFD 里,由主 IFD 中的 0x8825 标签指向它。 只要这个指针存在,你的图片里就有位置数据。现在的智能手机在这件事上格外积极, 精度往往足以指出你当时具体站在哪儿。

标签 ID名称说明
0x0000GPSVersionIDGPS 标签版本
0x0001GPSLatitudeRefN 或 S
0x0002GPSLatitude度、分、秒
0x0003GPSLongitudeRefE 或 W
0x0004GPSLongitude度、分、秒
0x0005GPSAltitudeRef海平面以上或以下
0x0006GPSAltitude米
0x0007GPSTimeStampUTC 时间
0x001DGPSDateStampUTC 日期
0x0012GPSMapDatum所用的大地测量基准
0x001BGPSProcessingMethodGPS/CELLID/WLAN/MANUAL
0x001CGPSAreaInformation地点名称

IPTC 标签速查表

IPTC 当初是为通讯社设计的,用来在图片里嵌入图注、署名和版权信息。 它存放在 APP13 里,标识符是“Photoshop 3.0”(没错,Adobe 把它接了过去)。 你在 Lightroom 或 Photoshop 里填过的版权信息和关键词,最后就落在这里。

0x0250 By-line(作者)
0x0255 By-line Title(作者职务)
0x025A City(城市)
0x025C Sub-location(具体地点)
0x025F Province/State(省或州)
0x0265 Country Name(国家)
0x0274 Copyright Notice(版权声明)
0x0276 Contact(联系方式)
0x0237 Date Created(创建日期)
0x023C Time Created(创建时间)
0x0278 Caption/Abstract(图注)
0x0219 Keywords(关键词)