exiftool-vendored.js

exiftool-vendored.js

Node.js 的高性能跨平台 ExifTool 库

exiftool-vendored.js 为 Node.js 提供快速、跨平台的 ExifTool 访问。这个库具有优异的性能和可靠性,支持读写标签、提取嵌入二进制和恢复元数据。它为常见标签提供强大的类型定义,支持 ExifTool 自动更新,并有完善的测试覆盖。该库被 PhotoStructure 等500多个项目用于处理照片和视频元数据。

ExifToolNode.js元数据跨平台图像处理Github开源项目

exiftool-vendored

快速、跨平台的 Node.js 访问 ExifTool 的方式。由 PhotoStructure 构建和支持。

npm 版本 Node.js CI GitHub 问题 已知漏洞

特性

  1. 同类最佳的跨平台性能和可靠性

    这是 PhotoStructure(以及其他 500+ 个项目)用于读取和写入照片和视频元数据的模块。

    与其他 Node.js ExifTool 模块相比,性能提升可达一个数量级

  2. 尽最大努力提取

    • 带有正确时区偏移编码日期
    • 以浮点数表示的纬度和经度(负值表示在子午线以西或以南)
  3. 支持

  4. 健壮的类型定义,涵盖了超过 6,000 种不同相机品牌和型号使用的 99.5% 的顶级标签(参见示例

  5. 自动更新 ExifTool(新版本频繁发布

  6. 强大的测试覆盖,在 macOS、Linux 和 Windows 上进行

安装

 yarn add exiftool-vendored

 npm install --save exiftool-vendored

调试日志

如果遇到任何问题,首先尝试启用日志记录。

您可以通过 ExifToolOptions.logger 提供一个 Logger 实现,或设置环境变量 NODE_DEBUG=exiftool-vendored查看 debuglog() 文档了解更多详情。

关于在 Electron 中使用

由于每个 Electron 应用程序的设置都不同,而且新版本经常有重大变更,请不要通过在此项目上开 GitHub issue 来寻求帮助

请通过 StackOverflow、Electron discord 或其他渠道寻求帮助。

Electron-builder 支持

electron-builder.ymlasarUnpack 中添加以下模式:

- "node_modules/exiftool-vendored.*/**/*"

默认的 exiftoolPath 实现会自动检测 require 路径中的 app.asar,并将其替换为 app.asar.unpacked

Electron-forge 支持

本库的 25.0 版本添加了对 electron-forge 的实验性支持: 将以下元素添加到 ForgeConfig.packagerConfig.extraResource 字符串数组中,主进程应该就能正常工作。

"./node_modules/exiftool-vendored." + (process.platform === "win32" ? "exe" : "pl")

如果您的主进程 fork 了任何 node 子进程,这些子进程中的 process.resourcesPath 将不会被设置,默认的 exiftoolPath 将无法工作。

如果是这种情况,您必须提供正确的 ExifToolOptions.exiftoolPath 实现, 可以通过 process.env 传递 resourcesPath,或使用其他方法。

安装注意事项

  • exiftool-vendored 通过 optionalDependencies 提供适用于您本地平台的 ExifTool 安装。

  • 除非您知道自己在做什么,否则不应将 exiftool-vendored.exeexiftool-vendored.pl 作为项目的直接依赖项。

  • 如果您在最小化的 Linux 发行版上安装,可能需要安装 perl。在 Alpine 上,运行 apk add perl

  • Node.js 的 -slim docker 镜像不包含可用的 perl 构建。请使用非 slim 镜像。详见问题报告。

  • 如果找不到平台正确的供应商模块(exiftool-vendored.exeexiftool-vendored.pl),系统会在您的PATH中搜索exiftool。请注意,目前支持的Linux发行版中存在一些非常旧版本的exiftool,这个库无法与之正常工作。

升级

有关自上次更新以来的重大变更,请参阅CHANGELOG

主版本号升级

如果现有代码可能受到影响,我会提升主版本号。

我曾多次因为其他库的小版本或补丁版本升级而导致代码出错。我认为在代码变更影响分析中保持悲观态度更好:"过度承诺,少量交付"您的破坏性代码变更。

当您升级到新的主版本时,请在验证自己的系统时多加小心,但如果一切仍然正常工作,也不要感到惊讶。

使用方法

ExifTool有许多配置选项,但所有值都有(或多或少合理的)默认设置。

这些默认设置已用于创建exiftool单例。请注意,如果您不使用默认单例,则无需调用.end()方法。

// 为方便起见,我们在这里使用单例: const exiftool = require("exiftool-vendored").exiftool // 验证一切是否正常工作: exiftool .version() .then((version) => console.log(`我们正在运行ExifTool v${version}`))

如果默认的ExifTool构造函数参数不适合您,它只是一个接受选项哈希的类:

const ExifTool = require("exiftool-vendored").ExifTool const exiftool = new ExifTool({ taskTimeoutMillis: 5000 })

您应该只使用导出的默认exiftool单例,或只创建一个ExifTool实例作为单例。

记得对您使用的单例调用.end()方法。

通用API

ExifTool.read()返回一个Promise,解析为Tags实例。请注意,错误可能通过拒绝promise返回,或对于不太严重的问题,通过errors字段返回。

所有其他公共ExifTool方法都返回Promise<void>,如果操作不成功,将拒绝promise。

Tags类型

ExifTool知道如何提取几千种不同的标签字段。

不幸的是,如果Tags接口很全面,TypeScript会崩溃并显示error TS2590: Expression produces a union type that is too complex to represent

相反,我们从超过10,000种不同的数码相机品牌和型号中构建了一个"常见"标签的语料库,其中许多来自ExifTool元数据存储库和<raw.pixls.us>。

以下是一些示例字段:

/** ★☆☆☆ ✔ 示例:200 */ ISO?: number /** ★★★★ ✔ 示例:1920 */ ImageHeight?: number /** ★★★★ ✔ 示例:1080 */ ImageWidth?: number /** ★★★★ ✔ 示例:"image/jpeg" */ MIMEType?: string

星星表示该字段在示例语料库中有值的常见程度。★★★★字段在超过50%的示例中找到。 ☆☆☆☆字段在不到1%的示例中找到。

勾号表示该字段是否在"流行"相机(如最近的尼康、佳能、索尼和苹果设备)中找到。

Tags的注意事项

Tags中的字段并不全面。

仅仅因为Tags接口中缺少某个字段并不意味着该字段在返回的对象中不存在。换句话说,这个库不会排除未知字段。您和您的代码需要自行查找您期望的其他字段,并将其强制转换为更相关的接口。

日志和事件

要启用此库和底层batch-cluster库的跟踪、调试、信息、警告或错误日志记录,请在ExifTool构造函数选项中提供Logger实例。

ExifTool实例通过batch-cluster发出许多生命周期和错误事件

读取标签

exiftool .read("path/to/image.jpg") .then((tags /*: Tags */) => console.log( `制造商:${tags.Make},型号:${tags.Model},错误:${tags.errors}` ) ) .catch((err) => console.error("发生严重错误:", err))

提取嵌入图像

path/to/image.jpg中提取低分辨率缩略图,将其写入path/to/thumbnail.jpg,并返回一个Promise<void>,当图像提取完成时该promise将被履行:

exiftool.extractThumbnail("path/to/image.jpg", "path/to/thumbnail.jpg")

提取Preview图像(仅在某些图像中找到):

exiftool.extractPreview("path/to/image.jpg", "path/to/preview.jpg")

提取JpgFromRaw图像(在某些RAW图像中找到):

exiftool.extractJpgFromRaw("path/to/image.cr2", "path/to/fromRaw.jpg")

path/to/image.jpg中的"tagname"标签提取二进制值,并将其写入dest.bin(该文件不能已存在,且其父目录必须已存在):

exiftool.extractBinaryTag("tagname", "path/to/file.exf", "path/to/dest.bin")

写入标签

请注意,只有部分标签是可写的。请参考文档并查看"Writable"列。

如果您应用格式错误的值或尝试写入不支持的标签,返回的Promise将被拒绝。

对象的值仅支持字符串和数字基本类型。

要向给定文件写入注释,使其显示在Windows资源管理器属性面板中:

exiftool.write("path/to/file.jpg", { XPComment: "这是一个测试评论" })

要将DateTimeOriginal、CreateDate和ModifyDate标签(使用AllDates快捷方式)更改为2016年2月6日16:56 UTC:

exiftool.write("path/to/file.jpg", { AllDates: "2016-02-06T16:56:00" })

要写入特定元数据组的标签,只需在标签名前加上组名。 (TypeScript用户:你需要进行类型转换才能编译。)

exiftool.write("path/to/file.jpg", { "IPTC:CopyrightNotice": "© 2021 PhotoStructure, Inc.", })

要删除一个标签,将值设为null

exiftool.write("path/to/file.jpg", { UserComment: null })

上面的例子删除了与UserComment标签相关的任何值。

始终注意:时区

如果你编辑时间戳标签,请注意exiftool-vendored使用更改后的时间戳标签与GPS值之间的差异来推断时区。

换句话说,如果你只编辑CreateDate而不编辑GPS时间戳,你的时区要么不正确,要么缺失。有关更多信息,请参阅下面的日期部分。

重写标签

你可能会发现一些图像的元数据已损坏,写入新日期或编辑旋转信息等操作可能会失败。ExifTool可以尝试通过将所有元数据重写到新文件中来修复这些图像,同时保留原始图像内容。有关此功能的更多详细信息,请参阅文档

rewriteAllTags返回一个void Promise,如果出现任何错误,该Promise将被拒绝。

exiftool.rewriteAllTags("problematic.jpg", "rewritten.jpg")

ExifTool配置支持(.ExifTool_config

ExifTool有一个广泛的用户配置系统。有几种使用方法:

  1. 将你的用户配置文件放在你的HOME目录中
  2. EXIFTOOL_HOME环境变量设置为包含用户配置的完全限定路径
  3. 在ExifTool构造函数选项中指定:
new ExifTool({ exiftoolEnv: { EXIFTOOL_HOME: resolve("path", "to", "config", "dir") }

资源卫生

使用完毕后调用ExifTool.end()

你必须显式调用任何使用过的ExifTool实例的.end()方法,以允许node正常退出。

ExifTool子进程会消耗系统资源,并且由于Node.js流的工作方式,会阻止node退出

请注意,你不能在process.on("exit")钩子中调用此方法,因为附加到子进程的stdio流无法被unref。(如果有解决方案,请在上述问题中发帖!)

Mocha v4.0.0

如果你使用mocha v4或更高版本,并且没有调用exiftool.end(),你会发现你的测试套件会挂起。相关变更在此处描述,可以通过添加一个after块来关闭测试中使用的ExifTool实例来解决:

after(() => exiftool.end()) // 假设你的单例名为`exiftool`

日期

你所有图像和视频中的日期元数据很可能都是未完全指定的。

图像和视频很少在其日期中指定时区。如果你的所有文件都是在当前时区捕获的,默认使用本地时区是一个安全的假设,但如果你有在世界不同地方捕获的文件,这个假设将不正确。在世界不同地方解析同一文件会导致同一文件的时间不同。

在7.0.0版本之前,应用了启发式1和3。

从7.0.0版本开始,exiftool-vendored使用以下启发式方法。优先级最高的启发式方法返回的值将用作所有尚未指定时区的日期时间标签的时区偏移。

启发式1:显式元数据

如果存在EXIFTimeZoneOffset标签,它将按照规范应用于DateTimeOriginal,如果有两个值,则也应用于ModifyDate标签。如果存在OffsetTimeOffsetTimeOriginalOffsetTimeDigitized,也会被采纳(但很少设置)。

启发式2:GPS位置

如果存在有效的GPS纬度和经度(值为0, 0被视为无效),将使用tz-lookup库来确定该位置的时区名称。

启发式3:UTC时间戳

如果存在GPSDateTimeDateTimeUTC,只要差值有效,就会使用它们与文件中找到的日期之间的差值作为时区偏移。大于14小时的差值被视为无效。

ExifDate和ExifDateTime

由于日期时间具有这种可选设置的时区,并且某些标签只指定日期,此库返回编码日期、一天中的时间或两者都有的类,带有可选的时区和可选的时区偏移ExifDateTimeExifTime。然后由你来确定什么对你的情况是正确的。

还要注意,一些智能手机记录的时间戳具有微秒精度(不仅仅是毫秒!),ExifDateTimeExifTime都有浮点毫秒。

标签

官方 EXIF 标签名采用 Pascal命名法,如 AFPointSelectedISO。(将字段名"修正"为驼峰命名法会导致难看的 aFPointSelectediSO 这样的畸形)。

Tags 接口由 mktags 脚本自动生成,该脚本解析了超过6,000个独特的相机品牌和型号图像,大部分源自ExifTool网站。mktags 对标签进行分组,提取其类型、使用频率和示例值,以便您的IDE可以自动完成。

标记为"★★★★"的标签,如 MIMEType,应该在大多数文件中都能找到。在几千个元数据标签中,需要意识到通常只有不到50个是常见的。您需要进行研究来确定哪些标签适用于您的用途。

请注意,如果解析失败(例如,日期时间字符串),将返回原始字符串。使用代码时应该合理地验证标签的存在性和类型以确保安全。

序列化

ExifTool.read() 返回的 Tags 对象可以使用 JSON.stringify 序列化为JSON。

要重新构建,请使用 parseJSON() 方法。

import { exiftool, parseJSON } from "exiftool-vendored" const tags: Tags = await exiftool.read("/path/to/file.jpg") const str: string = JSON.stringify(tags) // parseJSON 不验证输入,所以我们不断言它是一个 Tags 实例,但你可以(不安全地)将其转换 const tags2: Tags = parseJSON(str) as Tags

性能

默认的 exiftool 单例是故意限制的。如果可以接受充分利用系统资源:

  1. maxProcs 设置得更高

  2. 考虑将 minDelayBetweenSpawnMillis 设为0

  3. 在性能良好的Linux机器上,较小的 streamFlushMillis 值可能也有效:如果您看到 noTaskData 事件,则需要增加该值。

基准测试

yarn mktags ../path/to/examples 目标会读取示例图像和视频目录层次结构中找到的所有标签,并解析结果。

在2019年的AMD Ryzen 3900X上运行Ubuntu 20.04和SSD的 exiftool-vendored v16.0.0版本,每个线程每秒可以处理20多个文件,或者在利用所有CPU线程时每秒可以处理500多个文件。

批处理模式

使用ExifTool的 -stay_open 批处理模式意味着我们可以在多个请求中重复使用单个ExifTool实例,大大降低响应延迟并减少系统负载。

并行性

为避免系统负担过重,exiftool 单例配置的 maxProcs 设置为当前系统CPU数量的四分之一(最少1个);不会生成超过 maxProcs 数量的 exiftool 实例。但是,如果系统CPU受限,您可能需要更小的值。如果您有非常快的磁盘IO,增加 maxProcs 的值可能会提高速度,但请注意每个子进程可能会消耗100MB的RAM。

作者

贡献者 🎉

更新日志

请查看GitHub上的 CHANGELOG

编辑推荐精选

讯飞智文

讯飞智文

一键生成PPT和Word,让学习生活更轻松

讯飞智文是一个利用 AI 技术的项目,能够帮助用户生成 PPT 以及各类文档。无论是商业领域的市场分析报告、年度目标制定,还是学生群体的职业生涯规划、实习避坑指南,亦或是活动策划、旅游攻略等内容,它都能提供支持,帮助用户精准表达,轻松呈现各种信息。

AI办公办公工具AI工具讯飞智文AI在线生成PPTAI撰写助手多语种文档生成AI自动配图热门
讯飞星火

讯飞星火

深度推理能力全新升级,全面对标OpenAI o1

科大讯飞的星火大模型,支持语言理解、知识问答和文本创作等多功能,适用于多种文件和业务场景,提升办公和日常生活的效率。讯飞星火是一个提供丰富智能服务的平台,涵盖科技资讯、图像创作、写作辅助、编程解答、科研文献解读等功能,能为不同需求的用户提供便捷高效的帮助,助力用户轻松获取信息、解决问题,满足多样化使用场景。

热门AI开发模型训练AI工具讯飞星火大模型智能问答内容创作多语种支持智慧生活
Spark-TTS

Spark-TTS

一种基于大语言模型的高效单流解耦语音令牌文本到语音合成模型

Spark-TTS 是一个基于 PyTorch 的开源文本到语音合成项目,由多个知名机构联合参与。该项目提供了高效的 LLM(大语言模型)驱动的语音合成方案,支持语音克隆和语音创建功能,可通过命令行界面(CLI)和 Web UI 两种方式使用。用户可以根据需求调整语音的性别、音高、速度等参数,生成高质量的语音。该项目适用于多种场景,如有声读物制作、智能语音助手开发等。

Trae

Trae

字节跳动发布的AI编程神器IDE

Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。

AI工具TraeAI IDE协作生产力转型热门
咔片PPT

咔片PPT

AI助力,做PPT更简单!

咔片是一款轻量化在线演示设计工具,借助 AI 技术,实现从内容生成到智能设计的一站式 PPT 制作服务。支持多种文档格式导入生成 PPT,提供海量模板、智能美化、素材替换等功能,适用于销售、教师、学生等各类人群,能高效制作出高品质 PPT,满足不同场景演示需求。

讯飞绘文

讯飞绘文

选题、配图、成文,一站式创作,让内容运营更高效

讯飞绘文,一个AI集成平台,支持写作、选题、配图、排版和发布。高效生成适用于各类媒体的定制内容,加速品牌传播,提升内容营销效果。

热门AI辅助写作AI工具讯飞绘文内容运营AI创作个性化文章多平台分发AI助手
材料星

材料星

专业的AI公文写作平台,公文写作神器

AI 材料星,专业的 AI 公文写作辅助平台,为体制内工作人员提供高效的公文写作解决方案。拥有海量公文文库、9 大核心 AI 功能,支持 30 + 文稿类型生成,助力快速完成领导讲话、工作总结、述职报告等材料,提升办公效率,是体制打工人的得力写作神器。

openai-agents-python

openai-agents-python

OpenAI Agents SDK,助力开发者便捷使用 OpenAI 相关功能。

openai-agents-python 是 OpenAI 推出的一款强大 Python SDK,它为开发者提供了与 OpenAI 模型交互的高效工具,支持工具调用、结果处理、追踪等功能,涵盖多种应用场景,如研究助手、财务研究等,能显著提升开发效率,让开发者更轻松地利用 OpenAI 的技术优势。

Hunyuan3D-2

Hunyuan3D-2

高分辨率纹理 3D 资产生成

Hunyuan3D-2 是腾讯开发的用于 3D 资产生成的强大工具,支持从文本描述、单张图片或多视角图片生成 3D 模型,具备快速形状生成能力,可生成带纹理的高质量 3D 模型,适用于多个领域,为 3D 创作提供了高效解决方案。

3FS

3FS

一个具备存储、管理和客户端操作等多种功能的分布式文件系统相关项目。

3FS 是一个功能强大的分布式文件系统项目,涵盖了存储引擎、元数据管理、客户端工具等多个模块。它支持多种文件操作,如创建文件和目录、设置布局等,同时具备高效的事件循环、节点选择和协程池管理等特性。适用于需要大规模数据存储和管理的场景,能够提高系统的性能和可靠性,是分布式存储领域的优质解决方案。

下拉加载更多