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.
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.
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.
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:
PreserveAllkeeps existing standard portable namespace entries subject to the conflict order above.CanonicalizeManageddrops OpenMeta-managed standard portable properties from existing XMP when a generated replacement exists.
xmp_existing_namespace_policy controls breadth:
KnownPortableOnlykeeps only standard portable namespaces known to OpenMeta.PreserveCustomalso preserves safe simple or indexed properties from custom namespaces.
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.
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.