Skip to content

Latest commit

 

History

History
140 lines (109 loc) · 7.4 KB

File metadata and controls

140 lines (109 loc) · 7.4 KB

XMP Sync And Writeback Policy

This page defines the bounded public policy for generated portable XMP during metadata transfer.

It covers:

  • generated EXIF-to-XMP properties
  • generated IPTC-to-XMP properties
  • source embedded XMP decoded from the source metadata
  • destination embedded XMP loaded from the target file
  • destination sidecar XMP loaded from a sibling .xmp

This is not a full arbitrary metadata synchronization engine. It is the writer-side contract used by the transfer helpers so hosts can predict preserve, merge, and writeback behavior.

For target-specific embedded carrier replacement and unmanaged-data preservation rules, see writer_target_contract.md.

Default Contract

The default transfer behavior is conservative:

Option Default Effect
PrepareTransferRequest::xmp_project_exif true Generate portable XMP properties from EXIF/TIFF/GPS fields.
PrepareTransferRequest::xmp_project_iptc true Generate portable XMP properties from IPTC-IIM fields.
PrepareTransferRequest::xmp_include_existing true Include existing XMP already decoded into the source MetaStore.
PrepareTransferRequest::xmp_conflict_policy CurrentBehavior Emit generated EXIF properties, then existing XMP, then generated IPTC properties.
xmp_existing_sidecar_mode Ignore Do not merge a destination sidecar unless explicitly requested.
xmp_existing_destination_embedded_mode Ignore Do not merge destination embedded XMP unless explicitly requested.
xmp_writeback_mode EmbeddedOnly Keep generated XMP in the managed embedded carrier.
xmp_destination_embedded_mode PreserveExisting Preserve existing embedded XMP when sidecar-only writeback suppresses generated embedded XMP.
xmp_destination_sidecar_mode PreserveExisting Preserve an existing sibling .xmp when embedded-only writeback is used.

Native EXIF and IPTC carrier emission is independent from XMP projection. Turning off xmp_project_exif or xmp_project_iptc suppresses only the generated XMP projection, not native EXIF/IPTC transfer.

Existing XMP Carrier Precedence

OpenMeta first builds one decoded transfer store. Optional destination XMP carriers are merged into that store before or after the source entries according to explicit precedence options.

For duplicate existing XMP properties, earlier merged entries win during portable XMP output.

Conflict Option Default order Alternate order
destination sidecar vs source embedded XMP xmp_existing_sidecar_precedence sidecar before source (SidecarWins) source before sidecar (SourceWins)
destination embedded XMP vs source embedded XMP xmp_existing_destination_embedded_precedence destination before source (DestinationWins) source before destination (SourceWins)
destination sidecar vs destination embedded XMP xmp_existing_destination_carrier_precedence sidecar before embedded (SidecarWins) embedded before sidecar (EmbeddedWins)

The destination sidecar is loaded only when xmp_existing_sidecar_mode == MergeIfPresent. The destination embedded packet is loaded only when xmp_existing_destination_embedded_mode == MergeIfPresent.

If both destination sidecar and destination embedded XMP are merged on the same side of the source entries, xmp_existing_destination_carrier_precedence decides which destination carrier wins. If they are placed on opposite sides of the source entries, the two source-precedence options define the effective order.

Failed or missing optional destination carriers do not silently change the source metadata. The result reports a status and message for the attempted sidecar or destination-embedded load.

Generated EXIF/IPTC Versus Existing XMP

After the transfer store is assembled, xmp_conflict_policy decides the relative precedence between generated portable XMP and the existing XMP set. The existing XMP set includes source embedded XMP plus any destination XMP carriers that were explicitly merged.

Policy Pass order Practical effect
CurrentBehavior EXIF-derived, existing XMP, IPTC-derived EXIF projection wins over existing XMP; existing XMP wins over IPTC projection.
ExistingWins existing XMP, EXIF-derived, IPTC-derived Existing XMP wins over generated EXIF/IPTC projection.
GeneratedWins EXIF-derived, IPTC-derived, existing XMP Generated EXIF/IPTC projection wins over existing XMP.

When generated EXIF and generated IPTC projection both claim the same portable property, EXIF-derived output is emitted first and wins.

xmp_existing_standard_namespace_policy applies inside the existing-XMP pass:

  • PreserveAll keeps existing standard portable namespace entries subject to the conflict order above.
  • CanonicalizeManaged drops OpenMeta-managed standard portable properties from existing XMP when a generated replacement exists.

xmp_existing_namespace_policy controls breadth:

  • KnownPortableOnly keeps only standard portable namespaces known to OpenMeta.
  • PreserveCustom also preserves safe simple or indexed properties from custom namespaces.

Writeback Modes

Writeback mode controls where the generated XMP packet goes after transfer execution.

Mode Edited file Sibling .xmp Cleanup behavior
EmbeddedOnly Generated XMP stays in the managed embedded carrier. No generated sidecar output. Existing sidecar is preserved unless xmp_destination_sidecar_mode == StripExisting.
SidecarOnly Generated embedded XMP blocks are suppressed. Generated XMP is returned as sidecar output. Existing embedded XMP is preserved unless xmp_destination_embedded_mode == StripExisting.
EmbeddedAndSidecar Generated XMP stays in the managed embedded carrier. The same generated XMP is returned as sidecar output. No destination sidecar cleanup is requested.

Destination sidecar cleanup is supported only for embedded writeback. If xmp_destination_sidecar_mode == StripExisting, OpenMeta returns a cleanup request for the sibling .xmp; persist_prepared_transfer_file_result(...) performs the removal when remove_destination_xmp_sidecar is true.

Destination embedded-XMP stripping is supported for sidecar-only writeback on the current managed writer targets: JPEG, TIFF/DNG, PNG, WebP, JP2, JXL, and bounded BMFF targets (HEIF, AVIF, CR3). Other combinations report an unsupported policy result instead of guessing.

Sidecar output and cleanup paths are derived from xmp_sidecar_base_path when provided, otherwise from the edit/output target path. Hosts that do not have a filesystem path can set xmp_existing_destination_sidecar_state explicitly so OpenMeta can return deterministic cleanup guidance without probing the filesystem.

The persistence helper writes generated sidecars only when sidecar output is requested. It does not overwrite an existing sidecar unless overwrite_xmp_sidecar is true.

Non-Goals

This bounded policy intentionally does not claim:

  • full MWG-style EXIF/IPTC/XMP reconciliation
  • arbitrary XMP graph editing
  • raw packet passthrough or byte-for-byte XMP preservation
  • semantic conflict resolution beyond the documented portable property order
  • full sidecar and embedded synchronization for every possible namespace

Those remain broader parity work. The current contract is meant to be stable enough for predictable transfer and export workflows.