mcpField
P
photo-metadata

photo-metadata

github.com/jamditis创意与媒体43873 次安装4 天前更新
代码仓库

关于 photo-metadata

photo-metadata 是一项技能,用于在照片文件中嵌入并检查编辑、无障碍、版权和图像来源元数据。它介绍 ExifTool 工作流程、审慎撰写说明、移除 GPS,以及 C2PA 处理的限制。

主要功能

  1. 01写入 EXIF、IPTC 和 XMP 元数据
  2. 02添加说明并分别编写替代文本
  3. 03标记 AI 生成或编辑的图像
  4. 04从发布副本中移除 GPS
  5. 05读取 C2PA 清单但不签名
  6. 06写入后核验元数据

适用场景

  1. 01为新闻机构准备新闻照片
  2. 02添加摄影者署名和再利用许可
  3. 03披露图像由 AI 生成或编辑
  4. 04分享前移除敏感位置数据

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jamditis/claude-skills-journalism --skill photo-metadata

安装后在 Claude Code 中输入/photo-metadata确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

embed.py
reference.md
test_embed.py
agents/
openai.yaml

详细介绍

照片元数据

概览

嵌入图像文件的元数据会随文件一起传输。照片内容管理系统(Photo Mechanic、Lightroom、Capture One)和通讯社收稿系统会从照片的 IPTC 和 XMP 区块读取说明文字、署名和权利信息,而不是从单独的文档或收到照片的电子邮件中读取。如果说明文字、署名、替代文本和许可信息不在文件内部,那么照片一经下载、转发或重新上传,这些信息就会消失。

一次 exiftool 操作即可同时写入 EXIF、IPTC 和 XMP 层,并且不会改动其他任何标签(相机设置、拍摄时间)。现代软件会优先读取 XMP,其次是旧版 IPTC-IIM;EXIF 仅用于日期和 GPS 信息,因此应始终写入 XMP,并在 JPEG/TIFF 中额外写入 IIM 作为兼容副本(HEIC、AVIF 和 WebP 都没有 IIM 存储位置;请参见 reference.md)。

自从这套工作流还只是“说明文字、署名、版权”以来,有两件事发生了变化。第一,图像的制作方式如今也应写入元数据:IPTC 的数字来源类型字段会标记照片是由相机拍摄,还是由 AI 生成,Meta、Google 等平台以及欧盟《人工智能法案》也越来越多地读取这一字段。第二,**加密来源凭证(C2PA /“内容凭证”)**正在进入通讯社图片和相机;exiftool 可以读取这一签名层,但无法写入。下文将介绍这两者。

**能力出众的模型已经知道这些字段名称。**难点不在操作方法,而在下文的判断。请优先说明这一点。

适用场景

  • 为通讯社准备新闻照片,让合作新闻编辑室能够搜索、署名并转载
  • 发布或分享照片前,添加必需的摄影师署名和再使用许可
  • 标注图像的制作方式:未经修改的照片、AI 生成的插图、经 AI 编辑的合成图
  • 为一组拍摄作品批量添加标签(一个图像文件夹)
  • 让图像更易于访问(嵌入替代文本),并明确权利状态(版权或知识共享许可)
  • 读取并检查来自机构的图像所含的 C2PA 内容凭证是否合理

**不适用场景:**编辑像素(这里只处理元数据);为 HTML <img> 编写替代文本(请使用 accessibility-compliance);将网页存档以作为证据(请使用 web-archiving);签署内容凭证(exiftool 无法完成,请使用下文提到的 c2patool)。

纪律(Agent 容易犯的错误)

