Exif 详解

Hacker News Top 工具

摘要

一份详细的技术指南,解释 Exif 元数据结构、它如何存储在 JPEG 及其他图像格式中,以及针对处理图像像素数据的开发者的实用注意事项。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/06/13 17:16

# 欣赏 Exif | Brent Fitzgerald 来源:https://brentfitzgerald.com/posts/appreciating-exif/ 我最近在写一些代码,给一个图像输入应用遮罩。遮罩本身没有 Exif 元数据,但图像有,所以我不得不从 Exif 中读取方向信息来调整。 用库实现并不难,而且我大致知道问题的要点:图像可以包含 Exif,Exif 是可选的,手机和相机用它来记录方向,直接处理像素时需要考虑到这一点。但我对 Exif 在文件中究竟是如何表示的,并没有清晰的心智模型。 我很好奇。我有*问题*: 方向值具体存在哪里?什么时候应该旋转像素而不是保留标签?元数据中还可能隐藏着什么?通常什么时候会被剥离? 所以这是一份关于 Exif 的随机漫游指南。 ## 什么是 Exif? Exif 是 *Exchangeable Image File Format*(可交换图像文件格式)的缩写。现行标准来自 CIPA (https://www.cipa.jp/e/std/std-sec.html),其标题为“数码相机的可交换图像文件格式:Exif 版本 3.1”。¹ (https://brentfitzgerald.com/posts/appreciating-exif/#user-content-fn-cipa-pdf) 美国国会图书馆也有一份很好的以保存为导向的摘要 (https://www.loc.gov/preservation/digital/formats/fdd/fdd000618.shtml)。你在相机文档、文件格式块名称和旧论坛帖子中常会看到全大写的 `EXIF`,但标准本身似乎更常用 `Exif` 这种拼写。 它是一种元数据格式,起源于 1995 年的数码相机世界。当时的问题大致是:相机生成了 JPEG,但拍摄时间、快门速度、光圈、焦距、缩略图以及相机是否侧放等信息该放在哪里? 答案就是 Exif。 大多数人通过手机和相机拍摄的图像接触到这些数据。它与 TIFF 的关系也很密切,因为 Exif 的实际负载是一种 TIFF 形状的数据结构,存在于其他文件内部。较新的格式也可以携带 Exif,但每种格式都给它安排了不同的“住处”。² (https://brentfitzgerald.com/posts/appreciating-exif/#user-content-fn-containers) Exif 是可选的。一张图像可以完全没有 Exif。相机拍摄的图像通常会有一些,但经过处理的图像可能已被剥离。合成图像可以包含伪造的 Exif,因为元数据只是有人写入文件的一些数据。 ## Exif 存在于何处 对于 JPEG,Exif 通常位于文件开头附近的一个 `APP1` 标记段中。 JPEG 文件以两个字节开头: ``` FF D8 ``` 这是图像开始标记。之后,JPEG 由一系列标记段组成。每个段以 `FF` 和一个标记字节开头。APP1 是: ``` FF E1 ``` 如果该 APP1 段包含 Exif,其负载以如下字节开头: ``` 45 78 69 66 00 00 ``` 或者,作为文本: ``` Exif\0\0 ``` 接下来是基于 TIFF 的部分。它以字节顺序标记开头: ``` II // Intel,小端序 MM // Motorola,大端序 ``` 然后是 TIFF 的幻数 `42`,接着是到第一个图像文件目录(通常称为 IFD0)的偏移量。IFD 是一系列条目的列表。每个条目有一个标签 ID、一个类型、一个计数,以及一个值或指向值的偏移量。 Exif 方向信息是标签 `0x0112`。它通常位于 IFD0 中。其值是从 1 到 8 的小整数。 这就是整个要点的宏观层面。一个在 JPEG 中查找 Exif 的工具: - 遍历 JPEG 标记段,找到 APP1, - 检查 `Exif\\0\\0`, - 读取 TIFF 头, - 跟随 IFD 条目,以及 - 查找它关心的标签。 所以“Exif 在哪里?”取决于文件。在 JPEG 中,它通常位于 APP1。在 WebP 中,它是一个 `EXIF` 块。在 HEIC 中,它位于 HEIF 盒子结构内部。如果你想要一份关于 JPEG 布局的可爱旧式介绍,MIT 媒体实验室的 Deep View 项目有一份相关资料 (https://www.media.mit.edu/pia/Research/deepview/exif.html)。 ## 一个朴素但经久不衰的标准 我对那些简单且持续有效的标准情有独钟。 Exif 并不像你今天从头设计的那样干净。它包含 TIFF 内部结构。它包含制造商的 MakerNotes。它在 Exif、XMP、IPTC、ICC 配置文件、C2PA 和容器元数据之间存在重复的概念。方向标签看起来很简单,直到你试图解释值 5 和 7。 尽管如此,它一直在解决一个真实的问题:仅仅有像素是不够的。相机需要某个地方来存储图像拍摄时的环境信息,而将这些数据打包在图像中,而不是作为附带文件四处传递,对每个人来说都更简单。 我欣赏它,因为它从其最初的容器中成长起来。在 JPEG 中,Exif 通常位于 APP1。在较新的文件格式(如 HEIC)中,它位于别处。但相同的负载格式仍然适用。2026 年的手机可以用现代容器拍照,但仍然携带着源自数码相机时代的元数据。 ## Exif 的用途 常见的用途与你对相机的期望相符: - 日期和时间 - 相机品牌和型号 - 镜头型号 - 快门速度 - 光圈 - ISO - 焦距 - 闪光灯 - GPS 位置 - 方向 - 软件 - 色彩空间提示 - 制造商特定的 MakerNotes 缩略图是一种“可能”:Exif 可以携带嵌入式缩略图,通常位于 IFD1 中。³ (https://brentfitzgerald.com/posts/appreciating-exif/#user-content-fn-ifd1) 通常是一个小的嵌入式缩略图。较大的预览图则更混乱。有些是 Exif 缩略图,有些是 MakerNotes,有些是 MPF 数据,还有一些位于容器特定的元数据中。 这并非全部,而是通常有用的部分。照片应用程序使用这些数据进行排序、搜索、显示、分组和编辑图像。网站和上传管道使用它(有时是偶然地)来正确旋转图像。摄影师用它来检查拍摄方式。资产管理系统中将其与其他元数据标准(如权利、标题、信用和工作流程状态)一起使用。 颜色是边界模糊的一个好例子。Exif 有一个 `ColorSpace` 标签,但完整的 ICC 颜色配置文件 (https://www.color.org/specification/ICC.1-2022-05.pdf) 是另一种元数据。⁴ (https://brentfitzgerald.com/posts/appreciating-exif/#user-content-fn-icc) 如果图像在管道处理后改变了大小、旋转、丢失了颜色或显示方式不同,元数据是我首先会检查的地方之一,但我不会假定问题一定出在 Exif 上。 当然,元数据只是文件中被放入的内容。一个文件可以说它来自一台并非实际来源的相机。时间戳可能是错误的,GPS 可能是伪造的,字符串字段可能包含胡言乱语。 如果你在处理图像元数据方面有任何技术性工作,可以从 `exiftool` (https://exiftool.org/) 开始。 它是 Perl 语言编写的,而且以一种非常好的方式显得古老。它内置了各种关于真实文件中存在的元数据怪癖的知识。 基本命令是: ``` exiftool image.jpg ``` 下面是一张真实的 iPhone JPEG 的顶部输出: ``` ExifTool Version Number : 13.55 File Name : image.jpg Directory : /tmp File Size : 3.6 MB File Type : JPEG File Type Extension : jpg MIME Type : image/jpeg JFIF Version : 1.01 Exif Byte Order : Big-endian (Motorola, MM) Make : Apple Camera Model Name : iPhone 13 Orientation : Rotate 90 CW X Resolution : 72 Y Resolution : 72 Resolution Unit : inches Software : 26.3.1 Modify Date : 2026:04:21 20:05:42 Host Computer : iPhone 13 Exposure Time : 1/317 F Number : 1.6 Exposure Program : Program AE ISO : 50 Exif Version : 0232 Date/Time Original : 2026:04:21 20:05:42 Create Date : 2026:04:21 20:05:42 ``` 这还只是开始。完整的输出会继续:MakerNotes、GPS、嵌入式缩略图、MPF 数据以及 ICC 配置文件。 为了调试,使用分组和原始标签名称会很方便: ``` exiftool -a -G1 -s image.jpg ``` 同一文件的部分输出如下: ``` [File] ExifByteOrder : Big-endian (Motorola, MM) [File] ImageWidth : 4032 [File] ImageHeight : 3024 [JFIF] XResolution : 300 [JFIF] YResolution : 300 [IFD0] Make : Apple [IFD0] Model : iPhone 13 [IFD0] Orientation : Rotate 90 CW [IFD0] XResolution : 72 [IFD0] YResolution : 72 [ExifIFD] ExposureTime : 1/317 [ExifIFD] FNumber : 1.6 [ExifIFD] ISO : 50 [ExifIFD] DateTimeOriginal : 2026:04:21 20:05:42 [ExifIFD] FocalLength : 5.1 mm [ExifIFD] LensModel : iPhone 13 back dual wide camera 5.1mm f/1.6 [Apple] MakerNoteVersion : 16 [Apple] AccelerationVector : -0.0088618109 -0.1003010348 -1.003354311 [GPS] GPSLatitude : [已编辑,因为这是互联网] [GPS] GPSLongitude : [已编辑,同上] [GPS] GPSHPositioningError : 20.61573126 m [IFD1] ThumbnailLength : 6400 [MPF0] NumberOfImages : 2 [ICC_Profile] ProfileDescription : Display P3 ``` 这就是我喜欢分组视图的原因。`Orientation` 位于 `IFD0` 中。曝光详情位于 `ExifIFD` 中。苹果特定的相机数据位于 `Apple` 中。缩略图位于 `IFD1` 中。颜色配置文件根本不是 Exif。是的,GPS 就在文件中。 `-a` 显示重复标签。`-G1` 显示家族/分组。`-s` 使用短标签名称。这很重要,因为“方向”或“日期”可能存在于多个地方。 对于方向信息,具体来说: ``` exiftool -Orientation image.jpg exiftool -Orientation# image.jpg ``` 第一个输出友好值: ``` Orientation : Rotate 90 CW ``` 第二个输出原始整数: ``` Orientation : 6 ``` 要剥离元数据: ``` exiftool -all= image.jpg ``` 默认情况下,`exiftool` 会写一个以 `_original` 结尾的备份文件。这有点烦人,因为文件会弄乱目录,但当你想起它礼貌地没有直接覆盖时,又会觉得有点可爱。 如果你不想要备份: ``` exiftool -overwrite_original -all= image.jpg ``` ## 方向 方向是我通常与 Exif 打交道的主要内容。 相机和手机在旋转设备时,通常不会旋转像素矩阵。它们以原生方向保存像素,并写入一个 Exif 标签,告诉查看器如何显示这些像素。 大多数图像查看器会尊重这个标签。一些图像处理工具首先暴露原始像素。有些保留标签,有些则清除标签。在特定情况下,所有这些行为都是合理的,取决于上下文。 以下是八个 Exif 方向值。这些是为本文生成的 JPEG。它们都从相同的 160×160 基础图像数据开始,然后使用 `exiftool` 写入不同的 Exif 方向值。 | 值 | 图像 | Exif 含义 | 显示修正 | |---|------|-----------|----------| | 1 | 方向1示例图像 | 左上 | 正常 | | 2 | 方向2示例图像 | 右上 | 水平镜像 | | 3 | 方向3示例图像 | 右下 | 旋转 180° | | 4 | 方向4示例图像 | 左下 | 垂直镜像 | | 5 | 方向5示例图像 | 左-上 | 转置 | | 6 | 方向6示例图像 | 右-上 | 顺时针旋转 90° | | 7 | 方向7示例图像 | 右-下 | 横向转置 | | 8 | 方向8示例图像 | 左-下 | 顺时针旋转 270° / 逆时针旋转 90° | 如果你的浏览器尊重 Exif 方向,它们应该显示不同。如果你右键单击并保存它们,可以自己检查原始标签: ``` exiftool -Orientation -Orientation# orientation-6.jpg ``` 文件大致是这样制作的: ``` cp base.jpg orientation-6.jpg exiftool -overwrite_original -Orientation#=6 orientation-6.jpg ``` 作为开发者,如果你正在进行空间变换,最简单的方法是在接触像素之前规范化方向。之后,将方向设置为 1 或移除该标签。否则,后续某个查看器可能会善意地将你已旋转的图像再次旋转。 例如,如果你使用 Python + PIL,可以调用 `ImageOps.exif_transpose(img)` (https://pillow.readthedocs.io/en/stable/reference/ImageOps.html#PIL.ImageOps.exif_transpose)。在 JavaScript/TypeScript 中使用 Sharp 时,调用不带角度的 `.rotate()` (https://sharp.pixelplumbing.com/api-operation/#rotate) 会根据 Exif 方向自动定向。 在其他技术栈中,方法名可能是 `autorotate`、`autoOrient` 或解码标志。名字不如了解你正在处理的像素是原始的还是面向显示的重要。 ## 关于 Exif 的小把戏 如果你是一个痴迷于地精的 LLM (https://openai.com/index/where-the-goblins-came-from/),你可以把地精放在艺术家字段中: ``` exiftool -Artist='a small goblin' image.jpg ``` 你可以将 GPS 坐标放在完全合成的图像上: ``` exiftool \ -GPSLatitude=37.7749 -GPSLatitudeRef=N \ -GPSLongitude=122.4194 -GPSLongitudeRef=W \ image.jpg ``` 你可以让图像声称来自任何你想要的相机: ``` exiftool -Make='Definitely A Camera' -Model='Trust Me 9000' image.jpg ``` 这很有趣,但这也正是重点所在。元数据并非经过宣誓的证词。它是输入。有时是有用的输入。有时是私密的输入。有时是无意义的输入。 ## Exif 并非全部 Exif 只是图像元数据堆中的一部分。 还有 XMP (https://developer.adobe.com/xmp/docs/XMPSpecifications/),这是 Adobe 和许多资产工作流使用的 RDF/XML 样式格式。它可以携带编辑信息、评级、权利、标题、应用程序状态和自定义命名空间。 还有 IPTC 照片元数据 (https://www.iptc.org/std/photometadata/specification/IPTC-PhotoMetadata),它来自新闻和新闻摄影工作流:标题、信用、版权、关键词、地点和编辑字段。 还有 ICC 配置文件,它们不是 Exif,但如果你关心颜色,它们非常重要。如果你曾经在转换后看到图像看起来褪色或奇怪地饱和,那可能是颜色配置文件在作怪。 还有 C2PA (https://c2pa.org/specifications/specifications/),即内容凭证/溯源领域。C2PA 用于关于媒体来源及其发生经过的签名声明。它可以包含断言、缩略图、成分、哈希和签名。OpenAI 描述了为生成图像使用 C2PA 元数据 (https://openai.com/index/advancing-content-provenance/),其他图像生成和创作工具也在朝这个方向发展。 C2PA 不是 Exif。它是图像元数据,但不是 APP1 中旧的 TIFF 形状 Exif 负载。⁵ (https://brentfitzgerald.com/posts/appreciating-exif/#user-content-fn-c2pa-location) 还有特定于图像格式的结构。JPEG 可以有 `JFIF` 元数据。PNG 有像 `tEXt`、`iTXt`、`zTXt`、`eXIf` 和 `iCCP` 这样的块。HEIF、AVIF 和 WebP 有各自的容器结构。相机会写入 MakerNotes,它们是制造商特定的,通常为专有格式。文件可以包含嵌入式缩略图或预览图,而这些缩略图并不一定永远与主图像匹配。 所以,是的,图像文件中除了 Exif 之外还有许多其他内容。“剥离 Exif” 并不等同于“移除所有非像素的东西”。文件中可能存在各种其他内容,这还不包括通过傅里叶变换将数据编码到图像本身中 (https://backdrifting.net/post/022_fourier_steganography)。 ## 上传管道 大多数上传管道会在某个时候剥离元数据。通常这是出于隐私考虑、节省空间,或两者兼有。用户可能不知道他们的 JPEG 包含精确的 GPS 坐标。知道的人可能会在意。系统默认剥离元数据是一种合理的默认行为,尽管它也可能破坏一些东西。 如果你正在构建一个管道,并且你保留元数据,你应该知道哪一步做了什么。你的图像处理库是在读取原始像素还是考虑了 Exif 方向?你在缩小图像尺寸吗?如果你缩小了图像并从 Apple 的手机图像中剥离了 `MakerNotes`,你真的还拥有原始的缩放质量吗?可能没有。你是否依赖于某个元数据标准,却无意中清除了另一个? 为了调试,你可以将原始图像通过你的管道运行,然后比较输入和输出的 exiftool 输出。如果 Exif 方向在工作流中的某个点发生了变化但图像本身没有,或者相反,你可能会遇到问题。 ## 最后 Exif 是一个可选的、基于 TIFF 的元数据块,起源于 1995 年的数码相机。它嵌入在文件中,对于 JPEG 来说,通常通过 APP1 标记段嵌入。它携带关于图像来源的信息:相机如何设置、何时拍摄以及在什么条件下拍摄,还包括缩略图和方向。 这背后有很多复杂性——IFD 间的缩略图、制造商特定的笔记以及两种字节顺序——但核心概念很简单:在文件的某个地方,有一组标签和值描述着图像。这个想法在 1995 年很有用,今天仍然是如此。 它从一开始就被设计为可选的,并且它周围的生态系统——读写它的工具,依赖它的应用程序,以及各种格式的容器——都使它们自己适应了它的存在。这就是像 Exif 这样的标准如何持续有用:不是通过强制普遍遵守,而是通过解决一个足够多的人拥有的一致问题,以便包含或忽略它都是有意义的。 ¹ (https://brentfitzgerald.com/posts/appreciating-exif/#user-content-fnref-cipa-pdf) CIPA DC-008-Translation-2021, Exif 3.1。PDF 可通过 CIPA 标准页面获取。 ² (https://brentfitzgerald.com/posts/appreciating-exif/#user-content-fnref-containers) 参见 Exif 规范,附件 D,“图像容器中的 Exif 数据结构”。JPEG 使用 APP1;JPEG 2000 使用 UUID 盒子;PNG 使用 eXIf 块;TIFF 是原生的;DNG 是 TIFF 扩展;WebP 使用 EXIF 块;HEIF/AVIF 使用 Exif 数据盒子。 ³ (https://brentfitzgerald.com/posts/appreciating-exif/#user-content-fnref-ifd1) IFD1 是同一 JPEG 文件中的一个辅助 IFD,通过 IFD0 中的指向下一个 IFD 的指针到达。这个指针传统上被设置为指向 IFD1,但并非所有图像都有这个指针。 ⁴ (https://brentfitzgerald.com/posts/appreciating-exif/#user-content-fnref-icc) ICC 配置文件是一种不同类型的元数据,使用单独的容器和规范。Exif 有一个指向它们的标签,但配置文件数据本身是另一种格式。 ⁵ (https://brentfitzgerald.com/posts/appreciating-exif/#user-content-fnref-c2pa-location) C2PA 数据通常位于 JPEG 的 APP1 中,但使用与 Exif 不同的 UUID 引导标识符。许多 JPEG 在其 APP1 段中只包含 Exif 或只包含 C2PA,但理论上它们也可以同时存在,或者一个文件中有多个 APP1 段用于不同的目的。

相似文章

将SQLite结果列映射回其源 `表.列`

Simon Willison's Blog

本研究探索了在任意SQLite查询中,确定每个结果列的源表和源列的方法,通过使用SQLite内部列元数据API(通过Python的apsw库或ctypes桥接访问),并应用于Datasette等工具。

@vintcessun: RAG喂太多文档,检索质量反而从75%掉到40%?向量搜索被大量无关内容稀释,真实部署中命中率暴跌。 问题根源:异构文档混在一起检索,噪声淹没了信号。多智能体编排看似智能,实际引入精度-忠实度悖论——配置稍差就两头不讨好。 论文提出的MA…

X AI KOLs Timeline

This paper identifies 'vector search dilution' in RAG systems when scaling to large heterogeneous document collections, where accuracy dropped from 75% to 40% in a real-world deployment. The proposed MASDR-RAG method uses domain scoping via organizational metadata before retrieval, improving P@10 from 0.77 to 0.86 with low cost and easy deployment.