photo-metadata

GitHub

用于嵌入图片IPTC/EXIF/XMP元数据、AI来源标签及GPS剥离,确保新闻图片版权与可追溯性。

journalism-core/skills/photo-metadata/SKILL.md jamditis/claude-skills-journalism

Trigger Scenarios

为通讯社准备新闻照片以添加标题和授权 批量标记拍摄文件夹中的图像元数据 验证或读取图片中的C2PA内容凭证

Install

npx skills add jamditis/claude-skills-journalism --skill photo-metadata -g -y
More Options

Non-standard path

npx skills add https://github.com/jamditis/claude-skills-journalism/tree/master/journalism-core/skills/photo-metadata -g -y

Use without installing

npx skills use jamditis/claude-skills-journalism@photo-metadata

指定 Agent (Claude Code)

npx skills add jamditis/claude-skills-journalism --skill photo-metadata -a claude-code -g -y

安装 repo 全部 skill

npx skills add jamditis/claude-skills-journalism --all -g -y

预览 repo 内 skill

npx skills add jamditis/claude-skills-journalism --list

SKILL.md

Frontmatter
{
    "name": "photo-metadata",
    "description": "Embeds photo IPTC\/EXIF\/XMP metadata, caption, credit, alt text, license, AI-source label, GPS stripping, and C2PA credentials."
}

Photo metadata

Overview

Metadata embedded in an image file travels with the file. Photo CMSs (Photo Mechanic, Lightroom, Capture One) and wire intake systems read a photo's caption, credit, and rights from its IPTC and XMP blocks, not from a separate document or the email it arrived in. If the caption, credit, alt text, and license are not inside the file, they are gone the moment the photo is downloaded, forwarded, or re-uploaded.

One exiftool pass writes the EXIF, IPTC, and XMP layers together and leaves every other tag (camera settings, shot time) untouched. Modern software reads XMP first, legacy IPTC-IIM second, EXIF only for date and GPS, so write XMP everywhere and add IIM as a compatibility copy on JPEG/TIFF (HEIC, AVIF, and WebP have no IIM slot at all; see reference.md).

Two things changed since this workflow was "caption, credit, copyright." First, how an image was made now belongs in the metadata: the IPTC Digital Source Type field labels a camera photo versus an AI-generated one, and platforms (Meta, Google) and the EU AI Act increasingly read it. Second, cryptographic provenance (C2PA / "Content Credentials") is arriving on wire images and cameras, a signed layer exiftool can read but not write. Both are covered below.

A capable model already knows the field names. The hard part is not the mechanics, it is the judgment below. Lead with that.

When to use

  • Prepping press photos for a wire so partner newsrooms can search, credit, and republish them
  • Adding required photographer attribution and a reuse license before publishing or sharing
  • Labeling how an image was made, a straight photo, an AI-generated illustration, an AI-edited composite
  • Batch-tagging a shoot (a folder of images)
  • Making images accessible (embedded alt text) and rights-clear (copyright or Creative Commons)
  • Reading and sanity-checking the C2PA Content Credentials on an image that arrived from an agency

