English | 中文
照片元数据瑞士军刀 —— 用 Rust 实现的命令行工具。
无损批量修改照片的 EXIF 元数据:拍摄时间、作者版权、相机镜头、GPS 定位、方向,以及查看与清除。
只改写元数据段,不重新编码图像,照片的压缩像素数据逐比特不变,真正无损。
支持格式:JPEG / PNG / TIFF / WebP / HEIC / AVIF / JXL。
| 子命令 | 作用 |
|---|---|
time |
修改拍摄时间:固定值 / 相对偏移 / 序列递增 / 从文件名提取 |
show |
查看或导出元数据(表格 / JSON / CSV) |
set |
设置常见标签:作者、版权、描述、相机、镜头、方向等 |
gps |
设置或清除 GPS 定位 |
strip |
清除元数据保护隐私:全部 / 仅 GPS |
rotate |
无损旋转标记:在现有方向上叠加旋转/镜像 |
copy |
从一张参考照片复制元数据到一批照片 |
rename |
按拍摄时间批量重命名文件(--from-name 的逆操作) |
xmp |
读写 XMP:标题/描述/作者/评分/关键词/城市等(JPEG 与 PNG) |
iptc |
读写旧版 IPTC-IIM:标题/说明/关键词/作者/城市/版权等(JPEG) |
restore |
从 .bak 备份还原文件,撤销之前的修改 |
geotag |
用 GPX 轨迹按拍摄时间批量地理标记(插值写 GPS) |
apply |
从 CSV 批量导入元数据并写回(表格里批量编辑的写回端) |
report |
统计一批照片的元数据覆盖(拍摄时间/GPS/相机分布/时间跨度) |
verify |
体检:查元数据问题(损坏/坐标越界/时间异常/字段不一致) |
completions |
生成 shell 补全脚本(bash/zsh/fish/powershell)或 man 手册页 |
完整文档在 docs/,每份均有中英双语对照版本:
| 文档 | 说明 |
|---|---|
| 新手入门手册 | 20 分钟入门:安装、安全网、五个真实任务 |
| 用户手册 | 完整参考:16 个命令、每个选项、字段表、格式支持 |
| 审计报告 | 工程审计:架构、发现、安全性、测试覆盖 |
| 功能预研 | 竞品定位、能力差距、候选功能 |
前往 Releases 页 下载对应平台的压缩包,解压即得单个可执行文件:
| 平台 | 下载文件 |
|---|---|
| Windows x64 | pic-killer-<版本>-x86_64-pc-windows-msvc.zip |
| macOS (Apple Silicon) | pic-killer-<版本>-aarch64-apple-darwin.tar.gz |
| macOS (Intel) | pic-killer-<版本>-x86_64-apple-darwin.tar.gz |
| Linux x64 | pic-killer-<版本>-x86_64-unknown-linux-gnu.tar.gz(静态版:…-musl) |
| Linux ARM64 | pic-killer-<版本>-aarch64-unknown-linux-gnu.tar.gz |
每次发布都附带 SHA256SUMS.txt,可校验下载完整性:
sha256sum -c SHA256SUMS.txt需要 Rust 1.88+(代码使用 let-chain):
git clone https://github.com/adomore/pic-killer.git
cd pic-killer
cargo build --release # 产物:target/release/pic-killer
cargo install --path . # 或直接安装到 PATH所有子命令都接受一个或多个文件、目录或通配符作为处理对象:
-r, --recursive递归子目录(目录默认只处理一层)--ext <列表>指定处理的扩展名(默认jpg,jpeg,png,tif,tiff,webp)--where <条件>按元数据筛选要处理的文件(见下)- 内置通配符:
pic-killer set "*.jpg" ...(Windows 的 cmd/PowerShell 不会为外部程序展开*,本工具自己展开*/?)
任何命令都能用 --where 只处理满足条件的文件——例如「只给缺 GPS 的照片补定位」:
pic-killer show .\photos -r --where no-gps # 只列出没有 GPS 的
pic-killer time .\photos -r --where no-date --from-name # 只给缺拍摄时间的从文件名补
pic-killer set .\photos -r --where make=Canon --artist 张三 # 只改 Canon 拍的支持的条件(单条件;大小写不敏感):
| 条件 | 含义 |
|---|---|
has-gps / no-gps |
有/无 GPS 定位 |
has-date / no-date |
有/无拍摄时间 |
has-xmp / no-xmp |
有/无 XMP |
has:名称 / no:名称 |
某标签存在/不存在(覆盖 EXIF/XMP/IPTC) |
名称=值 名称!=值 |
标签值等于/不等于 |
名称~值 名称!~值 |
标签值包含/不包含 |
多个条件可用 &&(都满足)或 ||(任一满足)组合,例如
--where "no-gps && make=Canon"、--where "make=Canon || make=Nikon"。
两者不能混用,混用会直接报错。另外 != / !~ / no: 是取反语义,写了个不存在的标签名
(如 camera!=Canon)本会匹配全部文件,这种情况也会被拒绝——详见
用户手册 §6。
会写入的子命令(time/set/gps/strip/rotate/copy/xmp/iptc/geotag)还支持:
-n, --dry-run仅预览,不写入--backup处理前备份为<文件名>.bak-y, --yes跳过确认提示-v, --verbose详细输出-j, --jobs <N>并行线程数(默认按 CPU 核数自动,1=顺序)
并行处理 + 进度条:这些命令默认多线程处理,大图库批量操作明显更快; 在终端里会显示进度条(画在 stderr,不影响
show --json/--csv等 stdout 输出)。 逐文件写入互不干扰、结果仍按原顺序打印。
# 设为固定时间
pic-killer time .\photos --set "2024-01-01 12:00:00"
# 相对偏移(修相机时钟/时区)——支持 +1y2mo3d4h5m6s 任意组合
pic-killer time .\photos --shift "+2h" -r
pic-killer time .\photos --shift "-3d"
# 序列递增(强制排序),首张起每张 +1 分钟
pic-killer time .\photos --sequential "2021-01-01 08:00:00" --interval "+1m"
# 从文件名提取日期(IMG_20230115_143022.jpg、2022-07-04 09.15.00.jpg 等)
pic-killer time .\photos --from-name偏移单位(大小写不敏感、可组合):y年 mo月 w周 d天 h时 m分 s秒。
注意 m 是分钟、mo 是月;月/年按日历运算。
其它选项:
--tags <列表>写入哪些时间字段:original,digitized,modify(默认全部)--tz <偏移>一并写入时区偏移标签(OffsetTime*),如--tz +08:00--also-file-time同时把文件系统修改时间设为该拍摄时间
# 人类可读表格
pic-killer show .\photo.jpg
# 只看名称含 gps 的标签
pic-killer show .\photo.jpg --filter gps
# 导出为 JSON 或 CSV(便于脚本 / 表格处理)
pic-killer show .\photos -r --json > meta.json
pic-killer show .\photos -r --csv > meta.csv若含 GPS,会额外打印一行十进制经纬度和海拔。
pic-killer set .\photos --artist "张三" --copyright "© 2024 张三"
pic-killer set .\photos --make "Canon" --model "EOS R5" --lens-model "RF 24-70"
pic-killer set .\photo.jpg --description "海边日落" --user-comment "备注"
# 方向(无损旋转标记):normal / cw90 / ccw90 / 180 / mirror-h / mirror-v 或 1-8
pic-killer set .\photo.jpg --orientation cw90
# 通用设置任意字符串或数值标签(可重复)
pic-killer set .\photo.jpg --set-string "OwnerName=Zhang" --set-string "Software=PicKiller"
pic-killer set .\photo.jpg --set-string "iso=100" --set-string "fnumber=2.8" --set-string "exposuretime=1/200"
# 删除指定标签(可重复)
pic-killer set .\photo.jpg --remove artist --remove copyright常用标签的专用选项:--artist --copyright --description --software
--make --model --lens-model --user-comment --owner --orientation。
# 设置坐标(十进制度:北纬/东经为正,南纬/西经为负),海拔可选
pic-killer gps .\photo.jpg --lat 39.9042 --lon 116.4074 --alt 50
# 清除 GPS
pic-killer gps .\photos -r --clear# 清除全部元数据(保护隐私)
pic-killer strip .\photos -r
# 只清除 GPS 定位,保留其它信息
pic-killer strip .\photos -r --gps在照片现有方向基础上叠加旋转/镜像(会与已有方向正确复合,而非简单覆盖)。 这是无损的:只改 EXIF 方向标记,不动像素。
pic-killer rotate .\photo.jpg --cw # 顺时针 90°
pic-killer rotate .\photo.jpg --ccw # 逆时针 90°
pic-killer rotate .\photo.jpg --r180 # 旋转 180°
pic-killer rotate .\photo.jpg --flip-h # 水平镜像
pic-killer rotate .\photo.jpg --flip-v # 垂直镜像
pic-killer rotate .\photos -r --reset # 重置为正常
set --orientation是绝对设定方向码;rotate是在当前方向上相对叠加, 例如对已顺时针 90° 的照片再--cw会变成 180°。
从一张参考照片把元数据复制到一批照片(如整组连拍统一时间/地点)。
# 默认复制全部可复制的元数据(自动跳过尺寸/方向等与具体图像绑定的字段)
pic-killer copy .\burst\*.jpg --from .\reference.jpg
# 只复制拍摄时间,或只复制 GPS
pic-killer copy .\photos -r --from .\ref.jpg --time
pic-killer copy .\photos -r --from .\ref.jpg --gps按拍摄时间批量重命名(time --from-name 的逆操作)。同名自动加序号,无拍摄时间则跳过。
# 默认模板 %Y%m%d_%H%M%S → 20230115_143022.jpg
pic-killer rename .\photos -r
# 自定义模板(strftime 语法,不含扩展名)
pic-killer rename .\photos --pattern "%Y-%m-%d_%H.%M.%S"
# 先预览
pic-killer rename .\photos -r --dry-run读写 XMP 元数据——相机、Lightroom、手机等常把标题、评分、关键词、版权存在这里 (现代 IPTC Core 也是基于 XMP 的)。支持 JPEG 与 PNG(PNG 存于 iTXt chunk)。
XMP 是独立于 EXIF 的元数据块,两者互不影响;写 XMP 会保留所有未识别的既有属性, 只增改指定的那几个。
# 设置标题/描述/作者/评分/关键词
pic-killer xmp .\photo.jpg --title "西湖日出" --description "清晨的西湖" `
--creator "张三" --creator "李四" --rating 5 --keywords "风景,西湖,日出"
# 城市/国家、颜色标签
pic-killer xmp .\photo.jpg --city 杭州 --country 中国 --label 红色
# 通用设置任意属性(前缀:名称=值),删除属性
pic-killer xmp .\photo.jpg --set "photoshop:Headline=头条" --remove dc:description
# 清除整个 XMP 包
pic-killer xmp .\photos -r --clear专用选项:--title --description --creator(可重复) --rights --rating(0-5)
--label --keywords(逗号分隔) --city --country。查看用 show(会额外列出 XMP 段)。
Sidecar .xmp(支持 RAW):加 --sidecar 就写到旁挂的 <主干>.xmp 文件、完全不碰原图。
因为不解析原文件,所以连 little_exif 不认识的 RAW(CR2/NEF/ARW 等)也能写——正是 Lightroom/darktable
读取的那个 sidecar。show 会自动读取并显示 sidecar(原图读不了时也显示)。
pic-killer xmp shot.CR2 --sidecar --title 日出 --rating 5 # 生成 shot.xmp,不动 CR2
pic-killer xmp shot.CR2 --sidecar --clear # 删除 shot.xmp读写旧版 IPTC-IIM 元数据(存于 JPEG 的 APP13 / Photoshop 8BIM 块,新闻/图库工作流常用)。 仅支持 JPEG。写入以 UTF-8 编码并保留其它 8BIM 资源块(缩略图、色彩配置等)。
# 设置标题/说明/关键词/作者/城市/版权
pic-killer iptc .\photo.jpg --title "开幕式" --description "现场" `
--keywords "体育,开幕" --creator "记者甲" --city 北京 --copyright "© 新华社"
# 通用设置(字段名或 记录:数据集)、删除、清除
pic-killer iptc .\photo.jpg --set "2:105=头条" --remove keywords
pic-killer iptc .\photos -r --clear专用选项:--title --description --keywords --creator(可重复) --headline
--city --state --country --copyright --credit --source --instructions。
EXIF、XMP、IPTC 三套元数据彼此独立,可并存于同一张 JPEG,本工具保证互不破坏。
与 --backup 配套:把之前用 --backup 生成的 <文件名>.bak 还原回去,一键撤销修改。
# 先带备份修改
pic-killer set .\photo.jpg --artist 张三 --backup
# 反悔了,一键还原(默认还原后移除 .bak)
pic-killer restore .\photo.jpg
# 保留 .bak 以便反复还原
pic-killer restore .\photos -r --keep-backup
# 先预览哪些文件有备份可还原
pic-killer restore .\photos -r --dry-run没有 .bak 的文件会被跳过;还原是字节级的(.bak 就是原件的完整副本)。
用 GPS 轨迹(.gpx)按拍摄时间给照片批量补 GPS——手机/手表录轨迹,相机没定位时的经典工作流。
按每张照片的拍摄时刻在轨迹里线性插值出经纬度(和海拔)。
# 相机是北京时间,轨迹是 UTC:用 --tz 指明相机时区
pic-killer geotag .\photos -r --gpx .\track.gpx --tz +08:00
# 只给「还没有 GPS」的照片补(配合 --where)
pic-killer geotag .\photos -r --gpx .\track.gpx --tz +08:00 --where no-gps
# 相机时钟慢了 30 秒?用 --offset 修正
pic-killer geotag .\photos --gpx .\track.gpx --offset +30s选项:
--gpx <文件>GPX 轨迹(必填)--tz <偏移>相机时钟的时区,如+08:00(默认按系统本地时区解释拍摄时间)--offset <偏移>额外时间偏移,修正相机时钟误差,如-5m--max-gap <秒>与最近轨迹点相差超过此值则不标记(默认 600)
拍摄时间是本地时间、GPX 时间通常是 UTC,两者需对齐——所以
--tz很关键。 无拍摄时间、或落在轨迹空档(超--max-gap)的照片会被安全跳过。
用一份 file,field,value 三列 CSV 批量写回元数据——配合 show --csv --for-apply 导出,就能
「导出 → 表格里批量编辑 → 写回」。同一文件的多个字段会合并成一次写入(并行、原子)。
pic-killer show .\photos -r --csv --for-apply > meta.csv
pic-killer apply --from meta.csv注意要加
--for-apply。不带它的show --csv是转储格式(五列,含分组与十六进制码, GPS 还被拆成了分量标签),喂不回apply。
CSV 示例(含逗号的值用引号包裹;可带表头,自动跳过;容忍 Excel 的 UTF-8 BOM):
file,field,value
photo1.jpg,artist,张三
photo1.jpg,datetimeoriginal,2023-03-03 12:00:00
photo1.jpg,gps,"31.23,121.47,15"
photo1.jpg,iso,200
photo1.jpg,xmp:title,西湖日出
photo1.jpg,xmp:rating,5
photo1.jpg,iptc:city,杭州字段名加 xmp: / iptc: 前缀即写入对应体系(EXIF/XMP/IPTC 可在同一份 CSV 里混用,同一文件合并成各段一次写入)。
支持的字段(EXIF):datetimeoriginal/createdate/modifydate/alldates、
artist copyright description software make model lensmodel owner 等字符串标签、
数值/有理数标签 iso fnumber exposuretime(可写 1/200) focallength exposurecompensation 等、
orientation、usercomment、gps(值 纬度,经度[,海拔])、gps.clear。
只读地扫描一批照片,汇总元数据覆盖情况——快速看出「有多少缺 GPS/拍摄时间、都是什么相机拍的」。
pic-killer report .\photos -r
pic-killer report .\photos -r --where no-gps # 也可配合 --where输出包含:总数、有/无拍摄时间、有/无 GPS、时间跨度、相机型号分布。
只读地检查一批照片的元数据问题,分「问题」(错误)与「警告」两级:
pic-killer verify .\photos -r检查项:元数据损坏/无法读取、GPS 坐标越界、拍摄时间格式异常、拍摄时间在未来、
DateTimeOriginal 与 CreateDate 不一致、方向值越界(非 1-8)。发现问题时返回非零退出码,
便于脚本/CI 门禁。
# PowerShell:加入 $PROFILE
pic-killer completions powershell | Out-String | Invoke-Expression# bash:写入补全目录
pic-killer completions bash > /etc/bash_completion.d/pic-killer
pic-killer completions --man > pic-killer.1 # man 手册页支持 bash / zsh / fish / powershell / elvish。
JPEG 由若干「段」组成:EXIF 信息放在 APP1 段里,真正的图像像素是独立的压缩扫描数据。 本工具只删除旧的元数据段、插入新的,完全不触碰扫描数据,因此不存在重新压缩、 不会有任何画质损失。用任意图像库解码改前 / 改后的照片,得到的像素完全一致。
- 原子写入:先写临时文件,
fsync后再原子重命名覆盖,批量处理中途中断也不会损坏原文件。 - 默认保护文件时间戳:写入会新建文件,但默认恢复原文件系统 mtime/atime,除非
--also-file-time。 - 可预览可备份:
--dry-run先看再做,--backup留底。
- 元数据往返:底层 EXIF 库(
little_exif)识别数十个常见标签(时间、Make、Model、 Artist、GPS、光圈快门等),这些都会完整保留;但极少数它不认识的冷门标签(部分厂商 MakerNote)在重写时可能丢失。图像像素永远无损。 - HEIC / AVIF / JXL:底层库支持,但成熟度不及 JPEG,建议先用
--backup或--dry-run试跑。 - WebP:仅支持无损与扩展格式的 WebP。
- XMP:支持 JPEG 与 PNG;TIFF/WebP/HEIC 的 XMP 尚未做。
- IPTC-IIM:支持 JPEG(APP13);写入按 UTF-8 编码。
- 缩略图替换暂未支持(涉及 IFD1 数据偏移,风险较高)。
- 旧版 Windows 控制台里中文若显示为乱码,先执行
chcp 65001切到 UTF-8。
MIT