即使能力很强的 Agent 也会犯这些错误。它们比任何标签名称都重要。

  1. **只描述画面中可见的内容。**描述画面展示的内容,而不是别人告诉你的内容。不要推断画面中看不到的事件、意图、身份、关系或法律身份。“示威者聚集抗议法院裁决”是在陈述画面中没有的信息;“人群在法院外举着标语”才是对照片的描述。
  2. **根据可见证据标注人物。**只有在画面中能看到标记、带标签的背心、制服、徽章或臂章时,才注明机构或角色。否则写“身穿战术装备的警员”或“穿蓝色衬衫的男子”。除非画面中的证据明确无误,否则绝不声称某人的移民或法律身份(不写“被拘留者”或“无证移民”)。
  3. **始终编写替代文本,它不是说明文字。**两者都要写:在 XMP-iptcCore:AltTextAccessibility 中写简短的屏幕阅读器描述,在 IPTC:Caption-Abstract 中写可发布的说明文字。IPTC 刻意将两者区分开:说明文字陈述事实并显示在页面上;替代文本则由屏幕阅读器朗读,因此不要把一段文字直接复制到另一处。Agent 经常会写说明文字,却漏掉替代文本。
  4. **标注图像的生成方式,绝不弄虚作假。**如果图像由 AI 生成或经 AI 编辑,请在 XMP-iptcExt:DigitalSourceType 中注明;如果是未经修改的照片,则用 digitalCapture 明确标注。诚实地标注;谨慎处理,并且对于传入文件,绝不删除现有的 Digital Source Type 或 C2PA 凭证,因为这会抹去他人有意添加的披露信息。
  5. **当位置可能危及他人时,删除 GPS 信息。**抗议者、消息来源、虐待幸存者或未成年人,嵌入的坐标可能会暴露其住所或安全屋。从发布用的衍生文件中删除 GPS(-gps:all=),同时保留说明文字和署名;只有当位置信息属于编辑证据时,才保留含完整 GPS 信息的存档母版。GPS 是文件中风险最高的单个标签。
  6. **保持结构化字段中立。**编辑立场或有争议的标签应放在 Headline 中,而不是 City、Caption-Abstract 或位置字段中。合作新闻编辑室会采用自己的措辞;干净的结构化字段能让他们自行处理。
  7. **从源文件验证往返结果。**从写入后的文件中读取元数据,而不是从缓冲区读取。每次上传或传输后,都要从目标位置重新读取;收到 200 响应只能证明字节已被接受,不能证明元数据得以保留。大多数社交平台会在上传时重新编码,并剥除 IPTC、XMP、GPS 以及 C2PA(参见 reference.md),所以“我已嵌入”不等于“它已送达”。

快速参考:承载关键信息的字段

角色IPTC (IIM)XMPEXIF
摄影师By-linedc:CreatorArtist
署名Credit(机构,最多 32 个字符)photoshop:Credit(全名 / 机构)-
说明文字Caption-Abstractdc:DescriptionImageDescription
替代文本(简短)-iptcCore:AltTextAccessibility-
扩展说明-iptcCore:ExtDescrAccessibility(用于复杂图像;不是说明文字)-
制作方式-iptcExt:DigitalSourceType(完整 CV URI)-
关键词Keywords(可重复)dc:Subject-
版权CopyrightNoticedc:RightsCopyright
许可证(CC)-xmpRights:Marked/WebStatement/UsageTerms,cc:License(旧版)-
许可证 / 发现-xmpRights:WebStatement,plus:LicensorName/LicensorURL(Google)-
标题Headlinephotoshop:Headline-
地点Sub-location/City/Province-State/Country-*iptcCore:Location,photoshop:City/State/Country-
日期DateCreatedphotoshop:DateCreatedDateTimeOriginal(权威来源)

Digital Source Type 值(完全由 AI 生成 → trainedAlgorithmicMedia,AI 编辑 → compositeWithTrainedAlgorithmicMedia,直接拍摄的照片 → digitalCapture)、完整的 IPTC 受控词汇表、IPTC-IIM 字节限制、PLUS/Google 许可和 Creative Commons 字段集、C2PA 工具,以及 AP 说明文字配方:请参阅 reference.md。

一次性写入全部三个层

CAPTION="A crowd holds signs outside the Mercer County Courthouse, Friday, June 19, 2026, in Trenton, N.J. (Dana Rivera/Example News Collective)"
ALT="A crowd of people holding handmade signs stands on the steps of a stone courthouse."
# how the image was made, a full IPTC CV URI (see reference.md for all values)
DST="http://cv.iptc.org/newscodes/digitalsourcetype/digitalCapture"

exiftool -codedcharacterset=utf8 -overwrite_original -P \
  -EXIF:Artist="Dana Rivera" -XMP-dc:Creator="Dana Rivera" -IPTC:By-line="Dana Rivera" \
  -IPTC:Credit="Example News Collective" -XMP-photoshop:Credit="Dana Rivera / Example News Collective" \
  -IPTC:Caption-Abstract="$CAPTION" -XMP-dc:Description="$CAPTION" -EXIF:ImageDescription="$CAPTION" \
  -XMP-iptcCore:AltTextAccessibility="$ALT" \
  -XMP-iptcExt:DigitalSourceType="$DST" \
  -IPTC:Keywords="protest" -IPTC:Keywords+="Trenton" \
    -XMP-dc:Subject="protest" -XMP-dc:Subject+="Trenton" \
  -EXIF:Copyright="(c) 2026 Example News Collective. Licensed CC BY 4.0." \
    -IPTC:CopyrightNotice="(c) 2026 Example News Collective. CC BY 4.0." \
    -XMP-dc:Rights="(c) 2026 Example News Collective. Licensed CC BY 4.0." \
  -XMP-xmpRights:Marked=True \
    -XMP-xmpRights:WebStatement="https://creativecommons.org/licenses/by/4.0/" \
    -XMP-xmpRights:UsageTerms="Licensed CC BY 4.0. Credit: Dana Rivera / Example News Collective." \
    -XMP-cc:License="https://creativecommons.org/licenses/by/4.0/" \
    -XMP-cc:AttributionName="Dana Rivera / Example News Collective" \
  -IPTC:City="Trenton" -IPTC:Province-State="New Jersey" \
    -IPTC:Country-PrimaryLocationName="United States" -IPTC:Country-PrimaryLocationCode="USA" \
  "-IPTC:DateCreated<EXIF:DateTimeOriginal" "-IPTC:TimeCreated<EXIF:DateTimeOriginal" \
    "-XMP-photoshop:DateCreated<EXIF:DateTimeOriginal" \
  photo.jpg

