尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
10种Exif标签类型一文讲透:node-exif核心算法extractExifEntry源码深度剖析
10种Exif标签类型一文讲透node-exif核心算法extractExifEntry源码深度剖析【免费下载链接】node-exifA node.js library to extract Exif metadata from images.项目地址: https://gitcode.com/gh_mirrors/no/node-exifnode-exif是一个 Node.js 的Exif 元数据提取库只需一行代码就能从 JPEG 图片中解析出相机型号、拍摄时间、光圈快门、GPS 坐标等信息。本文将深入 lib/exif/ExifImage.js 中的核心函数extractExifEntry把 Exif 标签的10 种数据类型一次讲透并带你完整走一遍从 JPEG 字节流到结构化 JSON 的解析全流程。上图是测试目录中的一张索尼 ILCE-6000 样片node-exif 能从中提取出曝光参数、镜头信息E PZ 16-50mm等完整 Exif 标签。一、30秒认识 node-exif安装与快速上手安装只需一条命令npm install exif使用方式极其简单完整说明见 README.mdvar ExifImage require(exif).ExifImage; new ExifImage({ image: myImage.jpg }, function (error, exifData) { console.log(exifData); // 结构化后的全部 Exif 数据 });解析结果固定分为 6 个分组对应 JPEG 中不同的 IFD信息字典区域分组对应区域典型标签imageIFD0主图信息Make、Model、OrientationthumbnailIFD1缩略图ThumbnailOffset、ThumbnailLengthexifExif IFDFNumber、ISO、FocalLengthgpsGPS IFDGPSLatitude、GPSLongitudeinteroperabilityInterop IFDInteropIndexmakernote厂商私有区富士/奥林巴斯等私有标签二、解析全流程从 JPEG 字节流到标签表在理解 10 种标签类型之前先看清 node-exif 是如何找到 Exif 数据的。整个入口是 lib/exif/ExifImage.js 中的processImage校验 JPEG 头文件前 2 字节必须是0xFFD8否则抛出NOT_A_JPEG错误扫描 APP1 段循环读取以0xFF开头的各段找到0xFFE1APP1 段即停验证 Exif 魔数段内前 6 字节必须是Exif\0\0判定字节序TIFF 头为0x4949II小端或0x4D4DMM大端并校验0x002A魔数。文件名short-ascii-II正是小端II编码的佳能 S40 样片与大端MM样片short-ascii-MM.jpg一起覆盖了两种字节序的测试场景预期结果保存在同目录的 test/short-ascii-II.jpg.json 中。字节序判定完成后extractExifData依次解析 IFD0 → IFD1 → Exif IFD → GPS IFD → Interop IFD → Makernote每个 IFD 循环调用的都是同一个函数——extractExifEntry。这就是本文的主角。三、核心算法extractExifEntry 如何解码一条标签先建立背景知识Exif 数据本质是TIFF 格式每个 IFD 是一条字典链表而每条标签记录固定 12 个字节┌─────────┬─────────┬──────────┬────────────────────┐ │ Tag ID │ Format │ Count │ Value / Offset │ │ 2 字节 │ 2 字节 │ 4 字节 │ 4 字节 │ └─────────┴─────────┴──────────┴────────────────────┘Tag ID标签编号如0x829D是光圈 FNumberFormat数据类型也就是本文重点的10 种标签类型Count该类型的数据个数Value值本身或指向真实存储位置的偏移指针。extractExifEntry的骨架lib/exif/ExifImage.js分三步// 第1步读出 Tag ID、Format、Count 三个字段 var entry { tagId : null, format : data.getShort(entryOffset 2, isBigEndian), components: data.getLong(entryOffset 4, isBigEndian), ... }; // 第2步在 TAGS 字典中查名字查不到直接丢弃 if (tags tags[entry.tagId] typeof tags[entry.tagId] function) { entry.tagName tags[entry.tagId].call(this, entry); } else if (tags tags[entry.tagId]) { entry.tagName tags[entry.tagId]; } else { return false; // 未知标签安全跳过 } // 第3步根据 format 的 10 种类型走 switch 分支解码 switch (entry.format) { case 0x0001: // BYTE ... case 0x0002: // ASCII ... // 共 10 个 case } 注意isBigEndian参数被传入了每一次字节读取——这正是大端/小端通吃的关键。底层的getShort、getLong、getString等方法都由 lib/exif/Buffer.js 扩展在 Buffer 原型上例如getLong会按字节序拼接 4 个字节并做无符号化处理。标签名查表用的字典是ExifImage.TAGSlib/exif/ExifImage.js包含约 400 个 Exif/通用 TIFF 标签和 32 个 GPS 标签。3.1 10种Exif标签类型完整清单switch 分支里恰好覆盖 TIFF 规范定义的10 种数据格式这是理解一切 Exif 解析器的钥匙序号常量类型名每元素大小源码解码方式真实标签举例10x0001BYTE无符号字节1 字节循环getByteResolutionUnit20x0002ASCII字符串1 字节getString 去尾部\0MakeSONY30x0003SHORT无符号短整型2 字节循环getShortOrientation、ISO40x0004LONG无符号长整型4 字节循环getLongExifOffset、ThumbnailLength50x0005RATIONAL无符号分数8 字节分子getLong÷ 分母getLongExposureTime 1/8060x0006SBYTE有符号字节1 字节getSignedByte有符号小值70x0007UNDEFINED原始字节1 字节slice整段保留ExifVersion0230二进制形式80x0008SSHORT有符号短整型2 字节getSignedShort有符号中值90x0009SLONG有符号长整型4 字节getSignedLong有符号大值100x000ASRATIONAL有符号分数8 字节有符号分子÷分母ExposureCompensation三个值得记住的设计细节分数即两整数RATIONAL 由 4 字节分子 4 字节分母组成源码直接相除得到浮点数。所以索尼样片的ExposureTime: 6、FNumber: 8都来自这一步除法UNDEFINED 不解释类型 7 表示规范未定义的字节串如 ExifVersionnode-exif 用slice原样保留为 Buffer不做臆测——你在 test/sony-alpha-6000.jpg.json 中能看到ExifVersion:{type:Buffer,data:[48,50,51,48]}即 ASCII 的0230未知类型直接返回 falseswitch 的default分支丢弃该条保证遇到脏数据不会崩溃。3.2 黄金法则值放哪内联还是指针第 4 个字段的 4 字节到底是值本身还是指针源码给出了每条类型的判定阈值这是整个算法最精妙的部分case 0x0001: // BYTE≤4 个元素直接内联 entry.valueOffset (entry.components 4) ? entryOffset 8 : data.getLong(entryOffset 8, isBigEndian) tiffOffset; case 0x0005: // RATIONAL一个元素就要 8 字节永远走指针 entry.valueOffset data.getLong(entryOffset 8, isBigEndian) tiffOffset;规则一句话总结值总字节数 ≤ 4 就内联写在第 9~12 字节否则第 9~12 字节存的是相对 TIFF 头的偏移量。注意指针还原时要 tiffOffset把相对 TIFF 头的偏移换算成相对文件开头的偏移——缩略图数据定位就靠它。四、IFD 链与 MakerNote标签的六大归宿extractExifDatalib/exif/ExifImage.js中每个 IFD 都是相同的三段式循环读条目数 → 逐条调用extractExifEntry步长 12 字节→ 写入对应分组。evil1.jpg 是一张带缩略图的佳能样片解析时thumbnail分组会得到 ThumbnailOffset/ThumbnailLength可用于从原文件中切出缩略图。4.1 安全防线maxEntries 防恶意图片每个 IFD 的条目数都受选项钳制如ifd0MaxEntries、maxEntries默认上限DEFAULT_MAX_ENTRIES 128。这是典型的DoS 防护恶意构造的图片若声明百万条标签解析也最多只跑 128 条就停。4.2 MakerNote六大厂商私有格式0x927CMakerNote比较特殊——它不是普通标签而是一整块厂商私有数据。源码在提取时记下它的偏移然后按头部分流头部特征厂商解析模块OLYMP\0奥林巴斯lib/exif/makernotes/olympus.jsAGFA \0爱克发lib/exif/makernotes/agfa.jsEPSON\0爱普生lib/exif/makernotes/epson.jsFUJIFILM富士lib/exif/makernotes/fujifilm.jsPanasonic松下lib/exif/makernotes/panasonic.jsSANYO三洋lib/exif/makernotes/sanyo.js⚠️ 一个真实的反面教材索尼样片 sony-alpha-6000.jpg 的 MakerNote 头部是SONY DSC不在支持列表中所以其 test/sony-alpha-6000.jpg.json 里makernote分组是makernote: { error: Unable to extract Makernote information as it is in an unsupported or unrecognized format. }想支持新厂商在makernotes/目录仿写一个模块、在分流处加一行头部判断即可。五、动手验证4 张官方测试图覆盖全场景test/api-test.js 中的测试思路值得借鉴每张 jpg 都有一份.jpg.json预期结果断言实际输出与预期逐字节一致。四张图恰好覆盖了算法的四个关键路径测试图特点验证点evil1.jpg佳能 S400带缩略图APP1 扫描 IFD1 缩略图short-ascii-II.jpg佳能 S40小端 II字节序处理short-ascii-MM.jpg大端 MM字节序处理right.jpg极简元数据空 IFD 边界情况right.jpg 的 Exif 区只有 Orientation、XResolution 等寥寥数条标签其 test/right.jpg.json 中 thumbnail/exif/gps 分组全为空对象——extractExifEntry对空 IFD 的优雅降级正是靠返回false后continue实现的。六、总结一张图记住 extractExifEntry 的精髓12 字节一条Tag ID Format Count Value/OffsetIFD 就是这样的记录数组10 种 FormatBYTE / ASCII / SHORT / LONG / RATIONAL / SBYTE / UNDEFINED / SSHORT / SLONG / SRATIONALswitch 分支逐一解码4 字节内联法则值 ≤ 4 字节直接内联否则存指针记得 tiffOffset防御式解析未知标签返回false、maxEntries限流、未识别 MakerNote 降级为 error 字段——健壮性来自对脏数据的预设扩展点清晰加标签改TAGS字典加厂商写makernotes/模块。掌握这套12 字节 × 10 类型的心智模型后你不仅读懂了 node-exif也具备了阅读任何语言 Exif 解析器的底层能力。【免费下载链接】node-exifA node.js library to extract Exif metadata from images.项目地址: https://gitcode.com/gh_mirrors/no/node-exif创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED

