Skip to content

fix: preserve the full EXIF block in exports instead of the sidecar subset (#1165)#1373

Open
Serraniel wants to merge 3 commits into
CyberTimon:mainfrom
Serraniel:fix/export-full-exif
Open

fix: preserve the full EXIF block in exports instead of the sidecar subset (#1165)#1373
Serraniel wants to merge 3 commits into
CyberTimon:mainfrom
Serraniel:fix/export-full-exif

Conversation

@Serraniel

Copy link
Copy Markdown

Description

Exporting with Save with Metadata enabled silently drops most of the EXIF data. From a Fujifilm X-T50 JPEG with 78 EXIF tags, only 15 survive the export: the whole GPS block, DateTime/OffsetTime*/SubSecTime*, Flash, ExposureBiasValue, ApertureValue, ShutterSpeedValue, the MakerNote, body/lens serial numbers, LensSpecification, the Interop IFD and more are gone.

Root cause: write_image_with_metadata sources tags from three branches (.rrdata sidecar → kamadak-exif → rawler). Opening an image triggers persist_exif_if_missing, which creates the sidecar — so from then on the sidecar branch always wins. The sidecar only stores a display-formatted subset of the tags (e.g. "ApertureValue": "7.4 EV", MakerNote as a truncated hex dump), so it cannot reconstruct the original EXIF, and the kamadak/rawler branches (including their GPS handling) are never reached.

Fix: for non-RAW sources, copy the complete EXIF block (IFD0 + Exif/GPS/Interop sub-IFDs, including MakerNote and unknown tags) from the source file via little_exif, instead of reconstructing a subset:

  • The sidecar is still consulted afterwards, but only for the fields that are editable in the metadata panel (Artist, Copyright, ImageDescription, UserComment) — user edits override the source values, and a cleared field stays cleared in the export.
  • strip_gps=true still removes the entire GPS IFD (all GPS* tags, not just lat/lon/alt).
  • Orientation is reset to 1 as before (rotation is baked into the exported pixels), and ExifImageWidth/ExifImageHeight are now set to the actual export dimensions instead of carrying the stale source values.
  • IFD1 is not copied, since it contains the original's embedded thumbnail which no longer matches the exported pixels.
  • RAW sources are unchanged: they keep the existing sidecar/rawler reconstruction (a full block copy is not possible there, since little_exif cannot parse RAW containers).

Fixes #1165 (the GPS part of it as a side effect, see below). The closed duplicates #503, #427 and #401 report the same symptom.

Relationship to other PRs:

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Performance improvement
  • Code refactoring
  • Documentation update
  • UI/UX improvement
  • Build/CI or Dependency update

Changes Made

  • exif_processing::write_image_with_metadata: copy the full EXIF block from non-RAW source files (new copy_full_exif_from_source), skipping the GPS IFD when strip_gps is set and skipping IFD1; fall back to the previous sidecar/kamadak/rawler branches when the source has no parseable EXIF or is a RAW file.
  • New apply_sidecar_field_overrides: the four panel-editable fields are applied from the sidecar on top of the copied block.
  • Set ExifImageWidth/ExifImageHeight to the actual dimensions of the exported image.
  • Regression tests: full tag preservation (incl. MakerNote byte-identity) with a sidecar present, complete GPS removal with strip_gps=true, sidecar edits overriding/clearing source values, orientation reset + dimension tag update.
  • Separate commit for the WebP half of FEATURE: Export JPEG XL & WepB with EXIF metadata #1322: little_exif converts the exporter's simple-format WebP to the extended format and attaches an EXIF chunk, so WebP EXIF only needed a file-type mapping (tested with both the lossy VP8 output of the export pipeline and lossless VP8L).

Screenshots/Videos

Before/after on a real Fujifilm X-T50 JPEG, exported with Save with Metadata ON and Remove GPS Data OFF after the image had been opened once (sidecar present). Tag counts from exiftool -a -G1 -s, excluding the ExifTool/System/File/Composite/JFIF pseudo-groups:

tags missing vs. original
original DSCF0563.JPG 155
RapidRAW 1.5.8 export 14 GPS block, MakerNote (all 70+ Fujifilm tags), DateTime, OffsetTime*, SubSecTime*, Flash, ApertureValue, ShutterSpeedValue, ExposureBiasValue, body/lens serials, Interop IFD, PrintIM, ...
this PR 141 only IFD1 (stale embedded thumbnail, intentionally dropped), APP2 FlashPix preview + XMP Rating (separate segments, also dropped by 1.5.8, out of scope)

A tag-by-tag value diff of original vs. new export shows exactly the intended differences: Orientation (reset, rotation baked in), Software (RapidRAW), ExifImageWidth/Height (now the real export dimensions). With Remove GPS Data ON the export contains zero GPS* tags. exiftool parses the copied Fujifilm MakerNote in the export without errors, so the offsets survive the copy.

Testing

  • I have tested these changes locally and confirmed that they work as expected without issues

cargo fmt --check, cargo clippy --lib --tests --no-deps and cargo test pass. Verified against a real Fujifilm X-T50 JPEG (see table above): tag-by-tag exiftool diff of original vs. export matches except for the intentional differences (Orientation, pixel dimensions, Software, thumbnail).

Test Configuration:

  • OS: Arch Linux (RapidRAW 1.5.8 via rapidraw-bin AUR for the "before" state)
  • Hardware: AMD Ryzen 7 5700X, Radeon RX 6800 XT

Checklist

  • My code follows the project's code style
  • I haven't added unnecessary AI-generated code comments
  • My changes generate no new warnings or errors

Additional Notes

  • MakerNote is copied as an opaque blob. For self-contained MakerNotes (e.g. Fujifilm, whose offsets are relative to the MakerNote itself) this round-trips perfectly; MakerNotes that use absolute file offsets may have dangling offsets after the copy — still strictly better than dropping the MakerNote entirely, and the same trade-off most non-exiftool writers make.
  • exiftool -validate reports "entries out of order" notices on the exports because little_exif appends the ExifOffset/GPSInfo/InteropOffset pointer tags after the (otherwise sorted) IFD entries at encode time. That's a pre-existing quirk of the little_exif encoder (it just wasn't visible before because so few tags survived), readers are unaffected, and it would be fixed upstream, not here.
  • RAW-with-sidecar exports still only get the reconstructed subset (plus GPS once fix gps metadata being stripped from exports (#1165) #1207 lands). A follow-up could extract the full EXIF from the embedded preview JPEG.

AI Disclaimer:

Please state the involvement of AI in this PR:

  • This PR is entirely AI-generated
  • This PR is AI-generated but guided by a human
  • This PR was handwritten with AI assistance (spell check, logic suggestions, error resolving)
  • This PR contains only blood, sweat, and coffee (AI-free)

Serraniel and others added 2 commits July 13, 2026 20:49
…CyberTimon#1165)

Once an image has been opened, its .rrdata sidecar exists and
write_image_with_metadata reconstructed the export EXIF from the
sidecar's display-formatted subset, silently dropping most tags (GPS,
MakerNote, OffsetTime*, serials, ...). Copy the complete EXIF block from
non-RAW source files instead, keep the sidecar as the source of truth
for the panel-editable fields, strip the whole GPS IFD when requested,
and stamp the real export dimensions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
little_exif converts simple-format WebP (both the lossy VP8 output of
the export pipeline and lossless VP8L) to the extended format and
attaches an EXIF chunk, so WebP only needed a file-type mapping.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Serraniel
Serraniel requested a review from CyberTimon as a code owner July 13, 2026 18:54
@CyberTimon

Copy link
Copy Markdown
Owner

Thanks for the PR!
Before I review it, remove all code comments and tests.

Requested by the maintainer before review.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@r3nor

r3nor commented Jul 18, 2026

Copy link
Copy Markdown

I think this feature is important for JPEGXL and other formats, since currently they do not support metadata in the file...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BUG: Location data stripped from exported JPEG

3 participants