-P 会保留文件的修改时间;如果希望写入时更新时间戳,请去掉它。复杂图像(图表、信息图)的扩展无障碍说明应写入 XMP-iptcCore:ExtDescrAccessibility,这是一个与说明文字分开的字段,仅在替代文本加上周围文字仍无法传达图像内容时添加。

然后从文件中验证(这是 Agent 会跳过的步骤):

exiftool -G1 -s -IPTC:By-line -IPTC:Caption-Abstract -XMP-iptcCore:AltTextAccessibility \
  -XMP-iptcExt:DigitalSourceType -XMP-cc:License -IPTC:Keywords photo.jpg

标注图像的制作方式(AI 和合成内容)

XMP-iptcExt:DigitalSourceType 使用 IPTC 受控词汇表记录内容来源。其值必须是完整 URI;exiftool 不会对其进行验证,因此裸词或拼写错误会被静默接受,毫无用处。每家新闻编辑室都需要的三个值:

BASE="http://cv.iptc.org/newscodes/digitalsourcetype"
# a straight camera photo, worth stating even for real news images
exiftool -XMP-iptcExt:DigitalSourceType="$BASE/digitalCapture" photo.jpg
# fully AI-generated (a trained model produced the whole image)
exiftool -XMP-iptcExt:DigitalSourceType="$BASE/trainedAlgorithmicMedia" ai.jpg
# a real photo edited with generative AI (inpaint / outpaint / generative fill)
exiftool -XMP-iptcExt:DigitalSourceType="$BASE/compositeWithTrainedAlgorithmicMedia" edited.jpg

Meta 和 Google 会读取此字段以自动标记 AI 内容;欧盟《AI 法案》的机器可读披露义务(第 50 条,自 2026 年 8 月起执行)正推动这项功能从锦上添花变为必需。IPTC 2025.1 新增了配套字段:AISystemUsed、AISystemVersionUsed、AIPromptInformation、AIPromptWriterName(exiftool ≥ 13.40)。完整词汇表以及应避免使用的已弃用术语:请参阅 reference.md。

内容凭证(C2PA):exiftool 可以读取,但无法签名

内容凭证是一份经过加密签名、与图像像素绑定的 C2PA 清单,记录了图像的创作者、使用的工具,以及是否涉及 AI。如今,越来越多的相机(Leica M11-P、Nikon Z6III、Sony Alpha)和机构(AFP、AP、BBC 试点项目)开始采用内容凭证。它与 IPTC/XMP 属于不同层面,回答的问题也不同:不是“文件声称了什么”,而是“谁签署了它,以及它此后是否被更改”。

exiftool 可以读取,但无法写入或验证:

exiftool -G1 -a -jumbf:all incoming.jpg     # report the C2PA/JUMBF manifest (no signature check)

这会将清单显示为数据,并不会验证签名或签署者。如需真正验证,请将文件上传到 verify.contentauthenticity.org,确认签署者是你预期的机构。如需创建凭证,请使用 Adobe/CAI 工具、c2patool(brew install c2patool)或 pip install c2pa-python,而不是 exiftool。

向已签名文件写入元数据会破坏其凭证。 C2PA 硬绑定会对素材进行哈希,而哈希值包含嵌入的元数据,因此,任何 exiftool 写入、说明文字、署名、GPS 清除操作,甚至本技能中的标记,都会导致清单仍然存在,但变为无效。“绝不移除凭证”是必要条件,但并不足够。对于收到的已签名文件,要么保持原件不变,并在之后会用 c2patool 重新签名的衍生文件上处理元数据;要么接受嵌入的凭证不再有效,并如实说明。不要将元数据嵌入已签名原件后,仍把它的凭证视为有效。