相关推荐

external-snapshotter转换Webhook揭秘:v1beta1与v1beta2组快照API双向转换的完整实现原理

external-snapshotter转换Webhook揭秘:v1beta1与v1beta2组快照API双向转换的完整实现原理

external-snapshotter转换Webhook揭秘:v1beta1与v1beta2组快照API双向转换的完整实现原理 【免费下载链接】external-snapshotter Sidecar container that watches Kubernetes Snapshot CRD objects and triggers CreateSnapshot/DeleteSnapshot against a CSI endp…

📅 2026/10/12 16:27:44
3步搞定res-downloader视频解密

3步搞定res-downloader视频解密

3步搞定res-downloader视频解密 【免费下载链接】res-downloader 视频号、小程序、抖音、快手、小红书、直播流、m3u8、酷狗、QQ音乐等常见网络资源下载! 项目地址: https://gitcode.com/GitHub_Trending/re/res-downloader 从视频号下载的视频打不开,播放器…

📅 2026/10/3 12:00:55
LLM智能体安全:防御收敛性绕道劫持的资源滥用攻击

LLM智能体安全:防御收敛性绕道劫持的资源滥用攻击

1. 从“智能体失控”说起:一个被忽视的威胁场景 最近在折腾基于大语言模型的智能体(LLM Agents)时,我遇到了一个相当棘手且细思极恐的问题。我们通常关注智能体能否完成任务、回答是否准确,但很少深入思考:…

