Repository navigation
feat(tools): Metadata tool - #1108
lightscape-jm wants to merge 3 commits into
Conversation
A palette tool that shows every metadata field of a picture, PDF, video or sound file, grouped by where it lives, and lets you edit, remove or add them, or clear the location or everything at once. Saving is an ordinary conversion carrying the changes, written by ExifTool through a route edge of its own, so the file is never re-encoded and the copy is read back before it counts. ExifTool 13.60 is a new optional engine; without it MetadataExtractor shows the fields read-only (KnifeLemon#362). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main took settings schema 68 for signed .p7m files, so the Metadata tool moves to 69. An envelope is planned without PlanThrough when metadata changes are asked for: opening it would drop them without a word, so the file is refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
KnifeLemon
left a comment
There was a problem hiding this comment.
Thanks, @lightscape-jm. This is careful work. The argument file and the strict field-name regex leave no injection route that I could find, the original only goes through the existing Replace flow, metadata edges stay out of ordinary routes, v69 sits cleanly on main's 68, and all 44 keys are in all 20 languages.
Two things hold it back. I read the code and didn't run ExifTool, so please correct me if you see something different.
Must fix
1. Remove location can report success while location stays in the file
ExifTool.cs:301 and the read-back at :424-425 only look at f.Editable fields, and EditableFamilies (:28) leaves out maker notes. -ee isn't used either. So:
- Maker notes: location fields such as Panasonic's City, State and Country stay in the copy, and the read-back doesn't notice them.
- Video: timed GPS in tracks (GoPro, dashcams, drones) isn't read at all, so nothing says it's still there.
HoldsMore doesn't cover these, and no notice appears. For someone removing location before sharing a file, that success is wrong. At the least, show a notice when fields.Any(f => !f.Editable && IsLocation(f)) or when the file is a video. That means a new key in all the languages. If you can actually remove them, even better.
2. CI never runs the writer
MetadataTests skips without ExifTool ("No ExifTool on this computer"), and neither ci.yml nor portable.yml provides one, so the green checks here say nothing about writing, removal or read-back. Please fetch the pinned ExifTool in CI and set FILEE_TEST_EXIFTOOL, at least on Windows and one Linux job. This feature changes people's files, and later changes need that protection too.
Smaller
ExifTool.cs:404: Remove everything plus a new non-Latin-1 IPTC field fails when the file's IPTC is already UTF-8. The earlyreturn []skips writing the character set,-all=wipes it, the text becomes???, and the read-back refuses the copy. It fails safely, but the save is lost.if (!edits.RemoveAll && fields.Any(...))fixes it.MetadataViewModel.cs:173,243: on Linux or macOS without Perl, the engine shows as available because its status never checks for Perl. The start then fails and the window says Filee can't change this kind of file, which sends people looking in the wrong place.BuiltInData.cs:334,338,Preset.cs:293: comments say "settings schema 68". They should say 69, since 68 is.p7m.
Everything else looks ready. Once these are in and CI runs the writer tests, this should be quick to merge.
… and answer the review Remove location could report success with a place still in the file. Maker notes, a C2PA block, a PNG's or PDF's own field and a GeoTIFF's map position are out of ExifTool's reach, and timed GPS in a video's tracks is never read. The window now names what stays and warns on every video, in all 20 languages. CI never ran the writer, as it skipped without ExifTool. The Windows build now fetches the pinned ExifTool, a new linux-x64 job runs the Metadata tests against the pinned tarball, and a set FILEE_TEST_EXIFTOOL that points at nothing fails rather than skips. fetch-engines.ps1 sends its own User-Agent: SourceForge answers PowerShell's with an HTML page, so the checksum failed. Remove everything keeps the IPTC character set, as -all= wipes it and new text outside Latin-1 turned to ???. On macOS and Linux an ExifTool script with no Perl now says so, from the engine's status and in the window, instead of that the file can't be changed. Settings schema comments say 69. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks, @KnifeLemon. All of this is in 941f311. Must fix
Smaller
Every new test was checked to fail with its fix removed. The strings are now 48, still in all 20 languages, and the description is updated. One check is red: |
What does this change?
Closes #362. Adds Metadata, a palette tool to look at every metadata field of a picture, PDF, video or sound file and choose what to keep, as agreed in #362 and planned in #856 (step 6, after Add background). It is in the palette's Edit tab, not on a default donut. It sits next to the Remove metadata preset and doesn't replace it: the preset stays the one-click "remove it all", and this is for looking and choosing. The Balanced / Maximum privacy / Custom presets of the request are left for a later PR, as you suggested.
-all=would orphan or lose it. JPEGs from recent cameras and Pixel phones can be in this group. Remove location stays on offer there, and the notice says the embedded metadata can't be reached.Only the metadata is rewritten, never the picture, sound or document. This was the bar for the tool, so it is built and tested around it:
Preset.Metadata) has a route of one kind only:ConversionEdge.Metadata, which no ordinary route takes, and which is the whole route when asked for (as Whisper's caption edge is). Without ExifTool the file fails (error.no_route, with the route asked for, sofileecan name the package to install); it is never re-encoded by another engine instead. A signed.p7mis refused the same way: opening it for the file inside would lose the changes.Engines/Metadata/ExifToolConverterhas ExifTool edit a copy in a work folder beside the output, then moves it into place, so the output rules (Rename / Overwrite / Skip, Replace the original, Keep dates) work as for any conversion, and a long video needs room only on the output's disk. Tests compare the pixels or the streams of the copy with the original's.error.metadata_refused, with ExifTool's words).-all=alone leaves a TIFF's IFD fields, whose descriptive ones go by name on every page.ExifTool.IsLocation), and a small-configmakes theGPS…Reffields macOS writes into XMP removable; ExifTool otherwise reads them and won't touch them, so a picture saved by macOS couldn't be cleaned.%in a name would be expanded, and-orefuses WebP); edits go through an argument file, one per line, a value of several lines through a file of its own; field names must be "Group:Tag" and nothing else; a file it reads is an argument of its own, or in the UTF-8 argument file on Windows, where Perl's command line is in the ANSI code page.How it's built (also in
docs/ARCHITECTURE.md→ Metadata tool):MetadataEdits(fields set, removed, Remove location, Remove everything), read leniently: an entry that isn't one field, or has no value, is left out.MetadataTool.ConversionOfmakes the tool into the conversion; History offers no Retry, as for hidden parts, marks and backgrounds.Engines/Metadata/ExifToolreads with-j -G0:1: a list comes as a JSON array, so its entries stay whole, and IPTC's and a PDF's own fields, whose family and group share a name, are read too. Without ExifTool,MetadataReader(MetadataExtractor) shows the fields read-only, an XMP list as one field, and the window offers Settings → Engines; it reads the file again once ExifTool is installed.MetadataViewModelandMetadataWindowfollow Add background: the keys (Enter edits a field or saves, Shift+Enter starts a new line, Esc cancels or closes, Ctrl+F searches, the focus back on the row after an edit, a removal or an undo), names a screen reader says for every value and button, a summary when a file can't be read, texts that follow a language change.Compatibility: the built-in
tool-metadatacomes with settings schema 69, the next one free (UserDataStoreadds it to existing libraries after Add background, in the palette only). I can renumber it if another change takes 69 first. An older Filee doesn't know the tool and opens nothing for it. ExifTool 13.60 is a new optional engine package (Settings → Engines andfilee engines): the Windows build, itsexiftool(-k).exerenamed so it doesn't wait for a key, or the Perl distribution on macOS and Linux, pinned with the checksums exiftool.org publishes; a copy on thePATHis found too. MetadataExtractor 2.9.3 (Apache-2.0) is a new NuGet dependency; both are inTHIRD-PARTY-NOTICES.md.What Remove location can't reach, and says so: ExifTool can't delete maker-note fields one by one, and a C2PA block, a PNG's or a PDF's own fields and a GeoTIFF's map position stay too. The window names what stays (
ExifTool.LocationOutOfReach). Timed GPS in a video's tracks isn't read at all, so every video that can be edited gets a notice that its tracks may hold more. On macOS and Linux an ExifTool script with no Perl now reports that, from the engine's status and in the window, and the window offers no install that wouldn't help.Known limits: a row ExifTool refuses (a field it reads but won't write, as a custom XMP property) fails that file's save, with the reason in the toast; the file's other edits go with it, as the window has moved on. A value it coerces isn't caught (
abcfor an ISO). A file ExifTool itself can't read falls back to read-only. A video's or HEIC's header dates stay. PDF changes are an added update, so earlier values stay recoverable inside the file; the window says so.Type of change
How was it tested?
dotnet format --verify-no-changesFILEE_TEST_EXIFTOOL, and a newmetadata (linux-x64)job runs the Metadata tests with the pinned Perl distribution and FFmpeg. IfFILEE_TEST_EXIFTOOLis set and the file isn't there, the tests fail rather than skip. Windows CI has no FFmpeg, so the video test runs only in the Linux job there; I ran it by hand on Windows and it passes.fetch-engines.ps1now sends its own User-Agent, as SourceForge answers PowerShell's with an HTML page and the checksum then fails.dotnet test: Core, Cli and Platform pass, and all the Metadata tests in Core, Engines and App pass on macOS (ExifTool 13.60 and 12.58), in an Ubuntu 24.04 container (pinned 13.60, with FFmpeg, as the new job does) and on Windows 11 ARM64 (13.60; the cases that are about Perl skip there, as ExifTool is a program on Windows). On my Mac the Engines and App tests that fail on unmodifiedmainfail the same way (FFmpeg without some encoders, the engine-page renders, the flakyA_lost_animation_frame…). I didn't run the Windows installer (Setup) tests.main, ExifTool 12.58, dark): put on the Images donut from the palette's Edit tab; a photo with camera, GPS, XMP and IPTC fields opened from the donut; Remove location, a value changed, Save copy: saved as "venice_metadata.jpg", GPS and City gone, the rest as it was, "Kim, Alex" still one creator, the original untouched, pixels the same; search, a list's editor, Esc; Remove everything: only the orientation, the colour profile and EXIF's mandatory resolution fields left, pixels the same, the next copy "(2)". No errors in the log.New tests:
MetadataToolTests(20)MetadataTests(77)%, non-Latin and line-break file names, both ways of passing the path; what's after the picture left alone; the converter's formats, its route, and a conversion end to end (Overwrite, refused); what Remove location can't reach, a place and not a focus point; Remove everything with new text outside Latin-1 over UTF-8 IPTC; what needs Perl and what doesn't.OwnCopyTestschecks the engine's status says soMetadataWindowTests(69)Screenshots (UI changes)
A real photo with Remove location pressed and a value changed:
Search, and a list edited one entry per line:
Checklist
src/Filee.App/Assets/i18n/*.jsonfiles (48 strings, translated in every language)THIRD-PARTY-NOTICES.md(MetadataExtractor, ExifTool)🤖 Generated with Claude Code