向新闻编辑室说明时,还应提醒两点:有效凭证只能证明签名和信任链有效,不能证明场景真实(相机完全可以为屏幕照片签名);大多数社交平台会在上传时移除清单,因此平台上的来源信息往往只能通过“持久化”水印/指纹恢复来保留。参见 reference.md。

清除 GPS,生成适合发布的衍生文件

移除位置信息,同时保留说明文字、署名、版权和来源类型:

exiftool -gps:all= "-xmp:GPS*=" -overwrite_original photo.jpg
exiftool -a -G1 -gps:all "-xmp:GPS*" photo.jpg   # verify, this must print nothing

请使用 -xmp:GPS*= 通配符,而不只是三个主要坐标:目的地和图像方向字段(GPSDestLatitude、GPSImgDirection)同样属于位置信息,否则会被保留下来。请将包含完整 GPS 信息的文件作为锁定的归档主文件保存,在坐标属于编辑证据(地理定位、核验)时尤其如此。发布时使用已清除 GPS 的副本。标记完成后,embed.py --strip-gps 可对整个文件夹执行此操作。

可在 Google 图片搜索中显示的许可信息

如需获得 Google 图片搜索中的“可授权使用”徽章和可用的“获取此图片”链接,请设置权利声明网页(触发条件)和 PLUS 许可方字段:

exiftool -XMP-xmpRights:Marked=True \
  -XMP-xmpRights:WebStatement="https://example.org/license/photo123" \
  -XMP-plus:LicensorName="Example News" -XMP-plus:LicensorURL="https://example.org/buy/photo123" \
  photo.jpg

权利声明网页对应的是 xmpRights:WebStatement,而不是 dc:Rights,这是一个常见且代价高昂的混淆。Creative Commons 许可证也通过同一个 WebStatement 字段,使用 CC 许可协议页面 URL。详情和完整的 PLUS 字段集:reference.md。

批量标记文件夹

处理一次拍摄的文件时,可通过清单驱动 exiftool,而不必为每个文件单独运行命令。本目录中的 embed.py 接受一个文件夹和一个 JSON 清单(包含固定的署名、许可、许可方和数字来源类型字段,以及每张图片各自的替代文本、说明文字、扩展描述、关键词和可选的来源类型覆盖值),写入已标记的副本,读回每个副本以确认元数据已写入,并可通过 --strip-gps 移除副本中的 GPS 信息。它接受数字来源类型的简写(digitalCapture)或完整 URI;对于其他值会直接拒绝,而不会嵌入无效值。运行 python3 embed.py --help。

常见错误(基准测试所得)

错误修正方法
写了说明文字,却没有替代文本始终也要填写 AltTextAccessibility,它们是不同的字段
将说明文字复制到替代文本(或 ExtDescrAccessibility)中IPTC 将两者区分开来;请撰写适合屏幕阅读器的实际描述,仅对复杂图像使用 ExtDescr
By-line/Credit/City 被静默截断这些 IIM 字段最多可容纳 32 个字符;请将完整署名放在 XMP-photoshop:Credit 中
说明文字描述了画面中没有的内容只描述可见内容;将无法看到的背景信息移到其他位置
AI 生成的图像未标注将 DigitalSourceType 设为 trainedAlgorithmicMedia(或正确的复合值)
DigitalSourceType 设置成了单独的词语该值必须是完整的 http://cv.iptc.org/... URI;exiftool 不会验证它
删除了收到文件中的 Digital Source Type 或 C2PA切勿删除披露信息;请保留所接收文件的来源信息
发布时仍嵌有 GPS 信息当位置信息可能危及主体或信息来源时,使用 -gps:all= 将其删除
将 WebStatement 放入 dc:RightsGoogle/许可网页声明应放在 xmpRights:WebStatement 中
将编辑立场标签放在 City 或说明文字中将框架信息放在 Headline 中;结构化字段应保持中立
误以为上传后元数据仍然保留从目标位置重新读取;大多数社交平台都会删除 IPTC/XMP/GPS/C2PA 信息
将关键词写成用逗号连接的单个字符串请写入可重复的 Keywords 记录(以及 dc:Subject 列表)
仅以纯文本添加 CC 许可说明添加 xmpRights:WebStatement(CC deed URL)+ xmpRights:Marked

现实影响

嵌入式元数据能让合作新闻编辑室找到照片、正确署名,并在明确的许可下重新发布,而无需联系摄影师。如今,图像也会通过元数据说明是由人还是模型制作,并携带经过签名的 Content Credential。一旦这些信息被删除,同一张照片就会变成一份无主文件:没有署名,没有许可,也没有来源信息。

评论

支持 Markdown