📅 2026/10/3 14:12:23
MORE NEWS

更多资讯

📰

CATIA V5R18 CAA二次开发完整环境搭建与调试指南

简介:本资源是面向CATIA二次开发工程师与高级应用人员的CAA(Customer Adaptation Area)定制化开发套件,专为CATIA V5R18版本构建,助力用户突破标准功能限制,实现界面定制、流程自动化及企业级系统集成。压缩…

📰

应用系统负载分析与磁盘容量预测:一套完整的Python源码实践解析

简介:资源内含一份基于数据挖掘的应用系统负载分析与磁盘容量预测Python源码包,面向系统运维、数据分析与机器学习初学者,解决如何在历史负载数据基础上建立容量预测模型的问题。压缩包共6个文件,包含4个xls格式的数据文件&#x…

📰

PyQt5与YOLOv5桌面检测工具:环境搭建、线程优化与避坑指南

简介:这份资源是一套面向PyQt5与YOLOv5初学者的多目标检测GUI实战项目,适合刚接触界面开发或YOLO算法、希望有现成工程练手的人群。项目以PyTorch为深度学习框架,将YOLOv5检测能力与PyQt5界面结合,重点演示界面设计与后端逻辑分离…

📰

OpenLayers创建点要素全流程:从坐标系到样式与交互实战

做WebGIS开发,接触OpenLayers的第一件事基本都是往地图上画东西。画个点、连条线、圈个面,说到底都是在做同一件事——创建要素(Feature)。我刚入行的时候,前辈丢给我一句“去看官方示例”,结果一打开示例代…

📰

LCTFP代码实战:基于CNN与LSTM的高速公路交通流量预测

简介:基于CNN和LSTM组合的高速公路交通流量预测模型LCTFP完整Python实现,面向交通流量时空建模研究者与开发者,可用于短时交通流预测及类似时序任务。模型以1D CNN提取短时交通流空间特征,LSTM捕捉时间特征,有效融合时…

📰

OpenClaw 2.7.9 对接飞书机器人完整分步实操教程(含安装包)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