When not to use: editing pixels (this is metadata only); writing alt text for an HTML <img> (use accessibility-compliance); preserving web pages as evidence (use web-archiving); signing a Content Credential (exiftool can't, use c2patool, below).

The discipline (what agents get wrong)

These are the failures a capable agent makes anyway. They matter more than any tag name.

  1. Caption only what is visible. Describe what the frame shows, not what you were told. Do not infer events, intent, identities, relationships, or legal status you cannot see. "Demonstrators gather to protest a court ruling" is a claim about facts not in the frame; "A crowd holds signs outside a courthouse" is the photo.
  2. Label people from visible evidence. Name an agency or role only from a visible marking, a labeled vest, a uniform, a badge, a patch. Otherwise write "officers in tactical gear," "a man in a blue shirt." Never assert someone's immigration or legal status (no "detainee," no "undocumented") unless it is unambiguous in the frame.
  3. Always write alt text, it is not the caption. Write both: a short screen-reader description in XMP-iptcCore:AltTextAccessibility and the publishable caption in IPTC:Caption-Abstract. IPTC keeps these deliberately distinct, the caption states facts and is shown on the page; the alt text is read aloud by a screen reader, so do not just copy one into the other. Agents routinely write the caption and skip the alt text.
  4. Label how the image was made, and never lie about it. If an image is AI-generated or AI-edited, say so in XMP-iptcExt:DigitalSourceType; if it is a straight photo, digitalCapture states that plainly. Do the honest thing and label it; do the diligent thing and, on an inbound file, never strip an existing Digital Source Type or C2PA credential, that erases a disclosure someone made on purpose.
  5. Strip GPS when the location could endanger someone. A protester, a source, an abuse survivor, a minor, embedded coordinates can reveal a home or a safe house. Remove GPS from the published derivative (-gps:all=) while keeping the caption and credit; keep a full-GPS archival master only where location is editorial evidence. GPS is the single highest-risk tag in the file.
  6. Keep structured fields neutral. Editorial framing or a contested label belongs in Headline, never in City, Caption-Abstract, or the location fields. Partner newsrooms apply their own language; clean structured fields let them.
  7. Verify the round-trip from source. Read the metadata back from the written file, not from your buffer. After any upload or transfer, re-read it from the destination, a 200 response proves the bytes were accepted, not that the metadata survived. Most social platforms re-encode on upload and strip IPTC, XMP, GPS, and C2PA (see reference.md), so "I embedded it" is not "it arrived."

Quick reference, the fields that carry the weight

Role IPTC (IIM) XMP EXIF
Photographer By-line dc:Creator Artist
Credit Credit (org, max 32 chars) photoshop:Credit (full name / org) -
Caption Caption-Abstract dc:Description ImageDescription
Alt text (short) - iptcCore:AltTextAccessibility -
Extended description - iptcCore:ExtDescrAccessibility (complex images; not the caption) -
How it was made - iptcExt:DigitalSourceType (full CV URI) -
Keywords Keywords (repeatable) dc:Subject -
Copyright CopyrightNotice dc:Rights Copyright
License (CC) - xmpRights:Marked/WebStatement/UsageTerms, cc:License (legacy) -
License / discovery - xmpRights:WebStatement, plus:LicensorName/LicensorURL (Google) -
Headline Headline photoshop:Headline -
Location Sub-location/City/Province-State/Country-* iptcCore:Location, photoshop:City/State/Country -
Date DateCreated photoshop:DateCreated DateTimeOriginal (source of truth)

Digital Source Type values (fully AI → trainedAlgorithmicMedia, AI-edited → compositeWithTrainedAlgorithmicMedia, straight photo → digitalCapture), the full IPTC controlled vocabulary, the IPTC-IIM byte limits, the PLUS/Google-licensing and Creative Commons field sets, the C2PA tooling, and the AP caption recipe: see reference.md.

One pass that writes all three layers

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 preserves the file's modification time; drop it if you want the write to touch the timestamp. Extended accessibility descriptions for complex images (charts, infographics) go in XMP-iptcCore:ExtDescrAccessibility, a separate field from the caption, added only when the alt text plus surrounding text can't convey the image.

Then verify from the file (the step agents skip):

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

Label how an image was made (AI and synthetic)

XMP-iptcExt:DigitalSourceType records origin from the IPTC controlled vocabulary. The value is a full URI, exiftool does not validate it, so a bare word or a typo is silently accepted and useless. The three every newsroom needs:

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 and Google read this field to auto-label AI content, and the EU AI Act's machine-readable-disclosure duty (Article 50, enforcement from August 2026) is pushing it from nice-to-have toward required. IPTC 2025.1 adds companion fields, AISystemUsed, AISystemVersionUsed, AIPromptInformation, AIPromptWriterName (exiftool ≥ 13.40). Full vocabulary and the retired terms to avoid: reference.md.

Content Credentials (C2PA): provenance exiftool can read but not sign

A Content Credential is a cryptographically signed C2PA manifest bound to the pixels, who made the image, in what tool, and whether AI was involved, increasingly shipped by cameras (Leica M11-P, Nikon Z6III, Sony Alpha) and agencies (AFP, AP, BBC pilots). It is a different layer from IPTC/XMP and answers a different question: not "what does the file claim" but "who signed this, and has it changed since."

exiftool reads it and cannot write or verify it:

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

That shows the manifest as data, it does not validate the signature or the signer. For a real check, drop the file into verify.contentauthenticity.org and confirm the signer is the agency you expect. To create a credential, use Adobe/CAI tooling, c2patool (brew install c2patool) or pip install c2pa-python, not exiftool.

Writing metadata to a signed file breaks its credential. A C2PA hard binding hashes the asset, and that hash covers the embedded metadata, so any exiftool write, caption, credit, GPS strip, even the tagging in this skill, leaves the manifest present but invalid. "Never strip the credential" is necessary but not sufficient. On an inbound signed file, either leave the original untouched and do your metadata work on a derivative you will re-sign with c2patool, or accept that the embedded credential no longer validates and say so. Do not embed metadata into a signed original and treat its credential as still good.

Two more cautions worth stating to any newsroom: a valid credential proves a signature and a chain, not that the scene is real (a camera will happily sign a photo of a screen), and most social platforms strip the manifest on upload, so on-platform provenance often survives only via "durable" watermark/fingerprint recovery. See reference.md.

Strip GPS for a publish-safe derivative

Remove location without touching the caption, credit, copyright, or source type:

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

Use the -xmp:GPS*= wildcard, not just the three main coordinates: destination and image-direction fields (GPSDestLatitude, GPSImgDirection) are also a location and would otherwise survive. Keep the full-GPS file as a locked archival master where coordinates are editorial evidence (geolocation, verification). Publish the stripped copy. embed.py --strip-gps does this for a whole folder after tagging.

Licensing that shows up in search (Google Images)

To earn the Google Images "Licensable" badge and a working "Get this image" link, set the web statement of rights (the trigger) and the PLUS licensor fields:

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

The web statement is xmpRights:WebStatement, not dc:Rights, a common and costly mix-up. A Creative Commons license routes through the same WebStatement field with the CC deed URL. Details and the full PLUS field set: reference.md.

Batch tagging a folder

For a shoot, drive exiftool from a manifest instead of one command per file. embed.py in this directory takes a folder plus a JSON manifest (constant credit, license, licensor, and Digital Source Type fields, then per-image alt text, caption, extended description, keywords, and an optional per-image source-type override), writes tagged copies, reads each one back to confirm the metadata landed, and, with --strip-gps, removes GPS from the copies. It accepts a Digital Source Type shorthand (digitalCapture) or a full URI and refuses anything else rather than embedding a broken value. Run python3 embed.py --help.

Common mistakes (from baseline testing)

Mistake Fix
Wrote a caption, no alt text Always write AltTextAccessibility too, they are different fields
Copied the caption into the alt text (or ExtDescrAccessibility) IPTC keeps these distinct; write a real screen-reader sentence, keep ExtDescr for complex images only
By-line/Credit/City silently truncated Those IIM fields cap at 32 chars; put the full credit in XMP-photoshop:Credit
Caption states things not in the frame Describe only what is visible; move unseeable context out
AI-generated image left unlabeled Set DigitalSourceType to trainedAlgorithmicMedia (or the right composite value)
DigitalSourceType set to a bare word The value must be the full http://cv.iptc.org/... URI; exiftool won't validate it
Stripped an inbound file's Digital Source Type or C2PA Never erase a disclosure, preserve provenance on files you receive
Published with GPS still embedded Strip with -gps:all= when location could endanger a subject or source
WebStatement put in dc:Rights The Google/licensing web statement is xmpRights:WebStatement
Editorial label in City or caption Put framing in Headline; keep structured fields neutral
Assumed the upload kept the metadata Re-read from the destination; most social platforms strip IPTC/XMP/GPS/C2PA
Keywords as one comma-joined string Write repeatable Keywords records (and a dc:Subject list)
Set a CC license note in plain text only Add xmpRights:WebStatement (CC deed URL) + xmpRights:Marked

Real-world impact

Embedded metadata is what lets a partner newsroom find a photo, credit it correctly, and republish it under a clear license without ever contacting the photographer. It is also, now, where an image says whether a human or a model made it, and where a signed Content Credential travels. Strip it, and the same photo is an orphaned file, no credit, no license, no provenance.

Version History

  • cdf2292 Current 2026-08-20 05:11

    精简技能描述至130字符以内,修复因全局替换破折号导致的元数据触发词丢失问题。

  • 2ba6c24 2026-07-25 10:50

Same Skill Collection

dev-toolkit/skills/accessibility-compliance/SKILL.md
dev-toolkit/skills/claude-md-updater/SKILL.md
dev-toolkit/skills/context-engineering-fundamentals/SKILL.md
dev-toolkit/skills/electron-dev/SKILL.md
dev-toolkit/skills/mobile-debugging/SKILL.md
dev-toolkit/skills/one-way-door/SKILL.md
dev-toolkit/skills/python-pipeline/SKILL.md
dev-toolkit/skills/test-first-bugs/SKILL.md
dev-toolkit/skills/vibe-coding/SKILL.md
dev-toolkit/skills/web-scraping/SKILL.md
dev-toolkit/skills/web-ui-best-practices/SKILL.md
dev-toolkit/skills/zero-build-frontend/SKILL.md
journalism-core/skills/ai-writing-detox/SKILL.md
journalism-core/skills/brazil-records-requests/SKILL.md
journalism-core/skills/crisis-communications/SKILL.md
journalism-core/skills/data-journalism/SKILL.md
journalism-core/skills/editorial-workflow/SKILL.md
journalism-core/skills/fact-check-workflow/SKILL.md
journalism-core/skills/foia-requests/SKILL.md
journalism-core/skills/interview-prep/SKILL.md
journalism-core/skills/interview-transcription/SKILL.md
journalism-core/skills/newsletter-publishing/SKILL.md
journalism-core/skills/newsroom-style/SKILL.md
journalism-core/skills/social-media-intelligence/SKILL.md
journalism-core/skills/source-verification/SKILL.md
journalism-core/skills/story-pitch/SKILL.md
okf-wiki/SKILL.md
pdf-design/SKILL.md
pdf-playground/skills/document-design/SKILL.md
project-templates-toolkit/skills/project-memory/SKILL.md
project-templates-toolkit/skills/project-retrospective/SKILL.md
project-templates-toolkit/skills/template-selector/SKILL.md
research-toolkit/skills/academic-writing/SKILL.md
research-toolkit/skills/content-access/SKILL.md
research-toolkit/skills/digital-archive/SKILL.md
research-toolkit/skills/free-apis-catalog/SKILL.md
research-toolkit/skills/page-monitoring/SKILL.md
research-toolkit/skills/web-archiving/SKILL.md
security-toolkit/skills/api-hardening/SKILL.md
security-toolkit/skills/security-checklist/SKILL.md
superjawn/skills/brainstorming/SKILL.md
superjawn/skills/dispatching-parallel-agents/SKILL.md
superjawn/skills/executing-plans/SKILL.md
superjawn/skills/finishing-a-development-branch/SKILL.md
superjawn/skills/receiving-code-review/SKILL.md
superjawn/skills/requesting-code-review/SKILL.md
superjawn/skills/subagent-driven-development/SKILL.md
superjawn/skills/systematic-debugging/SKILL.md
superjawn/skills/test-driven-development/SKILL.md

Metadata

Files
0
Version
cdf2292
Hash
50a2b4f2
Indexed
2026-07-25 10:50

Главная - Вики-сайт
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-08-20 12:28
浙ICP备14020137号-1 $Гость$