如何修改图像的 EXIF 头信息?
使用exiv2修改图像的EXIF头信息
笔者编写了一个下载 Bing 必应美图的程序。然而笔者一直想修改一下
。当时查阅了"详细信息""属性"等相关信息,但未找到可行方法。
某日通过对比试验发现,修改了详细信息的 JPEG 文件会多出一个"头部",经查证此为 EXIF 头信息,于是有了下文。
编译 Exiv2
下文简要介绍通过搜索找到的 Exiv2 库的编译与使用过程。
从 Exiv2 官网下载了 2017msvc64 的 build 包,加载到项目中即出现编译错误。错误信息显示缺少 std::auto_ptr 类型。该类型在 C++11 中已被弃用,C++17 时已移除。由于项目使用 C++17 标准,因此该类型不再可用。笔者倾向于使用较新的语言标准,因此决定自行编译 Exiv2。
git clone
从仓库拉取最新源码(仓库地址可在官网下载页找到)。
用 VS CMake 编译 Exiv2
笔者对 CMake 并不熟悉,但 Visual Studio 提供了对 CMake 的支持。此前编译 tesseract 时已初步接触过 CMake。
在 exiv2 文件夹中通过右键菜单选择"用 Visual Studio 打开",VS 将自动建立 CMake 缓存,可在"输出"选项卡中查看进度。
随后遇到错误提示找不到 EXPAT,通过 vcpkg 安装解决:
vcpkg install expat:x64-windows
注意:笔者使用 x64 平台编译,因此仅安装 64 位版本;若使用 x86 平台,还需安装对应版本。
vcpkg 在日常项目中表现一般,但在 CMake 场景下十分便捷,缺什么包只需一条命令即可安装。
依赖问题解决后,CMake 缓存正常。检查源码发现已不存在 auto_ptr 相关代码,可能是较新版本已修复此问题。
接下来需要指定 C++17 标准。笔者使用以下配置成功编译并通过测试:
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("/std:c++17" _cpp_17_flag_supported)
if (_cpp_17_flag_supported)
add_compile_options("/std:c++17")
endif()
将上述代码附加到 CMakeLists.txt 末尾,全部生成并安装 Exiv2。
完成 Debug 版本编译后,建议在配置管理器中添加 Release 版本重复编译,以备发布使用。
使用 Exiv2
网上已有的教程多为读取 EXIF 信息,缺少写入的示例。笔者在此补充写入所需的额外步骤。
void BingPicker::addCopyRight(const QString& filepath, const QString& copyright) {
using namespace Exiv2;
// 这里已改用 unique_ptr
Image::UniquePtr image = ImageFactory::open(filepath.toStdString());
assert(image.get());
image->readMetadata();
ExifData ed = image->exifData();
ed["Exif.Image.Copyright"] = copyright.toStdString();
image->setExifData(ed); // 注意此处
image->writeMetadata();
}
写入的关键在于 setExifData 和 writeMetadata 两个调用。笔者此前在网上未找到写入示例,最终在官方文档示例中找到并补全了这两句。
ExifData::operator[] 返回的是一个引用,若键不存在则会直接新建(类似于 map 的 operator[]),用法直观,无需担心段错误。
结尾
本文撰写过程中参考了 StackOverflow 上的问题和回答(包括 CMake 切换 C++ 语言标准的代码)以及两篇 Exiv2 读取 EXIF 的教程。感谢所有相关教程的作者们。
源码已上传至 GitHub,同时提供 Release 版本可供下载。
Hook this up to your favourite commenting platform — Giscus, Disqus, or your own.
