API Reference

This page is generated from the public C++ headers via Doxygen (XML) + Breathe.

struct AppendPreparedJpegJumbfOptions

Options for explicit raw JUMBF append into a prepared JPEG bundle.

Public Members

bool replace_existing = false

If true, remove existing prepared jpeg:app11-jumbf blocks first.

struct ApplyDngSdkMetadataFileOptions
#include <dng_sdk_adapter.h>

File-helper options for DNG SDK adapter entry points.

Public Members

PrepareTransferFileOptions prepare
DngSdkAdapterOptions adapter
struct ApplyDngSdkMetadataFileResult
#include <dng_sdk_adapter.h>

File-helper result for DNG SDK adapter entry points.

Public Members

PrepareTransferFileResult prepared
DngSdkAdapterResult adapter
struct ApplyTimePatchOptions

Options for apply_time_patches.

Public Members

bool strict_width = true

If true, update value size must match slot width exactly.

bool require_slot = false

If true, each requested field must have at least one slot.

struct ApplyTimePatchResult

Result for apply_time_patches.

Public Members

TransferStatus status = TransferStatus::Ok
uint32_t patched_slots = 0
uint32_t skipped_slots = 0
uint32_t errors = 0
std::string message
struct BlockInfo
#include <meta_store.h>

Container-block identity used to associate Entry::origin with a source block.

Public Members

uint32_t format = 0
uint32_t container = 0
uint32_t id = 0
struct BlockSpan
#include <meta_store.h>

Public Members

uint32_t start = 0
uint32_t count = 0
struct BmffField
#include <meta_key.h>

Public Members

ByteSpan field
struct BmffField
#include <meta_key.h>

Public Members

std::string_view field
class BmffTransferEmitter

Backend contract for ISO-BMFF metadata item emission.

Public Functions

virtual ~BmffTransferEmitter() = default
virtual TransferStatus add_item(uint32_t item_type, std::span<const std::byte> payload) noexcept = 0
virtual TransferStatus add_mime_xmp_item(std::span<const std::byte> payload) noexcept = 0
virtual TransferStatus add_property(uint32_t property_type, std::span<const std::byte> payload) noexcept = 0
virtual TransferStatus close_items() noexcept = 0
struct BuildExrAttributeBatchFileOptions
#include <exr_adapter.h>

File-helper options for build_exr_attribute_batch_from_file.

Public Members

PrepareTransferFileOptions prepare
ExrAdapterOptions adapter
struct BuildExrAttributeBatchFileResult
#include <exr_adapter.h>

File-helper result for build_exr_attribute_batch_from_file.

Public Members

PrepareTransferFileResult prepared
ExrAdapterResult adapter
struct BuildInfo
#include <build_info.h>

OpenMeta build information.

Values are compiled into the binary at build time.

Public Members

std::string_view version

OpenMeta version string (e.g. “0.4.0”).

std::string_view build_timestamp_utc

Build timestamp in UTC (ISO-8601), or empty if not recorded.

std::string_view build_type

Build type string (e.g. “Release”, “Debug”, “multi-config”).

std::string_view cmake_generator

CMake generator used to configure the build (e.g. “Ninja”).

std::string_view system_name

Target platform (e.g. “Linux”, “Darwin”, “Windows”).

std::string_view system_processor

Target CPU architecture (e.g. “x86_64”, “arm64”).

std::string_view cxx_compiler_id

Compiler ID (e.g. “Clang”, “GNU”, “MSVC”).

std::string_view cxx_compiler_version

Compiler version string.

std::string_view cxx_compiler

Compiler executable path, if available.

bool linkage_static = false

True if this binary was built from the static library target.

bool linkage_shared = false

True if this binary was built from the shared library target.

bool option_with_zlib = false

Whether zlib decompression was enabled at configure time.

bool option_with_brotli = false

Whether brotli decompression was enabled at configure time.

bool option_with_expat = false

Whether Expat-based XMP parsing was enabled at configure time.

bool option_enable_rapidfuzz = false

Whether RapidFuzz-backed metadata query matching was enabled at configure time.

bool has_zlib = false

Whether zlib support is compiled in (linked).

bool has_brotli = false

Whether brotli support is compiled in (linked).

bool has_expat = false

Whether Expat support is compiled in (linked).

bool has_rapidfuzz = false

Whether RapidFuzz-backed metadata query matching is compiled in.

struct BuildPreparedC2paBindingResult

Result for materializing the exact content-binding byte stream.

Public Members

TransferStatus status = TransferStatus::Unsupported
EmitTransferCode code = EmitTransferCode::None
uint64_t written = 0
uint32_t errors = 0
std::string message
class ByteArena
#include <byte_arena.h>

Append-only storage for bytes and strings.

Note

ByteSpan values remain meaningful as long as the arena content is not cleared. However, any pointer/span returned by span() may be invalidated by subsequent arena growth (vector reallocation). Do not retain the returned span across arena mutations.

Public Functions

ByteArena() = default
void clear() noexcept

Discards all stored bytes.

void reserve(size_t size_bytes)

Reserves at least size_bytes capacity (may allocate).

void constrain_max_size(uint64_t max_size_bytes) noexcept

Applies a cumulative size ceiling. Repeated calls retain the lowest non-zero limit, so nested decoders cannot widen a parent budget.

bool limit_exceeded() const noexcept

Returns true after an allocation was refused by the cumulative ceiling.

ByteSpan append(std::span<const std::byte> bytes)

Appends raw bytes and returns a ByteSpan to the stored copy. Returns an empty span if the payload would exceed ByteSpan limits. Source bytes may alias the current arena buffer.

ByteSpan append_string(std::string_view text)

Appends the raw bytes of text (no terminator) and returns a span. Returns an empty span if the payload would exceed ByteSpan limits.

ByteSpan allocate(uint32_t size_bytes, uint32_t alignment)

Allocates size_bytes with alignment and returns the written span. Returns an empty span if the allocation cannot be represented.

std::span<const std::byte> bytes() const noexcept

Returns a view of the full buffer.

std::span<std::byte> bytes_mut() noexcept

Returns a mutable view of the full buffer.

std::span<const std::byte> span(ByteSpan view) const noexcept

Returns a view for view, or an empty span if out of range.

std::span<std::byte> span_mut(ByteSpan view) noexcept

Returns a mutable view for view, or an empty span if out of range.

Private Members

std::vector<std::byte> buffer_
uint64_t max_size_bytes_ = UINT32_MAX
bool limit_exceeded_ = false
struct ByteSpan
#include <byte_arena.h>

A span (offset,size) into a ByteArena buffer.

Public Members

uint32_t offset = 0
uint32_t size = 0
struct CcmField
#include <ccm_query.h>

One normalized CCM/white-balance/calibration field.

Public Members

std::string name

Canonical field name (e.g. ColorMatrix1).

std::string ifd

Source EXIF IFD token (e.g. ifd0).

uint16_t tag = 0

Source EXIF tag id.

uint32_t rows = 0

Logical row count (matrix/vector layout hint).

uint32_t cols = 0

Logical column count (matrix/vector layout hint).

std::vector<double> values

Normalized numeric values (row-major for matrices).

struct CcmIssue
#include <ccm_query.h>

Validation issue emitted by collect_dng_ccm_fields.

Public Members

CcmIssueSeverity severity = CcmIssueSeverity::Warning
CcmIssueCode code = CcmIssueCode::DecodeFailed
std::string ifd
std::string name
uint16_t tag = 0
std::string message
struct CcmQueryLimits
#include <ccm_query.h>

Limits for CCM query extraction.

Public Members

uint32_t max_fields = 128U
uint32_t max_values_per_field = 256U
struct CcmQueryOptions
#include <ccm_query.h>

Options for collect_dng_ccm_fields.

Public Members

bool require_dng_context = true

Require DNG context marker (DNGVersion) in the source IFD.

bool include_reduction_matrices = true

Include ReductionMatrix* tags.

CcmValidationMode validation_mode = CcmValidationMode::DngSpecWarnings

Validation mode for DNG matrix/tag coherency diagnostics.

CcmQueryLimits limits
struct CcmQueryResult
#include <ccm_query.h>

Query result for collect_dng_ccm_fields.

Public Members

CcmQueryStatus status = CcmQueryStatus::Ok
uint32_t fields_found = 0
uint32_t fields_dropped = 0
uint32_t issues_reported = 0
struct Comment
#include <meta_key.h>

Public Members

uint8_t reserved = 0
struct Comment
#include <meta_key.h>

Public Members

uint8_t reserved = 0
struct ContainerBlockRef
#include <container_scan.h>

Reference to a metadata payload within container bytes.

All offsets are relative to the start of the full file byte buffer passed to the scanner.

Note

Scanners are intentionally shallow: they locate blocks and annotate compression/chunking but do not decompress or parse the inner formats.

Public Members

ContainerFormat format = ContainerFormat::Unknown
ContainerBlockKind kind = ContainerBlockKind::Unknown
BlockCompression compression = BlockCompression::None
BlockChunking chunking = BlockChunking::None
uint64_t outer_offset = 0
uint64_t outer_size = 0
uint64_t data_offset = 0
uint64_t data_size = 0
uint32_t id = 0
uint32_t part_index = 0
uint32_t part_count = 0
uint64_t logical_offset = 0
uint64_t logical_size = 0
uint64_t group = 0
uint32_t aux_u32 = 0
struct ContainerRandomAccessScanResult
#include <container_scan.h>

Combined container-scan and source-I/O result.

Public Functions

inline bool complete() const noexcept

True when the positional source was read without an I/O or limit error. The container can still be malformed or unsupported; inspect scan.

Public Members

ScanResult scan
RandomAccessReadState input
struct ContainerRandomAccessScratch
#include <container_scan.h>

Caller-owned storage for callback-backed container scanning.

Public Members

std::span<std::byte> read_window

Reusable read-ahead cache. JPEG and RAF/X3F embedded-JPEG scanning require up to 512 bytes to preserve bare-XMP detection parity with the contiguous scanner. PNG, WebP, GIF, JP2, JXL, and ISO-BMFF scanning require at least 32 bytes.

RandomAccessReadWindowOptions window_options
union Data
#include <meta_key.h>

Public Functions

inline Data() noexcept

Public Members

struct openmeta::MetaKey::Data::ExifTag exif_tag
struct openmeta::MetaKey::Data::Comment comment
struct openmeta::MetaKey::Data::ExrAttribute exr_attribute
struct openmeta::MetaKey::Data::IptcDataset iptc_dataset
struct openmeta::MetaKey::Data::XmpProperty xmp_property
struct openmeta::MetaKey::Data::IccHeaderField icc_header_field
struct openmeta::MetaKey::Data::IccTag icc_tag
struct openmeta::MetaKey::Data::PhotoshopIrb photoshop_irb
struct openmeta::MetaKey::Data::PhotoshopIrbField photoshop_irb_field
struct openmeta::MetaKey::Data::GeotiffKey geotiff_key
struct openmeta::MetaKey::Data::PrintImField printim_field
struct openmeta::MetaKey::Data::BmffField bmff_field
struct openmeta::MetaKey::Data::JumbfField jumbf_field
struct openmeta::MetaKey::Data::JumbfCborKey jumbf_cbor_key
struct openmeta::MetaKey::Data::PngText png_text
union Data
#include <meta_key.h>

Public Functions

inline Data() noexcept

Public Members

struct openmeta::MetaKeyView::Data::ExifTag exif_tag
struct openmeta::MetaKeyView::Data::Comment comment
struct openmeta::MetaKeyView::Data::ExrAttribute exr_attribute
struct openmeta::MetaKeyView::Data::IptcDataset iptc_dataset
struct openmeta::MetaKeyView::Data::XmpProperty xmp_property
struct openmeta::MetaKeyView::Data::IccHeaderField icc_header_field
struct openmeta::MetaKeyView::Data::IccTag icc_tag
struct openmeta::MetaKeyView::Data::PhotoshopIrb photoshop_irb
struct openmeta::MetaKeyView::Data::PhotoshopIrbField photoshop_irb_field
struct openmeta::MetaKeyView::Data::GeotiffKey geotiff_key
struct openmeta::MetaKeyView::Data::PrintImField printim_field
struct openmeta::MetaKeyView::Data::BmffField bmff_field
struct openmeta::MetaKeyView::Data::JumbfField jumbf_field
struct openmeta::MetaKeyView::Data::JumbfCborKey jumbf_cbor_key
struct openmeta::MetaKeyView::Data::PngText png_text
union Data
#include <meta_value.h>

Public Functions

inline Data() noexcept

Public Members

uint64_t u64
int64_t i64
uint32_t f32_bits

Raw IEEE-754 bits for MetaElementType::F32.

uint64_t f64_bits

Raw IEEE-754 bits for MetaElementType::F64.

URational ur
SRational sr
ByteSpan span
struct DngSdkAdapterOptions
#include <dng_sdk_adapter.h>

Options for applying prepared OpenMeta metadata onto DNG SDK objects.

Public Members

bool apply_exif = true
bool apply_xmp = true
bool apply_iptc = true
bool synchronize_metadata = true
bool cleanup_for_update = true
struct DngSdkAdapterResult
#include <dng_sdk_adapter.h>

Result for DNG SDK adapter apply/update operations.

Public Members

DngSdkAdapterStatus status = DngSdkAdapterStatus::Ok
uint32_t applied_blocks = 0
uint32_t skipped_blocks = 0
bool exif_applied = false
bool xmp_applied = false
bool iptc_applied = false
bool synchronized_metadata = false
bool cleaned_for_update = false
bool updated_stream = false
TransferBlockKind failed_kind = TransferBlockKind::Other
std::string message
struct EditOp
#include <meta_edit.h>

A single edit operation recorded by MetaEdit.

Public Members

EditOpKind kind = EditOpKind::AddEntry
EntryId target = kInvalidEntryId
Entry entry
MetaValue value
struct EmittedBmffItemSummary

One emitted ISO-BMFF metadata item summary entry.

Public Members

uint32_t item_type = 0U
uint32_t count = 0U
uint64_t bytes = 0U
bool mime_xmp = false
struct EmittedBmffPropertySummary

One emitted ISO-BMFF metadata property summary entry.

Public Members

uint32_t property_type = 0U
uint32_t property_subtype = 0U
uint32_t count = 0U
uint64_t bytes = 0U
struct EmittedExrAttributeSummary

One emitted EXR attribute summary entry.

Public Members

std::string name
std::string type_name
uint32_t count = 0
uint64_t bytes = 0
struct EmittedJp2BoxSummary

One emitted JP2 box summary entry.

Public Members

std::array<char, 4> type = {'\0', '\0', '\0', '\0'}
uint32_t count = 0
uint64_t bytes = 0
struct EmittedJpegMarkerSummary

One emitted JPEG marker summary entry.

Public Members

uint8_t marker = 0
uint32_t count = 0
uint64_t bytes = 0
struct EmittedJxlBoxSummary

One emitted JPEG XL box summary entry.

Public Members

std::array<char, 4> type = {'\0', '\0', '\0', '\0'}
uint32_t count = 0
uint64_t bytes = 0
struct EmittedPngChunkSummary

One emitted PNG chunk summary entry.

Public Members

std::array<char, 4> type = {'\0', '\0', '\0', '\0'}
uint32_t count = 0
uint64_t bytes = 0
struct EmittedTiffTagSummary

One emitted TIFF tag summary entry.

Public Members

uint16_t tag = 0
uint32_t count = 0
uint64_t bytes = 0
struct EmittedWebpChunkSummary

One emitted WebP chunk summary entry.

Public Members

std::array<char, 4> type = {'\0', '\0', '\0', '\0'}
uint32_t count = 0
uint64_t bytes = 0
struct EmitTransferOptions

Emission options shared by backend emit entry points.

Public Members

bool skip_empty_payloads = true
bool stop_on_error = true
struct EmitTransferResult

Result details for bundle emission.

Public Members

TransferStatus status = TransferStatus::Ok
EmitTransferCode code = EmitTransferCode::None
uint32_t emitted = 0
uint32_t skipped = 0
uint32_t errors = 0
uint32_t failed_block_index = 0xFFFFFFFFU
std::string message
struct Entry
#include <meta_store.h>

A single metadata entry (key/value) with provenance.

Note

Duplicate keys are allowed and preserved.

Public Members

MetaKey key
MetaValue value
Origin origin
EntryFlags flags = EntryFlags::None
struct ExecutePreparedTransferBundleOptions

Options for execute_prepared_transfer_bundle.

Public Members

ExecutePreparedTransferOptions execute
OpenMetaResourcePolicy policy
std::string edit_target_path
std::string xmp_sidecar_base_path
XmpWritebackMode xmp_writeback_mode = XmpWritebackMode::EmbeddedOnly
XmpDestinationEmbeddedMode xmp_destination_embedded_mode = XmpDestinationEmbeddedMode::PreserveExisting
XmpDestinationSidecarMode xmp_destination_sidecar_mode = XmpDestinationSidecarMode::PreserveExisting
XmpExistingDestinationSidecarState xmp_existing_destination_sidecar_state = XmpExistingDestinationSidecarState::Unknown
bool c2pa_stage_requested = false
PreparedTransferC2paSignerInput c2pa_signer_input
bool c2pa_signed_package_provided = false
PreparedTransferC2paSignedPackage c2pa_signed_package
struct ExecutePreparedTransferFileOptions

Options for execute_prepared_transfer_file.

Public Members

PrepareTransferFileOptions prepare
ExecutePreparedTransferOptions execute
std::string edit_target_path
std::string xmp_sidecar_base_path

Base path used to derive sibling .xmp output or cleanup paths.

When empty, the file-helper derives the sidecar path from edit_target_path.

XmpExistingDestinationEmbeddedMode xmp_existing_destination_embedded_mode = XmpExistingDestinationEmbeddedMode::Ignore
XmpExistingDestinationEmbeddedPrecedence xmp_existing_destination_embedded_precedence = XmpExistingDestinationEmbeddedPrecedence::DestinationWins
XmpWritebackMode xmp_writeback_mode = XmpWritebackMode::EmbeddedOnly
XmpDestinationEmbeddedMode xmp_destination_embedded_mode = XmpDestinationEmbeddedMode::PreserveExisting
XmpDestinationSidecarMode xmp_destination_sidecar_mode = XmpDestinationSidecarMode::PreserveExisting
XmpExistingDestinationSidecarState xmp_existing_destination_sidecar_state = XmpExistingDestinationSidecarState::Unknown
bool c2pa_stage_requested = false
PreparedTransferC2paSignerInput c2pa_signer_input
bool c2pa_signed_package_provided = false
PreparedTransferC2paSignedPackage c2pa_signed_package
struct ExecutePreparedTransferFileResult

Result for execute_prepared_transfer_file.

Public Members

PrepareTransferFileResult prepared
ExecutePreparedTransferResult execute
bool xmp_existing_destination_embedded_loaded = false
TransferStatus xmp_existing_destination_embedded_status = TransferStatus::Unsupported
std::string xmp_existing_destination_embedded_message
std::string xmp_existing_destination_embedded_path
bool xmp_sidecar_requested = false
TransferStatus xmp_sidecar_status = TransferStatus::Unsupported
std::string xmp_sidecar_message
std::string xmp_sidecar_path
std::vector<std::byte> xmp_sidecar_output
bool xmp_sidecar_cleanup_requested = false
TransferStatus xmp_sidecar_cleanup_status = TransferStatus::Unsupported
std::string xmp_sidecar_cleanup_message
std::string xmp_sidecar_cleanup_path
struct ExecutePreparedTransferOptions

Options for execute_prepared_transfer.

Public Members

std::vector<TransferTimePatchInput> time_patches
ApplyTimePatchOptions time_patch
bool time_patch_auto_nul = true
EmitTransferOptions emit
uint32_t emit_repeat = 1
TransferByteWriter *emit_output_writer = nullptr

Optional metadata-only sink. BMFF targets write an ordered item/property payload handoff, not a standalone BMFF container.

bool edit_requested = false
bool edit_apply = false
TransferByteWriter *edit_output_writer = nullptr
bool strip_existing_xmp = false
PlanJpegEditOptions jpeg_edit
PlanTiffEditOptions tiff_edit
struct ExecutePreparedTransferResult

Result for execute_prepared_transfer.

Public Members

bool c2pa_stage_requested = false
ValidatePreparedC2paSignResult c2pa_stage_validation
EmitTransferResult c2pa_stage
ApplyTimePatchResult time_patch
EmitTransferResult compile
uint32_t compiled_ops = 0
EmitTransferResult emit
std::vector<EmittedJpegMarkerSummary> marker_summary
std::vector<EmittedTiffTagSummary> tiff_tag_summary
std::vector<EmittedJxlBoxSummary> jxl_box_summary
std::vector<EmittedWebpChunkSummary> webp_chunk_summary
std::vector<EmittedPngChunkSummary> png_chunk_summary
std::vector<EmittedJp2BoxSummary> jp2_box_summary
std::vector<EmittedExrAttributeSummary> exr_attribute_summary
std::vector<EmittedBmffItemSummary> bmff_item_summary
std::vector<EmittedBmffPropertySummary> bmff_property_summary
bool tiff_commit = false
uint64_t emit_output_size = 0
bool strip_existing_xmp = false
bool edit_requested = false
TransferStatus edit_plan_status = TransferStatus::Unsupported
std::string edit_plan_message
JpegEditPlan jpeg_edit_plan
TiffEditPlan tiff_edit_plan
EmitTransferResult edit_apply
uint64_t edit_input_size = 0
uint64_t edit_output_size = 0
std::vector<std::byte> edited_output
struct ExecutePreparedTransferSnapshotOptions

Options for execute_prepared_transfer_snapshot.

Public Members

PrepareTransferRequest prepare
ExecutePreparedTransferOptions execute
OpenMetaResourcePolicy policy
std::string edit_target_path
std::string xmp_existing_sidecar_base_path

Base path used to load one existing sibling .xmp sidecar for XMP merge during bundle preparation.

When empty, the helper uses edit_target_path.

std::string xmp_sidecar_base_path

Base path used to derive sibling .xmp output or cleanup paths.

When empty, the helper derives the sidecar path from edit_target_path.

XmpExistingSidecarMode xmp_existing_sidecar_mode = XmpExistingSidecarMode::Ignore
XmpExistingSidecarPrecedence xmp_existing_sidecar_precedence = XmpExistingSidecarPrecedence::SidecarWins
std::string xmp_existing_destination_embedded_path

Optional path used to load existing destination embedded XMP before bundle preparation.

When empty and destination embedded merge is requested, the helper uses edit_target_path.

XmpExistingDestinationEmbeddedMode xmp_existing_destination_embedded_mode = XmpExistingDestinationEmbeddedMode::Ignore
XmpExistingDestinationEmbeddedPrecedence xmp_existing_destination_embedded_precedence = XmpExistingDestinationEmbeddedPrecedence::DestinationWins
XmpExistingDestinationCarrierPrecedence xmp_existing_destination_carrier_precedence = XmpExistingDestinationCarrierPrecedence::SidecarWins
XmpWritebackMode xmp_writeback_mode = XmpWritebackMode::EmbeddedOnly
XmpDestinationEmbeddedMode xmp_destination_embedded_mode = XmpDestinationEmbeddedMode::PreserveExisting
XmpDestinationSidecarMode xmp_destination_sidecar_mode = XmpDestinationSidecarMode::PreserveExisting
XmpExistingDestinationSidecarState xmp_existing_destination_sidecar_state = XmpExistingDestinationSidecarState::Unknown
bool c2pa_stage_requested = false
PreparedTransferC2paSignerInput c2pa_signer_input
bool c2pa_signed_package_provided = false
PreparedTransferC2paSignedPackage c2pa_signed_package
struct ExifDecodeLimits
#include <exif_tiff_decode.h>

Resource limits applied during decode to bound hostile inputs.

Public Members

uint32_t max_ifds = 128
uint32_t max_entries_per_ifd = 4096
uint32_t max_total_entries = 200000
uint64_t max_value_bytes = 16ULL * 1024ULL * 1024ULL
uint64_t max_arena_bytes = 64ULL * 1024ULL * 1024ULL

Cumulative bytes copied into the destination store by this decode and all nested decoders (0 = unlimited).

struct ExifDecodeOptions
#include <exif_tiff_decode.h>

Decoder options for decode_exif_tiff.

Public Members

bool include_pointer_tags = true

If true, pointer tags are preserved as entries in addition to being followed.

bool decode_printim = true

If true, decode EXIF PrintIM (0xC4A5) into MetaKeyKind::PrintImField.

bool decode_geotiff = true

If true, decode GeoTIFF GeoKeyDirectoryTag (0x87AF) into MetaKeyKind::GeotiffKey entries (best-effort).

bool decode_makernote = false

If true, attempt best-effort MakerNote decoding (vendor blocks).

bool decode_embedded_containers = false

If true, attempt best-effort decoding of embedded containers stored as EXIF tag byte blobs (for example, Panasonic RW2 JpgFromRaw).

ExifIfdTokenPolicy tokens

IFD token naming policy (affects emitted EXIF key IFD strings).

ExifDecodeLimits limits
struct ExifDecodeResult
#include <exif_tiff_decode.h>

Aggregated decode statistics.

Public Members

ExifDecodeStatus status = ExifDecodeStatus::Ok
uint32_t ifds_written = 0
uint32_t ifds_needed = 0
uint32_t entries_decoded = 0
ExifLimitReason limit_reason = ExifLimitReason::None
uint64_t limit_ifd_offset = 0
uint16_t limit_tag = 0
struct ExifIfdRef
#include <exif_tiff_decode.h>

Reference to a decoded IFD within the input TIFF byte stream.

Public Members

ExifIfdKind kind = ExifIfdKind::Ifd
uint32_t index = 0
uint64_t offset = 0
BlockId block = kInvalidBlockId
struct ExifIfdTokenPolicy
#include <exif_tiff_decode.h>

Token strings used to label decoded IFD blocks.

Public Members

std::string_view ifd_prefix = "ifd"

Prefix used for generic IFD chain blocks (e.g. ifd0, ifd1).

std::string_view subifd_prefix = "subifd"

Prefix used for SubIFD blocks (e.g. subifd0, subifd1).

std::string_view exif_ifd_token = "exififd"

Token used for the EXIF sub-IFD pointer directory.

std::string_view gps_ifd_token = "gpsifd"

Token used for the GPS sub-IFD pointer directory.

std::string_view interop_ifd_token = "interopifd"

Token used for the Interop sub-IFD pointer directory.

struct ExifOrientationInterpretation
#include <orientation.h>

Normalized interpretation for one EXIF/TIFF orientation value.

Public Members

ExifOrientationStatus status = ExifOrientationStatus::Ok
uint16_t orientation = 1
uint16_t rotation_degrees_cw = 0
uint16_t rotation_only_orientation = 1
bool mirrored = false
bool swaps_width_height = false
const char *name = "Horizontal (normal)"
struct ExifRandomAccessDecodeResult
#include <exif_tiff_decode.h>

Combined decode, source-I/O, and residual nested-payload result.

Public Functions

inline bool complete() const noexcept

True when source I/O and supported nested paths had no scratch/residual gap. The TIFF payload can still be malformed or unsupported; inspect decode.status separately.

Public Members

ExifDecodeResult decode
RandomAccessReadState input
uint64_t value_scratch_needed = 0U

Largest value-buffer requirement observed when caller scratch was too small. Zero means no value was skipped for this reason.

uint32_t nested_payloads_skipped = 0U

Nested vendor payloads or derived subtables not fully decoded by the callback-backed path. Zero is required before claiming nested parity.

struct ExifRandomAccessScratch
#include <exif_tiff_decode.h>

Caller-owned buffers for callback-backed TIFF/DNG decoding.

Public Members

std::span<std::byte> read_window

Structural read cache. At least 20 bytes are required for BigTIFF.

std::span<std::byte> value

Reusable storage for one out-of-line value or the combined GeoTIFF parameter payloads. Insufficient capacity is reported, never allocated.

RandomAccessReadWindowOptions window_options
struct ExifTag
#include <meta_key.h>

Public Members

ByteSpan ifd
uint16_t tag = 0
struct ExifTag
#include <meta_key.h>

Public Members

std::string_view ifd
uint16_t tag = 0
struct ExportItem
#include <interop_export.h>

A single exported metadata item.

The name view is valid only for the duration of MetadataSink::on_item.

Public Members

std::string_view name
const Entry *entry = nullptr
const Origin *origin = nullptr
EntryFlags flags = EntryFlags::None
struct ExportOptions
#include <interop_export.h>

Export controls for visit_metadata.

Public Members

ExportNameStyle style = ExportNameStyle::Canonical
ExportNamePolicy name_policy = ExportNamePolicy::ExifToolAlias
bool include_origin = false
bool include_flags = false
bool include_makernotes = true
struct ExrAdapterAttribute
#include <exr_adapter.h>

One owned EXR-native attribute payload.

Public Members

uint32_t part_index = 0
std::string name
std::string type_name
std::vector<std::byte> value
bool is_opaque = false
struct ExrAdapterBatch
#include <exr_adapter.h>

One owned EXR-native attribute batch.

Public Members

uint32_t encoding_version = kExrCanonicalEncodingVersion
ExrAdapterOptions options
std::vector<ExrAdapterAttribute> attributes
struct ExrAdapterOptions
#include <exr_adapter.h>

Options for EXR attribute batch export.

Public Members

bool include_opaque = true

Include opaque/custom EXR attributes when type name is preserved.

bool fail_on_unencodable = true

If false, unencodable entries are skipped instead of failing.

struct ExrAdapterPartSpan
#include <exr_adapter.h>

One contiguous per-part span inside ExrAdapterBatch::attributes.

Public Members

uint32_t part_index = 0
uint32_t first_attribute = 0
uint32_t attribute_count = 0
struct ExrAdapterPartView
#include <exr_adapter.h>

One zero-copy per-part attribute view over ExrAdapterBatch.

Public Members

uint32_t part_index = 0
std::span<const ExrAdapterAttribute> attributes
struct ExrAdapterReplayCallbacks
#include <exr_adapter.h>

Replay callbacks for replay_exr_attribute_batch.

Public Members

ExrAdapterStatus (*begin_part)(void *user, uint32_t part_index, uint32_t attribute_count) noexcept = nullptr
ExrAdapterStatus (*emit_attribute)(void *user, uint32_t part_index, const ExrAdapterAttribute *attribute) noexcept = nullptr
ExrAdapterStatus (*end_part)(void *user, uint32_t part_index) noexcept = nullptr
void *user = nullptr
struct ExrAdapterReplayResult
#include <exr_adapter.h>

Result for EXR adapter batch replay.

Public Members

ExrAdapterStatus status = ExrAdapterStatus::Ok
uint32_t replayed_parts = 0
uint32_t replayed_attributes = 0
uint32_t failed_part_index = std::numeric_limits<uint32_t>::max()
uint32_t failed_attribute_index = std::numeric_limits<uint32_t>::max()
std::string message
struct ExrAdapterResult
#include <exr_adapter.h>

Result for EXR adapter batch export.

Public Members

ExrAdapterStatus status = ExrAdapterStatus::Ok
uint32_t exported = 0
uint32_t skipped = 0
uint32_t errors = 0
EntryId failed_entry = kInvalidEntryId
std::string message
struct ExrAttribute
#include <meta_key.h>

Public Members

uint32_t part_index = 0
ByteSpan name
struct ExrAttribute
#include <meta_key.h>

Public Members

uint32_t part_index = 0
std::string_view name
struct ExrDecodeLimits
#include <exr_decode.h>

Resource limits applied during EXR header decode.

Public Members

uint32_t max_parts = 64
uint32_t max_attributes_per_part = 1U << 16
uint32_t max_attributes = 200000
uint32_t max_name_bytes = 1024
uint32_t max_type_name_bytes = 1024
uint32_t max_attribute_bytes = 8U * 1024U * 1024U
uint64_t max_total_attribute_bytes = 64ULL * 1024ULL * 1024ULL
struct ExrDecodeOptions
#include <exr_decode.h>

Decoder options for decode_exr_header.

Public Members

bool decode_known_types = true

If true, decodes known scalar/vector EXR attribute types into typed values. Unknown and complex attribute types are always preserved as raw bytes.

bool preserve_unknown_type_name = true

If true, preserves original EXR type name for unknown/custom attrs in Origin::wire_type_name.

ExrDecodeLimits limits
struct ExrDecodeResult
#include <exr_decode.h>

Public Members

ExrDecodeStatus status = ExrDecodeStatus::Ok
uint32_t parts_decoded = 0
uint32_t entries_decoded = 0
struct ExrPreparedAttribute

EXR attribute payload for transfer emission.

Public Members

std::string name
std::string type_name
std::vector<std::byte> value
bool is_opaque = false
struct ExrPreparedAttributeView

Zero-copy EXR attribute view for prepared transfer emission.

Public Members

std::string_view name
std::string_view type_name
std::span<const std::byte> value
bool is_opaque = false
struct ExrRandomAccessDecodeResult
#include <exr_decode.h>

Combined EXR decode and source-I/O result.

Public Functions

inline bool complete() const noexcept

Public Members

ExrDecodeResult decode
RandomAccessReadState input
uint64_t value_scratch_needed = 0U

Largest value-buffer requirement observed when caller scratch was too small. Zero means no attribute was skipped for this reason.

struct ExrRandomAccessScratch
#include <exr_decode.h>

Caller-owned storage for callback-backed EXR header decoding.

Public Members

std::span<std::byte> read_window

Reusable structural read cache. At least 16 bytes are required.

std::span<std::byte> value

Reusable storage for one attribute value that does not fit the window.

RandomAccessReadWindowOptions window_options
class ExrTransferEmitter

Backend contract for OpenEXR header attribute emission.

Public Functions

virtual ~ExrTransferEmitter() = default
virtual TransferStatus set_attribute(const ExrPreparedAttribute &attr) noexcept = 0
inline virtual TransferStatus set_attribute_view(const ExrPreparedAttributeView &attr) noexcept
struct FlatHostImportItem
#include <interop_import.h>

One ordered typed record imported from a flat host attribute model.

Public Members

std::string_view name
FlatHostImportTarget target = FlatHostImportTarget::UniqueName
EntryId source_entry = kInvalidEntryId
MetaKeyView explicit_key
FlatHostImportValue value
struct FlatHostImportOptions
#include <interop_import.h>

Resource and naming policy for bounded flat host import.

Public Members

ExportNamePolicy name_policy = ExportNamePolicy::Spec
bool include_makernotes = false
uint32_t max_items = 200000U
uint32_t max_entries = 200000U
uint64_t max_arena_bytes = 64ULL * 1024ULL * 1024ULL
uint64_t max_value_bytes = 64ULL * 1024ULL * 1024ULL
uint32_t max_name_bytes = 4096U
struct FlatHostImportResult
#include <interop_import.h>

Transactional result for bounded flat host import.

Public Functions

inline bool ok() const noexcept

Public Members

FlatHostImportCode code = FlatHostImportCode::None
uint32_t imported = 0U
uint32_t updated = 0U
uint32_t added = 0U
uint32_t failed_item = 0xFFFFFFFFU
uint32_t errors = 0U
std::string message
MetaStore store
struct FlatHostImportValue
#include <interop_import.h>

Borrowed typed value supplied by a flat host.

Scalar values use scalar. Array, byte, and text values use payload; their element type, count, and text encoding remain explicit.

Public Members

MetaValueKind kind = MetaValueKind::Empty
MetaElementType elem_type = MetaElementType::U8
TextEncoding text_encoding = TextEncoding::Unknown
uint32_t count = 0U
MetaValue::Data scalar
std::span<const std::byte> payload
struct GeotiffKey
#include <meta_key.h>

Public Members

uint16_t key_id = 0
struct GeotiffKey
#include <meta_key.h>

Public Members

uint16_t key_id = 0
struct HostAdoptionProfile
#include <host_adoption.h>

Exact contract versions that form one host adoption profile.

This descriptor reports API compatibility, not format coverage. Query format/family support separately with metadata_capability(...), and inspect positional read residuals before treating a snapshot as complete.

Public Functions

constexpr bool operator==(const HostAdoptionProfile&) const noexcept = default

Public Members

uint32_t profile_version = kHostAdoptionProfileContractVersion
uint32_t random_access_source_version = kRandomAccessSourceContractVersion
uint32_t positional_snapshot_version = kReadTransferSourceSnapshotContractVersion
uint32_t snapshot_object_version = kTransferSourceSnapshotContractVersion
uint32_t snapshot_serialization_version = kTransferSourceSnapshotSerializationVersion
uint32_t flat_host_export_version = kFlatHostExportContractVersion
uint32_t flat_host_import_version = kFlatHostImportContractVersion
uint32_t read_diagnostics_version = kReadTransferSourceDiagnosticsContractVersion
uint32_t prepared_adapter_schema_version = kPreparedTransferAdapterContractVersion
struct IccDecodeLimits
#include <icc_decode.h>

Resource limits applied during ICC decode to bound hostile inputs.

Public Members

uint32_t max_tags = 1U << 16
uint32_t max_tag_bytes = 32U * 1024U * 1024U
uint64_t max_total_tag_bytes = 64ULL * 1024ULL * 1024ULL
struct IccDecodeOptions
#include <icc_decode.h>

Decoder options for decode_icc_profile.

Public Members

IccDecodeLimits limits
struct IccDecodeResult
#include <icc_decode.h>

Public Members

IccDecodeStatus status = IccDecodeStatus::Ok
uint32_t entries_decoded = 0
struct IccHeaderField
#include <meta_key.h>

Public Members

uint32_t offset = 0
struct IccHeaderField
#include <meta_key.h>

Public Members

uint32_t offset = 0
struct IccTag
#include <meta_key.h>

Public Members

uint32_t signature = 0
struct IccTag
#include <meta_key.h>

Public Members

uint32_t signature = 0
struct IccTagInterpretation
#include <icc_interpret.h>

Best-effort decoded view of an ICC tag payload.

Public Members

uint32_t signature = 0

ICC tag signature (from tag table).

std::string_view name

Tag display name for signature, when known.

std::string type

ICC tag type signature as text/fourcc (for example desc, XYZ, curv).

std::string text

Decoded text (for text-like tags).

std::vector<double> values

Decoded numeric values (for XYZ/curve/parametric forms).

uint32_t rows = 0

Optional layout hint for matrix-like values.

uint32_t cols = 0

Optional layout hint for matrix-like values.

struct IccTagInterpretLimits
#include <icc_interpret.h>

Limits for ICC tag interpretation helpers.

Public Members

uint32_t max_values = 512U
uint32_t max_text_bytes = 4096U
struct IccTagInterpretOptions
#include <icc_interpret.h>

Options for interpret_icc_tag.

Public Members

IccTagInterpretLimits limits
struct InteropSafetyError
#include <interop_export.h>

Structured error details returned by strict safe interop exports.

Public Members

InteropSafetyReason reason = InteropSafetyReason::None
std::string field_name
std::string key_path
std::string message
struct IptcDataset
#include <meta_key.h>

Public Members

uint16_t record = 0
uint16_t dataset = 0
struct IptcDataset
#include <meta_key.h>

Public Members

uint16_t record = 0
uint16_t dataset = 0
struct IptcIimDecodeLimits
#include <iptc_iim_decode.h>

Resource limits applied during IPTC-IIM decode to bound hostile inputs.

Public Members

uint32_t max_datasets = 200000
uint32_t max_dataset_bytes = 8U * 1024U * 1024U
uint64_t max_total_bytes = 64ULL * 1024ULL * 1024ULL
struct IptcIimDecodeOptions
#include <iptc_iim_decode.h>

Decoder options for decode_iptc_iim.

Public Members

IptcIimDecodeLimits limits
struct IptcIimDecodeResult
#include <iptc_iim_decode.h>

Public Members

IptcIimDecodeStatus status = IptcIimDecodeStatus::Ok
uint32_t entries_decoded = 0
class Jp2TransferEmitter

Backend contract for JP2 metadata box emission.

Public Functions

virtual ~Jp2TransferEmitter() = default
virtual TransferStatus add_box(std::array<char, 4> type, std::span<const std::byte> payload) noexcept = 0
virtual TransferStatus close_boxes() noexcept = 0
struct JpegEditPlan

Planned JPEG edit summary (draft API).

Public Members

TransferStatus status = TransferStatus::Ok
JpegEditMode requested_mode = JpegEditMode::Auto
JpegEditMode selected_mode = JpegEditMode::MetadataRewrite
bool in_place_possible = false
bool strip_existing_xmp = false
uint32_t emitted_segments = 0
uint32_t replaced_segments = 0
uint32_t appended_segments = 0
uint32_t removed_existing_segments = 0
uint32_t removed_existing_jumbf_segments = 0
uint32_t removed_existing_c2pa_segments = 0
uint64_t input_size = 0
uint64_t output_size = 0
uint64_t leading_scan_end = 0
std::string message
class JpegTransferEmitter

Backend contract for JPEG metadata emission.

Public Functions

virtual ~JpegTransferEmitter() = default
virtual TransferStatus write_app_marker(uint8_t marker_code, std::span<const std::byte> payload) noexcept = 0
struct JumbfCborKey
#include <meta_key.h>

Public Members

ByteSpan key
struct JumbfCborKey
#include <meta_key.h>

Public Members

std::string_view key
struct JumbfDecodeLimits
#include <jumbf_decode.h>

Resource limits for JUMBF/C2PA decode.

Public Members

uint64_t max_input_bytes = 64ULL * 1024ULL * 1024ULL

Maximum input bytes to accept (0 = unlimited).

uint32_t max_box_depth = 32

Maximum BMFF box depth. 0 is normalized to a safe default (32).

uint32_t max_boxes = 1U << 16

Maximum BMFF boxes to traverse. 0 is normalized to a safe default (65536).

uint32_t max_entries = 200000

Maximum emitted entries. 0 is normalized to a safe default (200000).

uint32_t max_cbor_depth = 64

Maximum CBOR recursion depth. 0 is normalized to a safe default (64).

uint32_t max_cbor_items = 200000

Maximum CBOR items to parse. 0 is normalized to a safe default (200000).

uint32_t max_cbor_key_bytes = 1024

Maximum CBOR string key bytes.

uint32_t max_cbor_text_bytes = 8U * 1024U * 1024U

Maximum CBOR text value bytes.

uint32_t max_cbor_bytes_bytes = 8U * 1024U * 1024U

Maximum CBOR byte-string value bytes.

struct JumbfDecodeOptions
#include <jumbf_decode.h>

Decoder options for decode_jumbf_payload.

Public Members

bool decode_cbor = true

If true, traverse cbor boxes and emit decoded CBOR key/value entries.

bool detect_c2pa = true

If true, emit a c2pa.detected marker when C2PA-like payload is seen.

bool verify_c2pa = false

If true, request draft C2PA verification scaffold fields.

C2paVerifyBackend verify_backend = C2paVerifyBackend::Auto

Verification backend preference (used when verify_c2pa is true).

bool verify_require_trusted_chain = false

If true, require the certificate chain to validate against the system trust store. Untrusted or missing chains fail verification even when the signature matches.

bool verify_require_resolved_references = false

If true, explicit claim references must resolve deterministically: unresolved or ambiguous explicit-reference signatures fail verification.

JumbfDecodeLimits limits
struct JumbfDecodeResult
#include <jumbf_decode.h>

JUMBF decode result summary.

Public Members

JumbfDecodeStatus status = JumbfDecodeStatus::Unsupported
uint32_t boxes_decoded = 0
uint32_t cbor_items = 0
uint32_t entries_decoded = 0
C2paVerifyStatus verify_status = C2paVerifyStatus::NotRequested
C2paVerifyBackend verify_backend_selected = C2paVerifyBackend::None
struct JumbfField
#include <meta_key.h>

Public Members

ByteSpan field
struct JumbfField
#include <meta_key.h>

Public Members

std::string_view field
struct JumbfStructureEstimate
#include <jumbf_decode.h>

Preflight structural estimate for a JUMBF/C2PA payload.

This is a scan-only estimate: it does not emit metadata entries.

Public Members

JumbfDecodeStatus status = JumbfDecodeStatus::Unsupported
uint32_t boxes_scanned = 0
uint32_t max_box_depth = 0
uint32_t cbor_payloads = 0
uint32_t cbor_items = 0
uint32_t max_cbor_depth = 0
class JxlTransferEmitter

Backend contract for JPEG XL metadata box emission.

Public Functions

virtual ~JxlTransferEmitter() = default
virtual TransferStatus set_icc_profile(std::span<const std::byte> payload) noexcept = 0
virtual TransferStatus add_box(std::array<char, 4> type, std::span<const std::byte> payload, bool compress) noexcept = 0
virtual TransferStatus close_boxes() noexcept = 0
struct KeySpan
#include <meta_store.h>

Public Members

uint32_t start = 0
uint32_t count = 0
EntryId repr = kInvalidEntryId
struct LibRawFlipToExifOptions
#include <libraw_adapter.h>

Options for map_libraw_flip_to_exif_orientation.

Public Members

LibRawOrientationTarget target = LibRawOrientationTarget::RawImage

Raw-image flips should normally map back into EXIF orientation.

bool preserve_embedded_preview_orientation = true

Embedded previews are usually delivered as-is or carry their own EXIF.

struct LibRawFlipToExifResult
#include <libraw_adapter.h>

Result for map_libraw_flip_to_exif_orientation.

Public Members

LibRawOrientationStatus status = LibRawOrientationStatus::Ok
LibRawFlipToExifCode code = LibRawFlipToExifCode::None
uint32_t libraw_flip = 0
uint16_t exif_orientation = 1
bool preview_passthrough = false
struct LibRawOrientationFileOptions
#include <libraw_adapter.h>

Options for map_meta_orientation_to_libraw_flip_from_file.

Public Members

uint64_t max_file_bytes = 0
SimpleMetaDecodeOptions decode
LibRawOrientationOptions orientation
struct LibRawOrientationFileResult
#include <libraw_adapter.h>

Result for map_meta_orientation_to_libraw_flip_from_file.

Public Members

LibRawOrientationFileStatus file_status = LibRawOrientationFileStatus::Ok
MappedFileStatus mapped_file_status = MappedFileStatus::Ok
uint64_t file_size = 0
SimpleMetaResult read
LibRawOrientationResult orientation
struct LibRawOrientationOptions
#include <libraw_adapter.h>

Options for map_exif_orientation_to_libraw_flip.

Public Members

LibRawOrientationTarget target = LibRawOrientationTarget::RawImage

Raw-image orientation should normally map into imgdata.sizes.flip.

bool preserve_embedded_preview_orientation = true

Embedded previews are usually delivered as-is or carry their own EXIF.

LibRawMirrorPolicy mirror_policy = LibRawMirrorPolicy::Reject

Mirrored TIFF/EXIF orientations are not representable in LibRaw flip.

struct LibRawOrientationResult
#include <libraw_adapter.h>

Result for map_exif_orientation_to_libraw_flip.

Public Members

LibRawOrientationStatus status = LibRawOrientationStatus::Ok
LibRawOrientationCode code = LibRawOrientationCode::None
LibRawOrientationSource source = LibRawOrientationSource::ExplicitInput
uint16_t exif_orientation = 1
uint32_t libraw_flip = 0
bool apply_flip = false
bool mirrored = false
bool preview_passthrough = false
bool has_exif_ifd0_orientation = false
bool has_xmp_tiff_orientation = false
uint16_t exif_ifd0_orientation = 0
uint16_t xmp_tiff_orientation = 0
bool orientation_conflict = false
class MappedFile
#include <mapped_file.h>

Read-only, whole-file memory mapping.

This is a utility used by tools/bindings to avoid copying multi-GB files into memory while still exposing a std::span<const std::byte> view that OpenMeta’s decoders can operate on.

Public Functions

MappedFile() noexcept
~MappedFile() noexcept
MappedFile(const MappedFile&) = delete
MappedFile &operator=(const MappedFile&) = delete
MappedFile(MappedFile &&other) noexcept
MappedFile &operator=(MappedFile &&other) noexcept
MappedFileStatus open(const char *path, uint64_t max_file_bytes = 0) noexcept

Opens and maps path (read-only). max_file_bytes is a hard cap (0 = unlimited).

void close() noexcept

Unmaps/closes the file (idempotent).

bool is_open() const noexcept
uint64_t size() const noexcept
std::span<const std::byte> bytes() const noexcept

Private Members

int fd_ = -1
const std::byte *data_ = nullptr
uint64_t size_ = 0
struct MetadataCapability

Capability record for one format/family pair.

struct MetadataCompatibilityDumpOptions

Options for dump_metadata_compatibility.

Public Members

ExportNameStyle style = ExportNameStyle::FlatHost
ExportNamePolicy name_policy = ExportNamePolicy::ExifToolAlias
bool include_values = true
bool include_origins = true
bool include_flags = true
uint32_t max_value_bytes = 256U
struct MetadataConceptCandidate

Public Members

MetadataConceptKind kind = MetadataConceptKind::Orientation
MetadataConceptRole role = MetadataConceptRole::Primary
MetadataConceptSourceFamily family = MetadataConceptSourceFamily::Unknown
MetadataQuerySemanticKind semantic = MetadataQuerySemanticKind::Unknown
MetadataQueryValueShape shape = MetadataQueryValueShape::Unknown
MetadataConceptRecordKind record_kind = MetadataConceptRecordKind::None

Normalized structured-record type; None for unstructured values.

MetadataImageRegionShape image_region_shape = MetadataImageRegionShape::Unknown

Source-declared shape for synthesized image-region geometry.

MetadataImageRegionCoordinateUnit image_region_coordinate_unit = MetadataImageRegionCoordinateUnit::Unknown

Coordinate space for synthesized image-region geometry.

MetadataConceptSensitivity sensitivity = MetadataConceptSensitivity::None

Host policy signal; independent from technical transfer safety.

EntryId entry_id = kInvalidEntryId
std::vector<EntryId> source_entries
uint8_t priority = 0U
bool preferred = false
bool conflict = false
MetadataConceptTransferHint transfer_hint = MetadataConceptTransferHint::Unknown
bool compatible_file_safe = false
bool rendered_image_safe = false
bool requires_target_image_spec = false
bool source_bound = false
MetadataRawApplicabilityState raw_applicability = MetadataRawApplicabilityState::Unknown
bool raw_applicability_requires_storage_context = false
bool raw_applicability_can_affect_decode = false
bool has_numeric = false
uint8_t numeric_count = 0U
double numeric[4] = {}
bool has_values = false
std::vector<double> values
bool has_origin = false
double origin[2] = {}
bool has_size = false
double size[2] = {}
bool has_rect = false
double rect[4] = {}

Rect is normalized as x, y, width, height.

bool has_margins = false
double margins[4] = {}

Margins are normalized as left, top, right, bottom.

std::string text
std::string value_key

Normalized value used for same-role conflict checks.

bool has_date_time = false
bool date_time_has_time = false
bool date_time_has_utc_offset = false
MetadataConceptDateTimePrecision date_time_precision = MetadataConceptDateTimePrecision::Unknown
MetadataConceptTimeZoneKind date_time_zone = MetadataConceptTimeZoneKind::Unknown
int16_t date_time_year = 0
uint8_t date_time_month = 0U
uint8_t date_time_day = 0U
uint8_t date_time_hour = 0U
uint8_t date_time_minute = 0U
uint8_t date_time_second = 0U
bool date_time_has_subsecond = false
std::string date_time_subsecond

Normalized decimal digits, bounded to nanosecond precision.

int16_t date_time_utc_offset_min = 0
bool has_gps_altitude_reference = false
bool gps_altitude_below_sea_level = false
uint8_t gps_altitude_reference_code = 0U
std::string location_scope

Structured XMP parent path, for example LocationShown[1].

std::string record_scope

Structured metadata parent path, for example Licensor[1].

std::string language

Normalized language tag for localized descriptive values.

struct MetadataConceptResolution

Public Members

MetadataConceptKind kind = MetadataConceptKind::Orientation
bool found = false
bool conflict = false
EntryId preferred_entry = kInvalidEntryId
std::vector<EntryId> source_entries
std::vector<MetadataConceptCandidate> candidates
struct MetadataConceptResult

Public Members

std::vector<MetadataConceptResolution> concepts
struct MetadataCreationField

One logical field supplied by a host application.

Public Members

MetadataCreationFieldKind kind = MetadataCreationFieldKind::Title
MetadataCreationValueKind value_kind = MetadataCreationValueKind::Text
std::string_view text
uint32_t unsigned_value = 0U
int32_t signed_value = 0
URational rational
struct MetadataCreationLimits

Caller-selected limits, bounded by the public hard maxima above.

Public Members

uint32_t max_fields = kMetadataCreationMaxFields
uint32_t max_text_bytes_per_field = kMetadataCreationMaxTextBytesPerField
uint64_t max_total_text_bytes = kMetadataCreationMaxTotalTextBytes
struct MetadataCreationRequest

Stable creation request.

Public Members

std::span<const MetadataCreationField> fields
MetadataCreationLimits limits
struct MetadataCreationResult

Result details for one creation request.

Public Members

MetadataCreationStatus status = MetadataCreationStatus::Ok
uint32_t failed_field_index = kInvalidMetadataCreationFieldIndex
uint32_t field_count = 0U
uint32_t entries_created = 0U
struct MetadataEditingLimits
#include <metadata_editing.h>

Public Members

uint32_t max_operations = kMetadataEditingMaxOperations
uint32_t max_text_bytes_per_operation = kMetadataEditingMaxTextBytesPerOperation
uint64_t max_total_text_bytes = kMetadataEditingMaxTotalTextBytes
struct MetadataEditingOperation
#include <metadata_editing.h>

One logical edit applied in request order.

Add ignores occurrence and appends a repeated field or creates an absent singleton. Set replaces one zero-based active occurrence. Remove deletes one occurrence, or all occurrences when occurrence is kMetadataEditingAllOccurrences.

Public Members

MetadataEditingOperationKind kind = MetadataEditingOperationKind::Add
MetadataCreationField field
uint32_t occurrence = 0U
struct MetadataEditingRequest
#include <metadata_editing.h>

Public Members

std::span<const MetadataEditingOperation> operations
MetadataEditingLimits limits
struct MetadataEditingResult
#include <metadata_editing.h>

Public Members

MetadataEditingStatus status = MetadataEditingStatus::Ok
uint32_t failed_operation_index = kInvalidMetadataEditingOperationIndex
uint32_t operation_count = 0U
uint32_t operations_applied = 0U
uint32_t entries_added = 0U
uint32_t entries_updated = 0U
uint32_t entries_removed = 0U
struct MetadataFuzzySearchMatch

Public Members

EntryId entry_id = kInvalidEntryId
MetaKeyKind key_kind = MetaKeyKind::ExifTag
MetadataFuzzySearchMatchKind match_kind = MetadataFuzzySearchMatchKind::Fuzzy
uint8_t score = 0U
bool group_truncated = false
bool name_truncated = false
std::string group
std::string name
struct MetadataFuzzySearchOptions

Public Members

uint8_t minimum_score = 80U

Inclusive score cutoff in the range 50..100.

uint32_t max_results = 16U

Bounded result count in the range 1..kMetadataFuzzySearchMaxResults.

struct MetadataFuzzySearchResult

Public Members

MetadataFuzzySearchStatus status = MetadataFuzzySearchStatus::Ok
uint32_t examined_entry_count = 0U
uint32_t qualified_match_count = 0U
bool truncated = false
std::vector<MetadataFuzzySearchMatch> matches
struct MetadataInterpretationRecord

One normalized interpretation record.

Records preserve the source entries that produced the interpretation and use the same semantic and shape vocabulary as metadata query. Numeric geometry is normalized where available: rect is x, y, width, height; margins are left, top, right, bottom.

Public Members

MetadataQueryKind query_kind = MetadataQueryKind::Crop
MetadataQuerySemanticKind semantic = MetadataQuerySemanticKind::Unknown
MetadataQueryValueShape shape = MetadataQueryValueShape::Unknown
uint8_t confidence = 0U
std::vector<EntryId> source_entries
bool has_origin = false
double origin[2] = {}
bool has_size = false
double size[2] = {}
bool has_rect = false
double rect[4] = {}
bool has_margins = false
double margins[4] = {}
bool has_values = false
std::vector<double> values
struct MetadataInterpretationResult

Public Members

std::vector<MetadataInterpretationRecord> records
struct MetadataQueryCandidate
#include <metadata_query.h>

Public Members

MetadataQuerySemanticKind semantic = MetadataQuerySemanticKind::Unknown
MetadataQueryValueShape normalized_shape = MetadataQueryValueShape::Unknown
uint8_t confidence = 0U
std::vector<EntryId> source_entries
bool has_origin = false
double origin[2] = {}
bool has_size = false
double size[2] = {}
bool has_rect = false
double rect[4] = {}

Rect is normalized as x, y, width, height.

bool has_margins = false
double margins[4] = {}

Margins are normalized as left, top, right, bottom.

bool has_values = false
std::vector<double> values
struct MetadataQueryMatch
#include <metadata_query.h>

Public Members

EntryId entry_id = kInvalidEntryId
MetaKeyKind key_kind = MetaKeyKind::ExifTag
MetadataQuerySemanticKind semantic = MetadataQuerySemanticKind::Unknown
MetadataQueryValueShape shape = MetadataQueryValueShape::Unknown
uint8_t confidence = 0U
uint32_t matched_terms = 0U
bool exact_match = false
bool fuzzy_match = false
uint8_t fuzzy_score = 0U
uint16_t exif_tag = 0U
std::string group
std::string name
struct MetadataQueryResult
#include <metadata_query.h>

Public Members

MetadataQueryKind kind = MetadataQueryKind::Crop
std::vector<MetadataQueryMatch> matches
std::vector<MetadataQueryCandidate> candidates
struct MetadataRawDataDescriptor

Public Members

MetadataRawDataEncoding encoding = MetadataRawDataEncoding::Unknown
bool has_dimensions = false
uint32_t width = 0U
uint32_t height = 0U
bool has_channel_count = false
uint32_t channel_count = 0U
bool has_bits_per_sample = false
uint32_t bits_per_sample = 0U
bool has_compression_code = false
uint32_t compression_code = 0U
bool has_plane_index = false
uint32_t plane_index = 0U
bool requires_compressed_raw_encoding = false
bool requires_primary_raw_plane = false
class MetadataSink
#include <interop_export.h>

Callback sink for visit_metadata.

API Stability

Stable host-facing v1 callback contract.

Public Functions

virtual ~MetadataSink() = default
virtual void on_item(const ExportItem &item) noexcept = 0
class MetaEdit
#include <meta_edit.h>

A batch of metadata edits to apply to a MetaStore.

Designed for multi-threaded production via per-thread edit buffers: build edits without mutating the base store, then apply with commit.

New keys/values that require storage use this edit’s ByteArena.

Public Functions

MetaEdit() = default
ByteArena &arena() noexcept
const ByteArena &arena() const noexcept
void reserve_ops(size_t count)

Reserves space for count operations (may allocate).

void add_entry(const Entry &entry)

Appends a new entry.

void set_value(EntryId target, const MetaValue &value)

Updates the value of an existing entry id.

void tombstone(EntryId target)

Marks an entry as deleted (tombstone).

std::span<const EditOp> ops() const noexcept

Private Members

ByteArena arena_
std::vector<EditOp> ops_
struct MetaKey
#include <meta_key.h>

An owned metadata key.

Uses ByteSpan fields for string-like components so keys can be stored compactly in a ByteArena (e.g. IFD token, XMP schema namespace).

Public Members

MetaKeyKind kind = MetaKeyKind::ExifTag
union openmeta::MetaKey::Data data
struct MetaKeyView
#include <meta_key.h>

A borrowed metadata key view.

Intended for lookups and comparisons without allocating/copying strings.

Public Members

MetaKeyKind kind = MetaKeyKind::ExifTag
union openmeta::MetaKeyView::Data data
class MetaStore
#include <meta_store.h>

Stores decoded metadata entries grouped into blocks.

Lifecycle:

  • Build phase: call add_block and add_entry (not thread-safe).

  • Finalize: call finalize to build lookup indices; treat as read-only.

Indices:

Public Functions

MetaStore() = default
BlockId add_block(const BlockInfo &info)

Adds a new block and returns its id.

EntryId add_entry(const Entry &entry)

Appends an entry and returns its id.

void constrain_resources(uint32_t max_entries, uint64_t max_arena_bytes) noexcept

Applies cumulative decode ceilings. Repeated calls retain the lowest non-zero limits, including across nested decoder calls.

bool resource_limit_exceeded() const noexcept

Returns true after a block, entry, or arena allocation was refused.

ByteArena &arena() noexcept
const ByteArena &arena() const noexcept
void finalize()

Builds lookup indices and marks the store as finalized.

void rehash()

Rebuilds indices after an edit pipeline (invalidates previous spans).

bool is_finalized() const noexcept

Returns whether lookup indices have been finalized.

uint32_t block_count() const noexcept
const BlockInfo &block_info(BlockId id) const noexcept
std::span<const Entry> entries() const noexcept
const Entry &entry(EntryId id) const noexcept
std::span<const EntryId> entries_in_block(BlockId block) const noexcept

Returns all entries in block, ordered by Origin::order_in_block.

std::span<const EntryId> find_all(const MetaKeyView &key) const noexcept

Returns all entry ids matching key (excluding tombstones).

Private Functions

void rebuild_block_index()
void rebuild_key_index()
void clear_indices() noexcept

Private Members

ByteArena arena_
std::vector<Entry> entries_
std::vector<BlockInfo> blocks_
std::vector<EntryId> entries_by_block_
std::vector<BlockSpan> block_spans_
std::vector<EntryId> entries_by_key_
std::vector<KeySpan> key_spans_
bool finalized_ = false
uint64_t max_entries_ = UINT32_MAX
bool entry_limit_exceeded_ = false

Friends

friend MetaStore commit(const MetaStore &base, std::span<const MetaEdit> edits)

Applies edits to base and returns a new MetaStore snapshot.

friend MetaStore compact(const MetaStore &base)

Compacts a store by removing tombstones and rewriting indices.

struct MetaValue
#include <meta_value.h>

A typed metadata value.

Storage rules:

  • Scalar values are stored inline in MetaValue::data.

  • Array/Bytes/Text values store their payload in MetaValue::data.span (a ByteSpan into a ByteArena). Text payload is not nul-terminated.

The count field is:

  • 1 for scalars

  • number of elements for arrays

  • number of bytes for bytes/text

Public Members

MetaValueKind kind = MetaValueKind::Empty
MetaElementType elem_type = MetaElementType::U8
TextEncoding text_encoding = TextEncoding::Unknown
uint32_t count = 0
union openmeta::MetaValue::Data data
struct OcioAdapterOptions
#include <ocio_adapter.h>

Options for build_ocio_metadata_tree.

Public Functions

inline OcioAdapterOptions() noexcept

Public Members

ExportOptions export_options
uint32_t max_value_bytes = 1024
bool include_empty = false
bool include_normalized_ccm = true

Append derived normalized DNG CCM fields under dngnorm:*.

struct OcioAdapterRequest
#include <ocio_adapter.h>

Stable flat request for OCIO adapter export.

Public Members

ExportNameStyle style = ExportNameStyle::XmpPortable
ExportNamePolicy name_policy = ExportNamePolicy::ExifToolAlias
bool include_makernotes = false
bool include_origin = false
bool include_flags = false
uint32_t max_value_bytes = 1024
bool include_empty = false
bool include_normalized_ccm = true
struct OcioMetadataNode
#include <ocio_adapter.h>

Minimal tree node similar to OCIO FormatMetadata composition.

Public Members

std::string name
std::string value
std::vector<OcioMetadataNode> children
struct OpenMetaResourcePolicy
#include <resource_policy.h>

Draft, storage-agnostic resource limits for untrusted metadata input.

This policy intentionally favors parser/output budgets over hard file-size caps, so large legitimate assets (for example RAW/EXR) can still be processed when decode limits are respected.

Public Members

uint64_t max_file_bytes = 0

Optional file mapping cap (0 = unlimited).

PayloadLimits payload_limits

Reassembly/decompression budgets.

ExifDecodeLimits exif_limits

EXIF/TIFF decode budgets.

XmpDecodeLimits xmp_limits

XMP RDF/XML decode budgets.

ExrDecodeLimits exr_limits

OpenEXR header decode budgets.

JumbfDecodeLimits jumbf_limits

JUMBF/C2PA decode budgets.

IccDecodeLimits icc_limits

ICC profile decode budgets.

IptcIimDecodeLimits iptc_limits

IPTC-IIM decode budgets.

PhotoshopIrbDecodeLimits photoshop_irb_limits

Photoshop IRB decode budgets.

PreviewScanLimits preview_scan_limits

Embedded preview discovery/extraction budgets.

uint64_t max_preview_output_bytes = 128ULL * 1024ULL * 1024ULL
XmpDumpLimits xmp_dump_limits

XMP sidecar dump budgets.

uint32_t max_decode_millis = 0

Draft future budget hooks (not enforced yet).

uint32_t max_decompression_ratio = 0
uint64_t max_total_decode_work_bytes = 0
struct Origin
#include <meta_store.h>

Where an Entry came from inside the original container.

Public Members

BlockId block = kInvalidBlockId
uint32_t order_in_block = 0
WireType wire_type
uint32_t wire_count = 0
ByteSpan wire_type_name

Optional wire type name (for formats with named types, e.g. OpenEXR custom attrs).

EntryNameContextKind name_context_kind = EntryNameContextKind::None
uint8_t name_context_variant = 0
struct PayloadLimits

Resource limits applied during payload extraction to bound hostile inputs.

Public Members

uint32_t max_parts = 1U << 14
uint64_t max_output_bytes = 64ULL * 1024ULL * 1024ULL
struct PayloadOptions

Options for payload extraction.

Public Members

bool decompress = true

If true, attempt to decompress payloads marked with BlockCompression.

PayloadLimits limits
struct PayloadRandomAccessResult

Combined logical-payload and source-I/O result.

Public Functions

inline bool complete() const noexcept

Public Members

PayloadResult payload
RandomAccessReadState input
uint64_t compressed_scratch_needed = 0U

Required compressed-stream storage when scratch.compressed was too small. Zero means no stream was skipped for this reason.

struct PayloadRandomAccessScratch

Caller-owned storage for callback-backed payload extraction.

Public Members

std::span<std::byte> read_window

Reusable cache for GIF sub-block framing and small positional reads.

std::span<std::byte> compressed

Storage for a compressed logical stream before decompression.

RandomAccessReadWindowOptions window_options
struct PayloadResult

Public Members

PayloadStatus status = PayloadStatus::Ok
uint64_t written = 0
uint64_t needed = 0
struct PersistPreparedTransferFileOptions

Options for persist_prepared_transfer_file_result.

Public Members

std::string output_path
bool write_output = true
bool overwrite_output = false
uint64_t prewritten_output_bytes = 0
bool overwrite_xmp_sidecar = false
bool remove_destination_xmp_sidecar = true
struct PersistPreparedTransferFileResult

Result for persist_prepared_transfer_file_result.

Public Members

TransferStatus status = TransferStatus::Unsupported
std::string message
TransferStatus output_status = TransferStatus::Unsupported
std::string output_message
std::string output_path
uint64_t output_bytes = 0
TransferStatus xmp_sidecar_status = TransferStatus::Unsupported
std::string xmp_sidecar_message
std::string xmp_sidecar_path
uint64_t xmp_sidecar_bytes = 0
TransferStatus xmp_sidecar_cleanup_status = TransferStatus::Unsupported
std::string xmp_sidecar_cleanup_message
std::string xmp_sidecar_cleanup_path
bool xmp_sidecar_cleanup_removed = false
struct PhaseOneRawGeometry

Public Members

uint32_t sensor_width = 0
uint32_t sensor_height = 0
uint32_t sensor_left_margin = 0
uint32_t sensor_top_margin = 0
uint32_t image_width = 0
uint32_t image_height = 0
uint32_t active_x = 0
uint32_t active_y = 0
uint32_t active_width = 0
uint32_t active_height = 0
uint32_t right_margin = 0
uint32_t bottom_margin = 0
struct PhaseOneRawGeometryResult
struct PhaseOneRawProcessingInfo

Public Members

bool has_color_matrix1 = false
double color_matrix1[9] = {}
bool has_color_matrix2 = false
double color_matrix2[9] = {}
bool has_wb_rgb_levels = false
double wb_rgb_levels[3] = {}
bool has_black_level = false
uint32_t black_level = 0
bool has_sensor_temperature_c = false
double sensor_temperature_c = 0.0
bool has_sensor_temperature2_c = false
double sensor_temperature2_c = 0.0
bool has_raw_format = false
uint32_t raw_format = 0
bool has_raw_data = false
uint64_t raw_data_bytes = 0
bool has_strip_offsets = false
uint64_t strip_offsets_bytes = 0
bool has_black_level_data = false
uint64_t black_level_data_bytes = 0
bool has_sensor_calibration = false
uint32_t sensor_calibration_entry_count = 0
uint64_t sensor_calibration_payload_bytes = 0
bool has_sensor_defects = false
uint64_t sensor_defects_bytes = 0
bool has_flat_field = false
uint64_t flat_field_bytes = 0
bool has_linearization_coefficients = false
uint32_t linearization_coefficients_count = 0
struct PhaseOneRawProcessingResult

Public Members

PhaseOneRawProcessingStatus status = PhaseOneRawProcessingStatus::MissingField
uint32_t fields_seen = 0
uint32_t fields_decoded = 0
uint32_t invalid_fields = 0
PhaseOneRawProcessingInfo info
struct PhotoshopIrb
#include <meta_key.h>

Public Members

uint16_t resource_id = 0
struct PhotoshopIrb
#include <meta_key.h>

Public Members

uint16_t resource_id = 0
struct PhotoshopIrbDecodeLimits

Resource limits applied during IRB decode to bound hostile inputs.

Public Members

uint32_t max_resources = 1U << 16
uint64_t max_total_bytes = 64ULL * 1024ULL * 1024ULL
uint32_t max_resource_len = 32U * 1024U * 1024U
struct PhotoshopIrbDecodeOptions

Decoder options for decode_photoshop_irb.

Public Members

bool decode_iptc_iim = true
bool decode_xmp_packet = true
bool decode_icc_profile = true
PhotoshopIrbStringCharset string_charset = PhotoshopIrbStringCharset::Latin
PhotoshopIrbDecodeLimits limits
IptcIimDecodeOptions iptc
XmpDecodeOptions xmp
IccDecodeOptions icc
struct PhotoshopIrbDecodeResult

Public Members

PhotoshopIrbDecodeStatus status = PhotoshopIrbDecodeStatus::Ok
uint32_t resources_decoded = 0
uint32_t entries_decoded = 0
uint32_t iptc_entries_decoded = 0
uint32_t xmp_entries_decoded = 0
uint32_t icc_entries_decoded = 0
struct PhotoshopIrbField
#include <meta_key.h>

Public Members

uint16_t resource_id = 0
ByteSpan field
struct PhotoshopIrbField
#include <meta_key.h>

Public Members

uint16_t resource_id = 0
std::string_view field
struct PlanJpegEditOptions

Options for JPEG edit planning.

Public Members

JpegEditMode mode = JpegEditMode::Auto
bool require_in_place = false
bool skip_empty_payloads = true
bool strip_existing_xmp = false
struct PlanTiffEditOptions

Options for TIFF edit planning.

Public Members

bool require_updates = true

If true, fail planning when the bundle has no TIFF-applicable updates.

bool strip_existing_xmp = false
struct PngText
#include <meta_key.h>

Public Members

ByteSpan keyword
ByteSpan field
struct PngText
#include <meta_key.h>

Public Members

std::string_view keyword
std::string_view field
class PngTransferEmitter

Backend contract for PNG metadata chunk emission.

Public Functions

virtual ~PngTransferEmitter() = default
virtual TransferStatus add_chunk(std::array<char, 4> type, std::span<const std::byte> payload) noexcept = 0
virtual TransferStatus close_chunks() noexcept = 0
struct PreparedBmffEmitOp

One precompiled ISO-BMFF metadata emit operation.

Public Members

PreparedBmffEmitKind kind = PreparedBmffEmitKind::Item
uint32_t block_index = 0
uint32_t item_type = 0U
uint32_t property_type = 0U
uint32_t property_subtype = 0U
struct PreparedBmffEmitPlan

Reusable precompiled ISO-BMFF metadata emit plan.

Public Members

uint32_t contract_version = kMetadataTransferContractVersion
std::vector<PreparedBmffEmitOp> ops
struct PreparedExrEmitOp

One precompiled EXR emit operation (prepared block -> EXR attribute).

Public Members

uint32_t block_index = 0
struct PreparedExrEmitPlan

Reusable precompiled EXR emit plan for a prepared transfer bundle.

Public Members

uint32_t contract_version = kMetadataTransferContractVersion
std::vector<PreparedExrEmitOp> ops
struct PreparedJp2EmitOp

One precompiled JP2 emit operation (route -> JP2 box mapping).

Public Members

uint32_t block_index = 0
std::array<char, 4> box_type = {'\0', '\0', '\0', '\0'}
struct PreparedJp2EmitPlan

Reusable precompiled JP2 emit plan for a prepared transfer bundle.

Public Members

uint32_t contract_version = kMetadataTransferContractVersion
std::vector<PreparedJp2EmitOp> ops
struct PreparedJpegEmitOp

One precompiled JPEG emit operation (route -> marker mapping).

Public Members

uint32_t block_index = 0
uint8_t marker_code = 0
struct PreparedJpegEmitPlan

Reusable precompiled JPEG emit plan for a prepared transfer bundle.

Public Members

uint32_t contract_version = kMetadataTransferContractVersion
std::vector<PreparedJpegEmitOp> ops
struct PreparedJxlEmitOp

One precompiled JPEG XL emit operation (route -> backend mapping).

Public Members

PreparedJxlEmitKind kind = PreparedJxlEmitKind::Box
uint32_t block_index = 0
std::array<char, 4> box_type = {'\0', '\0', '\0', '\0'}
bool compress = false
struct PreparedJxlEmitPlan

Reusable precompiled JPEG XL emit plan for a prepared transfer bundle.

Public Members

uint32_t contract_version = kMetadataTransferContractVersion
std::vector<PreparedJxlEmitOp> ops
struct PreparedJxlEncoderHandoff

Owned JXL encoder-side handoff independent from bundle payload storage.

Public Members

uint32_t contract_version = kMetadataTransferContractVersion
bool has_icc_profile = false
uint32_t icc_block_index = 0xFFFFFFFFU
uint32_t box_count = 0U
uint64_t box_payload_bytes = 0U
std::vector<std::byte> icc_profile
struct PreparedJxlEncoderHandoffIoResult

Result for serializing or parsing persisted JXL encoder handoff data.

Public Members

TransferStatus status = TransferStatus::Unsupported
EmitTransferCode code = EmitTransferCode::None
uint64_t bytes = 0U
uint32_t errors = 0U
std::string message
struct PreparedJxlEncoderHandoffView

Encoder-side handoff view for prepared JPEG XL metadata.

Public Members

uint32_t contract_version = kMetadataTransferContractVersion
bool has_icc_profile = false
uint32_t icc_block_index = 0xFFFFFFFFU
uint64_t icc_profile_bytes = 0U
std::span<const std::byte> icc_profile
uint32_t box_count = 0U
uint64_t box_payload_bytes = 0U
struct PreparedPngEmitOp

One precompiled PNG emit operation (route -> PNG chunk mapping).

Public Members

uint32_t block_index = 0
std::array<char, 4> chunk_type = {'\0', '\0', '\0', '\0'}
struct PreparedPngEmitPlan

Reusable precompiled PNG emit plan for a prepared transfer bundle.

Public Members

uint32_t contract_version = kMetadataTransferContractVersion
std::vector<PreparedPngEmitOp> ops
struct PreparedTiffEmitOp

One precompiled TIFF emit operation (route -> TIFF tag mapping).

Public Members

uint32_t block_index = 0
uint16_t tiff_tag = 0
struct PreparedTiffEmitPlan

Reusable precompiled TIFF emit plan for a prepared transfer bundle.

Public Members

uint32_t contract_version = kMetadataTransferContractVersion
std::vector<PreparedTiffEmitOp> ops
struct PreparedTransferAdapterOp

One compiled adapter-facing operation derived from a prepared bundle.

Public Members

TransferAdapterOpKind kind = TransferAdapterOpKind::JpegMarker
uint32_t block_index = 0U
uint64_t payload_size = 0U
uint64_t serialized_size = 0U
uint8_t jpeg_marker_code = 0U
uint16_t tiff_tag = 0U
std::array<char, 4> box_type = {'\0', '\0', '\0', '\0'}
std::array<char, 4> chunk_type = {'\0', '\0', '\0', '\0'}
uint32_t bmff_item_type = 0U
uint32_t bmff_property_type = 0U
uint32_t bmff_property_subtype = 0U
bool bmff_mime_xmp = false
bool compress = false
struct PreparedTransferAdapterView

One target-neutral adapter view over prepared transfer operations.

struct PreparedTransferArtifactInfo

Common summary for one persisted transfer artifact.

Public Members

PreparedTransferArtifactKind kind = PreparedTransferArtifactKind::Unknown
bool has_contract_version = false
uint32_t contract_version = 0U
bool has_target_format = false
TransferTargetFormat target_format = TransferTargetFormat::Jpeg
uint32_t entry_count = 0U
uint64_t payload_bytes = 0U
uint64_t binding_bytes = 0U
uint64_t signed_payload_bytes = 0U
bool has_icc_profile = false
uint32_t icc_block_index = 0xFFFFFFFFU
uint64_t icc_profile_bytes = 0U
uint64_t box_payload_bytes = 0U
std::string carrier_route
std::string manifest_label
struct PreparedTransferArtifactIoResult

Result for identifying and inspecting one persisted transfer artifact.

Public Members

TransferStatus status = TransferStatus::Unsupported
EmitTransferCode code = EmitTransferCode::None
uint64_t bytes = 0U
uint32_t errors = 0U
std::string message
struct PreparedTransferBlock

One container-ready payload in emit order.

Public Members

TransferBlockKind kind = TransferBlockKind::Other
uint32_t order = 0
std::string route

Route token for backend dispatch, for example: jpeg:app1-exif.

std::array<char, 4> box_type = {'\0', '\0', '\0', '\0'}

Optional 4CC when route is box-based (Exif, xml, jumb…).

std::vector<std::byte> payload

Payload bytes as prepared by the transfer packager.

struct PreparedTransferBundle

Immutable prepared metadata transfer artifact.

Public Members

uint32_t contract_version = kMetadataTransferContractVersion
TransferTargetFormat target_format = TransferTargetFormat::Jpeg
DngTargetMode dng_target_mode = DngTargetMode::MinimalFreshScaffold
TransferProfile profile
PreparedTransferC2paRewriteRequirements c2pa_rewrite
std::vector<PreparedTransferPolicyDecision> policy_decisions
std::vector<PreparedTransferBlock> blocks
std::vector<TimePatchSlot> time_patch_map
std::vector<std::byte> generated_xmp_sidecar
struct PreparedTransferC2paHandoffPackage

Structured external-signer handoff package for one prepared rewrite.

Public Members

PreparedTransferC2paSignRequest request
BuildPreparedC2paBindingResult binding
std::vector<std::byte> binding_bytes
struct PreparedTransferC2paPackageIoResult

Result for serializing or parsing persisted C2PA transfer packages.

Public Members

TransferStatus status = TransferStatus::Unsupported
EmitTransferCode code = EmitTransferCode::None
uint64_t bytes = 0
uint32_t errors = 0
std::string message
struct PreparedTransferC2paRewriteChunk

One deterministic chunk in the rewrite-without-C2PA byte stream.

Public Members

TransferC2paRewriteChunkKind kind = TransferC2paRewriteChunkKind::SourceRange
uint64_t source_offset = 0
uint64_t size = 0
uint32_t block_index = 0xFFFFFFFFU
uint8_t jpeg_marker_code = 0U
struct PreparedTransferC2paRewriteRequirements

Future-facing signer prerequisites for C2PA rewrite.

Public Members

TransferC2paRewriteState state = TransferC2paRewriteState::NotApplicable
TransferTargetFormat target_format = TransferTargetFormat::Jpeg
TransferC2paSourceKind source_kind = TransferC2paSourceKind::NotApplicable
uint32_t matched_entries = 0
uint32_t existing_carrier_segments = 0
bool target_carrier_available = false
bool content_change_invalidates_existing = false
bool requires_manifest_builder = false
bool requires_content_binding = false
bool requires_certificate_chain = false
bool requires_private_key = false
bool requires_signing_time = false
uint64_t content_binding_bytes = 0
std::vector<PreparedTransferC2paRewriteChunk> content_binding_chunks
std::string message
struct PreparedTransferC2paSignedPackage

Persistable external-signer result package for one prepared rewrite.

struct PreparedTransferC2paSignerInput

External signer material returned for one prepared C2PA rewrite request.

Public Members

std::string signing_time
std::vector<std::byte> certificate_chain_bytes
std::string private_key_reference
std::vector<std::byte> manifest_builder_output
std::vector<std::byte> signed_c2pa_logical_payload
struct PreparedTransferC2paSignRequest

Derived external signer input request for prepared C2PA rewrite.

Public Members

TransferStatus status = TransferStatus::Unsupported
TransferC2paRewriteState rewrite_state = TransferC2paRewriteState::NotApplicable
TransferTargetFormat target_format = TransferTargetFormat::Jpeg
TransferC2paSourceKind source_kind = TransferC2paSourceKind::NotApplicable
std::string carrier_route
std::string manifest_label
uint32_t existing_carrier_segments = 0
uint32_t source_range_chunks = 0
uint32_t prepared_segment_chunks = 0
uint64_t content_binding_bytes = 0
std::vector<PreparedTransferC2paRewriteChunk> content_binding_chunks
bool requires_manifest_builder = false
bool requires_content_binding = false
bool requires_certificate_chain = false
bool requires_private_key = false
bool requires_signing_time = false
std::string message
struct PreparedTransferExecutionPlan

Reusable compiled execution plan for high-throughput transfer workflows.

struct PreparedTransferPackageBatch

One owned final-output batch independent from input bytes or bundle storage.

Public Members

uint32_t contract_version = kMetadataTransferContractVersion
TransferTargetFormat target_format = TransferTargetFormat::Jpeg
uint64_t input_size = 0
uint64_t output_size = 0
std::vector<PreparedTransferPackageBlob> chunks
struct PreparedTransferPackageBlob

One owned output chunk materialized from a package plan.

Public Members

TransferPackageChunkKind kind = TransferPackageChunkKind::SourceRange
uint64_t output_offset = 0
uint64_t source_offset = 0
uint32_t block_index = 0xFFFFFFFFU
uint8_t jpeg_marker_code = 0U
std::string route
std::vector<std::byte> bytes
struct PreparedTransferPackageChunk

One deterministic output chunk for a packaged transfer write.

Public Members

TransferPackageChunkKind kind = TransferPackageChunkKind::SourceRange
uint64_t output_offset = 0
uint64_t source_offset = 0
uint64_t size = 0
uint32_t block_index = 0xFFFFFFFFU
uint8_t jpeg_marker_code = 0U
std::vector<std::byte> inline_bytes
struct PreparedTransferPackageIoResult

Result for serializing or parsing persisted transfer package batches.

Public Members

TransferStatus status = TransferStatus::Unsupported
EmitTransferCode code = EmitTransferCode::None
uint64_t bytes = 0
uint32_t errors = 0
std::string message
struct PreparedTransferPackagePlan

Deterministic chunk plan for a final transfer output.

Public Members

uint32_t contract_version = kMetadataTransferContractVersion
TransferTargetFormat target_format = TransferTargetFormat::Jpeg
uint64_t input_size = 0
uint64_t output_size = 0
std::vector<PreparedTransferPackageChunk> chunks
struct PreparedTransferPackageReplayCallbacks

Replay callbacks for replay_prepared_transfer_package_batch.

Public Members

TransferStatus (*begin_batch)(void *user, TransferTargetFormat target_format, uint32_t chunk_count) noexcept = nullptr
TransferStatus (*emit_chunk)(void *user, const PreparedTransferPackageView *view) noexcept = nullptr
TransferStatus (*end_batch)(void *user, TransferTargetFormat target_format) noexcept = nullptr
void *user = nullptr
struct PreparedTransferPackageReplayResult

Result for target-neutral package-batch replay.

Public Members

TransferStatus status = TransferStatus::Ok
EmitTransferCode code = EmitTransferCode::None
uint32_t replayed = 0
uint32_t failed_chunk_index = 0xFFFFFFFFU
std::string message
struct PreparedTransferPackageView

One zero-copy semantic view over a persisted transfer package chunk.

Public Members

TransferSemanticKind semantic_kind = TransferSemanticKind::Unknown
std::string_view route
TransferPackageChunkKind package_kind = TransferPackageChunkKind::SourceRange
uint64_t output_offset = 0
uint8_t jpeg_marker_code = 0U
std::span<const std::byte> bytes
struct PreparedTransferPayload

One owned semantic payload copied from a prepared transfer bundle.

Public Members

TransferSemanticKind semantic_kind = TransferSemanticKind::Unknown
std::string semantic_name
std::string route
PreparedTransferAdapterOp op
std::vector<std::byte> payload
struct PreparedTransferPayloadBatch

One owned semantic payload batch independent from bundle payload storage.

Public Members

uint32_t contract_version = kMetadataTransferContractVersion
TransferTargetFormat target_format = TransferTargetFormat::Jpeg
EmitTransferOptions emit
std::vector<PreparedTransferPayload> payloads
struct PreparedTransferPayloadIoResult

Result for serializing or parsing persisted transfer payload batches.

Public Members

TransferStatus status = TransferStatus::Unsupported
EmitTransferCode code = EmitTransferCode::None
uint64_t bytes = 0
uint32_t errors = 0
std::string message
struct PreparedTransferPayloadReplayCallbacks

Replay callbacks for replay_prepared_transfer_payload_batch.

Public Members

TransferStatus (*begin_batch)(void *user, TransferTargetFormat target_format, uint32_t payload_count) noexcept = nullptr
TransferStatus (*emit_payload)(void *user, const PreparedTransferPayloadView *view) noexcept = nullptr
TransferStatus (*end_batch)(void *user, TransferTargetFormat target_format) noexcept = nullptr
void *user = nullptr
struct PreparedTransferPayloadReplayResult

Result for target-neutral payload-batch replay.

Public Members

TransferStatus status = TransferStatus::Ok
EmitTransferCode code = EmitTransferCode::None
uint32_t replayed = 0
uint32_t failed_payload_index = 0xFFFFFFFFU
std::string message
struct PreparedTransferPayloadView

One zero-copy semantic payload view over a prepared transfer bundle.

Public Members

TransferSemanticKind semantic_kind = TransferSemanticKind::Unknown
std::string_view semantic_name
std::string_view route
PreparedTransferAdapterOp op
std::span<const std::byte> payload
struct PreparedTransferPolicyDecision

Effective policy decision captured during bundle preparation.

struct PreparedWebpEmitOp

One precompiled WebP emit operation (route -> RIFF chunk mapping).

Public Members

uint32_t block_index = 0
std::array<char, 4> chunk_type = {'\0', '\0', '\0', '\0'}
struct PreparedWebpEmitPlan

Reusable precompiled WebP emit plan for a prepared transfer bundle.

Public Members

uint32_t contract_version = kMetadataTransferContractVersion
std::vector<PreparedWebpEmitOp> ops
struct PrepareTransferFileOptions

File-read + decode options for prepare_metadata_for_target_file.

Public Members

bool include_pointer_tags = true
bool decode_makernote = false
bool decode_embedded_containers = true
bool decompress = true
std::string xmp_existing_sidecar_base_path
std::string xmp_existing_destination_embedded_path
XmpExistingSidecarMode xmp_existing_sidecar_mode = XmpExistingSidecarMode::Ignore
XmpExistingSidecarPrecedence xmp_existing_sidecar_precedence = XmpExistingSidecarPrecedence::SidecarWins
XmpExistingDestinationEmbeddedMode xmp_existing_destination_embedded_mode = XmpExistingDestinationEmbeddedMode::Ignore
XmpExistingDestinationEmbeddedPrecedence xmp_existing_destination_embedded_precedence = XmpExistingDestinationEmbeddedPrecedence::DestinationWins
XmpExistingDestinationCarrierPrecedence xmp_existing_destination_carrier_precedence = XmpExistingDestinationCarrierPrecedence::SidecarWins
OpenMetaResourcePolicy policy
PrepareTransferRequest prepare
struct PrepareTransferFileResult

High-level file read/prepare result.

Public Members

TransferFileStatus file_status = TransferFileStatus::Ok
PrepareTransferFileCode code = PrepareTransferFileCode::None
uint64_t file_size = 0
uint32_t entry_count = 0
bool xmp_existing_sidecar_loaded = false
TransferStatus xmp_existing_sidecar_status = TransferStatus::Unsupported
std::string xmp_existing_sidecar_message
std::string xmp_existing_sidecar_path
bool xmp_existing_destination_embedded_loaded = false
TransferStatus xmp_existing_destination_embedded_status = TransferStatus::Unsupported
std::string xmp_existing_destination_embedded_message
std::string xmp_existing_destination_embedded_path
SimpleMetaResult read
PrepareTransferResult prepare
PreparedTransferBundle bundle
struct PrepareTransferRequest

Request options for preparation.

Public Members

TransferTargetFormat target_format = TransferTargetFormat::Jpeg
DngTargetMode dng_target_mode = DngTargetMode::MinimalFreshScaffold
TransferProfile profile
TransferTargetImageSpec target_image_spec
bool has_source_raw_data_descriptor = false

Optional source pixel-storage context. When this says source pixels are rendered, prepare drops source RAW-processing metadata even for compatible-file transfer because it no longer applies to stored pixels.

MetadataRawDataDescriptor source_raw_data_descriptor
TransferRawCarrierPassthroughMode raw_carrier_passthrough_mode = TransferRawCarrierPassthroughMode::Disabled

Disabled by default. Currently used only for snapshot preparation.

bool include_exif_app1 = true
bool include_xmp_app1 = true
bool include_icc_app2 = true
bool include_iptc_app13 = true
bool xmp_portable = true
bool xmp_project_exif = true
bool xmp_project_iptc = true
bool xmp_include_existing = true
XmpExistingNamespacePolicy xmp_existing_namespace_policy = XmpExistingNamespacePolicy::KnownPortableOnly
XmpExistingStandardNamespacePolicy xmp_existing_standard_namespace_policy = XmpExistingStandardNamespacePolicy::PreserveAll
XmpConflictPolicy xmp_conflict_policy = XmpConflictPolicy::CurrentBehavior
bool xmp_exiftool_gpsdatetime_alias = false
struct PrepareTransferResult

Result details for preparation.

Public Members

TransferStatus status = TransferStatus::Ok
PrepareTransferCode code = PrepareTransferCode::None
uint32_t warnings = 0
uint32_t errors = 0
std::string message
struct PreviewCandidate
#include <preview_extract.h>

Preview candidate discovered in a container.

Public Members

PreviewKind kind = PreviewKind::ExifJpegInterchange
ContainerFormat format = ContainerFormat::Unknown
uint32_t block_index = 0
uint16_t offset_tag = 0
uint16_t length_tag = 0
uint64_t file_offset = 0
uint64_t size = 0
bool has_jpeg_soi_signature = false
struct PreviewExtractOptions
#include <preview_extract.h>

Options for preview extraction.

Public Members

uint64_t max_output_bytes = 128ULL * 1024ULL * 1024ULL
bool require_jpeg_soi = false
struct PreviewExtractResult
#include <preview_extract.h>

Result for preview extraction.

Public Members

PreviewExtractStatus status = PreviewExtractStatus::Ok
uint64_t written = 0
uint64_t needed = 0
struct PreviewScanLimits
#include <preview_extract.h>

Limits for preview candidate discovery.

Public Members

uint32_t max_ifds = 256
uint32_t max_total_entries = 8192
uint64_t max_preview_bytes = 512ULL * 1024ULL * 1024ULL
struct PreviewScanOptions
#include <preview_extract.h>

Options for preview candidate discovery.

Public Members

bool include_exif_jpeg_interchange = true
bool include_jpg_from_raw = true
bool include_cr3_prvw_jpeg = true
bool require_jpeg_soi = false
PreviewScanLimits limits
struct PreviewScanResult
#include <preview_extract.h>

Result for preview candidate discovery.

Public Members

PreviewScanStatus status = PreviewScanStatus::Ok
uint32_t written = 0
uint32_t needed = 0
struct PrintImDecodeLimits
#include <printim_decode.h>

Resource limits for decoding a PrintIM block.

Public Members

uint32_t max_entries = 4096

Maximum number of PrintIM entries to decode.

uint64_t max_bytes = 256ULL * 1024ULL

Maximum input bytes to accept (0 = unlimited).

struct PrintImDecodeResult
#include <printim_decode.h>

PrintIM decode result summary.

Public Members

PrintImDecodeStatus status = PrintImDecodeStatus::Unsupported
uint32_t entries_decoded = 0
struct PrintImField
#include <meta_key.h>

Public Members

ByteSpan field
struct PrintImField
#include <meta_key.h>

Public Members

std::string_view field
struct RandomAccessIoResult

Result returned by a host-provided positional read callback.

Public Members

RandomAccessIoCode code = RandomAccessIoCode::Ok
uint64_t bytes_read = 0U
struct RandomAccessReadLimits

Per-operation source-I/O ceilings. A zero ceiling means unlimited.

Public Members

uint32_t max_requests = 65536U
uint64_t max_total_bytes = 64ULL * 1024ULL * 1024ULL
uint64_t max_single_read_bytes = 16ULL * 1024ULL * 1024ULL
struct RandomAccessReadState

Per-operation accounting and first-failure diagnostics.

State is sticky after failure. Use one state object per independent read or decode operation; this keeps OpenMeta state local and permits concurrent operations against a host-declared concurrent source.

Public Functions

inline bool ok() const noexcept

Public Members

RandomAccessReadCode code = RandomAccessReadCode::Ok
RandomAccessIoCode io_code = RandomAccessIoCode::Ok
uint32_t requests_issued = 0U
uint64_t bytes_requested = 0U
uint64_t bytes_completed = 0U
uint64_t failure_offset = 0U
uint64_t failure_request_bytes = 0U
uint64_t failure_bytes_read = 0U
struct RandomAccessReadWindow

Caller-owned cache storage for bounded source views.

storage is configured by the caller. The remaining fields are managed by random_access_read_view and may be reset between operations.

Public Functions

inline void reset() noexcept

Public Members

std::span<std::byte> storage
uint64_t range_offset = 0U
uint64_t valid_bytes = 0U
bool valid = false
struct RandomAccessReadWindowOptions

Read-ahead policy for random_access_read_view.

Public Members

uint64_t minimum_read_bytes = 4096U

Minimum callback refill size. Zero reads only the requested bytes.

struct RandomAccessSource

Borrowed immutable random-access byte source.

Exactly one backing is used for a non-empty source: contiguous_data or read_at. OpenMeta does not own either backing or the callback context. concurrent_reads is descriptive; callers may share a source between independent OpenMeta operations only when it is true and the backing remains immutable for the complete operation.

Public Members

uint64_t size = 0U
const std::byte *contiguous_data = nullptr
void *context = nullptr
RandomAccessReadAt read_at = nullptr
bool concurrent_reads = false
struct RandomAccessSourceRange

Borrowed subrange of one random-access source.

Public Members

RandomAccessSource source
uint64_t source_offset = 0U
uint64_t size = 0U
struct RandomAccessViewResult

Borrowed view returned by random_access_read_view.

Public Functions

inline bool ok() const noexcept

Public Members

RandomAccessReadCode code = RandomAccessReadCode::Ok
std::span<const std::byte> bytes
bool cache_hit = false
struct ReadTransferSourceDiagnostic

One stable v1 allocation-free positional read diagnostic.

struct ReadTransferSourceDiagnosticOptions

Stable v1 optional lanes used to classify positional read residuals.

Public Members

bool decode_makernote_requested = false
bool decode_embedded_containers_requested = false
struct ReadTransferSourceDiagnosticsResult

Stable v1 caller-buffer result for positional read diagnostics.

Public Functions

inline bool complete() const noexcept

Public Members

uint32_t written = 0U
uint32_t needed = 0U
struct ReadTransferSourceSnapshotBytesResult

High-level in-memory read result for read_transfer_source_snapshot_bytes.

API Stability

Experimental host-facing API.

Public Members

TransferStatus status = TransferStatus::Ok
ReadTransferSourceSnapshotBytesCode code = ReadTransferSourceSnapshotBytesCode::None
uint64_t input_size = 0
uint32_t entry_count = 0
uint32_t raw_carrier_count = 0U
uint64_t raw_carrier_bytes = 0U
bool raw_carrier_bytes_truncated = false
SimpleMetaResult read
TransferSourceSnapshot snapshot
struct ReadTransferSourceSnapshotFileOptions

File-read + decode options for read_transfer_source_snapshot_file.

API Stability

Experimental host-facing API.

Public Members

bool include_pointer_tags = true
bool decode_makernote = false
bool decode_embedded_containers = true
bool decompress = true
bool preserve_raw_carriers = false
uint64_t max_raw_carrier_bytes = 64ULL * 1024ULL * 1024ULL
OpenMetaResourcePolicy policy
struct ReadTransferSourceSnapshotFileResult

High-level file read result for read_transfer_source_snapshot_file.

API Stability

Experimental host-facing API.

Public Members

TransferFileStatus file_status = TransferFileStatus::Ok
ReadTransferSourceSnapshotFileCode code = ReadTransferSourceSnapshotFileCode::None
uint64_t file_size = 0
uint32_t entry_count = 0
uint32_t raw_carrier_count = 0U
uint64_t raw_carrier_bytes = 0U
bool raw_carrier_bytes_truncated = false
SimpleMetaResult read
TransferSourceSnapshot snapshot
struct ReadTransferSourceSnapshotRandomAccessOptions

Stable v1 options for bounded positional source snapshot assembly.

Public Members

bool include_pointer_tags = true
bool decode_makernote = false
bool decode_embedded_containers = false

Embedded-container recursion is opt-in for positional workflows. Paths not yet converted are counted as explicit residuals.

bool decompress = true
bool preserve_raw_carriers = false
uint64_t max_raw_carrier_bytes = 64ULL * 1024ULL * 1024ULL
OpenMetaResourcePolicy policy
struct ReadTransferSourceSnapshotRandomAccessResult

Stable v1 result of bounded positional source snapshot assembly.

Public Functions

inline bool complete() const noexcept

Public Members

TransferStatus status = TransferStatus::Ok
ReadTransferSourceSnapshotRandomAccessCode code = ReadTransferSourceSnapshotRandomAccessCode::None
ContainerFormat format = ContainerFormat::Unknown
uint64_t input_size = 0U
uint32_t entry_count = 0U
uint32_t raw_carrier_count = 0U
uint64_t raw_carrier_bytes = 0U
bool raw_carrier_bytes_truncated = false
uint32_t residual_metadata_paths = 0U

Source-wide enrichment or container-specific decode paths that were intentionally not run by this bounded payload-backed assembly path.

uint64_t payload_scratch_needed = 0U
uint64_t compressed_scratch_needed = 0U
uint64_t value_scratch_needed = 0U
SimpleMetaResult read
RandomAccessReadState input
TransferSourceSnapshot snapshot
struct ReadTransferSourceSnapshotRandomAccessScratch

Stable v1 caller-owned storage for positional source snapshot assembly.

Public Members

std::span<ContainerBlockRef> blocks
std::span<ExifIfdRef> ifds
std::span<uint32_t> payload_indices
std::span<std::byte> read_window

Structural scanner/decoder read-ahead cache.

std::span<std::byte> payload

One reassembled or directly fetched logical metadata payload.

std::span<std::byte> compressed_payload

One compressed logical stream before decompression.

std::span<std::byte> value

One EXR/TIFF attribute or out-of-line metadata value.

RandomAccessReadWindowOptions window_options
struct ScanResult
#include <container_scan.h>

Public Members

ScanStatus status = ScanStatus::Ok
uint32_t written = 0
uint32_t needed = 0
struct SimpleMetaDecodeOptions
#include <simple_meta.h>

Full decoder option set for simple_meta_read.

Public Members

uint32_t max_total_entries = 200000U

Global ceilings shared by every decoder and nested decoder in one read.

uint64_t max_arena_bytes = 64ULL * 1024ULL * 1024ULL
ExifDecodeOptions exif
PayloadOptions payload
XmpDecodeOptions xmp
ExrDecodeOptions exr
JumbfDecodeOptions jumbf
IccDecodeOptions icc
IptcIimDecodeOptions iptc
PhotoshopIrbDecodeOptions photoshop_irb
struct SimpleMetaResult
#include <simple_meta.h>
class SpanTransferByteWriter : public openmeta::TransferByteWriter

Fixed-buffer writer for encoder integrations with preallocated memory.

Public Functions

inline explicit SpanTransferByteWriter(std::span<std::byte> buffer) noexcept
inline virtual TransferStatus write(std::span<const std::byte> bytes) noexcept override
inline void reset() noexcept
inline size_t capacity() const noexcept
inline size_t bytes_written() const noexcept
inline size_t remaining() const noexcept
inline TransferStatus status() const noexcept
inline virtual uint64_t remaining_capacity_hint() const noexcept override
inline std::span<const std::byte> written_bytes() const noexcept

Private Members

std::span<std::byte> buffer_
size_t written_ = 0U
TransferStatus status_ = TransferStatus::Ok
struct SRational
#include <meta_value.h>

Signed rational (numerator/denominator), typically used by EXIF/TIFF.

Public Members

int32_t numer = 0
int32_t denom = 1
struct TiffEditPlan

Planned TIFF edit summary (draft API).

Public Members

TransferStatus status = TransferStatus::Ok
uint32_t tag_updates = 0
bool has_exif_ifd = false
bool strip_existing_xmp = false
uint64_t input_size = 0
uint64_t output_size = 0
std::string message
class TiffTransferEmitter

Backend contract for TIFF metadata emission.

Public Functions

virtual ~TiffTransferEmitter() = default
virtual TransferStatus set_tag_u32(uint16_t tag, uint32_t value) noexcept = 0
virtual TransferStatus set_tag_bytes(uint16_t tag, std::span<const std::byte> payload) noexcept = 0
virtual TransferStatus commit_exif_directory(uint64_t *out_ifd_offset) noexcept = 0
struct TimePatchSlot

One fixed-width patch location in a prepared payload block.

Public Members

TimePatchField field = TimePatchField::DateTime
uint32_t block_index = 0
uint32_t byte_offset = 0
uint16_t width = 0
struct TimePatchUpdate

One time patch update payload for apply_time_patches.

Public Members

TimePatchField field = TimePatchField::DateTime
std::vector<std::byte> value
struct TimePatchView

Non-owning time patch view for hot-path transfer execution.

Public Members

TimePatchField field = TimePatchField::DateTime
std::span<const std::byte> value
class TransferAdapterSink

Generic host-side sink for adapter-view transfer operations.

Public Functions

virtual ~TransferAdapterSink() = default
virtual TransferStatus emit_op(const PreparedTransferAdapterOp &op, std::span<const std::byte> payload) noexcept = 0
class TransferByteWriter

Streaming byte sink for edit/write transfer paths.

Subclassed by openmeta::SpanTransferByteWriter

Public Functions

virtual ~TransferByteWriter() = default
virtual TransferStatus write(std::span<const std::byte> bytes) noexcept = 0
inline virtual uint64_t remaining_capacity_hint() const noexcept
struct TransferCompatibilityDumpOptions

Options for dump_transfer_compatibility.

Public Members

bool include_prepared_blocks = true
bool include_policy_decisions = true
bool include_writeback_summary = true
uint32_t max_message_bytes = 256U
struct TransferConceptDiagnostic

Public Members

MetadataConceptKind kind = MetadataConceptKind::Orientation
MetadataConceptRole role = MetadataConceptRole::Primary
MetadataConceptRecordKind record_kind = MetadataConceptRecordKind::None

Structured-record type copied from the concept candidate.

MetadataConceptSensitivity sensitivity = MetadataConceptSensitivity::None

Host policy signal; independent from hint and action.

MetadataConceptTransferHint hint = MetadataConceptTransferHint::Unknown
TransferConceptDiagnosticAction action = TransferConceptDiagnosticAction::Drop
TransferConceptDiagnosticReason reason = TransferConceptDiagnosticReason::Unknown
TransferConceptDiagnosticSeverity severity = TransferConceptDiagnosticSeverity::Warning
EntryId entry_id = kInvalidEntryId
std::vector<EntryId> source_entries
bool preferred = false
bool conflict = false
bool compatible_file_safe = false
bool rendered_image_safe = false
bool requires_target_image_spec = false
bool source_bound = false
MetadataRawApplicabilityState raw_applicability = MetadataRawApplicabilityState::Unknown
bool raw_applicability_requires_storage_context = false
bool raw_applicability_can_affect_decode = false
bool has_gps_altitude_reference = false
bool gps_altitude_below_sea_level = false
uint8_t gps_altitude_reference_code = 0U
std::string location_scope
std::string record_scope
std::string language
struct TransferConceptDiagnostics

Public Members

TransferSafetyMode safety = TransferSafetyMode::CompatibleFile
uint32_t candidate_count = 0U
uint32_t kept_count = 0U
uint32_t dropped_count = 0U
uint32_t requires_target_image_spec_count = 0U
uint32_t rendered_unsafe_count = 0U
uint32_t source_bound_count = 0U
uint32_t conflict_count = 0U
std::vector<TransferConceptDiagnostic> diagnostics
struct TransferMakerNoteAudit

Source evidence and current writer capabilities for MakerNote transfer.

Public Members

TransferMakerNoteTrust trust = TransferMakerNoteTrust::NotPresent
uint32_t raw_payload_count = 0U
uint32_t decoded_only_entry_count = 0U
bool opaque_payload_available = false
bool decoded_rewrite_available = false
bool internal_offset_relocation_available = false
bool vendor_checksum_recalculation_available = false
bool semantic_validation_available = false
bool raw_carrier_passthrough_available = false
struct TransferMakerNoteLayoutAudit

Vendor-layout evidence that can be established without rewriting a note.

Public Members

TransferMakerNoteLayoutTrust trust = TransferMakerNoteLayoutTrust::NotPresent
TransferMakerNoteVendor vendor = TransferMakerNoteVendor::Unknown
TransferMakerNoteLayout layout = TransferMakerNoteLayout::UnknownOrMixed
uint32_t raw_payload_count = 0U
uint32_t recognized_payload_count = 0U
uint32_t structurally_valid_payload_count = 0U
bool offset_basis_known = false
bool embedded_tiff_validation_available = false
bool embedded_tiff_validation_passed = false
bool embedded_tiff_offsets_self_contained = false
bool outer_tiff_offset_relocation_required = false
bool vendor_private_offsets_verified = false
bool vendor_checksum_validation_available = false
bool semantic_roundtrip_validation_available = false
struct TransferProfile

Transfer policy profile for initial no-edits workflows.

struct TransferRawCarrierPassthroughAudit

Diagnostic summary for raw-carrier passthrough eligibility.

Public Members

TransferTargetFormat target_format = TransferTargetFormat::Jpeg
TransferSafetyMode safety = TransferSafetyMode::CompatibleFile
uint32_t carrier_count = 0U
uint32_t eligible_count = 0U
uint32_t blocked_missing_payload = 0U
uint32_t blocked_target_incompatible = 0U
uint32_t blocked_safety_filtered = 0U
uint32_t blocked_content_bound_metadata = 0U
uint32_t blocked_policy = 0U
uint32_t blocked_unsupported_kind = 0U
std::vector<TransferRawCarrierPassthroughDecision> decisions
struct TransferRawCarrierPassthroughAuditOptions

Options for auditing raw-carrier passthrough eligibility.

Public Members

TransferTargetFormat target_format = TransferTargetFormat::Jpeg
TransferProfile profile
bool require_decoded_entry_links = true
struct TransferRawCarrierPassthroughDecision

One raw-carrier passthrough eligibility decision.

Public Members

uint32_t carrier_index = 0U
uint32_t decoded_entry_count = 0U
TransferBlockKind semantic_kind = TransferBlockKind::Other
bool eligible = false
TransferRawCarrierPassthroughReason reason = TransferRawCarrierPassthroughReason::UnsupportedKind
std::string source_route
std::string target_route
struct TransferSafetyAudit

Source metadata and filtered-entry counts for one transfer safety mode.

Public Members

TransferSafetyMode safety = TransferSafetyMode::CompatibleFile
uint32_t source_image_properties = 0U
uint32_t source_raw_color_calibration = 0U
uint32_t source_camera_raw_settings = 0U
uint32_t source_icc_profiles = 0U
uint32_t source_makernotes = 0U
uint32_t source_non_c2pa_jumbf = 0U
uint32_t source_c2pa = 0U
uint32_t filtered_image_properties = 0U
uint32_t filtered_raw_color_calibration = 0U
uint32_t filtered_camera_raw_settings = 0U
uint32_t filtered_icc_profiles = 0U
uint32_t filtered_makernotes = 0U
uint32_t filtered_non_c2pa_jumbf = 0U
uint32_t invalidated_c2pa = 0U
VendorRawProcessingSummary sony_raw_processing
VendorRawProcessingSummary canon_raw_processing
VendorRawProcessingSummary nikon_raw_processing
VendorRawProcessingSummary fujifilm_raw_processing
VendorRawProcessingSummary pentax_raw_processing
VendorRawProcessingSummary panasonic_raw_processing
VendorRawProcessingSummary olympus_raw_processing
VendorRawProcessingSummary kodak_raw_processing
VendorRawProcessingSummary minolta_raw_processing
VendorRawProcessingSummary sigma_raw_processing
VendorRawProcessingSummary samsung_raw_processing
VendorRawProcessingSummary ricoh_raw_processing
VendorRawProcessingSummary apple_raw_processing
VendorRawProcessingSummary dji_raw_processing
VendorRawProcessingSummary google_raw_processing
VendorRawProcessingSummary flir_raw_processing
VendorRawProcessingSummary casio_raw_processing
VendorRawProcessingSummary sanyo_raw_processing
VendorRawProcessingSummary kyocera_raw_processing
VendorRawProcessingSummary reconyx_raw_processing
VendorRawProcessingSummary hp_raw_processing
VendorRawProcessingSummary jvc_raw_processing
VendorRawProcessingSummary ge_raw_processing
VendorRawProcessingSummary motorola_raw_processing
VendorRawProcessingSummary nintendo_raw_processing
VendorRawProcessingSummary microsoft_raw_processing
struct TransferSourceRawCarrier

One opt-in raw source carrier captured next to a decoded snapshot.

Public Members

ContainerBlockRef block

Original container block reference, including byte ranges and chunking.

TransferBlockKind semantic_kind = TransferBlockKind::Other

Transfer semantic family inferred from the scanned block kind.

uint32_t order = 0U

Scan order among preserved source carriers.

std::string route

Stable route hint for passthrough and decoded re-emission policy.

bool payload_preserved = false

True when payload contains the original block payload bytes.

std::vector<std::byte> payload

Original metadata payload bytes, bounded by read options.

std::vector<EntryId> decoded_entry_ids

Decoded MetaStore entry ids attributed to this source carrier.

struct TransferSourceSnapshot

Reusable source snapshot for later transfer preparation.

Const reuse is safe when callers do not mutate the snapshot and do not share returned result objects across writers.

API Stability

Stable decoded-store object contract in Host Adoption Profile v1. Raw carrier provenance and payload bytes are optional snapshot data; their target passthrough policy remains experimental and is not part of the profile.

Public Members

MetaStore store
std::vector<TransferSourceRawCarrier> raw_carriers
uint64_t raw_carrier_bytes = 0U
bool raw_carrier_bytes_truncated = false
struct TransferSourceSnapshotIoOptions

Resource limits for persisted source snapshot serialization and parsing.

Public Members

uint64_t max_serialized_bytes = 256ULL * 1024ULL * 1024ULL
uint64_t max_arena_bytes = 64ULL * 1024ULL * 1024ULL
uint64_t max_raw_carrier_bytes = 64ULL * 1024ULL * 1024ULL
uint64_t max_decoded_entry_links = 1000000ULL
uint32_t max_blocks = 65536U
uint32_t max_entries = 200000U
uint32_t max_raw_carriers = 65536U
uint32_t max_route_bytes = 4096U
struct TransferSourceSnapshotIoResult

Result for persisted target-neutral source snapshot I/O.

Public Members

TransferStatus status = TransferStatus::Unsupported
TransferSourceSnapshotIoCode code = TransferSourceSnapshotIoCode::None
uint64_t bytes = 0U
uint32_t errors = 0U
std::string message
struct TransferTargetImageSpec

Host-supplied target image facts for content-changing transfer.

These values describe the actual output image buffer/container, not the source metadata. When present, prepared transfer uses these target facts for generated EXIF/XMP image-layout fields after filtering stale source fields. Leave fields unset when the host cannot guarantee that the value matches the target pixels.

Public Members

bool has_dimensions = false
uint32_t width = 0U
uint32_t height = 0U
bool has_orientation = false
uint16_t orientation = 1U
bool has_samples_per_pixel = false
uint16_t samples_per_pixel = 0U
uint16_t bits_per_sample_count = 0U
std::array<uint16_t, kTransferTargetImageSpecMaxSamples> bits_per_sample = {}
uint16_t sample_format_count = 0U
std::array<uint16_t, kTransferTargetImageSpecMaxSamples> sample_format = {}
bool has_photometric_interpretation = false
uint16_t photometric_interpretation = 0U
bool has_planar_configuration = false
uint16_t planar_configuration = 1U
bool has_compression = false
uint16_t compression = 0U
bool has_exif_color_space = false
uint16_t exif_color_space = 0U
struct TransferTimePatchInput

One high-level time patch input for transfer execution helpers.

Public Members

TimePatchField field = TimePatchField::DateTime
std::vector<std::byte> value
bool text_value = false
struct URational
#include <meta_value.h>

Unsigned rational (numerator/denominator), typically used by EXIF/TIFF.

Public Members

uint32_t numer = 0
uint32_t denom = 1
struct ValidateIssue
#include <validate.h>

One validation issue emitted by validate_file.

Public Members

ValidateIssueSeverity severity = ValidateIssueSeverity::Warning
std::string category

Domain/category (scan, exif, ccm, file, …).

std::string code

Stable issue token (malformed, limit_exceeded, …).

std::string ifd

Optional source IFD token (for CCM issues).

std::string name

Optional source field/tag name (for CCM issues).

uint16_t tag = 0

Optional source tag id (for CCM issues).

std::string message

Human-readable details.

struct ValidateOptions
#include <validate.h>

Options for validate_file.

Public Members

bool include_pointer_tags = true
bool decode_makernote = false
bool decode_printim = true
bool decompress = true
bool include_xmp_sidecar = false
bool verify_c2pa = false
C2paVerifyBackend verify_backend = C2paVerifyBackend::Auto
bool verify_require_trusted_chain = false
bool verify_require_resolved_references = false
bool warnings_as_errors = false

Treat warnings as failures in ValidateResult::failed.

CcmQueryOptions ccm

DNG/CCM query + validation options.

OpenMetaResourcePolicy policy

Resource budgets for decode/scans.

struct ValidatePreparedC2paSignResult

Result for validating one externally signed C2PA payload before staging.

Public Members

TransferStatus status = TransferStatus::Unsupported
EmitTransferCode code = EmitTransferCode::None
TransferC2paSignedPayloadKind payload_kind = TransferC2paSignedPayloadKind::NotApplicable
TransferC2paSemanticStatus semantic_status = TransferC2paSemanticStatus::NotChecked
uint64_t logical_payload_bytes = 0
uint64_t staged_payload_bytes = 0
uint64_t semantic_manifest_present = 0
uint64_t semantic_manifest_count = 0
uint64_t semantic_claim_generator_present = 0
uint64_t semantic_assertion_count = 0
uint64_t semantic_primary_claim_assertion_count = 0
uint64_t semantic_primary_claim_referenced_by_signature_count = 0
uint64_t semantic_primary_signature_linked_claim_count = 0
uint64_t semantic_primary_signature_reference_key_hits = 0
uint64_t semantic_primary_signature_explicit_reference_present = 0
uint64_t semantic_primary_signature_explicit_reference_resolved_claim_count = 0
uint64_t semantic_claim_count = 0
uint64_t semantic_signature_count = 0
uint64_t semantic_signature_linked = 0
uint64_t semantic_signature_orphan = 0
uint64_t semantic_explicit_reference_signature_count = 0
uint64_t semantic_explicit_reference_unresolved_signature_count = 0
uint64_t semantic_explicit_reference_ambiguous_signature_count = 0
uint32_t staged_segments = 0
uint32_t errors = 0
std::string semantic_reason
std::string message
struct ValidateResult
#include <validate.h>

Result of validate_file.

Public Members

ValidateStatus status = ValidateStatus::Ok
uint64_t file_size = 0
SimpleMetaResult read

Decode summary from simple_meta_read.

CcmQueryResult ccm

CCM query summary from collect_dng_ccm_fields.

uint32_t ccm_fields = 0

Number of extracted CCM fields.

uint32_t entries = 0

Final decoded entry count.

uint32_t warning_count = 0
uint32_t error_count = 0
bool failed = false
std::vector<ValidateIssue> issues
struct VendorRawProcessingSummary

Public Members

uint32_t fields_seen = 0U
uint32_t color_fields = 0U
uint32_t white_balance_fields = 0U
uint32_t geometry_fields = 0U
uint32_t storage_fields = 0U
uint32_t lens_correction_fields = 0U
uint32_t raw_data_fields = 0U
uint32_t sensor_fields = 0U
uint32_t private_table_fields = 0U
uint32_t preview_fields = 0U
uint32_t face_geometry_fields = 0U
uint32_t computational_fields = 0U
uint32_t thermal_fields = 0U
uint32_t stitch_fields = 0U
class WebpTransferEmitter

Backend contract for WebP metadata chunk emission.

Public Functions

virtual ~WebpTransferEmitter() = default
virtual TransferStatus add_chunk(std::array<char, 4> type, std::span<const std::byte> payload) noexcept = 0
virtual TransferStatus close_chunks() noexcept = 0
struct WireType
#include <meta_store.h>

Wire-format element type + family (e.g. TIFF type code).

Public Members

WireFamily family = WireFamily::None
uint16_t code = 0
struct XmpDecodeLimits
#include <xmp_decode.h>

Resource limits applied during XMP decode to bound hostile inputs.

Public Members

uint32_t max_depth = 128
uint32_t max_properties = 200000
uint64_t max_input_bytes = 64ULL * 1024ULL * 1024ULL

Caps the input XMP packet size (0 = unlimited).

uint32_t max_path_bytes = 1024

Max bytes per decoded property path string.

uint32_t max_namespace_bytes = 4096

Max bytes in a schema namespace URI copied into a property key.

uint32_t max_value_bytes = 8U * 1024U * 1024U

Max text bytes per decoded value (element/attribute).

uint64_t max_total_value_bytes = 64ULL * 1024ULL * 1024ULL

Max total text bytes accumulated across values (0 = unlimited).

uint64_t max_arena_bytes = 64ULL * 1024ULL * 1024ULL

Cumulative bytes copied into the destination store (0 = unlimited).

struct XmpDecodeOptions
#include <xmp_decode.h>

Decoder options for decode_xmp_packet.

Public Members

bool decode_description_attributes = true

If true, decodes attributes on rdf:Description as XMP properties.

XmpDecodeMalformedMode malformed_mode = XmpDecodeMalformedMode::Malformed

Controls whether malformed XML should be reported as Malformed or as best-effort OutputTruncated.

XmpDecodeLimits limits
struct XmpDecodeResult
#include <xmp_decode.h>

Public Members

XmpDecodeStatus status = XmpDecodeStatus::Ok
uint32_t entries_decoded = 0
struct XmpDumpLimits
#include <xmp_dump.h>

Resource limits applied during dump to bound output generation.

Public Members

uint64_t max_output_bytes = 0

If non-zero, refuse to generate output larger than this many bytes.

uint32_t max_entries = 0

If non-zero, refuse to emit more than this many entries.

struct XmpDumpOptions
#include <xmp_dump.h>

Dump options for dump_xmp_lossless.

Public Members

XmpDumpLimits limits
bool include_origin = true
bool include_wire = true

Includes wire family/code/count and EXR-specific wire type name when available.

bool include_flags = true
bool include_names = true
struct XmpDumpResult
#include <xmp_dump.h>

Dump result (size stats + how many entries were emitted).

Public Members

XmpDumpStatus status = XmpDumpStatus::Ok
uint64_t written = 0
uint64_t needed = 0
uint32_t entries = 0
struct XmpPortableOptions
#include <xmp_dump.h>

Options for dump_xmp_portable.

Public Members

XmpDumpLimits limits
bool include_exif = true

Include TIFF/EXIF/GPS derived properties.

bool include_iptc = true

Include IPTC-IIM derived portable XMP properties.

bool include_existing_xmp = false

Include MetaKeyKind::XmpProperty entries already present in the store.

Note

Currently simple property_path values, indexed [n] paths, bounded lang-alt paths like title[@xml:lang=x-default], bounded one-level structured paths like CreatorContactInfo/CiEmailWork, bounded qualified one-level structured child paths like LocationShown[1]/xmp:Identifier[1], LocationShown[1]/exif:GPSLatitude, DerivedFrom/stRef:documentID, JobRef[1]/stJob:id, RenditionOf/stRef:filePath, Ingredients[1]/stRef:documentID, MaxPageSize/stDim:w, Fonts[1]/stFnt:fontName, Fonts[1]/stFnt:childFontFiles[1], Colorants[1]/xmpG:swatchName, SwatchGroups[1]/xmpG:groupName, ProjectRef/path, beatSpliceParams/riseInTimeDuration/scale, markers/cuePointParams/key, contributedMedia[1]/duration/scale, Tracks[1]/trackName, Tracks[1]/markers/name, Tracks[1]/markers/cuePointParams/key, resampleParams/quality, startTimecode/timeValue, timeScaleParams/quality, Pantry[1]/InstanceID, Pantry[1]/dc:format, videoFrameSize/stDim:w, videoAlphaPremultipleColor/xmpG:mode, Manifest[1]/stMfs:reference/stRef:filePath, and Versions[1]/stVer:event/stEvt:action, bounded indexed-structured paths like Licensee[1]/LicenseeName, bounded second-level structured scalar paths like CreatorContactInfo/CiAdrRegion/ProvinceName, bounded structured child indexed paths like CreatorContactInfo/CiAdrExtadr[1], and bounded structured child lang-alt paths like CreatorContactInfo/CiAdrCity[@xml:lang=x-default] are emitted. Known standard malformed flat structured child values like Creator[1]/Name and Creator[1]/Role are also promoted into the canonical lang-alt or indexed shapes when no explicit canonical child entries already exist. Known malformed Adobe structured child paths like DerivedFrom/documentID, JobRef[1]/id, Manifest[1]/reference/filePath, and Versions[1]/event/action are likewise promoted into their canonical qualified child prefixes. The same bounded promotion applies to known second-level standard shapes like CreatorContactInfo/CiAdrRegion/ProvinceName and CreatorContactInfo/CiAdrRegion/ProvinceCode. Bounded second-level structured child lang-alt paths like CreatorContactInfo/CiAdrRegion/ProvinceName[@xml:lang=x-default] and bounded second-level structured child indexed paths like CreatorContactInfo/CiAdrRegion/ProvinceCode[1] are also emitted.

XmpExistingNamespacePolicy existing_namespace_policy = XmpExistingNamespacePolicy::KnownPortableOnly

Existing XMP namespace writeback policy for portable output.

XmpExistingStandardNamespacePolicy existing_standard_namespace_policy = XmpExistingStandardNamespacePolicy::PreserveAll

Existing standard portable-namespace reconciliation policy.

XmpConflictPolicy conflict_policy = XmpConflictPolicy::CurrentBehavior

Conflict policy between existing decoded XMP and generated portable EXIF/IPTC mappings.

bool exiftool_gpsdatetime_alias = false

Emit exif:GPSDateTime instead of exif:GPSTimeStamp for GPS time.

Default keeps standard portable naming. This compatibility mode is useful for tools that normalize XMP GPS time under GPSDateTime.

struct XmpProperty
#include <meta_key.h>

Public Members

ByteSpan schema_ns
ByteSpan property_path
struct XmpProperty
#include <meta_key.h>

Public Members

std::string_view schema_ns
std::string_view property_path
struct XmpSidecarOptions
#include <xmp_dump.h>

High-level sidecar options for dump_xmp_sidecar.

Public Members

XmpSidecarFormat format = XmpSidecarFormat::Lossless
XmpDumpOptions lossless
XmpPortableOptions portable
uint64_t initial_output_bytes = 0

Initial output buffer size before automatic growth (0 uses default).

struct XmpSidecarRequest
#include <xmp_dump.h>

Stable flat request for sidecar export.

This shape is intended for wrapper/front-end APIs that need one option set independent of selected format.

Public Members

XmpSidecarFormat format = XmpSidecarFormat::Lossless
XmpDumpLimits limits
bool include_exif = true

Portable mode options (applied when format == Portable).

bool include_iptc = true
bool include_existing_xmp = false
XmpExistingNamespacePolicy portable_existing_namespace_policy = XmpExistingNamespacePolicy::KnownPortableOnly
XmpExistingStandardNamespacePolicy portable_existing_standard_namespace_policy = XmpExistingStandardNamespacePolicy::PreserveAll
XmpConflictPolicy portable_conflict_policy = XmpConflictPolicy::CurrentBehavior
bool portable_exiftool_gpsdatetime_alias = false
bool include_origin = true

Lossless mode options (applied when format == Lossless).

bool include_wire = true
bool include_flags = true
bool include_names = true
uint64_t initial_output_bytes = 0

Initial output buffer size before automatic growth (0 uses default).

namespace openmeta

Scalar constructors

MetaValue make_u8(uint8_t value) noexcept
MetaValue make_i8(int8_t value) noexcept
MetaValue make_u16(uint16_t value) noexcept
MetaValue make_i16(int16_t value) noexcept
MetaValue make_u32(uint32_t value) noexcept
MetaValue make_i32(int32_t value) noexcept
MetaValue make_u64(uint64_t value) noexcept
MetaValue make_i64(int64_t value) noexcept
MetaValue make_f32_bits(uint32_t bits) noexcept
MetaValue make_f64_bits(uint64_t bits) noexcept
MetaValue make_urational(uint32_t numer, uint32_t denom) noexcept
MetaValue make_srational(int32_t numer, int32_t denom) noexcept

Arena-backed constructors

MetaValue make_bytes(ByteArena &arena, std::span<const std::byte> bytes)
MetaValue make_text(ByteArena &arena, std::string_view text, TextEncoding encoding)
MetaValue make_array(ByteArena &arena, MetaElementType elem_type, std::span<const std::byte> raw_elements, uint32_t element_size)

Convenience array constructors

MetaValue make_u8_array(ByteArena &arena, std::span<const uint8_t> values)
MetaValue make_i8_array(ByteArena &arena, std::span<const int8_t> values)
MetaValue make_u16_array(ByteArena &arena, std::span<const uint16_t> values)
MetaValue make_i16_array(ByteArena &arena, std::span<const int16_t> values)
MetaValue make_u32_array(ByteArena &arena, std::span<const uint32_t> values)
MetaValue make_i32_array(ByteArena &arena, std::span<const int32_t> values)
MetaValue make_u64_array(ByteArena &arena, std::span<const uint64_t> values)
MetaValue make_i64_array(ByteArena &arena, std::span<const int64_t> values)
MetaValue make_f32_bits_array(ByteArena &arena, std::span<const uint32_t> bits)
MetaValue make_f64_bits_array(ByteArena &arena, std::span<const uint64_t> bits)
MetaValue make_urational_array(ByteArena &arena, std::span<const URational> values)
MetaValue make_srational_array(ByteArena &arena, std::span<const SRational> values)

Typedefs

using BlockId = uint32_t
using EntryId = uint32_t
using ReadTransferSourceSnapshotOptions = ReadTransferSourceSnapshotFileOptions

Generic decode options for transfer source snapshot reads.

using RandomAccessReadAt = RandomAccessIoResult (*)(void *context, uint64_t offset, std::span<std::byte> destination) noexcept

Host callback for one synchronous positional read.

Ok requires exactly destination.size() bytes. A callback that reaches a premature end returns Ok with the actual shorter count; OpenMeta reports a short read. If the source no longer has the size captured in RandomAccessSource, return SourceChanged.

The callback must not throw. It may partially overwrite destination on failure. OpenMeta never invokes one callback concurrently within a single read operation.

Enums

enum class CcmQueryStatus : uint8_t

Query status for collect_dng_ccm_fields.

Values:

enumerator Ok
enumerator LimitExceeded

Input was valid but query limits were exceeded.

enum class CcmValidationMode : uint8_t

Validation mode for CCM query normalization.

Values:

enumerator None

Do not emit spec-level diagnostics.

enumerator DngSpecWarnings

Emit DNG-oriented structure/coherency diagnostics as warnings.

enum class CcmIssueSeverity : uint8_t

Validation issue severity.

Values:

enumerator Warning
enumerator Error

Field-level hard-invalid issue (the field is skipped).

enum class CcmIssueCode : uint16_t

Validation issue code for CcmIssue.

Values:

enumerator DecodeFailed
enumerator NonFiniteValue
enumerator UnexpectedCount
enumerator MatrixCountNotDivisibleBy3
enumerator NonPositiveValue
enumerator AsShotConflict
enumerator MissingCompanionTag
enumerator TripleIlluminantRule
enumerator CalibrationSignatureMismatch
enumerator MissingIlluminantData
enumerator InvalidIlluminantCode
enumerator WhiteXYOutOfRange
enum class PayloadStatus : uint8_t

Payload extraction result status.

Values:

enumerator Ok
enumerator OutputTruncated

Output buffer was too small; PayloadResult::needed reports required size.

enumerator Unsupported

The payload encoding requires an optional dependency that is not available.

enumerator Malformed

The container data is malformed or inconsistent.

enumerator LimitExceeded

Resource limits were exceeded (e.g. too many parts or too large output).

enum class ScanStatus : uint8_t

Scanner result status.

Values:

enumerator Ok
enumerator OutputTruncated

Output buffer was too small; ScanResult::needed reports required size.

enumerator Unsupported

The bytes do not match the container format handled by the scanner.

enumerator Malformed

The container structure is malformed or inconsistent.

enum class ContainerFormat : uint8_t

Supported high-level container formats for block scanning.

Values:

enumerator Unknown
enumerator Jpeg
enumerator Png
enumerator Webp
enumerator Gif
enumerator Tiff
enumerator Crw
enumerator Raf
enumerator X3f
enumerator Jp2
enumerator Jxl
enumerator Heif
enumerator Avif
enumerator Cr3
enumerator Exr
enum class ContainerBlockKind : uint8_t

Logical kind of a discovered metadata block.

Values:

enumerator Unknown
enumerator Exif
enumerator Ciff

Canon CRW (CIFF) directory tree (non-TIFF metadata container).

enumerator MakerNote
enumerator Xmp
enumerator XmpExtended
enumerator Jumbf

JPEG Universal Metadata Box Format payload (including C2PA manifests).

enumerator Icc
enumerator IptcIim
enumerator PhotoshopIrB
enumerator Mpf
enumerator Comment
enumerator Text
enumerator CompressedMetadata
enum class BlockCompression : uint8_t

Compression type for the block payload bytes (if any).

Values:

enumerator None
enumerator Deflate
enumerator Brotli
enum class BlockChunking : uint8_t

Chunking scheme used to represent a logical stream split across blocks.

Values:

enumerator None
enumerator JpegApp2SeqTotal
enumerator JpegXmpExtendedGuidOffset
enumerator GifSubBlocks
enumerator BmffExifTiffOffsetU32Be
enumerator BrobU32BeRealTypePrefix
enumerator Jp2UuidPayload
enumerator PsIrB8Bim
enum class DngSdkAdapterStatus : uint8_t

Result status for the optional DNG SDK adapter.

Values:

enumerator Ok
enumerator InvalidArgument
enumerator Unsupported
enumerator Malformed
enumerator InternalError
enum class ExifTagNamePolicy : uint8_t

Values:

enumerator Canonical
enumerator ExifToolCompat
enum class ExifDecodeStatus : uint8_t

EXIF/TIFF decode result status.

Values:

enumerator Ok
enumerator OutputTruncated
enumerator Unsupported
enumerator Malformed
enumerator LimitExceeded
enum class ExifLimitReason : uint8_t

Best-effort reason for ExifDecodeStatus::LimitExceeded.

Values:

enumerator None
enumerator MaxIfds
enumerator MaxEntriesPerIfd
enumerator MaxTotalEntries
enumerator ValueCountTooLarge
enumerator MaxArenaBytes
enum class ExifIfdKind : uint8_t

Logical IFD kinds exposed by decode_exif_tiff().

Values:

enumerator Ifd
enumerator ExifIfd
enumerator GpsIfd
enumerator InteropIfd
enumerator SubIfd
enum class ExrAdapterStatus : uint8_t

Result status for EXR adapter export.

Values:

enumerator Ok
enumerator InvalidArgument
enumerator Unsupported
enum class ExrDecodeStatus : uint8_t

OpenEXR decode result status.

Values:

enumerator Ok
enumerator Unsupported

The bytes do not look like an OpenEXR file.

enumerator Malformed

The EXR header is malformed or inconsistent.

enumerator LimitExceeded

Resource limits were exceeded.

enumerator OutputTruncated

Caller-owned value storage was too small for one or more attributes.

enum class IccDecodeStatus : uint8_t

ICC decode result status.

Values:

enumerator Ok
enumerator Unsupported

The bytes do not look like an ICC profile.

enumerator Malformed

The profile is malformed or inconsistent.

enumerator LimitExceeded

Resource limits were exceeded.

enum class IccTagInterpretStatus : uint8_t

Best-effort status for interpret_icc_tag.

Values:

enumerator Ok
enumerator Unsupported
enumerator Malformed
enumerator LimitExceeded
enum class InteropSafetyStatus : uint8_t

Status for strict safe interop export APIs.

Values:

enumerator Ok
enumerator InvalidArgument
enumerator UnsafeData
enumerator InternalError
enum class InteropSafetyReason : uint8_t

Reason code for InteropSafetyError.

Values:

enumerator None
enumerator UnsafeBytes
enumerator InvalidTextEncoding
enumerator UnsafeTextControlCharacter
enumerator InternalMismatch
enum class ExportNameStyle : uint8_t

Key naming policy used by visit_metadata.

API Stability

Stable enum shape. Canonical, XmpPortable, and FlatHost naming contracts are stable.

Values:

enumerator Canonical

Stable, key-space-aware names (for example: exif:ifd0:0x010F).

enumerator XmpPortable

Portable XMP-like names (for example: tiff:Make, exif:ExposureTime).

enumerator FlatHost

Stable v1 flat host-attribute names (Make, Exif:ExposureTime).

enum class ExportNamePolicy : uint8_t

Name normalization policy for interop exports.

Values:

enumerator Spec

Preserve native OpenMeta/EXIF naming (spec-oriented).

enumerator ExifToolAlias

Apply ExifTool-compatible aliases and filtering for parity workflows.

enum class FlatHostImportTarget : uint8_t

How one flat host record identifies its destination metadata key.

Values:

enumerator SourceEntry

Update one exact source entry exported earlier by the host.

enumerator UniqueName

Update an existing source entry only when the exported name is unique.

enumerator ExplicitKey

Append a new entry using the explicit typed key in the import item.

enumerator RemoveSourceEntry

Tombstone one exact source entry exported earlier by the host.

enumerator RemoveUniqueName

Tombstone an existing source entry only when its exported name is unique.

enum class FlatHostImportCode : uint16_t

Stable result code for import_flat_host_metadata.

Values:

enumerator None
enumerator InvalidArgument
enumerator SourceNotFinalized
enumerator LimitExceeded
enumerator EntryNotFound
enumerator EntryNotExported
enumerator NameMismatch
enumerator AmbiguousName
enumerator DuplicateTarget
enumerator InvalidKey
enumerator InvalidValue
enum class IptcIimDecodeStatus : uint8_t

IPTC-IIM decode result status.

Values:

enumerator Ok
enumerator Unsupported

The bytes do not look like an IPTC-IIM dataset stream.

enumerator Malformed

The stream is malformed or inconsistent.

enumerator LimitExceeded

Resource limits were exceeded.

enum class JumbfDecodeStatus : uint8_t

JUMBF decode result status.

Values:

enumerator Ok
enumerator Unsupported

Input does not look like a JUMBF payload.

enumerator Malformed

Input is truncated or structurally invalid.

enumerator LimitExceeded

Refused due to configured resource limits.

enum class C2paVerifyBackend : uint8_t

Draft C2PA verification backend selection.

Values:

enumerator None
enumerator Auto
enumerator Native
enumerator OpenSsl
enum class C2paVerifyStatus : uint8_t

Draft C2PA verification status.

Values:

enumerator NotRequested
enumerator DisabledByBuild
enumerator BackendUnavailable
enumerator NoSignatures
enumerator InvalidSignature
enumerator VerificationFailed
enumerator Verified

Complete asset binding, signature, and trust policy were validated. Current OpenMeta verification code does not emit this status.

enumerator NotImplemented
enumerator SignatureVerifiedOnly

The internal claim/signature bytes matched, but the signature was not validated against the complete containing asset.

enum class LibRawOrientationStatus : uint8_t

Result status for EXIF/XMP orientation to LibRaw flip mapping.

Values:

enumerator Ok
enumerator InvalidArgument
enumerator Unsupported
enum class LibRawOrientationCode : uint8_t

Detailed mapping code for LibRawOrientationResult.

Values:

enumerator None
enumerator PreviewPassThrough
enumerator MissingExifOrientationAssumedDefault
enumerator InvalidExifOrientation
enumerator UnsupportedMirroredOrientation
enumerator MirroredOrientationDropped
enum class LibRawOrientationSource : uint8_t

Canonical metadata source used for LibRawOrientationResult.

Values:

enumerator ExplicitInput
enumerator AssumedDefault
enumerator ExifIfd0
enumerator XmpTiffOrientation
enum class LibRawOrientationTarget : uint8_t

Output target for LibRaw orientation mapping.

Values:

enumerator RawImage
enumerator EmbeddedPreview
enum class LibRawMirrorPolicy : uint8_t

Policy for mirrored EXIF orientations (2/4/5/7).

Values:

enumerator Reject
enumerator DropMirror
enum class LibRawFlipToExifCode : uint8_t

Detailed mapping code for LibRawFlipToExifResult.

Values:

enumerator None
enumerator PreviewPassThrough
enumerator InvalidLibRawFlip
enum class LibRawOrientationFileStatus : uint8_t

Status for map_meta_orientation_to_libraw_flip_from_file.

Values:

enumerator Ok
enumerator InvalidArgument
enumerator OpenFailed
enumerator StatFailed
enumerator TooLarge
enumerator MapFailed
enumerator DecodeFailed
enum class MappedFileStatus : uint8_t

Status code for MappedFile operations.

Values:

enumerator Ok
enumerator OpenFailed
enumerator StatFailed
enumerator TooLarge
enumerator MapFailed
enum class EditOpKind : uint8_t

The operation kind for a MetaEdit command stream.

Values:

enumerator AddEntry
enumerator SetValue
enumerator Tombstone
enum class EntryFlags : uint8_t

Per-entry flags used during edits and provenance tracking.

Values:

enumerator None
enumerator Deleted

Entry is logically removed (kept for stable ids / provenance).

enumerator Dirty

Entry was modified or added relative to an origin snapshot.

enumerator Derived

Entry was derived from other data (e.g. EXIF->XMP mapping).

enumerator Truncated

Value payload was truncated or omitted due to configured limits.

enumerator Unreadable

Value payload could not be read from the underlying container.

enumerator ContextualName

Entry name has a decode-time contextual display variant.

enum class MetaKeyKind : uint8_t

Namespace for different metadata key spaces.

Values:

enumerator ExifTag
enumerator Comment
enumerator ExrAttribute
enumerator IptcDataset
enumerator XmpProperty
enumerator IccHeaderField
enumerator IccTag
enumerator PhotoshopIrb
enumerator PhotoshopIrbField
enumerator GeotiffKey
enumerator PrintImField
enumerator BmffField
enumerator JumbfField
enumerator JumbfCborKey
enumerator PngText
enum class WireFamily : uint8_t

The wire-format family a value came from (used for round-trip encoding).

Values:

enumerator None
enumerator Tiff
enumerator Other
enum class EntryNameContextKind : uint8_t

Decode-time contextual-name selector for compatibility/display surfaces.

Values:

enumerator None
enumerator CasioType2Legacy
enumerator FujifilmMain1304
enumerator OlympusFocusInfo1600
enumerator KodakMain0028
enumerator MinoltaMainCompat
enumerator MotorolaMain6420
enumerator SonyMainCompat
enumerator SonyTag94060005
enumerator SigmaMainCompat
enumerator RicohMainCompat
enumerator NikonSettingsMain
enumerator NikonMainZ
enumerator NikonMainCompactType2
enumerator NikonFlashInfoGroups
enumerator NikonFlashInfoLegacy
enumerator NikonShotInfoD800
enumerator NikonShotInfoD850
enumerator NikonShotInfoZ8
enumerator PentaxMain0062
enumerator CanonMain0038
enumerator CanonShotInfo000E
enumerator CanonCameraSettings0021
enumerator CanonColorData4PSInfo
enumerator CanonColorData7PSInfo2
enumerator CanonColorData400EA
enumerator CanonColorData400EE
enumerator CanonColorData402CF
enumerator CanonColorCalib0038
enumerator CanonCameraInfo1D0048
enumerator CanonCameraInfo600D00EA
enumerator CanonCustomFunctions20103
enumerator CanonCustomFunctions2010C
enumerator CanonCustomFunctions20510
enumerator CanonCustomFunctions20701
enumerator CanonMain0000
enum class MetaValueKind : uint8_t

Top-level value storage kind.

Values:

enumerator Empty
enumerator Scalar

An inline scalar stored in MetaValue::data.

enumerator Array

An array stored as raw bytes in a ByteArena span.

enumerator Bytes

Raw uninterpreted bytes in a ByteArena span.

enumerator Text

Text bytes in a ByteArena span with an associated encoding.

enum class MetaElementType : uint8_t

Element type used for scalar and array values.

Values:

enumerator U8
enumerator I8
enumerator U16
enumerator I16
enumerator U32
enumerator I32
enumerator U64
enumerator I64
enumerator F32
enumerator F64
enumerator URational
enumerator SRational
enum class TextEncoding : uint8_t

Encoding hint for text values.

Values:

enumerator Unknown
enumerator Ascii
enumerator Utf8
enumerator Utf16LE
enumerator Utf16BE
enum class MetadataCapabilityFamily : uint8_t

Metadata family used by metadata_capability.

Values:

enumerator Exif
enumerator Xmp
enumerator Icc
enumerator Iptc
enumerator MakerNote
enumerator PhotoshopIrb
enumerator Jumbf
enumerator C2pa
enumerator BmffFields
enumerator GeoTiff
enumerator ExrAttribute
enum class MetadataCapabilitySupport : uint8_t

Support level for one operation in MetadataCapability.

Values:

enumerator Unsupported
enumerator Supported
enumerator Bounded
enumerator Disabled
enum class MetadataConceptKind : uint8_t

Values:

enumerator Orientation
enumerator DateTime
enumerator ColorProfile
enumerator Gps
enumerator Geometry
enumerator LensCorrection
enumerator RawProcessing
enumerator Exposure
enumerator ContainerGraph
enumerator Descriptive
enum class MetadataConceptSourceFamily : uint8_t

Values:

enumerator Unknown
enumerator Exif
enumerator Xmp
enumerator Iptc
enumerator Icc
enumerator PngText
enumerator InterpretationRecord
enum class MetadataConceptRole : uint8_t

Values:

enumerator Primary
enumerator Orientation
enumerator Created
enumerator Digitized
enumerator Modified
enumerator MetadataDate
enumerator DateCreated
enumerator ColorSpace
enumerator IccProfile
enumerator ColorMatrix
enumerator WhiteBalance
enumerator Latitude
enumerator Longitude
enumerator Altitude
enumerator Timestamp
enumerator Crop
enumerator ActiveArea
enumerator Border
enumerator SensorGeometry
enumerator LensCorrection
enumerator BlackLevel
enumerator WhiteLevel
enumerator Linearization
enumerator CfaLayout
enumerator RawStorage
enumerator SourceProcessing
enumerator ComputationalProcessing
enumerator ThermalProcessing
enumerator StitchProcessing
enumerator ExposureTime
enumerator Aperture
enumerator IsoSensitivity
enumerator ExposureBias
enumerator ExposureProgram
enumerator Gain
enumerator RawExposureAdjustment
enumerator SourceColorTransform
enumerator RawValueCurve
enumerator RawLinearityLimit
enumerator RawCalibrationCurve
enumerator RawCurveControlPoints
enumerator ContentBoundMetadata
enumerator MultiImageScene
enumerator DerivedImageConstruction
enumerator TiledImageConfiguration
enumerator DestinationLatitude
enumerator DestinationLongitude
enumerator LocationShownLatitude
enumerator LocationShownLongitude
enumerator LocationShownAltitude
enumerator LocationCreatedLatitude
enumerator LocationCreatedLongitude
enumerator LocationCreatedAltitude
enumerator Title
enumerator Headline
enumerator Description
enumerator Creator
enumerator Keywords
enumerator LocationName
enumerator Sublocation
enumerator City
enumerator ProvinceState
enumerator CountryName
enumerator CountryCode
enumerator WorldRegion
enumerator LocationIdentifier
enumerator CopyrightNotice
enumerator CopyrightStatus
enumerator RightsUsageTerms
enumerator RightsWebStatement
enumerator RightsCertificate
enumerator RightsMarked
enumerator RightsHolderName
enumerator RightsHolderIdentifier
enumerator LicenseIdentifier
enumerator LicenseTermsUrl
enumerator LicensorName
enumerator LicensorIdentifier
enumerator CreditLine
enumerator CreditLineRequired
enumerator Source
enumerator DigitalSourceType
enumerator Name
enumerator Identifier
enumerator Address
enumerator PostalCode
enumerator Email
enumerator Telephone
enumerator Url
enumerator Characteristic
enumerator Gtin
enumerator InventoryNumber
enumerator StylePeriod
enumerator CreatorIdentifier
enumerator Age
enumerator ContentDescription
enumerator ContributionDescription
enumerator PhysicalDescription
enumerator RightsExpression
enumerator RightsExpressionEncoding
enumerator RightsExpressionLanguage
enumerator LicenseStartDate
enumerator LicenseEndDate
enumerator MediaConstraint
enumerator RegionConstraint
enumerator ProductOrServiceConstraint
enumerator ImageFileConstraint
enumerator ImageAlterationConstraint
enumerator OtherLicenseRequirement
enumerator OtherCondition
enumerator LicenseeTransactionIdentifier
enumerator LicensorTransactionIdentifier
enumerator LicenseeProjectReference
enumerator LicenseTransactionDate
enumerator ReleaseStatus
enumerator ReleaseIdentifier
enumerator Urgency
enumerator Category
enumerator SupplementalCategory
enumerator Instructions
enumerator CreatorTitle
enumerator TransmissionReference
enumerator CaptionWriter
enumerator AccessibilityAltText
enumerator AccessibilityExtendedDescription
enumerator IntellectualGenre
enumerator SceneCode
enumerator SubjectCode
enumerator ResourceIdentifier
enumerator DerivedFromIdentifier
enumerator DocumentIdentifier
enumerator InstanceIdentifier
enumerator OriginalDocumentIdentifier
enumerator RenditionClass
enumerator ImageIdentifier
enumerator Notes
enumerator MediaSummaryCode
enumerator ImageDuplicationConstraint
enumerator MinorModelAgeDisclosure
enumerator AdultContentWarning
enumerator DeliveredImageType
enumerator DeliveredFileName
enumerator DeliveredFileFormat
enumerator DeliveredFileSize
enumerator CopyrightRegistrationNumber
enumerator FirstPublicationDate
enumerator OtherImageInformation
enumerator Reuse
enumerator DataMining
enumerator OtherLicenseDocument
enumerator OtherLicenseInformation
enumerator VocabularyIdentifier
enumerator TermIdentifier
enumerator TermName
enumerator RefinedAbout
enumerator RegistryItemIdentifier
enumerator RegistryOrganizationIdentifier
enumerator RegistryEntryRole
enumerator RegionIdentifier
enumerator RegionName
enumerator RegionContentTypeIdentifier
enumerator RegionContentTypeName
enumerator RegionRoleIdentifier
enumerator RegionRoleName
enumerator VersionIdentifier
enumerator RenditionParameters
enumerator FilePath
enumerator FromPart
enumerator ToPart
enumerator Manager
enumerator ManagerVariant
enumerator ManageTo
enumerator ManageUi
enumerator AlternatePath
enumerator LastModifiedDate
enumerator MaskMarkers
enumerator PartMapping
enumerator LastUrl
enumerator LinkForm
enumerator LinkCategory
enumerator PlacedXResolution
enumerator PlacedYResolution
enumerator PlacedResolutionUnit
enumerator EventAction
enumerator EventParameters
enumerator SoftwareAgent
enumerator EventWhen
enumerator ChangedParts
enumerator Format
enumerator RegionBoundary
enumerator RegionBoundaryShape
enumerator RegionBoundaryUnit
enumerator RegionBoundaryX
enumerator RegionBoundaryY
enumerator RegionBoundaryWidth
enumerator RegionBoundaryHeight
enumerator RegionBoundaryRadius
enumerator RegionBoundaryVertexX
enumerator RegionBoundaryVertexY
enumerator RegionBoundaryVertex
enumerator VersionComments
enumerator VersionModifier
enumerator ObjectTypeReference
enumerator ObjectAttributeReference
enumerator EditStatus
enumerator EditorialUpdate
enumerator SubjectReference
enumerator FixtureIdentifier
enumerator EditorialReleaseDate
enumerator EditorialExpirationDate
enumerator ActionAdvised
enumerator ReferenceService
enumerator ReferenceDate
enumerator ReferenceNumber
enumerator ObjectCycle
enumerator LanguageIdentifier
enumerator Contact
enumerator RasterizedCaption
enumerator ImageType
enumerator ImageComponentCount
enumerator ImageColorComponentCode
enumerator ImageLayout
enumerator AudioType
enumerator AudioChannelCount
enumerator AudioContentCode
enumerator AudioSamplingRate
enumerator AudioSamplingResolution
enumerator AudioDuration
enumerator AudioOutcue
enumerator PreviewFormat
enumerator PreviewVersion
enumerator PreviewData
enum class MetadataConceptRecordKind : uint8_t

Values:

enumerator None
enumerator CreatorContact
enumerator Event
enumerator Person
enumerator Organization
enumerator Product
enumerator ArtworkOrObject
enumerator RightsExpression
enumerator RightsHolder
enumerator Licensor
enumerator Licensee
enumerator License
enumerator Release
enumerator EndUser
enumerator ImageCreator
enumerator ImageSupplier
enumerator ImageAsset
enumerator ControlledVocabularyTerm
enumerator RegistryEntry
enumerator ImageRegion
enumerator ResourceReference
enumerator ResourceEvent
enumerator PantryItem
enumerator ImageRegionBoundary
enumerator ManifestItem
enumerator Version
enumerator EditorialWorkflow
enumerator SourceSoftware
enumerator EditorialContact
enumerator TechnicalImage
enumerator AudioAsset
enumerator PreviewAsset
enum class MetadataImageRegionShape : uint8_t

Values:

enumerator Unknown
enumerator Rectangle
enumerator Circle
enumerator Polygon
enum class MetadataImageRegionCoordinateUnit : uint8_t

Values:

enumerator Unknown
enumerator Pixel
enumerator Relative
enum class MetadataConceptSensitivity : uint8_t

Policy sensitivity is independent from technical transfer safety.

Values:

enumerator None
enumerator PersonalContact
enumerator PersonIdentity
enumerator Location
enumerator LegalRights
enum class MetadataConceptDateTimePrecision : uint8_t

Values:

enumerator Unknown
enumerator Date
enumerator DateTime
enumerator DateTimeSubsecond
enum class MetadataConceptTimeZoneKind : uint8_t

Values:

enumerator Unknown
enumerator Local
enumerator Utc
enumerator Offset
enum class MetadataConceptTransferHint : uint8_t

Values:

enumerator Unknown
enumerator Safe
enumerator SourceBound
enumerator RenderedUnsafe
enumerator RequiresTargetImageSpec
enum class MetadataRawDataEncoding : uint8_t

Values:

enumerator Unknown
enumerator Uncompressed
enumerator Packed
enumerator LosslessCompressed
enumerator LossyCompressed
enumerator Rendered
enum class MetadataRawApplicabilityState : uint8_t

Values:

enumerator Unknown
enumerator AppliesToStoredRaw
enumerator ConditionalOnRawEncoding
enumerator NotApplicableToStoredRaw
enum class MetadataCreationFieldKind : uint8_t

Logical portable field accepted by create_metadata(...).

Values:

enumerator Title
enumerator Description
enumerator Creator
enumerator Keyword
enumerator Copyright
enumerator RightsUsageTerms
enumerator Credit
enumerator Source
enumerator CreateDate
enumerator ModifyDate
enumerator Rating
enumerator Label
enumerator CameraMake
enumerator CameraModel
enumerator Software
enumerator DateTimeOriginal
enumerator Orientation
enumerator PixelWidth
enumerator PixelHeight
enumerator ColorSpace
enumerator ExposureTime
enumerator FNumber
enumerator IsoSensitivity
enumerator FocalLength
enum class MetadataCreationValueKind : uint8_t

Input value representation for one creation field.

Values:

enumerator Text
enumerator UnsignedInteger
enumerator SignedInteger
enumerator UnsignedRational
enum class MetadataCreationStatus : uint8_t

Status returned by create_metadata(...).

Values:

enumerator Ok
enumerator NullOutput
enumerator InvalidLimits
enumerator TooManyFields
enumerator WrongValueKind
enumerator EmptyText
enumerator TextTooLong
enumerator TotalTextTooLong
enumerator InvalidText
enumerator InvalidValue
enumerator DuplicateSingleton
enumerator InternalError
enum class MetadataEditingOperationKind : uint8_t

Values:

enumerator Add
enumerator Set
enumerator Remove
enum class MetadataEditingStatus : uint8_t

Values:

enumerator Ok
enumerator NullOutput
enumerator BaseNotFinalized
enumerator InvalidLimits
enumerator TooManyOperations
enumerator InvalidOperationKind
enumerator InvalidOccurrence
enumerator WrongValueKind
enumerator EmptyText
enumerator TextTooLong
enumerator TotalTextTooLong
enumerator InvalidText
enumerator InvalidValue
enumerator SingletonAlreadyExists
enumerator TargetNotFound
enumerator AmbiguousTarget
enumerator EntryLimitExceeded
enumerator InternalError
enum class MetadataFuzzySearchStatus : uint8_t

Values:

enumerator Ok
enumerator FeatureUnavailable
enumerator EmptyQuery
enumerator QueryTooShort
enumerator QueryTooLong
enumerator UnsupportedQueryText
enumerator InvalidOptions
enum class MetadataFuzzySearchMatchKind : uint8_t

Values:

enumerator Exact

Exact normalized phrase match.

enumerator Alias

Exact or typo-tolerant match through the curated alias vocabulary.

enumerator Fuzzy

General RapidFuzz candidate-name match.

enum class MetadataQueryKind : uint8_t

Values:

enumerator Crop
enumerator ExposureGain
enumerator WhiteBalance
enumerator Color
enumerator LensCorrection
enumerator Orientation
enumerator RawProcessing
enumerator Descriptive
enum class MetadataQuerySemanticKind : uint8_t

Values:

enumerator Unknown
enumerator Crop
enumerator Border
enumerator ActiveArea
enumerator Exposure
enumerator Gain
enumerator Color
enumerator ColorProfile
enumerator WhiteBalance
enumerator ColorMatrix
enumerator LensCorrection
enumerator Orientation
enumerator ExposureGain
enumerator BlackLevel
enumerator WhiteLevel
enumerator Linearization
enumerator CfaLayout
enumerator SensorGeometry
enumerator RawStorage
enumerator SourceProcessing
enumerator ComputationalProcessing
enumerator ThermalProcessing
enumerator StitchProcessing
enumerator Title
enumerator Description
enumerator Creator
enumerator Keywords
enumerator SourceColorTransform
enumerator RawValueCurve
enumerator RawLinearityLimit
enumerator RawCalibrationCurve
enumerator RawCurveControlPoints
enumerator Rights
enumerator License
enumerator Credit
enumerator Source
enumerator Contact
enumerator Event
enumerator Person
enumerator Organization
enumerator Product
enumerator Artwork
enumerator RightsExpression
enumerator Release
enumerator Editorial
enumerator Accessibility
enumerator Taxonomy
enumerator DocumentIdentity
enumerator Registry
enumerator ImageRegion
enumerator DocumentLineage
enumerator DocumentHistory
enumerator TechnicalImage
enumerator Audio
enumerator Preview
enum class MetadataQueryValueShape : uint8_t

Values:

enumerator Unknown
enumerator Scalar
enumerator Vec2
enumerator Vec3
enumerator Vec4
enumerator Rect
enumerator Matrix3x3
enumerator VectorSet
enumerator MatrixSet
enumerator Table
enumerator Array
enumerator Blob
enumerator Text
enum class MetadataQueryMatchTerm : uint32_t

Values:

enumerator None
enumerator Crop
enumerator Border
enumerator Margin
enumerator Padding
enumerator ActiveArea
enumerator Origin
enumerator Offset
enumerator Size
enumerator Sensor
enumerator Image
enumerator Exposure
enumerator Bias
enumerator Gain
enumerator WhiteBalance
enumerator Color
enumerator Matrix
enumerator Calibration
enumerator Profile
enumerator Lens
enumerator Correction
enumerator Orientation
enumerator BlackLevel
enumerator WhiteLevel
enumerator Linearization
enumerator Cfa
enumerator Raw
enumerator Storage
enumerator SourceProcessing
enumerator Title
enumerator Description
enumerator Creator
enumerator Keywords
enum class TransferTargetFormat : uint8_t

Target container family for prepared transfer bundles.

Values:

enumerator Jpeg
enumerator Tiff
enumerator Jxl
enumerator Webp
enumerator Heif
enumerator Avif
enumerator Cr3
enumerator Exr
enumerator Png
enumerator Jp2
enumerator Dng
enum class DngTargetMode : uint8_t

Public DNG target contract for metadata-only transfer workflows.

Values:

enumerator ExistingTarget
enumerator TemplateTarget
enumerator MinimalFreshScaffold
enum class TransferBlockKind : uint8_t

Prepared payload block category.

Values:

enumerator Exif
enumerator Xmp
enumerator IptcIim
enumerator PhotoshopIrb
enumerator Icc
enumerator Jumbf
enumerator C2pa
enumerator ExrAttribute
enumerator Other
enum class TransferStatus : uint8_t

Status for transfer preparation and emit APIs.

Values:

enumerator Ok
enumerator InvalidArgument
enumerator Unsupported
enumerator LimitExceeded
enumerator Malformed
enumerator UnsafeData
enumerator InternalError
enum class PrepareTransferCode : uint16_t

Stable preparation error code for PrepareTransferResult.

Values:

enumerator None
enumerator NullOutBundle
enumerator UnsupportedTargetFormat
enumerator ExifPackFailed
enumerator XmpPackFailed
enumerator IccPackFailed
enumerator IptcPackFailed
enumerator RequestedMetadataNotSerializable
enum class EmitTransferCode : uint16_t

Stable emit error code for EmitTransferResult.

Values:

enumerator None
enumerator InvalidArgument
enumerator BundleTargetNotJpeg
enumerator UnsupportedRoute
enumerator InvalidPayload
enumerator ContentBoundPayloadUnsupported
enumerator BackendWriteFailed
enumerator PlanMismatch
enum class PrepareTransferFileCode : uint16_t

Stable file/read/prepare error code for PrepareTransferFileResult.

Values:

enumerator None
enumerator EmptyPath
enumerator MapFailed
enumerator PayloadBufferPlatformLimit
enumerator DecodeFailed
enum class ReadTransferSourceSnapshotFileCode : uint16_t

Stable file/read error code for ReadTransferSourceSnapshotFileResult.

Values:

enumerator None
enumerator EmptyPath
enumerator MapFailed
enumerator PayloadBufferPlatformLimit
enumerator DecodeFailed
enum class ReadTransferSourceSnapshotBytesCode : uint16_t

Stable bytes/read error code for ReadTransferSourceSnapshotBytesResult.

Values:

enumerator None
enumerator PayloadBufferPlatformLimit
enumerator DecodeFailed
enum class ReadTransferSourceSnapshotRandomAccessCode : uint16_t

Stable result code for positional source snapshot assembly.

Values:

enumerator None
enumerator InvalidArgument
enumerator UnsupportedFormat
enumerator ScanFailed
enumerator ScratchTooSmall
enumerator DecodeFailed
enumerator ResidualMetadataPaths

A usable snapshot was assembled, but explicitly reported source-wide or container-specific metadata paths were not decoded.

enum class ReadTransferSourceDiagnosticSeverity : uint8_t

Severity of one structured positional snapshot read diagnostic.

Values:

enumerator Info
enumerator Warning
enumerator Error
enum class ReadTransferSourceDiagnosticDomain : uint8_t

Decode or input domain associated with a structured read diagnostic.

Values:

enumerator Input
enumerator Container
enumerator Payload
enumerator Exif
enumerator Xmp
enumerator Jumbf
enumerator Exr
enumerator MakerNote
enumerator ResidualPath
enum class ReadTransferSourceDiagnosticCode : uint16_t

Stable machine-readable positional snapshot read diagnostic code.

Values:

enumerator InputFailure
enumerator MalformedContainer
enumerator MalformedPayload
enumerator MalformedExif
enumerator MalformedXmp
enumerator MalformedJumbf
enumerator MalformedExr
enumerator ResourceLimit
enumerator ScratchTooSmall
enumerator IncompleteMakerNote
enumerator ResidualMetadataPath
enumerator RawCarrierTruncated
enum class TransferFileStatus : uint8_t

Status for high-level file-to-bundle transfer preparation.

Values:

enumerator Ok
enumerator InvalidArgument
enumerator OpenFailed
enumerator StatFailed
enumerator TooLarge
enumerator MapFailed
enumerator ReadFailed
enum class TransferPolicySubject : uint8_t

Transfer-policy subject handled during bundle preparation.

Values:

enumerator MakerNote
enumerator Jumbf
enumerator C2pa
enumerator XmpExifProjection
enumerator XmpIptcProjection
enumerator ImageProperties
enumerator IccProfile
enumerator RawColorCalibration
enumerator CameraRawSettings
enum class TransferPolicyAction : uint8_t

Requested/effective action for a metadata family during transfer.

Values:

enumerator Keep
enumerator Drop
enumerator Invalidate
enumerator Rewrite
enum class TransferPolicyReason : uint8_t

Reason attached to one prepared transfer policy decision.

Values:

enumerator Default
enumerator NotPresent
enumerator ExplicitDrop
enumerator CarrierDisabled
enumerator ProjectedPayload
enumerator DraftInvalidationPayload
enumerator ExternalSignedPayload
enumerator ContentBoundTransferUnavailable
enumerator SignedRewriteUnavailable
enumerator PortableInvalidationUnavailable
enumerator RewriteUnavailablePreservedRaw
enumerator TargetSerializationUnavailable
enumerator TargetImageProperties
enumerator SafetyModeFiltered
enumerator RawDataDescriptorFiltered
enumerator OpaquePayloadPreservedUnverified

Opaque bytes are retained, but nested offsets, vendor checksums, and semantic readability after relocation are not verified.

enumerator RewriteUnavailableDropped

Rewrite was requested, but no safe serializer is available; payloads are dropped rather than silently treated as preserved rewrites.

enum class TransferC2paMode : uint8_t

Explicit current C2PA transfer mode resolved during prepare.

Values:

enumerator NotApplicable
enumerator NotPresent
enumerator Drop
enumerator DraftUnsignedInvalidation
enumerator PreserveRaw
enumerator SignedRewrite
enum class TransferC2paSourceKind : uint8_t

Classified C2PA source state observed during prepare.

Values:

enumerator NotApplicable
enumerator NotPresent
enumerator DecodedOnly
enumerator ContentBound
enumerator DraftUnsignedInvalidation
enum class TransferC2paPreparedOutput : uint8_t

Prepared C2PA output contract selected during prepare.

Values:

enumerator NotApplicable
enumerator NotPresent
enumerator Dropped
enumerator PreservedRaw
enumerator GeneratedDraftUnsignedInvalidation
enumerator SignedRewrite
enum class TransferC2paRewriteState : uint8_t

Current rewrite-signing readiness for C2PA transfer.

Values:

enumerator NotApplicable
enumerator NotRequested
enumerator SigningMaterialRequired
enumerator Ready
enum class TransferC2paRewriteChunkKind : uint8_t

One deterministic chunk in the future C2PA rewrite binding sequence.

Values:

enumerator SourceRange
enumerator PreparedJpegSegment
enumerator PreparedJxlBox
enumerator PreparedBmffMetaBox
enum class TransferSafetyMode : uint8_t

Coarse transfer safety mode for source metadata reuse.

Values:

enumerator CompatibleFile

Compatible metadata repackage/recompression; preserves source color and camera-specific metadata except target-owned image-layout fields.

enumerator RenderedImage

Rendered/exported pixels; drops source color-calibration, raw pipeline, lens-correction, raw settings, source ICC, MakerNote, and non-C2PA JUMBF data unless host code supplies target-correct replacements.

enum class TransferC2paSignedPayloadKind : uint8_t

Classified logical C2PA payload kind supplied by an external signer.

Values:

enumerator NotApplicable
enumerator GenericJumbf
enumerator DraftUnsignedInvalidation
enumerator ContentBound
enum class TransferC2paSemanticStatus : uint8_t

Semantic validation status for a staged logical C2PA payload.

Values:

enumerator NotChecked
enumerator Ok
enumerator Invalid
enum class TransferMakerNoteTrust : uint8_t

Trust state for vendor MakerNote data observed in a decoded store.

Values:

enumerator NotPresent
enumerator DecodedOnlyNotSerializable
enumerator OpaquePreservationUnverified
enum class TransferMakerNoteVendor : uint8_t

Vendor identified from a raw MakerNote payload layout.

Values:

enumerator Unknown
enumerator Nikon
enum class TransferMakerNoteLayout : uint8_t

Raw MakerNote layout relevant to offset-safe transfer.

Values:

enumerator UnknownOrMixed
enumerator NikonType1OuterTiff
enumerator NikonType3EmbeddedTiff
enum class TransferMakerNoteLayoutTrust : uint8_t

Structural trust established for a raw MakerNote layout.

Values:

enumerator NotPresent
enumerator UnrecognizedOrMixed
enumerator OuterTiffOffsetsUnsafe
enumerator EmbeddedTiffStructureUnverified
enumerator EmbeddedTiffStructureVerified
enum class TransferConceptDiagnosticAction : uint8_t

Values:

enumerator Keep
enumerator Drop
enumerator RequiresTargetImageSpec
enum class TransferConceptDiagnosticReason : uint8_t

Values:

enumerator Unknown
enumerator Safe
enumerator SourceBound
enumerator RenderedUnsafe
enumerator TargetImageSpecRequired
enumerator RawApplicabilityConditional
enumerator RawApplicabilityNotApplicable
enum class TransferConceptDiagnosticSeverity : uint8_t

Values:

enumerator Info
enumerator Warning
enum class TimePatchField : uint8_t

Optional fixed-width patch field identifiers for per-frame updates.

Values:

enumerator DateTime
enumerator DateTimeOriginal
enumerator DateTimeDigitized
enumerator SubSecTime
enumerator SubSecTimeOriginal
enumerator SubSecTimeDigitized
enumerator OffsetTime
enumerator OffsetTimeOriginal
enumerator OffsetTimeDigitized
enumerator GpsDateStamp
enumerator GpsTimeStamp
enum class TransferRawCarrierPassthroughReason : uint8_t

Primary passthrough eligibility result for one preserved raw carrier.

Values:

enumerator Candidate
enumerator MissingPayload
enumerator TargetIncompatible
enumerator SafetyFiltered
enumerator ContentBoundMetadata
enumerator PolicyBlocked
enumerator DecodeLinkUnavailable
enumerator UnsupportedKind
enum class TransferRawCarrierPassthroughMode : uint8_t

Opt-in raw-carrier use during snapshot transfer preparation.

Values:

enumerator Disabled

Do not reuse preserved raw carriers while preparing from a snapshot.

enumerator WhenSafe

Reuse only bounded carrier families that pass the active policy checks.

enum class TransferSourceSnapshotIoCode : uint16_t

Stable result code for source snapshot serialization and parsing.

Values:

enumerator None
enumerator InvalidArgument
enumerator SnapshotNotFinalized
enumerator InvalidSnapshot
enumerator InvalidMagic
enumerator UnsupportedVersion
enumerator LimitExceeded
enumerator Malformed
enum class JpegEditMode : uint8_t

Draft JPEG edit strategy selection.

Values:

enumerator Auto
enumerator InPlace
enumerator MetadataRewrite
enum class TransferPackageChunkKind : uint8_t

One chunk in a packaged transfer output plan.

Values:

enumerator SourceRange
enumerator PreparedTransferBlock
enumerator PreparedJpegSegment
enumerator InlineBytes
enum class TransferSemanticKind : uint8_t

Semantic metadata family carried by one transfer payload or package chunk.

Values:

enumerator Unknown
enumerator Exif
enumerator Xmp
enumerator Icc
enumerator Iptc
enumerator Jumbf
enumerator C2pa
enum class PreparedJxlEmitKind : uint8_t

Kind of precompiled JPEG XL emit operation.

Values:

enumerator Box
enumerator IccProfile
enum class PreparedTransferArtifactKind : uint8_t

Persisted transfer artifact family recognized by the generic inspect path.

Values:

enumerator Unknown
enumerator TransferPayloadBatch
enumerator TransferPackageBatch
enumerator C2paHandoffPackage
enumerator C2paSignedPackage
enumerator JxlEncoderHandoff
enum class PreparedBmffEmitKind : uint8_t

Kind of precompiled ISO-BMFF metadata emit operation.

Values:

enumerator Item
enumerator MimeXmp
enumerator Property
enum class TransferAdapterOpKind : uint8_t

One normalized adapter operation for external encoder or host integration.

Values:

enumerator JpegMarker
enumerator TiffTagBytes
enumerator JxlBox
enumerator JxlIccProfile
enumerator WebpChunk
enumerator PngChunk
enumerator Jp2Box
enumerator ExrAttribute
enumerator BmffItem
enumerator BmffProperty
enum class XmpExistingSidecarMode : uint8_t

Existing sibling XMP sidecar handling for transfer preparation.

Values:

enumerator Ignore
enumerator MergeIfPresent
enum class XmpExistingSidecarPrecedence : uint8_t

Conflict precedence between a merged destination-side .xmp and source-embedded existing XMP.

Values:

enumerator SidecarWins
enumerator SourceWins
enum class XmpExistingDestinationEmbeddedMode : uint8_t

Existing destination embedded-XMP handling for file-helper transfer execution.

Values:

enumerator Ignore
enumerator MergeIfPresent
enum class XmpExistingDestinationEmbeddedPrecedence : uint8_t

Conflict precedence between merged destination embedded XMP and source-embedded existing XMP.

Values:

enumerator DestinationWins
enumerator SourceWins
enum class XmpExistingDestinationCarrierPrecedence : uint8_t

Conflict precedence between existing destination sidecar XMP and existing destination embedded XMP when both are merged during transfer preparation.

Values:

enumerator SidecarWins
enumerator EmbeddedWins
enum class XmpWritebackMode : uint8_t

XMP carrier preference for file-helper transfer execution.

Values:

enumerator EmbeddedOnly

Keep generated XMP only in the managed embedded carrier.

enumerator SidecarOnly

Return generated XMP only as sibling .xmp output.

Existing embedded XMP stays in the edited file unless
\ref XmpDestinationEmbeddedMode::StripExisting is requested.

enumerator EmbeddedAndSidecar

Keep generated XMP in the managed embedded carrier and also return the same generated XMP packet for sibling .xmp writeback.

enum class XmpDestinationEmbeddedMode : uint8_t

Destination embedded-XMP handling for file-helper transfer execution.

Values:

enumerator PreserveExisting

Leave existing embedded XMP in the edited file when sidecar-only writeback suppresses generated embedded XMP.

enumerator StripExisting

Remove managed embedded XMP from the edited file when sidecar-only writeback is selected.

enum class XmpDestinationSidecarMode : uint8_t

Destination sibling XMP sidecar handling for file-helper transfer execution.

Values:

enumerator PreserveExisting

Leave an existing sibling .xmp untouched when embedded-only writeback is selected.

enumerator StripExisting

Request removal of an existing sibling .xmp when embedded-only writeback is selected.

enum class XmpExistingDestinationSidecarState : uint8_t

Host-reported presence of an existing destination sibling .xmp sidecar.

Values:

enumerator Unknown

Use path-based detection when a sidecar base path is available.

enumerator NotPresent

Host knows there is no existing destination sidecar.

enumerator Present

Host knows there is an existing destination sidecar to remove.

enum class ExifOrientationStatus : uint8_t

Result status for EXIF/TIFF orientation interpretation.

Values:

enumerator Ok
enumerator InvalidArgument
enum class PhaseOneRawGeometryStatus : uint8_t

Values:

enumerator Ok
enumerator MissingField
enumerator InvalidValue
enumerator OutOfBounds
enum class PhaseOneRawProcessingStatus : uint8_t

Values:

enumerator Ok
enumerator MissingField
enumerator InvalidValue
enumerator Partial
enum class PhotoshopIrbDecodeStatus : uint8_t

Photoshop IRB decode result status.

Values:

enumerator Ok
enumerator Unsupported

The bytes do not look like an IRB stream.

enumerator Malformed

The stream is malformed or inconsistent.

enumerator LimitExceeded

Resource limits were exceeded.

enum class PhotoshopIrbStringCharset : uint8_t

Charset policy for legacy 8-bit Photoshop IRB text payloads.

Values:

enumerator Latin
enumerator Ascii
enum class PreviewKind : uint8_t

Candidate preview source kind.

Values:

enumerator ExifJpegInterchange

EXIF/TIFF pair JPEGInterchangeFormat (0x0201) + length (0x0202).

enumerator ExifJpgFromRaw

EXIF/TIFF blob tag JpgFromRaw (0x002E).

enumerator ExifJpgFromRaw2

EXIF/TIFF blob tag JpgFromRaw2 (0x0127).

enumerator Cr3PrvwJpeg

Canon CR3 preview JPEG stored in a PRVW stream inside a UUID box.

enum class PreviewScanStatus : uint8_t

Status for preview candidate discovery.

Values:

enumerator Ok
enumerator OutputTruncated
enumerator Unsupported
enumerator Malformed
enumerator LimitExceeded
enum class PreviewExtractStatus : uint8_t

Status for preview extraction.

Values:

enumerator Ok
enumerator OutputTruncated
enumerator Malformed
enumerator LimitExceeded
enum class PrintImDecodeStatus : uint8_t

PrintIM decode result status.

Values:

enumerator Ok
enumerator Unsupported

Input does not look like a PrintIM block.

enumerator Malformed

Input is truncated or structurally invalid.

enumerator LimitExceeded

Refused due to size/entry-count limits.

enum class RandomAccessIoCode : uint8_t

Status returned directly by a host-provided positional read callback.

Values:

enumerator Ok
enumerator IoError
enumerator SourceChanged
enumerator Cancelled
enum class RandomAccessReadCode : uint8_t

OpenMeta result for an exact bounded source read.

Values:

enumerator Ok
enumerator InvalidArgument
enumerator OutOfRange
enumerator RequestTooLarge
enumerator RequestLimitExceeded
enumerator ByteLimitExceeded
enumerator ShortRead
enumerator IoError
enumerator SourceChanged
enumerator Cancelled
enumerator ContractViolation
enumerator ScratchTooSmall
enum class ValidateStatus : uint8_t

Top-level validation status for validate_file.

Values:

enumerator Ok
enumerator OpenFailed
enumerator TooLarge
enumerator ReadFailed
enum class ValidateIssueSeverity : uint8_t

Validation issue severity.

Values:

enumerator Warning
enumerator Error
enum class VendorRawProcessingFamily : uint8_t

Values:

enumerator Sony
enumerator Canon
enumerator Nikon
enumerator Fujifilm
enumerator Pentax
enumerator Panasonic
enumerator Olympus
enumerator Kodak
enumerator Minolta
enumerator Sigma
enumerator Samsung
enumerator Ricoh
enumerator Apple
enumerator Dji
enumerator Google
enumerator Flir
enumerator Casio
enumerator Sanyo
enumerator KyoceraRaw
enumerator Reconyx
enumerator Hp
enumerator Jvc
enumerator Ge
enumerator Motorola
enumerator Nintendo
enumerator Microsoft
enum class VendorRawProcessingGroup : uint32_t

Values:

enumerator None
enumerator Color
enumerator WhiteBalance
enumerator Geometry
enumerator Storage
enumerator LensCorrection
enumerator RawData
enumerator Sensor
enumerator PrivateTable
enumerator Preview
enumerator FaceGeometry
enumerator Computational
enumerator Thermal
enumerator Stitch
enum class XmpDecodeStatus : uint8_t

XMP decode result status.

Values:

enumerator Ok
enumerator OutputTruncated
enumerator Unsupported
enumerator Malformed
enumerator LimitExceeded
enum class XmpDecodeMalformedMode : uint8_t

Controls how malformed XMP packets are reported to callers.

Some workflows prefer treating malformed XML as “best-effort partial output” rather than a hard failure.

Values:

enumerator Malformed

Report malformed XML as XmpDecodeStatus::Malformed.

enumerator OutputTruncated

Report malformed XML as XmpDecodeStatus::OutputTruncated.

enum class XmpConflictPolicy : uint8_t

Conflict policy for existing XMP versus generated portable XMP properties.

This currently applies to portable XMP generation only.

Values:

enumerator CurrentBehavior

Preserve the historical OpenMeta order: EXIF-derived properties first, then existing XMP, then IPTC-derived properties.

enumerator ExistingWins

Existing decoded XMP properties win over generated EXIF/IPTC mappings.

enumerator GeneratedWins

Generated EXIF/IPTC mappings win over existing decoded XMP properties.

enum class XmpExistingNamespacePolicy : uint8_t

Existing XMP namespace policy for portable XMP generation.

Values:

enumerator KnownPortableOnly

Keep only the standard portable namespaces known to OpenMeta.

enumerator PreserveCustom

Also preserve safe simple/indexed properties from custom namespaces.

enum class XmpExistingStandardNamespacePolicy : uint8_t

Existing standard portable-namespace reconciliation policy.

Values:

enumerator PreserveAll

Preserve existing standard portable namespaces subject to conflict order.

enumerator CanonicalizeManaged

Drop OpenMeta-managed standard portable properties and regenerate them canonically from EXIF/IPTC mappings when available.

enum class XmpDumpStatus : uint8_t

XMP dump result status.

Values:

enumerator Ok
enumerator OutputTruncated

Output buffer was too small; XmpDumpResult::needed reports required size.

enumerator LimitExceeded

Caller-specified limits prevented generating a complete dump.

enum class XmpSidecarFormat : uint8_t

Sidecar format selection for dump_xmp_sidecar.

Values:

enumerator Lossless
enumerator Portable

Functions

const BuildInfo &build_info() noexcept

Returns build information for the linked OpenMeta library.

void format_build_info_lines(const BuildInfo &info, std::string *line1, std::string *line2) noexcept

Formats a stable, human-readable build info header (2 lines).

Output format:

  • OpenMeta vX.Y.Z <build_type> [features] <linkage>

  • built with <compiler> for <system>/<arch> (<timestamp>)

void format_build_info_lines(std::string *line1, std::string *line2) noexcept

Convenience overload for the linked OpenMeta library build.

CcmQueryResult collect_dng_ccm_fields(const MetaStore &store, std::vector<CcmField> *out, const CcmQueryOptions &options = CcmQueryOptions{}, std::vector<CcmIssue> *issues = nullptr) noexcept

Extracts normalized DNG/RAW CCM-related fields from a MetaStore.

The query scans EXIF tags and emits stable field names for:

  • ColorMatrix*, ForwardMatrix*, CameraCalibration*

  • ReductionMatrix* (optional)

  • AsShotNeutral, AsShotWhiteXY, AnalogBalance

  • CalibrationIlluminant*

bool dump_metadata_compatibility(const MetaStore &store, const MetadataCompatibilityDumpOptions &options, std::string *out) noexcept

Emit a deterministic line-oriented metadata compatibility dump.

The dump includes exported names, value kinds, scalar element types, optional value text, optional origin fields, and optional flags.

bool dump_transfer_compatibility(const ExecutePreparedTransferFileResult &result, const PersistPreparedTransferFileResult *persisted, const TransferCompatibilityDumpOptions &options, std::string *out) noexcept

Emit deterministic transfer and writeback decision summaries.

Pass persisted when file persistence results should be included.

bool append_console_escaped_ascii(std::string_view s, uint32_t max_bytes, std::string *out) noexcept
void append_hex_bytes(std::span<const std::byte> bytes, uint32_t max_bytes, std::string *out) noexcept
PayloadResult extract_payload(std::span<const std::byte> file_bytes, std::span<const ContainerBlockRef> blocks, uint32_t seed_index, std::span<std::byte> out_payload, std::span<uint32_t> scratch_indices, const PayloadOptions &options) noexcept

Extracts the logical payload for a discovered block.

The function uses seed_index to identify the logical stream to extract and, when applicable, gathers additional parts from blocks to reassemble it.

Supported reassembly:

Supported decompression (optional):

Callers provide buffers to keep data flow explicit and allocation-free.

PayloadRandomAccessResult extract_payload_random_access(const RandomAccessSourceRange &source, std::span<const ContainerBlockRef> blocks, uint32_t seed_index, std::span<std::byte> out_payload, std::span<uint32_t> scratch_indices, const PayloadRandomAccessScratch &scratch, const PayloadOptions &options, const RandomAccessReadLimits &read_limits = RandomAccessReadLimits{}) noexcept

Extracts one logical metadata payload through positional reads.

Offsets in blocks are relative to source. The function reads only the selected logical stream. Direct uncompressed reads stop at the accepted output prefix; framing read-ahead for GIF sub-blocks may overlap adjacent payload bytes. Compressed streams use caller-owned compressed scratch before bounded decompression into out_payload.

API Stability

Experimental host-facing API.

static constexpr uint32_t fourcc(char a, char b, char c, char d) noexcept

Packs four ASCII characters into a big-endian FourCC integer.

ScanResult scan_auto(std::span<const std::byte> bytes, std::span<ContainerBlockRef> out) noexcept
ScanResult measure_scan_auto(std::span<const std::byte> bytes) noexcept

Measures discovered metadata block count for scan_auto.

Performs the same bounded scan logic and reports ScanResult::needed without requiring output block storage.

ScanResult scan_jpeg(std::span<const std::byte> bytes, std::span<ContainerBlockRef> out) noexcept

Scans a JPEG byte stream and returns all metadata segments found.

ScanResult measure_scan_jpeg(std::span<const std::byte> bytes) noexcept
ContainerRandomAccessScanResult scan_jpeg_random_access(const RandomAccessSourceRange &jpeg, std::span<ContainerBlockRef> out, const ContainerRandomAccessScratch &scratch, const RandomAccessReadLimits &read_limits = RandomAccessReadLimits{}) noexcept

Scans JPEG metadata segments through a bounded positional source.

Discovered offsets are relative to jpeg, not the backing source. Callback input uses caller-owned scratch and never reads entropy-coded image data. A 512-byte read window preserves all contiguous scanner classifications; smaller windows report RandomAccessReadCode::ScratchTooSmall when a larger segment probe is required.

API Stability

Experimental host-facing API.

ContainerRandomAccessScanResult measure_scan_jpeg_random_access(const RandomAccessSourceRange &jpeg, const ContainerRandomAccessScratch &scratch, const RandomAccessReadLimits &read_limits = RandomAccessReadLimits{}) noexcept

Measures JPEG metadata block count through the same positional scan path.

ContainerRandomAccessScanResult scan_raf_random_access(const RandomAccessSourceRange &raf, std::span<ContainerBlockRef> out, const ContainerRandomAccessScratch &scratch, const RandomAccessReadLimits &read_limits = RandomAccessReadLimits{}) noexcept

Scans declared RAF preview-JPEG and FujiIFD metadata ranges.

Offsets are relative to raf. The scanner reads the fixed RAF header, JPEG metadata segments, and TIFF signatures only; it does not read preview entropy data or RAW image payloads. Source-wide signature searches are not performed by this bounded API. Callback input uses the same caller-owned read window as scan_jpeg_random_access; 512 bytes preserve complete JPEG segment-classification parity.

API Stability

Experimental host-facing API.

ContainerRandomAccessScanResult measure_scan_raf_random_access(const RandomAccessSourceRange &raf, const ContainerRandomAccessScratch &scratch, const RandomAccessReadLimits &read_limits = RandomAccessReadLimits{}) noexcept
ContainerRandomAccessScanResult scan_x3f_random_access(const RandomAccessSourceRange &x3f, std::span<ContainerBlockRef> out, const ContainerRandomAccessScratch &scratch, const RandomAccessReadLimits &read_limits = RandomAccessReadLimits{}) noexcept

Scans JPEG metadata in declared X3F IMA2/IMAG sections.

Offsets are relative to x3f. The scanner traverses the bounded SECd section directory and reads JPEG metadata from SECi sections without reading entropy-coded image data. Source-wide Exif signature searches are not performed by this bounded API. Callback input uses the same caller-owned read window as scan_jpeg_random_access; 512 bytes preserve complete JPEG segment-classification parity.

API Stability

Experimental host-facing API.

ContainerRandomAccessScanResult measure_scan_x3f_random_access(const RandomAccessSourceRange &x3f, const ContainerRandomAccessScratch &scratch, const RandomAccessReadLimits &read_limits = RandomAccessReadLimits{}) noexcept
ScanResult scan_png(std::span<const std::byte> bytes, std::span<ContainerBlockRef> out) noexcept

Scans a PNG byte stream and returns all metadata chunks found.

ScanResult measure_scan_png(std::span<const std::byte> bytes) noexcept
ContainerRandomAccessScanResult scan_png_random_access(const RandomAccessSourceRange &png, std::span<ContainerBlockRef> out, const ContainerRandomAccessScratch &scratch, const RandomAccessReadLimits &read_limits = RandomAccessReadLimits{}) noexcept

Scans PNG metadata chunks through a bounded positional source.

Offsets are relative to png. Callback input requires at least 32 bytes of caller-owned read-window storage and skips pixel payloads.

API Stability

Experimental host-facing API.

ContainerRandomAccessScanResult measure_scan_png_random_access(const RandomAccessSourceRange &png, const ContainerRandomAccessScratch &scratch, const RandomAccessReadLimits &read_limits = RandomAccessReadLimits{}) noexcept
ScanResult scan_webp(std::span<const std::byte> bytes, std::span<ContainerBlockRef> out) noexcept

Scans a RIFF/WebP byte stream and returns all metadata chunks found.

ScanResult measure_scan_webp(std::span<const std::byte> bytes) noexcept
ContainerRandomAccessScanResult scan_webp_random_access(const RandomAccessSourceRange &webp, std::span<ContainerBlockRef> out, const ContainerRandomAccessScratch &scratch, const RandomAccessReadLimits &read_limits = RandomAccessReadLimits{}) noexcept

Scans WebP metadata chunks through a bounded positional source.

Offsets are relative to webp. Callback input requires at least 32 bytes of caller-owned read-window storage and skips image payloads.

API Stability

Experimental host-facing API.

ContainerRandomAccessScanResult measure_scan_webp_random_access(const RandomAccessSourceRange &webp, const ContainerRandomAccessScratch &scratch, const RandomAccessReadLimits &read_limits = RandomAccessReadLimits{}) noexcept
ScanResult scan_gif(std::span<const std::byte> bytes, std::span<ContainerBlockRef> out) noexcept

Scans a GIF byte stream and returns all metadata extension blocks found.

ScanResult measure_scan_gif(std::span<const std::byte> bytes) noexcept
ContainerRandomAccessScanResult scan_gif_random_access(const RandomAccessSourceRange &gif, std::span<ContainerBlockRef> out, const ContainerRandomAccessScratch &scratch, const RandomAccessReadLimits &read_limits = RandomAccessReadLimits{}) noexcept

Scans GIF metadata extensions through a bounded positional source.

Offsets are relative to gif. Callback input requires at least 32 bytes of caller-owned read-window storage. Image raster sub-block payloads are skipped; metadata extension payloads are located but not fetched.

API Stability

Experimental host-facing API.

ContainerRandomAccessScanResult measure_scan_gif_random_access(const RandomAccessSourceRange &gif, const ContainerRandomAccessScratch &scratch, const RandomAccessReadLimits &read_limits = RandomAccessReadLimits{}) noexcept
ScanResult scan_tiff(std::span<const std::byte> bytes, std::span<ContainerBlockRef> out) noexcept

Scans a TIFF/DNG byte stream; the whole file is exposed as an EXIF/TIFF-IFD block.

ScanResult measure_scan_tiff(std::span<const std::byte> bytes) noexcept
ScanResult scan_jp2(std::span<const std::byte> bytes, std::span<ContainerBlockRef> out) noexcept

Scans a JPEG 2000 (JP2) byte stream and returns metadata boxes found.

ScanResult measure_scan_jp2(std::span<const std::byte> bytes) noexcept
ContainerRandomAccessScanResult scan_jp2_random_access(const RandomAccessSourceRange &jp2, std::span<ContainerBlockRef> out, const ContainerRandomAccessScratch &scratch, const RandomAccessReadLimits &read_limits = RandomAccessReadLimits{}) noexcept

Scans JP2 metadata boxes through a bounded positional source.

Offsets are relative to jp2. Callback input requires at least 32 bytes of caller-owned read-window storage and skips codestream payloads.

API Stability

Experimental host-facing API.

ContainerRandomAccessScanResult measure_scan_jp2_random_access(const RandomAccessSourceRange &jp2, const ContainerRandomAccessScratch &scratch, const RandomAccessReadLimits &read_limits = RandomAccessReadLimits{}) noexcept
ScanResult scan_jxl(std::span<const std::byte> bytes, std::span<ContainerBlockRef> out) noexcept

Scans a JPEG XL container byte stream and returns metadata boxes found.

ScanResult measure_scan_jxl(std::span<const std::byte> bytes) noexcept
ContainerRandomAccessScanResult scan_jxl_random_access(const RandomAccessSourceRange &jxl, std::span<ContainerBlockRef> out, const ContainerRandomAccessScratch &scratch, const RandomAccessReadLimits &read_limits = RandomAccessReadLimits{}) noexcept

Scans JXL metadata boxes through a bounded positional source.

Offsets are relative to jxl. Callback input requires at least 32 bytes of caller-owned read-window storage and skips codestream payloads.

API Stability

Experimental host-facing API.

ContainerRandomAccessScanResult measure_scan_jxl_random_access(const RandomAccessSourceRange &jxl, const ContainerRandomAccessScratch &scratch, const RandomAccessReadLimits &read_limits = RandomAccessReadLimits{}) noexcept
ScanResult scan_bmff(std::span<const std::byte> bytes, std::span<ContainerBlockRef> out) noexcept

Scans an ISO-BMFF (ftyp) container (e.g. HEIF/AVIF/CR3) and returns metadata items found within meta boxes.

ScanResult measure_scan_bmff(std::span<const std::byte> bytes) noexcept
ContainerRandomAccessScanResult scan_bmff_random_access(const RandomAccessSourceRange &bmff, std::span<ContainerBlockRef> out, const ContainerRandomAccessScratch &scratch, const RandomAccessReadLimits &read_limits = RandomAccessReadLimits{}) noexcept

Scans ISO-BMFF metadata through a bounded positional source.

Offsets are relative to bmff. Callback input requires at least 32 bytes of caller-owned read-window storage. Structural boxes and metadata item tables are traversed without reading mdat payloads.

API Stability

Experimental host-facing API.

ContainerRandomAccessScanResult measure_scan_bmff_random_access(const RandomAccessSourceRange &bmff, const ContainerRandomAccessScratch &scratch, const RandomAccessReadLimits &read_limits = RandomAccessReadLimits{}) noexcept
bool dng_sdk_adapter_available() noexcept

Returns true when OpenMeta was built with the optional DNG SDK adapter enabled.

DngSdkAdapterResult apply_prepared_dng_sdk_metadata(const PreparedTransferBundle &bundle, ::dng_host *host, ::dng_negative *negative, const DngSdkAdapterOptions &options = DngSdkAdapterOptions{}) noexcept

Applies prepared DNG-target metadata onto a DNG SDK negative.

Current v1 coverage is bounded to EXIF, XMP, and IPTC payloads emitted by OpenMeta’s prepared DNG transfer bundle. This API does not encode pixels or synthesize raw-image structure.

DngSdkAdapterResult update_prepared_dng_sdk_stream_metadata(const PreparedTransferBundle &bundle, ::dng_host *host, ::dng_negative *negative, ::dng_stream *stream, const DngSdkAdapterOptions &options = DngSdkAdapterOptions{}) noexcept

Applies prepared metadata onto a DNG SDK negative, then runs the SDK’s in-place metadata update path on an existing DNG stream.

ApplyDngSdkMetadataFileResult apply_dng_sdk_metadata_from_file(const char *path, ::dng_host *host, ::dng_negative *negative, const ApplyDngSdkMetadataFileOptions &options = ApplyDngSdkMetadataFileOptions{}) noexcept

Reads one source file, prepares a DNG-target bundle, then applies it onto a DNG SDK negative.

ApplyDngSdkMetadataFileResult update_dng_sdk_stream_metadata_from_file(const char *path, ::dng_host *host, ::dng_negative *negative, ::dng_stream *stream, const ApplyDngSdkMetadataFileOptions &options = ApplyDngSdkMetadataFileOptions{}) noexcept

Reads one source file, prepares a DNG-target bundle, applies it onto a DNG SDK negative, then updates an existing DNG stream in place.

ApplyDngSdkMetadataFileResult update_dng_sdk_file_from_file(const char *source_path, const char *target_path, const ApplyDngSdkMetadataFileOptions &options = ApplyDngSdkMetadataFileOptions{}) noexcept

Reads one source file, prepares a DNG-target bundle, parses one existing target DNG file through the Adobe DNG SDK, then updates that target file’s metadata in place.

This is the thin public file-helper used by bindings and host tools that want an end-to-end “source file -> existing DNG file” metadata update path without directly managing SDK object lifetimes.

std::string_view exif_tag_name(std::string_view ifd, uint16_t tag) noexcept

Returns a human-readable EXIF/TIFF tag name for a given IFD token and tag id.

The IFD token matches the decoder output (e.g. "ifd0", "exififd", "gpsifd").

Returns:

An empty view for unknown tags.

std::string_view exif_entry_name(const MetaStore &store, const Entry &entry, ExifTagNamePolicy policy) noexcept

Returns a human-readable name for an EXIF-tag entry.

Canonical names come from the static tag registry. Compatibility policy may use decode-time contextual variants for ambiguous MakerNote tags.

ExifDecodeResult decode_exif_tiff(std::span<const std::byte> tiff_bytes, MetaStore &store, std::span<ExifIfdRef> out_ifds, const ExifDecodeOptions &options) noexcept

Decodes a TIFF header + IFD chain and appends tags into store.

The decoded entries use:

  • MetaKeyKind::ExifTag

  • an IFD token string such as "ifd0", "exififd", "gpsifd", "subifd0"

  • the numeric TIFF tag id.

Provenance is recorded in Origin (block + order + wire type/count).

Parameters:
  • tiff_bytes – TIFF header + IFD stream (from an EXIF blob or a TIFF/DNG file).

  • store – Destination MetaStore (entries are appended).

  • out_ifds – Optional output array for decoded IFD references (may be empty).

  • options – Decode options + limits.

ExifRandomAccessDecodeResult decode_exif_tiff_random_access(const RandomAccessSourceRange &tiff, MetaStore &store, std::span<ExifIfdRef> out_ifds, const ExifRandomAccessScratch &scratch, const ExifDecodeOptions &options, const RandomAccessReadLimits &read_limits = RandomAccessReadLimits{}) noexcept

Decodes TIFF/DNG metadata through a bounded positional source.

Contiguous source ranges retain the complete existing decoder behavior. Callback sources use caller-owned scratch, never materialize the complete source, and report vendor payloads or derived subtables that still require callback-reader conversion.

API Stability

Experimental host-facing API.

ExifDecodeResult measure_exif_tiff(std::span<const std::byte> tiff_bytes, const ExifDecodeOptions &options = ExifDecodeOptions{}) noexcept

Estimates EXIF/TIFF decode counts using the same limits/options.

This function performs a bounded decode pass into an internal scratch store and returns the same status/counter model as decode_exif_tiff. Callers can use this to preflight entry counts before full decode/export.

const char *tiff_compression_name(uint64_t value) noexcept
const char *tiff_photometric_interpretation_name(uint64_t value) noexcept
const char *tiff_planar_configuration_name(uint64_t value) noexcept
const char *tiff_resolution_unit_name(uint64_t value) noexcept
const char *tiff_ycbcr_positioning_name(uint64_t value) noexcept
const char *exif_exposure_program_name(uint64_t value) noexcept
const char *exif_exposure_mode_name(uint64_t value) noexcept
const char *exif_metering_mode_name(uint64_t value) noexcept
const char *exif_light_source_name(uint64_t value) noexcept
const char *exif_flash_name(uint64_t value) noexcept
const char *exif_color_space_name(uint64_t value) noexcept
const char *exif_white_balance_name(uint64_t value) noexcept
const char *exif_scene_capture_type_name(uint64_t value) noexcept
const char *exif_gain_control_name(uint64_t value) noexcept
const char *exif_sensitivity_type_name(uint64_t value) noexcept
const char *exif_focal_plane_resolution_unit_name(uint64_t value) noexcept
const char *exif_sensing_method_name(uint64_t value) noexcept
const char *exif_file_source_name(uint64_t value) noexcept
const char *exif_scene_type_name(uint64_t value) noexcept
const char *exif_custom_rendered_name(uint64_t value) noexcept
const char *exif_contrast_name(uint64_t value) noexcept
const char *exif_saturation_name(uint64_t value) noexcept
const char *exif_sharpness_name(uint64_t value) noexcept
const char *exif_subject_distance_range_name(uint64_t value) noexcept
const char *dng_cfa_layout_name(uint64_t value) noexcept
const char *dng_calibration_illuminant_name(uint64_t value) noexcept
const char *exif_tag_numeric_value_name(std::string_view ifd, uint16_t tag, uint64_t value) noexcept

Interprets common numeric enum-like values by EXIF/TIFF/DNG tag id and selected bounded MakerNote contexts.

Returns an empty string when OpenMeta has no stable public interpretation for the value. Unknown values remain numeric and lossless in the underlying MetaStore entry.

bool exif_tag_numeric_value_format(std::string_view ifd, uint16_t tag, uint64_t value, char *out, std::size_t out_size) noexcept

Formats selected version/firmware-style numeric values.

This is separate from exif_tag_numeric_value_name because firmware and version fields are formatted values, not enum labels. Returns false when the context is unsupported or the output buffer is too small; in both cases the output buffer is cleared when possible.

bool exif_tag_byte_value_format(std::string_view ifd, uint16_t tag, std::span<const std::byte> value, char *out, std::size_t out_size) noexcept

Formats selected one-byte enums and version/firmware-style payloads.

Stable standard enum labels are emitted for one-byte payloads. Printable ASCII payloads are copied after NUL/space trimming. Other payloads are formatted as bounded dotted decimal bytes only for version-like contexts. Returns false when the context is unsupported or the output buffer is too small; in both cases the output buffer is cleared when possible.

ExrAdapterResult build_exr_attribute_batch(const MetaStore &store, ExrAdapterBatch *out, const ExrAdapterOptions &options = ExrAdapterOptions{}) noexcept

Builds one owned EXR-native attribute batch from a MetaStore.

Only MetaKeyKind::ExrAttribute entries are exported. Known scalar and vector EXR types are encoded back into EXR little-endian attribute bytes. Unknown/custom attributes are preserved as opaque raw bytes when the original type name is available in Origin::wire_type_name.

ExrAdapterResult build_prepared_exr_attribute_batch(const PreparedTransferBundle &bundle, ExrAdapterBatch *out, const ExrAdapterOptions &options = ExrAdapterOptions{}) noexcept

Builds one EXR-native attribute batch from a prepared EXR transfer bundle.

This bridges the transfer pipeline with EXR host integrations: callers can prepare metadata once with prepare_metadata_for_target using TransferTargetFormat::Exr, then materialize a host-facing ExrAdapterBatch without re-projecting from the source MetaStore.

Current EXR prepared transfer blocks serialize one logical string attribute per block and target part 0.

BuildExrAttributeBatchFileResult build_exr_attribute_batch_from_file(const char *path, ExrAdapterBatch *out, const BuildExrAttributeBatchFileOptions &options = BuildExrAttributeBatchFileOptions{}) noexcept

Reads one file, prepares EXR transfer metadata, then materializes a host-facing ExrAdapterBatch.

This is the direct public file-helper for thin bindings and host tools. Internally it wraps prepare_metadata_for_target_file, forces the prepared target format to TransferTargetFormat::Exr, then calls build_prepared_exr_attribute_batch.

ExrAdapterStatus build_exr_attribute_part_spans(const ExrAdapterBatch &batch, std::vector<ExrAdapterPartSpan> *out) noexcept

Builds contiguous per-part spans over one ExrAdapterBatch.

The batch must keep attributes grouped by nondecreasing part index. Batches built by build_exr_attribute_batch satisfy this contract.

ExrAdapterStatus build_exr_attribute_part_views(const ExrAdapterBatch &batch, std::vector<ExrAdapterPartView> *out) noexcept

Builds zero-copy per-part views over one ExrAdapterBatch.

ExrAdapterReplayResult replay_exr_attribute_batch(const ExrAdapterBatch &batch, const ExrAdapterReplayCallbacks &callbacks) noexcept

Replays one ExrAdapterBatch through explicit host callbacks.

ExrAdapterReplayCallbacks::emit_attribute must be non-null. ExrAdapterReplayCallbacks::begin_part and ExrAdapterReplayCallbacks::end_part are optional.

ExrDecodeResult decode_exr_header(std::span<const std::byte> exr_bytes, MetaStore &store, EntryFlags flags = EntryFlags::None, const ExrDecodeOptions &options = ExrDecodeOptions{}) noexcept

Decodes OpenEXR header attributes and appends entries into store.

Each decoded header attribute becomes one Entry with:

Duplicate attribute names are preserved.

ExrDecodeResult measure_exr_header(std::span<const std::byte> exr_bytes, const ExrDecodeOptions &options = ExrDecodeOptions{}) noexcept

Estimates EXR header decode counts using the same limits/options.

ExrRandomAccessDecodeResult decode_exr_header_random_access(const RandomAccessSourceRange &exr, MetaStore &store, const ExrRandomAccessScratch &scratch, EntryFlags flags = EntryFlags::None, const ExrDecodeOptions &options = ExrDecodeOptions{}, const RandomAccessReadLimits &read_limits = RandomAccessReadLimits{}) noexcept

Decodes EXR header attributes through a bounded positional source.

Callback input uses caller-owned structural and value storage and stops at the end of the EXR header without reading chunk-offset tables or pixel data. Contiguous source ranges retain the existing direct decode behavior.

API Stability

Experimental host-facing API.

ExrRandomAccessDecodeResult measure_exr_header_random_access(const RandomAccessSourceRange &exr, const ExrRandomAccessScratch &scratch, const ExrDecodeOptions &options = ExrDecodeOptions{}, const RandomAccessReadLimits &read_limits = RandomAccessReadLimits{}) noexcept

Measures EXR header attributes without fetching attribute bodies.

std::string_view geotiff_key_name(uint16_t key_id) noexcept

Returns a best-effort GeoTIFF key name for a numeric GeoKey id.

HostAdoptionProfile host_adoption_profile() noexcept

Returns the profile contract versions compiled into the linked library.

bool host_adoption_profile_matches(const HostAdoptionProfile &expected) noexcept

Checks an exact profile descriptor against the linked library.

IccDecodeResult decode_icc_profile(std::span<const std::byte> icc_bytes, MetaStore &store, const IccDecodeOptions &options = IccDecodeOptions{}) noexcept

Decodes an ICC profile header and tag table into store.

The decoder emits:

IccDecodeResult measure_icc_profile(std::span<const std::byte> icc_bytes, const IccDecodeOptions &options = IccDecodeOptions{}) noexcept

Estimates ICC decode entry count using the same limits/options.

std::string_view icc_tag_name(uint32_t signature) noexcept

Returns a short display name for an ICC tag signature.

IccTagInterpretStatus interpret_icc_tag(uint32_t signature, std::span<const std::byte> tag_bytes, IccTagInterpretation *out, const IccTagInterpretOptions &options = IccTagInterpretOptions{}) noexcept

Best-effort interpretation for selected ICC tag payload types.

Supported payload type signatures:

  • desc (ASCII profile description)

  • text (ASCII text payload)

  • sig (embedded 4-byte signature)

  • data (ASCII/binary data payload summary)

  • mluc (multi-localized Unicode)

  • ncl2 (named-color table summary)

  • dtim (date/time number)

  • view (viewing conditions summary + numeric values)

  • meas (measurement summary + backing/flare values)

  • chrm (chromaticity coordinates + colorant summary)

  • sf32 (s15Fixed16 array)

  • uf32 (u16Fixed16 array)

  • ui08 (uInt8 array)

  • ui16 (uInt16 array)

  • ui32 (uInt32 array)

  • mft1 / mft2 (LUT summaries)

  • mAB / mBA (LUT-A/B structural summaries)

  • XYZ (s15Fixed16 XYZ triplets)

  • curv (TRC curves)

  • para (parametric curves)

bool format_icc_tag_display_value(uint32_t signature, std::span<const std::byte> tag_bytes, uint32_t max_values, uint32_t max_text_bytes, std::string *out) noexcept

Formats a best-effort human-readable value string for an ICC tag.

This helper is intended for CLI/Python display paths. It uses interpret_icc_tag and returns false for unsupported/malformed payloads.

void visit_metadata(const MetaStore &store, const ExportOptions &options, MetadataSink &sink) noexcept

Visits exported metadata entries in store order.

Deleted entries are skipped. Name mapping depends on ExportOptions::style.

API Stability

Stable host-facing v1 traversal API. The callback receives borrowed views that are valid only during the call to MetadataSink::on_item.

FlatHostImportResult import_flat_host_metadata(const MetaStore &source, std::span<const FlatHostImportItem> items, const FlatHostImportOptions &options = FlatHostImportOptions{}) noexcept

Import ordered typed flat-host records into a detached store.

The finalized source is never modified. Existing entries may be selected by exact entry id or by a unique FlatHost name under options. Remove targets retain the source entry as a Dirty | Deleted tombstone so entry ids, provenance, and snapshot raw-carrier links remain stable; their value must be the default empty value. New entries require an explicit typed key, because FlatHost names are intentionally lossy and cannot safely reconstruct arbitrary metadata namespaces. FlatHostImportResult::updated includes both value updates and tombstones.

Calls use only local mutable state and are safe to run concurrently against an immutable finalized source store.

API Stability

Stable host-facing v1 API in Host Adoption Profile v1.

IptcIimDecodeResult decode_iptc_iim(std::span<const std::byte> iptc_bytes, MetaStore &store, EntryFlags flags = EntryFlags::None, const IptcIimDecodeOptions &options = IptcIimDecodeOptions{}) noexcept

Decodes an IPTC-IIM dataset stream and appends datasets into store.

Each dataset becomes one Entry with:

Duplicate datasets are preserved.

IptcIimDecodeResult measure_iptc_iim(std::span<const std::byte> iptc_bytes, const IptcIimDecodeOptions &options = IptcIimDecodeOptions{}) noexcept

Estimates IPTC-IIM dataset count using the same limits/options.

JumbfDecodeResult decode_jumbf_payload(std::span<const std::byte> bytes, MetaStore &store, EntryFlags flags = EntryFlags::None, const JumbfDecodeOptions &options = JumbfDecodeOptions{}) noexcept

Decodes a JUMBF/C2PA payload and appends entries into store.

Emitted entries use:

Duplicate keys are preserved.

JumbfDecodeResult measure_jumbf_payload(std::span<const std::byte> bytes, const JumbfDecodeOptions &options = JumbfDecodeOptions{}) noexcept

Estimates JUMBF decode entry count using the same limits/options.

JumbfStructureEstimate measure_jumbf_structure(std::span<const std::byte> bytes, const JumbfDecodeLimits &limits = JumbfDecodeLimits{}) noexcept

Estimates structural nesting for a JUMBF/C2PA payload.

Performs bounded BMFF box traversal and bounded CBOR structural parsing to report maximum observed nesting depth and item counts. This function is intended for preflight risk checks before full decode.

LibRawOrientationResult map_exif_orientation_to_libraw_flip(uint16_t exif_orientation, const LibRawOrientationOptions &options = LibRawOrientationOptions{}) noexcept

Maps one EXIF/TIFF/XMP orientation value into the common LibRaw imgdata.sizes.flip convention.

Supported exact mappings are:

  • EXIF 1 -> LibRaw 0

  • EXIF 3 -> LibRaw 3

  • EXIF 6 -> LibRaw 6

  • EXIF 8 -> LibRaw 5

Mirrored EXIF orientations (2, 4, 5, 7) are not directly representable in LibRaw’s common flip model. With LibRawMirrorPolicy::Reject they fail explicitly. With LibRawMirrorPolicy::DropMirror they are collapsed to the nearest rotation-only convention:

  • 2 -> 1

  • 4 -> 3

  • 5 -> 8

  • 7 -> 6

For LibRawOrientationTarget::EmbeddedPreview, the default policy is to pass previews through unchanged because preview orientation is often already baked into the extracted bytes or carried by the preview’s own metadata.

LibRawFlipToExifResult map_libraw_flip_to_exif_orientation(uint32_t libraw_flip, const LibRawFlipToExifOptions &options = LibRawFlipToExifOptions{}) noexcept

Maps one common LibRaw imgdata.sizes.flip value back into EXIF/TIFF orientation space.

Supported exact mappings are:

  • LibRaw 0 -> EXIF 1

  • LibRaw 3 -> EXIF 3

  • LibRaw 5 -> EXIF 8

  • LibRaw 6 -> EXIF 6

This recovers only the non-mirrored EXIF orientation states because the common LibRaw flip model does not preserve the full TIFF 8-state orientation space.

For LibRawOrientationTarget::EmbeddedPreview, the default policy is to pass previews through unchanged and assume EXIF orientation 1.

LibRawOrientationResult map_meta_orientation_to_libraw_flip(const MetaStore &store, const LibRawOrientationOptions &options = LibRawOrientationOptions{}) noexcept

Extracts canonical orientation metadata from a MetaStore and maps it into the common LibRaw flip convention.

Source precedence is:

  • EXIF ifd0:0x0112

  • XMP tiff:Orientation

  • assumed default EXIF orientation 1 if neither is present

LibRawOrientationFileResult map_meta_orientation_to_libraw_flip_from_file(const char *path, const LibRawOrientationFileOptions &options = LibRawOrientationFileOptions{}) noexcept

Reads one file, decodes supported metadata, then maps canonical orientation metadata into the LibRaw flip convention.

This is the direct file-helper for thin host integrations that want the same explicit orientation result without manually calling simple_meta_read and extracting ifd0:0x0112.

MetaStore commit(const MetaStore &base, std::span<const MetaEdit> edits)

Applies edits to base and returns a new MetaStore snapshot.

MetaStore compact(const MetaStore &base)

Compacts a store by removing tombstones and rewriting indices.

constexpr EntryFlags operator|(EntryFlags a, EntryFlags b) noexcept
constexpr EntryFlags operator&(EntryFlags a, EntryFlags b) noexcept
constexpr EntryFlags &operator|=(EntryFlags &a, EntryFlags b) noexcept
constexpr bool any(EntryFlags flags, EntryFlags test) noexcept

Returns true if any bits in test are present in flags.

MetaKey make_exif_tag_key(ByteArena &arena, std::string_view ifd, uint16_t tag)

Creates a key for an EXIF/TIFF tag within a named IFD token (e.g. “ifd0”, “exififd”).

MetaKey make_comment_key() noexcept
MetaKey make_exr_attribute_key(ByteArena &arena, uint32_t part_index, std::string_view name)

Creates a key for an OpenEXR attribute name in a specific part.

MetaKey make_iptc_dataset_key(uint16_t record, uint16_t dataset) noexcept
MetaKey make_xmp_property_key(ByteArena &arena, std::string_view schema_ns, std::string_view property_path)
MetaKey make_icc_header_field_key(uint32_t offset) noexcept
MetaKey make_icc_tag_key(uint32_t signature) noexcept
MetaKey make_photoshop_irb_key(uint16_t resource_id) noexcept
MetaKey make_photoshop_irb_field_key(ByteArena &arena, uint16_t resource_id, std::string_view field)
MetaKey make_geotiff_key(uint16_t key_id) noexcept
MetaKey make_printim_field_key(ByteArena &arena, std::string_view field)
MetaKey make_bmff_field_key(ByteArena &arena, std::string_view field)
MetaKey make_jumbf_field_key(ByteArena &arena, std::string_view field)
MetaKey make_jumbf_cbor_key(ByteArena &arena, std::string_view key)
MetaKey make_png_text_key(ByteArena &arena, std::string_view keyword, std::string_view field)
int compare_key(const ByteArena &arena, const MetaKey &a, const MetaKey &b) noexcept

Orders keys for deterministic storage/indexing.

int compare_key_view(const ByteArena &arena, const MetaKeyView &a, const MetaKey &b) noexcept

Orders a borrowed key against an owned key using the same ordering as compare_key.

const char *metadata_capability_family_name(MetadataCapabilityFamily family) noexcept
const char *metadata_capability_support_name(MetadataCapabilitySupport support) noexcept
bool metadata_capability_available(MetadataCapabilitySupport support) noexcept
MetadataCapability metadata_capability(TransferTargetFormat format, MetadataCapabilityFamily family) noexcept
MetadataConceptResolution resolve_metadata_concept(const MetaStore &store, MetadataConceptKind kind)
MetadataConceptResolution resolve_metadata_concept(const MetaStore &store, MetadataConceptKind kind, const MetadataRawDataDescriptor &raw_descriptor)
MetadataConceptResult resolve_metadata_concepts(const MetaStore &store)
MetadataConceptResult resolve_metadata_concepts(const MetaStore &store, const MetadataRawDataDescriptor &raw_descriptor)
MetadataRawApplicabilityState metadata_raw_applicability_for_descriptor(MetadataConceptRole role, const MetadataRawDataDescriptor &descriptor) noexcept
const char *metadata_concept_kind_name(MetadataConceptKind kind) noexcept
const char *metadata_concept_source_family_name(MetadataConceptSourceFamily family) noexcept
const char *metadata_concept_role_name(MetadataConceptRole role) noexcept
const char *metadata_concept_record_kind_name(MetadataConceptRecordKind kind) noexcept
const char *metadata_image_region_shape_name(MetadataImageRegionShape shape) noexcept
const char *metadata_image_region_coordinate_unit_name(MetadataImageRegionCoordinateUnit unit) noexcept
const char *metadata_concept_sensitivity_name(MetadataConceptSensitivity sensitivity) noexcept
const char *metadata_concept_datetime_precision_name(MetadataConceptDateTimePrecision precision) noexcept
const char *metadata_concept_timezone_kind_name(MetadataConceptTimeZoneKind kind) noexcept
const char *metadata_concept_transfer_hint_name(MetadataConceptTransferHint hint) noexcept
const char *metadata_raw_data_encoding_name(MetadataRawDataEncoding encoding) noexcept
const char *metadata_raw_applicability_state_name(MetadataRawApplicabilityState state) noexcept
const char *metadata_concept_gps_altitude_reference_name(uint8_t code) noexcept
MetadataCreationField make_metadata_creation_text(MetadataCreationFieldKind kind, std::string_view value) noexcept

Creates a text-valued field without copying value.

MetadataCreationField make_metadata_creation_u32(MetadataCreationFieldKind kind, uint32_t value) noexcept

Creates an unsigned-integer-valued field.

MetadataCreationField make_metadata_creation_i32(MetadataCreationFieldKind kind, int32_t value) noexcept

Creates a signed-integer-valued field.

MetadataCreationField make_metadata_creation_urational(MetadataCreationFieldKind kind, uint32_t numer, uint32_t denom) noexcept

Creates an unsigned-rational-valued field.

MetadataCreationResult create_metadata(const MetadataCreationRequest &request, MetaStore *out_store)

Builds a finalized store containing canonical portable-XMP entries.

Validation is transactional: on any non-Ok result, out_store is not modified. Creator and Keyword fields are additive and preserve request order; every other field is a singleton. Text must be non-empty, valid UTF-8, and valid XML 1.0 character data.

The output representation is intentionally portable XMP. Projecting these logical values into EXIF or IPTC wire fields belongs to the Translation stage. Entries are marked EntryFlags::Dirty and can be passed directly to existing portable-XMP and metadata-transfer APIs.

The function keeps no global state. Concurrent calls are safe when each call uses a distinct output store.

const char *metadata_creation_field_kind_name(MetadataCreationFieldKind kind) noexcept
const char *metadata_creation_status_name(MetadataCreationStatus status) noexcept
MetadataEditingOperation make_metadata_edit_add(const MetadataCreationField &field) noexcept
MetadataEditingOperation make_metadata_edit_set(const MetadataCreationField &field, uint32_t occurrence = 0U) noexcept
MetadataEditingOperation make_metadata_edit_remove(MetadataCreationFieldKind kind, uint32_t occurrence = 0U) noexcept
MetadataEditingOperation make_metadata_edit_remove_all(MetadataCreationFieldKind kind) noexcept
MetadataEditingResult edit_metadata(const MetaStore &base, const MetadataEditingRequest &request, MetaStore *out_store)

Applies a validated logical edit transaction to a finalized store.

The output is replaced only after every operation succeeds. Set preserves the existing key, origin, block, wire provenance, and flags while replacing the value and adding EntryFlags::Dirty. Remove preserves the entry as a dirty tombstone. Add emits a new dirty canonical portable-XMP entry.

Operations observe earlier operations in the same request. This function keeps no global state and is safe for concurrent calls that use distinct output stores.

const char *metadata_editing_operation_kind_name(MetadataEditingOperationKind kind) noexcept
const char *metadata_editing_status_name(MetadataEditingStatus status) noexcept
MetadataFuzzySearchResult fuzzy_search_metadata(const MetaStore &store, std::string_view query, const MetadataFuzzySearchOptions &options = {})

Searches decoded metadata names and property paths.

Results are ordered by descending score, then match provenance (exact, alias, fuzzy), then ascending stable entry id. The result count is bounded by MetadataFuzzySearchOptions::max_results.

The current normalization contract is ASCII-only and locale-independent. ASCII case and separators are normalized, including camel-case and acronym-to-word boundaries. Non-ASCII query text returns MetadataFuzzySearchStatus::UnsupportedQueryText; no Unicode normalization or transliteration is attempted. Non-ASCII candidate bytes act as separators while ASCII fragments remain searchable. Query and candidate scanning are bounded by kMetadataFuzzySearchMaxQueryBytes and kMetadataFuzzySearchMaxCandidateBytes.

The function keeps no global state and is safe for concurrent calls when the finalized input store is not being mutated.

bool metadata_fuzzy_search_available() noexcept
const char *metadata_fuzzy_search_status_name(MetadataFuzzySearchStatus status) noexcept
const char *metadata_fuzzy_search_match_kind_name(MetadataFuzzySearchMatchKind kind) noexcept
MetadataInterpretationResult interpret_metadata_query(const MetaStore &store, MetadataQueryKind kind)
MetadataInterpretationResult interpret_metadata(const MetaStore &store)
MetadataQueryResult query_metadata(const MetaStore &store, MetadataQueryKind kind)
MetadataQueryResult query_crop_metadata(const MetaStore &store)
MetadataQueryResult query_exposure_gain_metadata(const MetaStore &store)
MetadataQueryResult query_white_balance_metadata(const MetaStore &store)
MetadataQueryResult query_color_metadata(const MetaStore &store)
MetadataQueryResult query_lens_correction_metadata(const MetaStore &store)
MetadataQueryResult query_orientation_metadata(const MetaStore &store)
MetadataQueryResult query_raw_processing_metadata(const MetaStore &store)
MetadataQueryResult query_descriptive_metadata(const MetaStore &store)
bool metadata_query_fuzzy_search_available() noexcept

Compatibility capability query; prefer metadata_fuzzy_search_available().

const char *metadata_query_kind_name(MetadataQueryKind kind) noexcept
const char *metadata_query_semantic_kind_name(MetadataQuerySemanticKind kind) noexcept
const char *metadata_query_value_shape_name(MetadataQueryValueShape shape) noexcept
PersistPreparedTransferFileResult persist_prepared_transfer_file_result(const ExecutePreparedTransferFileResult &prepared, const PersistPreparedTransferFileOptions &options) noexcept

Persists edited output, generated XMP sidecar output, and any requested destination-sidecar cleanup from execute_prepared_transfer_file.

This is a bounded file helper for host applications that want the same output/sidecar behavior as the CLI or Python wrapper without reimplementing write and cleanup logic.

EmitTransferResult build_executed_transfer_package_batch(std::span<const std::byte> edit_input, const PreparedTransferBundle &bundle, const ExecutePreparedTransferResult &execute, PreparedTransferPackageBatch *out_batch) noexcept

Materializes the final persisted package batch for one executed transfer state.

For direct emit targets this builds the target-neutral emit package batch. For JPEG/TIFF/BMFF edit flows this builds the rewrite package batch from the selected edit state and input bytes.

PrepareTransferResult prepare_metadata_for_target(const MetaStore&, const PrepareTransferRequest&, PreparedTransferBundle *out_bundle) noexcept

Draft bundle preparation entry point.

PrepareTransferResult prepare_metadata_for_target_snapshot(const TransferSourceSnapshot &snapshot, const PrepareTransferRequest &request, PreparedTransferBundle *out_bundle) noexcept

Prepare a target-specific transfer bundle from a decoded source snapshot.

This is the fileless counterpart to prepare_metadata_for_target_file for host applications that already hold a reusable decoded source snapshot from an earlier read.

Current snapshot execution is decoded-store-backed. Opt-in raw carrier payloads can be retained in the snapshot for host diagnostics and future passthrough policy, but are not consumed by this preparation entry point yet.

API Stability

Experimental host-facing API.

TransferSourceSnapshot build_transfer_source_snapshot(const MetaStore &store) noexcept

Build a reusable decoded source snapshot from an existing MetaStore.

The snapshot stores its own finalized copy of the input store so later transfer preparation or execution does not depend on the caller keeping the original store alive or immutable.

API Stability

Experimental host-facing API.

TransferSafetyAudit transfer_safety_audit_from_store(const MetaStore &store, TransferSafetyMode safety) noexcept

Summarize metadata that a transfer safety mode will keep, filter, or invalidate before writing a target.

API Stability

Experimental host-facing API for diagnostics, UI, and preflight decisions.

TransferMakerNoteAudit makernote_transfer_audit_from_store(const MetaStore &store) noexcept

Report MakerNote source evidence and the current writer trust bound.

A raw ExifIFD:MakerNote value can be carried forward as opaque bytes, but OpenMeta does not currently relocate vendor-private offsets, rebuild a note from decoded sub-IFDs, recalculate vendor checksums, or verify that a moved note remains semantically readable. Generic raw-carrier passthrough is also intentionally unavailable for MakerNotes.

API Stability

Experimental host-facing API for diagnostics, UI, and preflight decisions.

TransferMakerNoteLayoutAudit makernote_layout_transfer_audit_from_store(const MetaStore &store) noexcept

Classify raw MakerNote layouts that affect offset-safe transfer.

The first bounded implementation recognizes canonical Nikon type 1 notes, whose offsets depend on the outer TIFF, and Nikon type 3 notes containing an embedded TIFF at byte 10. A valid embedded TIFF proves only that standard TIFF directory/value offsets remain inside that payload. Vendor-private binary offsets, checksums, and semantic readability are not validated.

API Stability

Experimental host-facing API for diagnostics, UI, and preflight decisions.

TransferConceptDiagnostics transfer_concept_diagnostics_from_store(const MetaStore &store, TransferSafetyMode safety)
TransferConceptDiagnostics transfer_concept_diagnostics_from_store(const MetaStore &store, TransferSafetyMode safety, const MetadataRawDataDescriptor &raw_descriptor)
const char *transfer_concept_diagnostic_action_name(TransferConceptDiagnosticAction action) noexcept
const char *transfer_concept_diagnostic_reason_name(TransferConceptDiagnosticReason reason) noexcept
TransferConceptDiagnosticSeverity transfer_concept_diagnostic_severity(const TransferConceptDiagnostic &diagnostic) noexcept
const char *transfer_concept_diagnostic_severity_name(TransferConceptDiagnosticSeverity severity) noexcept
const char *transfer_concept_diagnostic_message(const TransferConceptDiagnostic &diagnostic) noexcept
std::string transfer_concept_diagnostic_token(const TransferConceptDiagnostic &diagnostic)
std::string transfer_concept_diagnostic_message_token(const TransferConceptDiagnostic &diagnostic)
std::vector<std::string> transfer_concept_diagnostic_message_arguments(const TransferConceptDiagnostic &diagnostic)
TransferRawCarrierPassthroughAudit raw_carrier_passthrough_audit_from_snapshot(const TransferSourceSnapshot &snapshot, const TransferRawCarrierPassthroughAuditOptions &options = TransferRawCarrierPassthroughAuditOptions{}) noexcept

Report which opt-in raw source carriers are passthrough candidates.

This helper is diagnostic only. It checks preserved payload availability, target carrier compatibility, decoded-entry safety filtering, content-bound C2PA rules, and explicit profile drops. It does not enable passthrough by itself; callers must opt in through PrepareTransferRequest.

API Stability

Experimental host-facing API for diagnostics, UI, and preflight decisions.

EmitTransferResult append_prepared_bundle_jpeg_jumbf(PreparedTransferBundle *bundle, std::span<const std::byte> logical_payload, const AppendPreparedJpegJumbfOptions &options = AppendPreparedJpegJumbfOptions{}) noexcept

Append one logical raw JUMBF payload as JPEG APP11 transfer blocks.

The input must be a logical JUMBF BMFF payload (jumb/jumd…), not an already wrapped APP11 marker payload. C2PA content-bound payloads are rejected by this helper; they require a dedicated invalidation/re-sign path.

On success, the bundle policy decision for JUMBF is updated to explicit Keep, and one or more jpeg:app11-jumbf prepared blocks are appended.

EmitTransferResult emit_prepared_bundle_jpeg(const PreparedTransferBundle &bundle, JpegTransferEmitter &emitter, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Emit prepared metadata blocks into a JPEG backend.

Route mapping:

  • jpeg:app1-exif -> APP1 (0xE1)

  • jpeg:app1-xmp -> APP1 (0xE1)

  • jpeg:app2-icc -> APP2 (0xE2)

  • jpeg:app13-iptc -> APP13 (0xED)

  • jpeg:appN / jpeg:appN-* where N in [0,15]

  • jpeg:com -> COM (0xFE)

EmitTransferResult emit_prepared_bundle_tiff(const PreparedTransferBundle &bundle, TiffTransferEmitter &emitter, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Emit prepared metadata blocks into a TIFF backend.

Route mapping:

  • tiff:tag-700-xmp -> TIFF tag 700 (XMP packet)

  • tiff:ifd-exif-app1 -> serialized EXIF APP1 input for ExifIFD materialization

  • tiff:tag-34675-icc -> TIFF tag 34675 (ICC profile)

  • tiff:tag-33723-iptc -> TIFF tag 33723 (IPTC IIM stream)

EmitTransferResult emit_prepared_bundle_jxl(const PreparedTransferBundle &bundle, JxlTransferEmitter &emitter, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Emit prepared metadata blocks into a JPEG XL backend.

Route mapping:

  • jxl:icc-profile -> encoder ICC profile

  • jxl:box-exif -> Exif

  • jxl:box-xml -> xml

  • jxl:box-jumb -> jumb

  • jxl:box-c2pa -> c2pa

EmitTransferResult emit_prepared_bundle_webp(const PreparedTransferBundle &bundle, WebpTransferEmitter &emitter, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Emit prepared metadata blocks into a WebP backend.

Route mapping:

  • webp:chunk-exif -> EXIF

  • webp:chunk-xmp -> XMP

  • webp:chunk-iccp -> ICCP

  • webp:chunk-c2pa -> C2PA

EmitTransferResult emit_prepared_bundle_png(const PreparedTransferBundle &bundle, PngTransferEmitter &emitter, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Emit prepared metadata blocks into a PNG backend.

Route mapping:

  • png:chunk-exif -> eXIf

  • png:chunk-xmp -> iTXt

  • png:chunk-iccp -> iCCP

EmitTransferResult emit_prepared_bundle_jp2(const PreparedTransferBundle &bundle, Jp2TransferEmitter &emitter, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Emit prepared metadata blocks into a JP2 backend.

Route mapping:

  • jp2:box-exif -> Exif

  • jp2:box-xml -> xml

  • jp2:box-jp2h-colr -> jp2h carrying one colr ICC child box

EmitTransferResult emit_prepared_bundle_exr(const PreparedTransferBundle &bundle, ExrTransferEmitter &emitter, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Emit prepared metadata blocks into an EXR backend.

Route mapping:

  • exr:attribute-string -> EXR string header attribute

This first-class EXR target is intentionally bounded to safe flattened string attributes. It does not rewrite complete EXR files.

EmitTransferResult emit_prepared_bundle_bmff(const PreparedTransferBundle &bundle, BmffTransferEmitter &emitter, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Emit prepared metadata blocks into an ISO-BMFF metadata backend.

Route mapping:

  • bmff:item-exif -> Exif item payload

  • bmff:item-xmp -> mime item carrying XMP

  • bmff:item-jumb -> jumb item payload

  • bmff:item-c2pa -> c2pa item payload

  • bmff:property-colr-icc -> colr property payload with prof ICC data

EmitTransferResult compile_prepared_bundle_tiff(const PreparedTransferBundle &bundle, PreparedTiffEmitPlan *out_plan, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Compile a reusable TIFF emit plan from a prepared bundle.

This maps route strings to TIFF tags once for high-throughput “prepare once, emit many” workflows.

EmitTransferResult emit_prepared_bundle_tiff_compiled(const PreparedTransferBundle &bundle, const PreparedTiffEmitPlan &plan, TiffTransferEmitter &emitter, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Emit a prepared bundle using a precompiled TIFF emit plan.

EmitTransferResult compile_prepared_bundle_jxl(const PreparedTransferBundle &bundle, PreparedJxlEmitPlan *out_plan, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Compile a reusable JPEG XL emit plan from a prepared bundle.

This maps route strings to JPEG XL box types once for high-throughput “prepare once, emit many” workflows.

EmitTransferResult emit_prepared_bundle_jxl_compiled(const PreparedTransferBundle &bundle, const PreparedJxlEmitPlan &plan, JxlTransferEmitter &emitter, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Emit a prepared bundle using a precompiled JPEG XL emit plan.

EmitTransferResult build_prepared_jxl_encoder_handoff_view(const PreparedTransferBundle &bundle, PreparedJxlEncoderHandoffView *out_view, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Builds one encoder-side handoff view for prepared JPEG XL metadata.

This exposes the single encoder ICC profile separately from the normal JXL box path. Boxes remain on the regular jxl:box-* route contract.

EmitTransferResult build_prepared_jxl_encoder_handoff(const PreparedTransferBundle &bundle, PreparedJxlEncoderHandoff *out_handoff, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept
PreparedJxlEncoderHandoffIoResult serialize_prepared_jxl_encoder_handoff(const PreparedJxlEncoderHandoff &handoff, std::vector<std::byte> *out_bytes) noexcept
PreparedJxlEncoderHandoffIoResult deserialize_prepared_jxl_encoder_handoff(std::span<const std::byte> bytes, PreparedJxlEncoderHandoff *out_handoff) noexcept
EmitTransferResult compile_prepared_bundle_webp(const PreparedTransferBundle &bundle, PreparedWebpEmitPlan *out_plan, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Compile a reusable WebP emit plan from a prepared bundle.

EmitTransferResult compile_prepared_bundle_png(const PreparedTransferBundle &bundle, PreparedPngEmitPlan *out_plan, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Compile a reusable PNG emit plan from a prepared bundle.

EmitTransferResult compile_prepared_bundle_jp2(const PreparedTransferBundle &bundle, PreparedJp2EmitPlan *out_plan, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Compile a reusable JP2 emit plan from a prepared bundle.

EmitTransferResult compile_prepared_bundle_exr(const PreparedTransferBundle &bundle, PreparedExrEmitPlan *out_plan, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Compile a reusable EXR emit plan from a prepared bundle.

EmitTransferResult compile_prepared_bundle_bmff(const PreparedTransferBundle &bundle, PreparedBmffEmitPlan *out_plan, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Compile a reusable ISO-BMFF metadata emit plan from a prepared bundle.

EmitTransferResult emit_prepared_bundle_webp_compiled(const PreparedTransferBundle &bundle, const PreparedWebpEmitPlan &plan, WebpTransferEmitter &emitter, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Emit a prepared bundle using a precompiled WebP emit plan.

EmitTransferResult emit_prepared_bundle_png_compiled(const PreparedTransferBundle &bundle, const PreparedPngEmitPlan &plan, PngTransferEmitter &emitter, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Emit a prepared bundle using a precompiled PNG emit plan.

EmitTransferResult emit_prepared_bundle_jp2_compiled(const PreparedTransferBundle &bundle, const PreparedJp2EmitPlan &plan, Jp2TransferEmitter &emitter, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Emit a prepared bundle using a precompiled JP2 emit plan.

EmitTransferResult emit_prepared_bundle_exr_compiled(const PreparedTransferBundle &bundle, const PreparedExrEmitPlan &plan, ExrTransferEmitter &emitter, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Emit a prepared bundle using a precompiled EXR emit plan.

EmitTransferResult emit_prepared_bundle_bmff_compiled(const PreparedTransferBundle &bundle, const PreparedBmffEmitPlan &plan, BmffTransferEmitter &emitter, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Emit a prepared bundle using a precompiled ISO-BMFF metadata emit plan.

EmitTransferResult compile_prepared_bundle_jpeg(const PreparedTransferBundle &bundle, PreparedJpegEmitPlan *out_plan, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Compile a reusable JPEG emit plan from a prepared bundle.

This maps route strings to marker codes once for high-throughput “prepare once, emit many” workflows.

EmitTransferResult emit_prepared_bundle_jpeg_compiled(const PreparedTransferBundle &bundle, const PreparedJpegEmitPlan &plan, JpegTransferEmitter &emitter, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Emit a prepared bundle using a precompiled JPEG emit plan.

EmitTransferResult write_prepared_bundle_jpeg(const PreparedTransferBundle &bundle, TransferByteWriter &writer, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Write prepared JPEG metadata marker bytes directly to a byte sink.

This emits serialized APP/COM marker records only. It does not write SOI, SOS/image data, or EOI.

EmitTransferResult write_prepared_bundle_jpeg_compiled(const PreparedTransferBundle &bundle, const PreparedJpegEmitPlan &plan, TransferByteWriter &writer, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Write prepared JPEG metadata marker bytes using a precompiled plan.

ReadTransferSourceSnapshotFileResult read_transfer_source_snapshot_file(const char *path, const ReadTransferSourceSnapshotFileOptions &options = ReadTransferSourceSnapshotFileOptions{}) noexcept

Read a file into a reusable decoded source snapshot.

This helper hides the scratch-buffer management needed by simple_meta_read and returns an owned TransferSourceSnapshot that can be reused later with prepare_metadata_for_target_snapshot without reopening the source file.

Current snapshot contract is decoded-store-backed. Raw carrier provenance and payload bytes are preserved only when read options request them; transfer execution still uses decoded re-emission.

API Stability

Experimental host-facing API.

ReadTransferSourceSnapshotBytesResult read_transfer_source_snapshot_bytes(std::span<const std::byte> bytes, const ReadTransferSourceSnapshotOptions &options = ReadTransferSourceSnapshotOptions{}) noexcept

Read host-owned bytes into a reusable decoded source snapshot.

This is the in-memory counterpart to read_transfer_source_snapshot_file for hosts that already own the source bytes and do not want a file-path API.

Current snapshot contract is decoded-store-backed. Raw carrier provenance and payload bytes are preserved only when read options request them; transfer execution still uses decoded re-emission.

API Stability

Experimental host-facing API.

ReadTransferSourceSnapshotRandomAccessResult read_transfer_source_snapshot_random_access(const RandomAccessSourceRange &source, ContainerFormat format, const ReadTransferSourceSnapshotRandomAccessScratch &scratch, const ReadTransferSourceSnapshotRandomAccessOptions &options = ReadTransferSourceSnapshotRandomAccessOptions{}, const RandomAccessReadLimits &read_limits = RandomAccessReadLimits{}) noexcept

Assemble a reusable source snapshot through bounded positional reads.

format must identify the supplied source range. The function scans only structural container data, fetches discovered metadata payloads into caller-owned scratch, and never materializes the complete source. TIFF/DNG and EXR use their native positional decoders. RAF and X3F can additionally follow declared preview/FujiIFD and section-JPEG metadata when embedded decoding is requested, without reading JPEG entropy or RAW image payloads. The returned snapshot owns its finalized decoded store and any explicitly requested bounded raw carriers.

residual_metadata_paths reports requested or format-specific enrichment paths that are not represented by discovered payload blocks. A nonzero value keeps the usable result but makes complete() false.

API Stability

Stable host-facing v1 API in Host Adoption Profile v1. Format coverage may grow additively; callers must inspect complete() and residual diagnostics.

ReadTransferSourceDiagnosticsResult collect_read_transfer_source_diagnostics(const ReadTransferSourceSnapshotRandomAccessResult &result, std::span<ReadTransferSourceDiagnostic> out, const ReadTransferSourceDiagnosticOptions &options = ReadTransferSourceDiagnosticOptions{}) noexcept

Project structured diagnostics from a positional snapshot result.

The function does not allocate. It reports the total required count in needed and writes the prefix that fits in out. Pass the same optional lane requests used for the read so residual paths can be classified as an incomplete requested MakerNote or embedded-container lane where applicable.

API Stability

Stable host-facing v1 API in Host Adoption Profile v1.

const char *read_transfer_source_diagnostic_severity_name(ReadTransferSourceDiagnosticSeverity severity) noexcept

Stable v1 name for one positional diagnostic severity.

const char *read_transfer_source_diagnostic_domain_name(ReadTransferSourceDiagnosticDomain domain) noexcept

Stable v1 name for one positional diagnostic domain.

const char *read_transfer_source_diagnostic_code_name(ReadTransferSourceDiagnosticCode code) noexcept

Stable v1 name for one positional diagnostic code.

const char *read_transfer_source_diagnostic_message(ReadTransferSourceDiagnosticCode code) noexcept

Stable v1 default English message for one positional diagnostic code.

TransferSourceSnapshotIoResult serialize_transfer_source_snapshot(const TransferSourceSnapshot &snapshot, std::vector<std::byte> *out_bytes, const TransferSourceSnapshotIoOptions &options = TransferSourceSnapshotIoOptions{}) noexcept

Serialize a target-neutral source snapshot into owned bytes.

The versioned representation preserves the decoded store, duplicate entry order, typed values, provenance, flags, and any opt-in raw carriers. It does not make a raw carrier safe to relocate or write into another container.

API Stability

Stable host-facing object API and v1 wire format in Host Adoption Profile v1.

TransferSourceSnapshotIoResult deserialize_transfer_source_snapshot(std::span<const std::byte> bytes, TransferSourceSnapshot *out_snapshot, const TransferSourceSnapshotIoOptions &options = TransferSourceSnapshotIoOptions{}) noexcept

Parse a versioned target-neutral source snapshot.

Parsing is bounded by options and replaces out_snapshot only after the complete representation and every arena reference have been validated.

API Stability

Stable host-facing object API and v1 wire format in Host Adoption Profile v1.

PrepareTransferFileResult prepare_metadata_for_target_file(const char *path, const PrepareTransferFileOptions &options = PrepareTransferFileOptions{}) noexcept

High-level helper: read file, decode metadata, and prepare transfer bundle.

This helper is intended for thin wrappers (CLI/Python) that need read -> prepare with consistent resource policies.

TransferStatus build_prepared_c2pa_sign_request(const PreparedTransferBundle &bundle, PreparedTransferC2paSignRequest *out_request) noexcept

Derive an external signer request from a prepared C2PA rewrite bundle.

The returned request is preparation-only. It does not build a manifest or perform signing. For supported targets, it exposes the deterministic rewrite-without-C2PA byte sequence as preserved source ranges plus prepared target carrier chunks.

TransferStatus build_prepared_c2pa_handoff_package(const PreparedTransferBundle &bundle, std::span<const std::byte> target_input, PreparedTransferC2paHandoffPackage *out_package) noexcept

Build a structured external-signer handoff package.

This wraps build_prepared_c2pa_sign_request and build_prepared_c2pa_sign_request_binding into one reusable core result.

TransferStatus build_prepared_c2pa_signed_package(const PreparedTransferBundle &bundle, const PreparedTransferC2paSignerInput &input, PreparedTransferC2paSignedPackage *out_package) noexcept

Build a persistable signed-result package from a prepared bundle.

This wraps build_prepared_c2pa_sign_request and copies the external signer material into one reusable core object.

EmitTransferResult apply_prepared_c2pa_sign_result(PreparedTransferBundle *bundle, const PreparedTransferC2paSignRequest &request, const PreparedTransferC2paSignerInput &input) noexcept

Stage externally signed C2PA rewrite output into a prepared bundle.

This consumes the request built by build_prepared_c2pa_sign_request and replaces prepared target C2PA carrier blocks with the external signed logical payload. OpenMeta does not perform signing here; it only validates the input contract and re-packs the logical payload into the prepared target carrier.

EmitTransferResult apply_prepared_c2pa_signed_package(PreparedTransferBundle *bundle, const PreparedTransferC2paSignedPackage &package) noexcept

Stage one persisted signed C2PA package into a prepared bundle.

BuildPreparedC2paBindingResult build_prepared_c2pa_sign_request_binding(const PreparedTransferBundle &bundle, std::span<const std::byte> target_input, const PreparedTransferC2paSignRequest &request, std::vector<std::byte> *out_bytes) noexcept

Materialize the exact content-binding byte stream for a C2PA sign request.

This reconstructs the deterministic rewrite-without-C2PA byte sequence described by request by combining preserved source ranges from target_input with prepared target carrier chunks from bundle.

ValidatePreparedC2paSignResult validate_prepared_c2pa_sign_result(const PreparedTransferBundle &bundle, const PreparedTransferC2paSignRequest &request, const PreparedTransferC2paSignerInput &input) noexcept

Validate one externally signed C2PA payload before staging it.

This performs the same input and payload checks used by apply_prepared_c2pa_sign_result, but does not mutate bundle.

ValidatePreparedC2paSignResult validate_prepared_c2pa_signed_package(const PreparedTransferBundle &bundle, const PreparedTransferC2paSignedPackage &package) noexcept

Validate one persisted signed C2PA package before staging it.

PreparedTransferC2paPackageIoResult serialize_prepared_c2pa_handoff_package(const PreparedTransferC2paHandoffPackage &package, std::vector<std::byte> *out_bytes) noexcept

Serialize one C2PA handoff package into a stable binary transport.

PreparedTransferC2paPackageIoResult deserialize_prepared_c2pa_handoff_package(std::span<const std::byte> bytes, PreparedTransferC2paHandoffPackage *out_package) noexcept

Parse one serialized C2PA handoff package.

PreparedTransferC2paPackageIoResult serialize_prepared_c2pa_signed_package(const PreparedTransferC2paSignedPackage &package, std::vector<std::byte> *out_bytes) noexcept

Serialize one persisted signed C2PA package into a stable binary transport.

PreparedTransferC2paPackageIoResult deserialize_prepared_c2pa_signed_package(std::span<const std::byte> bytes, PreparedTransferC2paSignedPackage *out_package) noexcept

Parse one serialized signed C2PA package.

EmitTransferResult compile_prepared_transfer_execution(const PreparedTransferBundle &bundle, const EmitTransferOptions &options, PreparedTransferExecutionPlan *out_plan) noexcept

Compile a reusable execution plan for execute_prepared_transfer_compiled.

This performs route-to-backend compilation once and stores the selected emit options inside the plan for repeated runtime execution.

EmitTransferResult build_prepared_transfer_adapter_view(const PreparedTransferBundle &bundle, PreparedTransferAdapterView *out_view, const EmitTransferOptions &options = {}) noexcept

Build one target-neutral adapter view over prepared transfer ops.

This compiles the same target-specific route mappings used by emit execution, then flattens them into one explicit operation list for host integrations that want to consume prepared blocks without parsing routes.

API Stability

Experimental host-facing API.

EmitTransferResult validate_prepared_transfer_adapter_view(const PreparedTransferBundle &bundle, const PreparedTransferAdapterView &view) noexcept

Validate a codec-facing adapter view against its source bundle.

Validation rebuilds the canonical operation list and compares every kind-specific field, including marker/tag/box/chunk/BMFF identifiers. Hosts may use this as a preflight before handing operations to a codec.

API Stability

Experimental host-facing API. The typed operation schema is stable v1, but this validator remains coupled to the experimental prepared-bundle model.

EmitTransferResult get_prepared_transfer_adapter_exr_attribute_view(const PreparedTransferBundle &bundle, const PreparedTransferAdapterOp &op, ExrPreparedAttributeView *out_attribute) noexcept

Resolve one EXR adapter operation into typed insertion values.

The returned name, type, and value borrow storage from bundle and remain valid only while that bundle and its block payloads are unchanged. This avoids exposing the internal EXR route and payload framing to host codecs.

API Stability

Experimental host-facing API. The returned typed fields follow the stable v1 adapter schema, but resolution remains coupled to the prepared-bundle model.

EmitTransferResult emit_prepared_transfer_adapter_view(const PreparedTransferBundle &bundle, const PreparedTransferAdapterView &view, TransferAdapterSink &sink) noexcept

Emit one prepared adapter view into a generic host-side sink.

This lets host integrations consume the flattened adapter operation list without re-parsing routes or target-specific dispatch tokens.

API Stability

Experimental host-facing API.

ApplyTimePatchResult apply_time_patches(PreparedTransferBundle *bundle, std::span<const TimePatchUpdate> updates, const ApplyTimePatchOptions &options = ApplyTimePatchOptions{}) noexcept

Apply fixed-width time patch updates in-place on a prepared bundle.

Patches are applied to byte ranges listed in bundle.time_patch_map (typically filled for EXIF APP1 during prepare).

ApplyTimePatchResult apply_time_patches_view(PreparedTransferBundle *bundle, std::span<const TimePatchView> updates, const ApplyTimePatchOptions &options = ApplyTimePatchOptions{}) noexcept

Apply fixed-width time patch views in-place on a prepared bundle.

This overload avoids owned patch buffers and is intended for high-throughput prepare once -> compile once -> patch/emit many integrations.

ExecutePreparedTransferResult execute_prepared_transfer(PreparedTransferBundle *bundle, std::span<const std::byte> edit_input = {}, const ExecutePreparedTransferOptions &options = ExecutePreparedTransferOptions{}) noexcept

Execute the high-level transfer flow on a prepared bundle.

This helper applies optional time patches, compiles/emits prepared blocks, and optionally plans/applies a target-stream edit using edit_input. It is intended for thin wrappers and high-throughput “prepare once, reuse” integrations.

ExecutePreparedTransferResult execute_prepared_transfer_compiled(PreparedTransferBundle *bundle, const PreparedTransferExecutionPlan &plan, std::span<const std::byte> edit_input = {}, const ExecutePreparedTransferOptions &options = ExecutePreparedTransferOptions{}) noexcept

Execute the transfer flow using a precompiled execution plan.

This is intended for high-throughput integrations that want prepare once -> compile once -> patch/emit many.

ExecutePreparedTransferResult write_prepared_transfer_compiled(PreparedTransferBundle *bundle, const PreparedTransferExecutionPlan &plan, TransferByteWriter &writer, std::span<const TimePatchView> time_patches = {}, const ApplyTimePatchOptions &time_patch = ApplyTimePatchOptions{}, uint32_t emit_repeat = 1U) noexcept

Hot-path helper: apply non-owning time patches and stream emit bytes.

This is a thin encoder-integration helper for prepare once -> compile once -> patch -> write workflows. It reuses execute_prepared_transfer_compiled for plan validation and emission, but accepts non-owning patch views to avoid per-call owned patch buffers.

ExecutePreparedTransferResult emit_prepared_transfer_compiled(PreparedTransferBundle *bundle, const PreparedTransferExecutionPlan &plan, JpegTransferEmitter &emitter, std::span<const TimePatchView> time_patches = {}, const ApplyTimePatchOptions &time_patch = ApplyTimePatchOptions{}, uint32_t emit_repeat = 1U) noexcept

Hot-path helper: apply non-owning time patches and emit through a JPEG backend.

This is the direct backend-emitter path for prepare once -> compile once -> patch -> emit integrations that already own a JPEG encoder/backend.

ExecutePreparedTransferResult emit_prepared_transfer_compiled(PreparedTransferBundle *bundle, const PreparedTransferExecutionPlan &plan, TiffTransferEmitter &emitter, std::span<const TimePatchView> time_patches = {}, const ApplyTimePatchOptions &time_patch = ApplyTimePatchOptions{}, uint32_t emit_repeat = 1U) noexcept

Hot-path helper: apply non-owning time patches and emit through a TIFF backend.

TIFF intentionally uses backend-emitter or rewrite/edit paths instead of a metadata-only byte-writer emit contract.

ExecutePreparedTransferResult emit_prepared_transfer_compiled(PreparedTransferBundle *bundle, const PreparedTransferExecutionPlan &plan, JxlTransferEmitter &emitter, std::span<const TimePatchView> time_patches = {}, const ApplyTimePatchOptions &time_patch = ApplyTimePatchOptions{}, uint32_t emit_repeat = 1U) noexcept

Hot-path helper: apply non-owning time patches and emit through a JPEG XL backend.

ExecutePreparedTransferResult emit_prepared_transfer_compiled(PreparedTransferBundle *bundle, const PreparedTransferExecutionPlan &plan, WebpTransferEmitter &emitter, std::span<const TimePatchView> time_patches = {}, const ApplyTimePatchOptions &time_patch = ApplyTimePatchOptions{}, uint32_t emit_repeat = 1U) noexcept

Hot-path helper: apply non-owning time patches and emit through a WebP backend.

ExecutePreparedTransferResult emit_prepared_transfer_compiled(PreparedTransferBundle *bundle, const PreparedTransferExecutionPlan &plan, PngTransferEmitter &emitter, std::span<const TimePatchView> time_patches = {}, const ApplyTimePatchOptions &time_patch = ApplyTimePatchOptions{}, uint32_t emit_repeat = 1U) noexcept

Hot-path helper: apply non-owning time patches and emit through a PNG backend.

ExecutePreparedTransferResult emit_prepared_transfer_compiled(PreparedTransferBundle *bundle, const PreparedTransferExecutionPlan &plan, Jp2TransferEmitter &emitter, std::span<const TimePatchView> time_patches = {}, const ApplyTimePatchOptions &time_patch = ApplyTimePatchOptions{}, uint32_t emit_repeat = 1U) noexcept

Hot-path helper: apply non-owning time patches and emit through a JP2 backend.

ExecutePreparedTransferResult emit_prepared_transfer_compiled(PreparedTransferBundle *bundle, const PreparedTransferExecutionPlan &plan, ExrTransferEmitter &emitter, std::span<const TimePatchView> time_patches = {}, const ApplyTimePatchOptions &time_patch = ApplyTimePatchOptions{}, uint32_t emit_repeat = 1U) noexcept

Hot-path helper: apply non-owning time patches and emit through an EXR backend.

ExecutePreparedTransferResult emit_prepared_transfer_compiled(PreparedTransferBundle *bundle, const PreparedTransferExecutionPlan &plan, BmffTransferEmitter &emitter, std::span<const TimePatchView> time_patches = {}, const ApplyTimePatchOptions &time_patch = ApplyTimePatchOptions{}, uint32_t emit_repeat = 1U) noexcept

Hot-path helper: apply non-owning time patches and emit through an ISO-BMFF metadata backend.

ExecutePreparedTransferFileResult execute_prepared_transfer_file(const char *path, const ExecutePreparedTransferFileOptions &options = ExecutePreparedTransferFileOptions{}) noexcept

High-level helper: read file, prepare a bundle, then execute transfer.

This wraps prepare_metadata_for_target_file plus execute_prepared_transfer for CLI/Python entry points that want a single file-based execution path.

ExecutePreparedTransferFileResult execute_prepared_transfer_snapshot(const TransferSourceSnapshot &snapshot, const ExecutePreparedTransferSnapshotOptions &options = ExecutePreparedTransferSnapshotOptions{}) noexcept

High-level helper: prepare from a decoded source snapshot, then execute transfer.

This mirrors execute_prepared_transfer_file for hosts that already keep a reusable decoded source snapshot from an earlier read.

The input snapshot is not mutated. The helper copies the decoded store into a fresh local bundle-preparation state, so the same snapshot can be reused safely by concurrent callers that do not share the returned result object.

Current snapshot contract is decoded-store-backed. Raw carrier provenance and payload bytes are preserved only when read options request them; transfer execution still uses decoded re-emission.

API Stability

Experimental host-facing API.

ExecutePreparedTransferFileResult execute_prepared_transfer_snapshot(const TransferSourceSnapshot &snapshot, std::span<const std::byte> target_bytes, const ExecutePreparedTransferSnapshotOptions &options = ExecutePreparedTransferSnapshotOptions{}) noexcept

High-level helper: prepare from a decoded source snapshot, then edit a host-owned target byte buffer.

This is the fileless destination counterpart to execute_prepared_transfer_snapshot for hosts that already own the target bytes in memory and do not want OpenMeta to reopen the destination file.

The input snapshot and target byte span are not mutated. The helper copies decoded source state into a fresh local preparation store before executing the edit path.

API Stability

Experimental host-facing API.

ExecutePreparedTransferFileResult execute_prepared_transfer_bundle(const PreparedTransferBundle &bundle, std::span<const std::byte> target_bytes, const ExecutePreparedTransferBundleOptions &options = ExecutePreparedTransferBundleOptions{}) noexcept

High-level helper: execute a previously prepared bundle against host-owned target bytes.

This wraps execute_prepared_transfer with the same bounded sidecar and cleanup contract used by the file/snapshot helpers, but it starts from an already prepared bundle instead of rebuilding source state first.

API Stability

Experimental host-facing API. Treat the bundle as an immutable prepared input unless using documented patch helpers.

JpegEditPlan plan_prepared_bundle_jpeg_edit(std::span<const std::byte> input_jpeg, const PreparedTransferBundle &bundle, const PlanJpegEditOptions &options = PlanJpegEditOptions{}) noexcept

Plan JPEG metadata injection/edit strategy for a prepared bundle.

Auto selects InPlace when all emitted payloads can replace existing leading JPEG metadata segments with exact size match; otherwise it selects MetadataRewrite.

EmitTransferResult apply_prepared_bundle_jpeg_edit(std::span<const std::byte> input_jpeg, const PreparedTransferBundle &bundle, const JpegEditPlan &plan, std::vector<std::byte> *out_jpeg) noexcept

Apply a planned JPEG metadata edit and produce edited output bytes.

For InPlace, this replaces matched existing segment payload bytes in a copy of the input stream. For MetadataRewrite, this rewrites leading metadata segments and preserves the remaining codestream bytes unchanged.

EmitTransferResult write_prepared_bundle_jpeg_edit(std::span<const std::byte> input_jpeg, const PreparedTransferBundle &bundle, const JpegEditPlan &plan, TransferByteWriter &writer) noexcept

Apply a planned JPEG metadata edit and stream output bytes to a writer.

TiffEditPlan plan_prepared_bundle_tiff_edit(std::span<const std::byte> input_tiff, const PreparedTransferBundle &bundle, const PlanTiffEditOptions &options = PlanTiffEditOptions{}) noexcept

Plan TIFF metadata rewrite for a prepared bundle.

This computes the expected output size and validates that TIFF-applicable prepared blocks can be materialized on the target stream.

EmitTransferResult apply_prepared_bundle_tiff_edit(std::span<const std::byte> input_tiff, const PreparedTransferBundle &bundle, const TiffEditPlan &plan, std::vector<std::byte> *out_tiff) noexcept

Apply a planned TIFF metadata rewrite and produce edited output bytes.

EmitTransferResult write_prepared_bundle_tiff_edit(std::span<const std::byte> input_tiff, const PreparedTransferBundle &bundle, const TiffEditPlan &plan, TransferByteWriter &writer) noexcept

Apply a planned TIFF metadata rewrite and stream output bytes to a writer.

Current implementation uses the same rewrite path as apply_prepared_bundle_tiff_edit and then writes the final bytes to the supplied sink.

EmitTransferResult build_prepared_transfer_emit_package(const PreparedTransferBundle &bundle, PreparedTransferPackagePlan *out_plan, const EmitTransferOptions &options = {}) noexcept

Build one deterministic direct-emit package plan for a prepared bundle.

Current implementation supports direct JPEG marker, JXL/WebP/PNG/JP2 carrier, and BMFF item/property payload packaging without requiring an input container byte stream.

EmitTransferResult build_prepared_bundle_jpeg_package(std::span<const std::byte> input_jpeg, const PreparedTransferBundle &bundle, const JpegEditPlan &plan, PreparedTransferPackagePlan *out_plan) noexcept
EmitTransferResult build_prepared_bundle_tiff_package(std::span<const std::byte> input_tiff, const PreparedTransferBundle &bundle, const TiffEditPlan &plan, PreparedTransferPackagePlan *out_plan) noexcept
EmitTransferResult write_prepared_transfer_package(std::span<const std::byte> input, const PreparedTransferBundle &bundle, const PreparedTransferPackagePlan &plan, TransferByteWriter &writer) noexcept
EmitTransferResult build_prepared_transfer_package_batch(std::span<const std::byte> input, const PreparedTransferBundle &bundle, const PreparedTransferPackagePlan &plan, PreparedTransferPackageBatch *out_batch) noexcept
EmitTransferResult write_prepared_transfer_package_batch(const PreparedTransferPackageBatch &batch, TransferByteWriter &writer) noexcept
TransferSemanticKind classify_transfer_route_semantic_kind(std::string_view route) noexcept

Classifies one prepared transfer route into a target-neutral semantic kind.

std::string_view transfer_semantic_name(TransferSemanticKind kind) noexcept

Stable display name for one semantic transfer kind.

std::string_view prepared_transfer_artifact_kind_name(PreparedTransferArtifactKind kind) noexcept

Stable display name for one persisted transfer artifact kind.

EmitTransferResult collect_prepared_transfer_payload_views(const PreparedTransferBundle &bundle, std::vector<PreparedTransferPayloadView> *out, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Builds zero-copy semantic payload views over one prepared transfer bundle.

EmitTransferResult collect_prepared_transfer_payload_views(const PreparedTransferPayloadBatch &batch, std::vector<PreparedTransferPayloadView> *out) noexcept

Builds zero-copy semantic payload views over one persisted payload batch.

EmitTransferResult build_prepared_transfer_payload_batch(const PreparedTransferBundle &bundle, PreparedTransferPayloadBatch *out, const EmitTransferOptions &options = EmitTransferOptions{}) noexcept

Builds one owned semantic payload batch from one prepared transfer bundle.

PreparedTransferPayloadIoResult serialize_prepared_transfer_payload_batch(const PreparedTransferPayloadBatch &batch, std::vector<std::byte> *out_bytes) noexcept
PreparedTransferArtifactIoResult inspect_prepared_transfer_artifact(std::span<const std::byte> bytes, PreparedTransferArtifactInfo *out_info) noexcept
PreparedTransferPayloadIoResult deserialize_prepared_transfer_payload_batch(std::span<const std::byte> bytes, PreparedTransferPayloadBatch *out_batch) noexcept
PreparedTransferPayloadReplayResult replay_prepared_transfer_payload_batch(const PreparedTransferPayloadBatch &batch, const PreparedTransferPayloadReplayCallbacks &callbacks) noexcept
EmitTransferResult collect_prepared_transfer_package_views(const PreparedTransferPackageBatch &batch, std::vector<PreparedTransferPackageView> *out) noexcept

Builds zero-copy semantic package views over one persisted package batch.

PreparedTransferPackageReplayResult replay_prepared_transfer_package_batch(const PreparedTransferPackageBatch &batch, const PreparedTransferPackageReplayCallbacks &callbacks) noexcept
PreparedTransferPackageIoResult serialize_prepared_transfer_package_batch(const PreparedTransferPackageBatch &batch, std::vector<std::byte> *out_bytes) noexcept
PreparedTransferPackageIoResult deserialize_prepared_transfer_package_batch(std::span<const std::byte> bytes, PreparedTransferPackageBatch *out_batch) noexcept
void build_ocio_metadata_tree(const MetaStore &store, OcioMetadataNode *root, const OcioAdapterOptions &options) noexcept

Builds a deterministic metadata tree for OCIO-style consumers.

Mapping rules:

  • Item names with a prefix:name form become namespace nodes (prefix) with leaf children (name=value).

  • Other names are added as direct leaves under the root.

InteropSafetyStatus build_ocio_metadata_tree_safe(const MetaStore &store, OcioMetadataNode *root, const OcioAdapterOptions &options, InteropSafetyError *error) noexcept

Strict safe export for OCIO-style metadata tree.

Unlike build_ocio_metadata_tree, this API fails when unsafe payloads are encountered (for example raw bytes or invalid/unsafe text sequences).

OcioAdapterOptions make_ocio_adapter_options(const OcioAdapterRequest &request) noexcept

Converts OcioAdapterRequest into OcioAdapterOptions.

void build_ocio_metadata_tree(const MetaStore &store, OcioMetadataNode *root, const OcioAdapterRequest &request) noexcept

Builds metadata tree via the stable request model.

InteropSafetyStatus build_ocio_metadata_tree_safe(const MetaStore &store, OcioMetadataNode *root, const OcioAdapterRequest &request, InteropSafetyError *error) noexcept

Request-based strict safe export for OCIO-style metadata tree.

bool exif_orientation_is_valid(uint16_t orientation) noexcept
bool exif_orientation_is_mirrored(uint16_t orientation) noexcept
bool exif_orientation_swaps_width_height(uint16_t orientation) noexcept
uint16_t exif_orientation_rotation_degrees_cw(uint16_t orientation, bool *out_valid = nullptr) noexcept

Returns the clockwise rotation component for a standard EXIF/TIFF orientation value.

Mirrored values keep the same decomposition used by common metadata tools. For example, orientation 5 reports mirror + 270 degrees clockwise. Invalid values return 0 and set out_valid to false when provided.

uint16_t exif_orientation_rotation_only(uint16_t orientation) noexcept

Returns the nearest rotation-only orientation.

Valid non-mirrored values are returned unchanged. Mirrored values are mapped to the closest non-mirrored rotation: 2 -> 1, 4 -> 3, 5 -> 8, 7 -> 6. Invalid values return 0.

const char *exif_orientation_name(uint16_t orientation) noexcept
ExifOrientationInterpretation interpret_exif_orientation(uint16_t orientation) noexcept
PhaseOneRawGeometryResult phaseone_raw_geometry_from_values(uint32_t sensor_width, uint32_t sensor_height, uint32_t sensor_left_margin, uint32_t sensor_top_margin, uint32_t image_width, uint32_t image_height) noexcept
PhaseOneRawGeometryResult phaseone_raw_geometry_from_store(const MetaStore &store) noexcept
PhaseOneRawProcessingResult phaseone_raw_processing_from_store(const MetaStore &store) noexcept
const char *phaseone_raw_geometry_status_name(PhaseOneRawGeometryStatus status) noexcept
const char *phaseone_raw_processing_status_name(PhaseOneRawProcessingStatus status) noexcept
PhotoshopIrbDecodeResult decode_photoshop_irb(std::span<const std::byte> irb_bytes, MetaStore &store, const PhotoshopIrbDecodeOptions &options = PhotoshopIrbDecodeOptions{}) noexcept

Decodes a Photoshop IRB stream and appends resources into store.

Each resource becomes one Entry with:

A bounded interpreted subset is additionally emitted as MetaKeyKind::PhotoshopIrbField entries for fixed-layout and descriptor-header resources:

  • ResolutionInfo (0x03ED)

  • AlphaChannelsNames (0x03EE)

  • DisplayInfo (0x03EF)

  • PStringCaption (0x03F0)

  • BorderInformation (0x03F1)

  • BackgroundColor (0x03F2)

  • VersionInfo (0x0421)

  • PrintFlags (0x03F3)

  • EffectiveBW (0x03FB)

  • QuickMaskInfo (0x03FE)

  • TargetLayerID (0x0400)

  • LayersGroupInfo (0x0402)

  • JPEG_Quality (0x0406)

  • GridGuidesInfo (0x0408)

  • PhotoshopBGRThumbnail / PhotoshopThumbnail header fields (0x0409/0x040C)

  • CopyrightFlag (0x040A)

  • URL (0x040B)

  • GlobalAngle (0x040D)

  • ColorSamplersResource / ColorSamplersResource2 headers and records (0x040E/0x0431)

  • Watermark (0x0410)

  • ICC_Untagged (0x0411)

  • EffectsVisible (0x0412)

  • IDsBaseValue (0x0414)

  • UnicodeAlphaNames (0x0415)

  • IndexedColorTableCount (0x0416)

  • TransparentIndex (0x0417)

  • GlobalAltitude (0x0419)

  • SliceInfo (0x041A)

  • WorkflowURL (0x041B)

  • AlphaIdentifiers (0x041D)

  • URL_List (0x041E)

  • ICC_Profile byte count (0x040F)

  • EXIFInfo byte count (0x0422)

  • ExifInfo2 byte count (0x0423)

  • XMP byte count (0x0424)

  • IPTCDigest (0x0425)

  • PrintScaleInfo (0x0426)

  • PixelInfo / PixelAspectRatio (0x0428)

  • Descriptor-backed resource headers for LayerComps, MeasurementScale, TimelineInfo, SheetDisclosure, OnionSkins, CountInfo, PrintInfo2, PrintStyle, PathSelectionState, and OriginPathInfo

  • LayerSelectionIDs (0x042D)

  • LayerGroupsEnabledID (0x0430)

  • ChannelOptions (0x0435)

  • PrintFlagsInfo (0x2710)

  • ClippingPathName (0x0BB7)

If enabled, embedded IPTC-IIM, XMP, and ICC payloads are additionally decoded from resource ids 0x0404, 0x0424, and 0x040F into their regular OpenMeta entry families. IPTC-IIM and XMP entries are marked as EntryFlags::Derived.

PhotoshopIrbDecodeResult measure_photoshop_irb(std::span<const std::byte> irb_bytes, const PhotoshopIrbDecodeOptions &options = PhotoshopIrbDecodeOptions{}) noexcept

Estimates Photoshop IRB decode counts using the same limits/options.

std::string_view photoshop_irb_resource_name(uint16_t resource_id) noexcept
PreviewScanResult find_preview_candidates(std::span<const std::byte> file_bytes, std::span<const ContainerBlockRef> blocks, std::span<PreviewCandidate> out, const PreviewScanOptions &options) noexcept

Finds preview candidates from already scanned blocks.

This function currently analyzes EXIF/TIFF blocks and discovers:

  • JPEGInterchangeFormat/JPEGInterchangeFormatLength pairs

  • JpgFromRaw and JpgFromRaw2 byte blobs

  • Canon CR3 PRVW UUID stream preview JPEGs

Candidates are file-relative (file_offset + size) and can be copied with extract_preview_candidate.

PreviewScanResult scan_preview_candidates(std::span<const std::byte> file_bytes, std::span<ContainerBlockRef> blocks_scratch, std::span<PreviewCandidate> out, const PreviewScanOptions &options) noexcept

Convenience wrapper that runs scan_auto first, then find_preview_candidates.

PreviewExtractResult extract_preview_candidate(std::span<const std::byte> file_bytes, const PreviewCandidate &candidate, std::span<std::byte> out, const PreviewExtractOptions &options) noexcept

Extracts bytes for one preview candidate into out.

PrintImDecodeResult decode_printim(std::span<const std::byte> bytes, MetaStore &store, const PrintImDecodeLimits &limits) noexcept

Decodes a PrintIM block and appends fields into store.

On success, this creates a new block in store containing MetaKeyKind::PrintImField entries. The original EXIF tag should still be preserved separately by the EXIF/TIFF decoder.

Field naming:

  • version for the header version (ASCII, 4 bytes)

  • 0xNNNN for each 16-bit entry id

RandomAccessSource make_memory_random_access_source(std::span<const std::byte> bytes) noexcept

Creates a non-owning source descriptor for caller-owned contiguous bytes.

RandomAccessSource make_callback_random_access_source(uint64_t size, void *context, RandomAccessReadAt read_at, bool concurrent_reads = false) noexcept

Creates a source descriptor for a caller-owned positional read callback.

bool random_access_source_valid(const RandomAccessSource &source) noexcept

Validates backing-selection and representability invariants.

RandomAccessSourceRange make_random_access_source_range(const RandomAccessSource &source) noexcept

Creates a range covering one complete source descriptor.

RandomAccessSourceRange make_random_access_source_range(const RandomAccessSource &source, uint64_t source_offset, uint64_t size) noexcept

Creates a source-relative range without touching the backing storage.

bool random_access_source_range_valid(const RandomAccessSourceRange &range) noexcept

Validates the source and range bounds.

RandomAccessReadCode random_access_read_exact(const RandomAccessSource &source, uint64_t offset, std::span<std::byte> destination, RandomAccessReadState *state, const RandomAccessReadLimits &limits = RandomAccessReadLimits{}) noexcept

Performs one exact, synchronous, range-checked source read.

Limits are checked before touching the source. Request counters account for issued memory copies and callback calls. The function performs no allocation and does not retry a short read, because retry semantics belong to the host source implementation.

API Stability

Stable host-facing v1 API in Host Adoption Profile v1.

RandomAccessReadCode random_access_read_exact(const RandomAccessSourceRange &range, uint64_t offset, std::span<std::byte> destination, RandomAccessReadState *state, const RandomAccessReadLimits &limits = RandomAccessReadLimits{}) noexcept

Exact-read overload using an offset relative to a validated source range.

RandomAccessViewResult random_access_read_view(const RandomAccessSourceRange &range, uint64_t offset, uint64_t size, RandomAccessReadWindow *window, RandomAccessReadState *state, const RandomAccessReadLimits &limits = RandomAccessReadLimits{}, const RandomAccessReadWindowOptions &options = RandomAccessReadWindowOptions{}) noexcept

Returns a bounded source view using direct memory or a caller window.

Contiguous sources return a direct borrowed span and do not consume callback I/O counters. Callback sources reuse or refill window. A callback-backed result remains valid only until the next window refill or caller mutation of the window storage.

inline void normalize_resource_policy(OpenMetaResourcePolicy *policy) noexcept

Normalizes traversal/recursion-related limits to safe defaults.

OpenMeta design goal: recursion/traversal limits should never become “unlimited” through a zero value in user policy. This helper keeps decode paths bounded for untrusted metadata.

inline OpenMetaResourcePolicy recommended_resource_policy() noexcept
inline void apply_resource_policy(const OpenMetaResourcePolicy &policy, ExifDecodeOptions *exif, PayloadOptions *payload) noexcept
inline void apply_resource_policy(const OpenMetaResourcePolicy &policy, XmpDecodeOptions *xmp, ExrDecodeOptions *exr, JumbfDecodeOptions *jumbf, IccDecodeOptions *icc, IptcIimDecodeOptions *iptc, PhotoshopIrbDecodeOptions *irb) noexcept
inline void apply_resource_policy(const OpenMetaResourcePolicy &policy, XmpDecodeOptions *xmp, ExrDecodeOptions *exr, IccDecodeOptions *icc, IptcIimDecodeOptions *iptc, PhotoshopIrbDecodeOptions *irb) noexcept
inline void apply_resource_policy(const OpenMetaResourcePolicy &policy, PreviewScanOptions *scan, PreviewExtractOptions *extract) noexcept
inline void apply_resource_policy(const OpenMetaResourcePolicy &policy, XmpSidecarRequest *request) noexcept
SimpleMetaResult simple_meta_read(std::span<const std::byte> file_bytes, MetaStore &store, std::span<ContainerBlockRef> out_blocks, std::span<ExifIfdRef> out_ifds, std::span<std::byte> payload, std::span<uint32_t> payload_scratch_indices, const SimpleMetaDecodeOptions &options) noexcept

Scans a file container and decodes supported metadata payloads.

Current decode support:

Caller provides the scratch buffers (blocks + decoded IFD list) to keep the data flow explicit and allocation-free.

Parameters:
  • file_bytes – Full file bytes in memory.

  • store – Destination MetaStore (entries are appended).

  • out_blocks – Scratch buffer for block scanning results.

  • out_ifds – Scratch buffer for decoded IFD references.

  • payload – Scratch buffer for reassembled EXIF payload bytes.

  • payload_scratch_indices – Scratch buffer for payload part indices.

  • options – Full decode option set (EXIF/payload/XMP/EXR/JUMBF/ICC/IPTC/IRB).

SimpleMetaResult simple_meta_read(std::span<const std::byte> file_bytes, MetaStore &store, std::span<ContainerBlockRef> out_blocks, std::span<ExifIfdRef> out_ifds, std::span<std::byte> payload, std::span<uint32_t> payload_scratch_indices, const ExifDecodeOptions &exif_options, const PayloadOptions &payload_options) noexcept

Backward-compatible overload using EXIF and payload options only.

ValidateResult validate_file(const char *path, const ValidateOptions &options = ValidateOptions{}) noexcept

Validate one file using normal OpenMeta decode + CCM checks.

Validation covers:

  • decoder status health (scan/payload/exif/xmp/exr/jumbf/c2pa)

  • optional sidecar XMP read status (--xmp-sidecar equivalent)

  • DNG/CCM query/validation issues (collect_dng_ccm_fields)

VendorRawProcessingGroup classify_vendor_raw_processing_field(std::string_view ifd, std::string_view name, uint16_t tag) noexcept
VendorRawProcessingSummary vendor_raw_processing_from_store(const MetaStore &store, VendorRawProcessingFamily family) noexcept
bool vendor_raw_processing_group_has(VendorRawProcessingGroup groups, VendorRawProcessingGroup group) noexcept
const char *vendor_raw_processing_family_name(VendorRawProcessingFamily family) noexcept
const char *vendor_raw_processing_group_name(VendorRawProcessingGroup group) noexcept
XmpDecodeResult decode_xmp_packet(std::span<const std::byte> xmp_bytes, MetaStore &store, EntryFlags flags = EntryFlags::None, const XmpDecodeOptions &options = XmpDecodeOptions{}) noexcept

Decodes an XMP packet and appends properties into store.

The decoder emits one Entry per decoded property value with:

Duplicate properties are preserved.

XmpDecodeResult measure_xmp_packet(std::span<const std::byte> xmp_bytes, const XmpDecodeOptions &options = XmpDecodeOptions{}) noexcept

Estimates XMP decode counts using the same limits/options.

This function performs a bounded decode pass into an internal scratch store and returns the same status/counter model as decode_xmp_packet.

XmpDumpResult dump_xmp_lossless(const MetaStore &store, std::span<std::byte> out, const XmpDumpOptions &options) noexcept

Emits a lossless OpenMeta dump as a valid XMP RDF/XML packet.

The output is safe-by-default:

  • Text fields are XML-escaped and additionally restricted to a safe ASCII subset.

  • Binary payloads (bytes/text/arrays/scalars) are stored as base64.

This dump is intended as a storage-agnostic sidecar format for debugging and offline workflows. It uses a private namespace (urn:openmeta:dump:1.0) and is not meant to replace standard, interoperable XMP mappings.

XmpDumpResult dump_xmp_portable(const MetaStore &store, std::span<std::byte> out, const XmpPortableOptions &options) noexcept

Emits a portable XMP sidecar packet (standard XMP schemas).

The output is safe-by-default:

  • XML reserved characters are escaped.

  • Invalid control bytes are emitted as deterministic ASCII escapes.

This mode is intended for interoperability (e.g. XMP sidecars alongside RAW/JPEG files). It emits a best-effort mapping from decoded EXIF/TIFF/GPS/IPTC-IIM fields to standard XMP properties (e.g. tiff:Make, exif:ExposureTime, xmp:ModifyDate, xmp:CreateDate, exif:GPSLatitude, dc:subject, photoshop:City, Iptc4xmpCore:Location).

XmpDumpResult dump_xmp_sidecar(const MetaStore &store, std::vector<std::byte> *out, const XmpSidecarOptions &options) noexcept

Emits an XMP sidecar into a resizable byte buffer.

This is a high-level wrapper around dump_xmp_lossless and dump_xmp_portable that:

XmpSidecarOptions make_xmp_sidecar_options(const XmpSidecarRequest &request) noexcept

Converts XmpSidecarRequest into XmpSidecarOptions.

Useful for wrappers and adapters that expose one flattened option model.

XmpDumpResult dump_xmp_sidecar(const MetaStore &store, std::vector<std::byte> *out, const XmpSidecarRequest &request) noexcept

Emits an XMP sidecar using the stable XmpSidecarRequest model.

Variables

constexpr uint32_t kCompatibilityDumpContractVersion = 1U

Stable compatibility dump contract version.

constexpr uint32_t kExrCanonicalEncodingVersion = 1U

Stable EXR canonical value encoding contract version.

constexpr uint32_t kHostAdoptionProfileContractVersion = 1U

Stable high-performance host adoption profile version.

constexpr HostAdoptionProfile kHostAdoptionProfileV1 = {}

Compile-time descriptor for Host Adoption Profile v1.

constexpr uint32_t kInteropExportContractVersion = 1U

Stable interop export naming contract version.

constexpr uint32_t kFlatHostExportContractVersion = 1U

Stable FlatHost naming contract version.

constexpr uint32_t kFlatHostImportContractVersion = 1U

Stable typed FlatHost import and reconciliation contract version.

static constexpr BlockId kInvalidBlockId = 0xffffffffU
static constexpr EntryId kInvalidEntryId = 0xffffffffU
constexpr uint32_t kMetadataCapabilitiesContractVersion = 1U

Stable metadata capability contract version.

constexpr uint32_t kMetadataCreationContractVersion = 1U

Stable metadata creation contract version.

constexpr uint32_t kMetadataCreationMaxFields = 1024U
constexpr uint32_t kMetadataCreationMaxTextBytesPerField = 1024U * 1024U
constexpr uint64_t kMetadataCreationMaxTotalTextBytes = 8ULL * 1024ULL * 1024ULL
constexpr uint32_t kInvalidMetadataCreationFieldIndex = 0xffffffffU
constexpr uint32_t kMetadataEditingContractVersion = 1U

Stable high-level metadata editing contract version.

constexpr uint32_t kMetadataEditingMaxOperations = 1024U
constexpr uint32_t kMetadataEditingMaxTextBytesPerOperation = 1024U * 1024U
constexpr uint64_t kMetadataEditingMaxTotalTextBytes = 8ULL * 1024ULL * 1024ULL
constexpr uint32_t kMetadataEditingAllOccurrences = 0xffffffffU
constexpr uint32_t kInvalidMetadataEditingOperationIndex = 0xffffffffU
static constexpr uint32_t kMetadataFuzzySearchMaxResults = 256U
static constexpr uint32_t kMetadataFuzzySearchMaxQueryBytes = 256U
static constexpr uint32_t kMetadataFuzzySearchMaxCandidateBytes = 1024U
constexpr uint32_t kMetadataTransferContractVersion = 1U

Stable metadata transfer contract version.

constexpr uint32_t kPreparedTransferAdapterContractVersion = 1U

Version of the codec-facing typed adapter operation contract.

constexpr uint32_t kTransferSourceSnapshotSerializationVersion = 1U

Version of the persisted target-neutral source snapshot wire format.

constexpr uint32_t kReadTransferSourceSnapshotContractVersion = 1U

Stable positional source snapshot contract version.

constexpr uint32_t kTransferSourceSnapshotContractVersion = 1U

Stable decoded source snapshot object contract version.

constexpr uint32_t kReadTransferSourceDiagnosticsContractVersion = 1U

Stable positional snapshot diagnostic contract version.

constexpr uint16_t kTransferTargetImageSpecMaxSamples = 8U

Maximum channel/sample count represented by TransferTargetImageSpec.

constexpr uint32_t kRandomAccessSourceContractVersion = 1U

Stable allocation-free positional source contract version.

file api_stability.md
file compatibility_dump.md
file creation.md
file exr_canonical_value_encoding.md
file development.md
file doxygen.md
file editing.md
file flat_host_mapping.md
file fuzzy_search.md
file host_adoption_profile.md
file host_integration.md
file interpretation_status.md
file metadata_backend_matrix.md
file metadata_support.md
file metadata_transfer_plan.md
file quick_start.md
file random_access_input.md
file raw_read_parity_plan.md
file openexr_metadata_fit.md
file shared_library.md
file writer_target_contract.md
file xmp_sync_policy.md
file README.md
file api.h

Defines

OPENMETA_API
OPENMETA_PUBLIC_BEGIN
OPENMETA_PUBLIC_END
file build_info.h
#include “openmeta/api.h
#include <string>
#include <string_view>

Runtime information about how OpenMeta was built.

file byte_arena.h
#include “openmeta/api.h
#include <cstddef>
#include <cstdint>
#include <span>
#include <string_view>
#include <vector>

Append-only byte arena used to store metadata payloads and strings.

file ccm_query.h
#include “openmeta/api.h
#include “openmeta/meta_store.h
#include <cstdint>
#include <string>
#include <vector>

Query helpers for normalized DNG/RAW color matrix metadata.

file compatibility_dump.h
#include “openmeta/api.h
#include <cstdint>
#include <string>

Deterministic text dumps for host compatibility tests.

API Stability

Stable host-facing v1 dump contract.

file console_format.h
#include “openmeta/api.h
#include <cstddef>
#include <cstdint>
#include <span>
#include <string>
#include <string_view>
file container_payload.h
#include “openmeta/api.h
#include <cstddef>
#include <cstdint>
#include <span>

Reassembles and optionally decompresses logical metadata payloads.

file container_scan.h
#include “openmeta/api.h
#include <cstddef>
#include <cstdint>
#include <span>

Container scanners that locate metadata blocks within file bytes.

file dng_sdk_adapter.h
#include “openmeta/api.h
#include <cstdint>
#include <string>

Optional Adobe DNG SDK bridge for prepared OpenMeta DNG transfers.

file exif_tag_names.h
#include “openmeta/api.h
#include <cstdint>
#include <string_view>

Human-readable names for common EXIF/TIFF tags.

file exif_tiff_decode.h
#include “openmeta/api.h
#include “openmeta/meta_store.h
#include <cstddef>
#include <cstdint>
#include <span>
#include <string_view>

Decoder for TIFF-IFD tag streams (used by EXIF and TIFF/DNG).

file exif_value_names.h
#include “openmeta/api.h
#include <cstddef>
#include <cstdint>
#include <span>
#include <string_view>

Human-readable names for common EXIF/TIFF/DNG numeric values and selected bounded MakerNote contexts.

file exr_adapter.h
#include “openmeta/api.h
#include “openmeta/exr_decode.h
#include “openmeta/meta_store.h
#include <cstddef>
#include <cstdint>
#include <limits>
#include <string>
#include <vector>

EXR-native attribute bridge for OpenEXR-style host integrations.

file exr_decode.h
#include “openmeta/api.h
#include “openmeta/meta_store.h
#include <cstddef>
#include <cstdint>
#include <span>

Decoder for OpenEXR header attributes.

file geotiff_key_names.h
#include “openmeta/api.h
#include <cstdint>
#include <string_view>

GeoTIFF GeoKey name lookup.

file host_adoption.h
#include “openmeta/api.h
#include <cstdint>

Versioned compatibility profile for high-performance host integration.

file icc_decode.h
#include “openmeta/api.h
#include “openmeta/meta_store.h
#include <cstddef>
#include <cstdint>
#include <span>

Decoder for ICC profile blobs (header + tag table).

file icc_interpret.h
#include “openmeta/api.h
#include <cstddef>
#include <cstdint>
#include <span>
#include <string>
#include <string_view>
#include <vector>

Selected ICC tag-name and tag-payload interpretation helpers.

file interop_export.h
#include “openmeta/api.h
#include “openmeta/meta_store.h
#include <cstdint>
#include <string>
#include <string_view>

Metadata export traversal API for interop adapters.

file interop_import.h
#include “openmeta/api.h
#include “openmeta/meta_store.h
#include <cstddef>
#include <cstdint>
#include <span>
#include <string>
#include <string_view>

Bounded typed import from flat host metadata models.

file iptc_iim_decode.h
#include “openmeta/api.h
#include “openmeta/meta_store.h
#include <cstddef>
#include <cstdint>
#include <span>

Decoder for IPTC-IIM dataset streams.

file jumbf_decode.h
#include “openmeta/api.h
#include “openmeta/meta_store.h
#include <cstddef>
#include <cstdint>
#include <span>

Decoder for JUMBF/C2PA payload blocks.

file libraw_adapter.h
#include “openmeta/api.h
#include “openmeta/mapped_file.h
#include “openmeta/meta_store.h
#include “openmeta/simple_meta.h
#include <cstdint>

Explicit orientation bridge for LibRaw-facing host integrations.

file mapped_file.h
#include “openmeta/api.h
#include <cstddef>
#include <cstdint>
#include <span>

Read-only file mapping helper.

file meta_edit.h
#include “openmeta/api.h
#include “openmeta/meta_store.h
#include <span>
#include <vector>

Batch edit operations for MetaStore (append/set/tombstone).

file meta_flags.h
#include “openmeta/api.h
#include <cstdint>

Flags attached to metadata entries.

file meta_key.h
#include “openmeta/api.h
#include “openmeta/byte_arena.h
#include <cstdint>
#include <string_view>

Normalized key identifiers for EXIF/IPTC/XMP/etc. metadata entries.

file meta_store.h
#include “openmeta/api.h
#include “openmeta/byte_arena.h
#include “openmeta/meta_flags.h
#include “openmeta/meta_key.h
#include “openmeta/meta_value.h
#include <cstdint>
#include <span>
#include <vector>

In-memory representation of decoded metadata (keys/values + provenance).

file meta_value.h
#include “openmeta/api.h
#include “openmeta/byte_arena.h
#include <cstdint>
#include <span>
#include <string_view>

Typed metadata value representation (scalar/array/bytes/text).

file metadata_capabilities.h
#include “openmeta/api.h
#include <cstdint>

Runtime capability query API for host integrations.

API Stability

Stable host-facing v1 query contract.

file metadata_concepts.h
#include “openmeta/api.h
#include “openmeta/meta_store.h
#include <cstdint>
#include <string>
#include <vector>

Experimental cross-family metadata concept resolution.

file metadata_creation.h
#include “openmeta/api.h
#include “openmeta/meta_store.h
#include <cstdint>
#include <span>
#include <string_view>

Bounded construction of fresh portable metadata stores.

file metadata_editing.h
#include “openmeta/api.h
#include <cstdint>
#include <span>

Bounded transactional editing of canonical logical metadata fields.

file metadata_fuzzy_search.h
#include “openmeta/api.h
#include “openmeta/meta_key.h
#include “openmeta/meta_store.h
#include <cstdint>
#include <string>
#include <string_view>
#include <vector>

Optional bounded fuzzy search over metadata names and property paths.

file metadata_interpretation.h
#include “openmeta/api.h
#include “openmeta/meta_store.h
#include <cstdint>
#include <vector>

Structured metadata interpretation records built from semantic query candidates.

file metadata_query.h
#include “openmeta/api.h
#include “openmeta/meta_key.h
#include “openmeta/meta_store.h
#include <cstdint>
#include <string>
#include <vector>

Experimental semantic metadata query helpers.

file metadata_transfer.h
#include “openmeta/api.h
#include “openmeta/meta_store.h
#include “openmeta/simple_meta.h
#include “openmeta/xmp_dump.h
#include <array>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <span>
#include <string>
#include <string_view>
#include <vector>

Draft metadata transfer bundle and backend emitter contracts.

This header defines a stable draft contract for “prepare once, emit many” metadata transfer workflows.

file ocio_adapter.h
#include “openmeta/api.h
#include <cstdint>
#include <string>
#include <vector>

Adapter helpers for OCIO-style metadata trees.

file orientation.h
#include “openmeta/api.h
#include <cstdint>

Helpers for interpreting EXIF/TIFF orientation values.

file phaseone_geometry.h
#include “openmeta/api.h
#include “openmeta/meta_store.h
#include <cstdint>

Normalized helpers for Phase One/Leaf RAW sensor geometry and processing tags.

file photoshop_irb_decode.h
#include “openmeta/api.h
#include “openmeta/icc_decode.h
#include “openmeta/meta_store.h
#include “openmeta/xmp_decode.h
#include <cstddef>
#include <cstdint>
#include <span>
#include <string_view>

Decoder for Photoshop Image Resource Blocks (IRB / 8BIM resources).

file preview_extract.h
#include “openmeta/api.h
#include <cstddef>
#include <cstdint>
#include <span>

Read-only preview/thumbnail candidate discovery and extraction.

file printim_decode.h
#include “openmeta/api.h
#include “openmeta/meta_store.h
#include <cstddef>
#include <cstdint>
#include <span>

Decoder for the EXIF PrintIM (0xC4A5) embedded block.

file random_access_source.h
#include “openmeta/api.h
#include <cstddef>
#include <cstdint>
#include <span>

Allocation-free positional byte-source contract for bounded readers.

API Stability

Stable host-facing v1 API in Host Adoption Profile v1.

file resource_policy.h
#include “openmeta/api.h
#include “openmeta/exr_decode.h
#include “openmeta/icc_decode.h
#include “openmeta/jumbf_decode.h
#include “openmeta/xmp_decode.h
#include “openmeta/xmp_dump.h
#include <cstdint>

Draft resource-budget policy for OpenMeta read/dump workflows.

file simple_meta.h
#include “openmeta/api.h
#include “openmeta/exr_decode.h
#include “openmeta/icc_decode.h
#include “openmeta/jumbf_decode.h
#include “openmeta/meta_store.h
#include “openmeta/xmp_decode.h
#include <cstddef>
#include <span>

High-level “read” helper for scanning containers and decoding metadata.

file validate.h
#include “openmeta/api.h
#include “openmeta/ccm_query.h
#include “openmeta/jumbf_decode.h
#include “openmeta/simple_meta.h
#include <cstdint>
#include <string>
#include <vector>

High-level metadata validation API (decode health + DNG/CCM checks).

file vendor_raw_processing.h
#include “openmeta/api.h
#include “openmeta/meta_store.h
#include <cstdint>
#include <string_view>

Conservative vendor RAW-processing metadata classification helpers.

file xmp_decode.h
#include “openmeta/api.h
#include “openmeta/meta_store.h
#include <cstddef>
#include <cstdint>
#include <span>

Decoder for XMP packets (RDF/XML).

file xmp_dump.h
#include “openmeta/api.h
#include “openmeta/meta_store.h
#include <cstddef>
#include <cstdint>
#include <span>
#include <vector>

XMP sidecar generation for a decoded MetaStore.

page API Stability

This page defines the adoption status for public OpenMeta APIs. Python bindings mirror these labels unless a Python wrapper documents a different status.

Stability Levels

Level

Meaning

Stable

Intended for downstream use. Breaking changes require a new contract version, a compatibility path, or a documented migration.

Experimental

Public and tested, but the exact shape or semantics may still evolve while the surrounding workflow is being hardened.

Internal

Publicly visible only because it is part of a lower-level implementation surface. Do not build new downstream integrations on it unless another doc names it as supported.

Host-Facing API Map

API surface

Header

Stability

Notes

Host Adoption Profile v1: host_adoption_profile(), host_adoption_profile_matches(...)

openmeta/host_adoption.h

Stable

Exact compile-time/runtime contract descriptor for the narrow positional read, persistence, reconciliation, diagnostics, and typed codec-operation schema. See host_adoption_profile.md.

Runtime capability query: metadata_capability(...)

openmeta/metadata_capabilities.h

Stable

v1 query contract for read, structured decode, transfer preparation, target edit, and raw-preservation status by format/family.

Positional source, snapshot, and read diagnostics: RandomAccessSource, source ranges/read windows, random_access_read_exact(...), read_transfer_source_snapshot_random_access(...), and collect_read_transfer_source_diagnostics(...)

openmeta/random_access_source.h, openmeta/metadata_transfer.h

Stable v1

Allocation-free exact callback reads, caller-owned accounting/scratch, owned finalized snapshots, explicit completeness/residual semantics, and caller-buffered structured diagnostics. Format coverage may grow additively. See host_adoption_profile.md and random_access_input.md.

Low-level positional format decode, payload, and scan APIs: decode_exif_tiff_random_access(...), decode_exr_header_random_access(...), extract_payload_random_access(...), and the scan_*_random_access(...) family

openmeta/exif_tiff_decode.h, openmeta/exr_decode.h, openmeta/container_payload.h, openmeta/container_scan.h

Experimental

Format-specific structures and scratch requirements may still evolve. The stable top-level snapshot result exposes unsupported or incomplete lanes as explicit residuals.

Compatibility dumps: dump_metadata_compatibility(...), dump_transfer_compatibility(...)

openmeta/compatibility_dump.h

Stable

Stable v1 line-oriented compatibility dump contract, including generic BMFF component membership, role, relation-summary, policy, derived-image construction, and tiled-image configuration fields as normal bmff_field entries. See compatibility_dump.md.

XMP sync and writeback policy enums: XmpConflictPolicy, existing-carrier precedence enums, XmpWritebackMode, destination carrier modes

openmeta/xmp_dump.h, openmeta/metadata_transfer.h

Stable

Stable bounded writer policy for generated portable XMP. See xmp_sync_policy.md.

Generic metadata traversal: visit_metadata(...), MetadataSink, ExportOptions, ExportItem

openmeta/interop_export.h

Stable

v1 traversal contract. Borrowed names are valid only during MetadataSink::on_item(...).

ExportNameStyle::Canonical and ExportNameStyle::XmpPortable

openmeta/interop_export.h

Stable

Stable naming modes for key-space-aware and portable exports.

ExportNameStyle::FlatHost

openmeta/interop_export.h

Stable

Stable v1 flat host naming contract. See flat_host_mapping.md.

Typed FlatHost import: import_flat_host_metadata(...)

openmeta/interop_import.h

Stable v1

Transactional detached-store reconciliation. Existing values and tombstones use exact source identity or a unique FlatHost name; duplicate names are rejected, removals retain stable ids/provenance as Dirty \| Deleted, and new arbitrary entries require an explicit typed MetaKeyView.

Fresh metadata creation: create_metadata(...) and typed field helpers

openmeta/metadata_creation.h

Experimental

Transactional v1 contract for bounded host-provided logical fields. Produces a finalized canonical portable-XMP MetaStore, preserves additive creator/keyword order, rejects duplicate singletons, validates UTF-8/XML text and typed numeric constraints, and exposes the same C++ policy through a thin Python create_metadata(...) wrapper. Direct EXIF/IPTC projection remains a Translation concern. See creation.md.

Logical metadata editing: edit_metadata(...) and add/set/remove helpers

openmeta/metadata_editing.h

Experimental

Transactional v1 contract over finalized stores and the Creation logical field map. Set/remove preserve provenance through dirty values and tombstones; add handles deterministic repeated fields and explicit singleton conflicts. Python returns a detached edited Document without mutating its source. See editing.md.

EXIF/TIFF orientation helpers: interpret_exif_orientation(...), exif_orientation_name(...), exif_orientation_rotation_degrees_cw(...), exif_orientation_rotation_only(...)

openmeta/orientation.h

Stable

Small utility contract for user-facing orientation labels, clockwise rotation degrees, mirrored-state detection, dimension-swap detection, and rotation-only fallbacks. Python exposes the same helpers through thin scalar/dictionary wrappers.

EXIF/TIFF/DNG numeric value names and version formatting: exif_tag_numeric_value_name(...), exif_tag_numeric_value_format(...), exif_tag_byte_value_format(...), and focused helpers

openmeta/exif_value_names.h

Stable

Small helper contract for common enum-like TIFF/EXIF/DNG numeric values such as compression, photometric interpretation, planar configuration, exposure program/mode, metering mode, light source, flash, color space, white balance, scene capture type, gain control, CFA layout, DNG calibration illuminants, and EXIF 3.1 lens-correction / noise-reduction status values, plus selected bounded Canon/Nikon/Sony/Fujifilm/Pentax/Olympus/Panasonic/Phase One/Kodak/Minolta/Sigma/Samsung/Ricoh/Apple/FLIR/JVC/GE/Reconyx/Microsoft/Motorola/Nintendo/Sanyo MakerNote contexts including NikonSettings On/Off labels, Reconyx scalar labels, Microsoft stitch labels, Motorola CustomRendered labels, Nintendo category labels, Sanyo public-context scalar labels, current Canon RF lens-type labels, current Nikon Z LensData0800 LensID labels, and an ambiguous Pentax Sigma/Samsung/Tokina lens-family label where stable. Version/firmware helpers format selected standard EXIF byte-version fields, Nikon version-like payloads, Olympus packed firmware values, and native RAF firmware payloads without treating formatted versions as enum labels. Unknown or ambiguous values return an empty string or false and remain lossless metadata.

Photoshop IRB decode: decode_photoshop_irb(...), measure_photoshop_irb(...)

openmeta/photoshop_irb_decode.h

Experimental

Bounded resource traversal with stable raw resource preservation behavior, but the interpreted subset can still grow. Current interpretation includes fixed-layout resource fields, display/grid/thumbnail/color-sampler headers, working-path and numbered clipping-path byte counts / record summaries, descriptor-header summaries plus safe descriptor class-name/class-ID/item-count fields, bounded descriptor item bodies for bool, long, comp, doub, UntF, TEXT, enum, type, and GlbC, opaque alis and tdta byte counts, ordered obj property/class/enumerated/offset/identifier/index/name reference fields with per-value and aggregate limits, descriptor item/reference type-name/type-code fields, parsed maximum depth, and parsed per-type counters, nested object/list traversal with item path/depth/list-index and parsed-value count fields, XMLData, ImageReady ASCII text resources, Lightroom workflow text, MacintoshPrintInfo / Macintosh NSPrintInfo / Windows DEVMODE / AlternateDuotoneColors / AlternateSpotColors / obsolete Photoshop tag byte counts, legacy halftone/transfer/duotone/EPS byte summaries, embedded IPTC/ICC/EXIF/EXIF2/XMP byte-count fields, and optional embedded IPTC-IIM, XMP, and ICC payload decode.

Semantic metadata query: query_metadata(...), query_crop_metadata(...), and focused query helpers

openmeta/metadata_query.h

Experimental

Query contract for inspection matches plus normalized candidates. Current coverage includes crop/active-area/border margins, exposure/gain, white balance, color/profile/source-color-transform, lens correction, orientation, descriptive EXIF/IPTC/XMP fields including exact contact/event/person/organization/product/artwork/rights/license/credit/source/rights-expression/release semantics, and RAW/source-processing metadata across standard tags, selected DNG tags, RAW value curves, RAW linearity limits, RAW calibration curves, RAW curve control points, EXIF color-space evidence, ICC header/tag entries, XMP ICC/profile/color-space fields, XMP camera RAW profile/look/tone-curve fields, PNG profile text carriers, Fujifilm RAF raw crop/zoom rectangles, Canon aspect/crop metadata, Canon AF micro-adjustment, Canon ambience-selection, Canon ColorData source color-transform, NikonSettings source-processing aliases, Nikon Capture crop bounds, Sony panorama crop margins, selected decoded vendor/MakerNote exposure names, crop/border XMP paths, and vendor RAW-processing classification. Semantic Query uses deterministic tag, namespace, and name matching; tolerant partial matching is isolated in the separate Fuzzy Search API so near names cannot change metadata meaning. Matches retain exact_match, fuzzy_match, and fuzzy_score compatibility fields. Exact descriptive semantics added after the full legacy 32-bit match-term mask may have zero matched_terms; their explicit semantic and confidence remain authoritative. Grouped candidates include matrix_set, vector_set, and table shapes for related non-crop metadata, including RAW black/white levels, linearization, raw value curves, raw linearity limits, raw calibration curves, raw curve control points, CFA/sensor layout, source geometry, raw-storage identifiers, source-processing buckets, and per-family vendor MakerNote/RAW white-balance, source-color-transform, raw-storage, sensor, computational, thermal, stitch/panorama, and source-processing groups. Matrix/vector/table groups are promoted only when the available numeric payloads meet conservative minimum shapes, so malformed color matrices, white-balance vectors, and lens-correction records remain per-entry inspection data instead of becoming normalized groups. Long-tail source color/style/lens/source-processing aliases such as camera-to-XYZ/RGB matrices, creative/picture style, film simulation, dynamic-range, optical-correction, AF micro-adjustment, ambience selection, Canon ColorData, NikonSettings, and raw-development terms are classified for query and transfer-policy inspection; camera RAW profiles, looks, tone curves, and vendor source color tables use the explicit source_color_transform semantic, RAW curve/linearity metadata uses dedicated RAW-processing semantics, and computational, thermal, and stitch/panorama fields use explicit source-processing subroles. Python Document and TransferSourceSnapshot mirror this as thin dictionary-returning wrappers.

Bounded fuzzy entry search: fuzzy_search_metadata(...), metadata_fuzzy_search_available()

openmeta/metadata_fuzzy_search.h

Experimental

Optional RapidFuzz-backed search over decoded metadata names and property paths. The API has bounded query/candidate/result sizes, caller-selected score cutoff, deterministic top-k ordering, stable entry-id ties, explicit exact/curated-alias/general-fuzzy provenance, and status returns for unavailable, invalid, short, long, or non-ASCII queries. The current normalization contract is locale-independent ASCII with separator, camel-case, and acronym-boundary normalization but without Unicode normalization or transliteration. Calls use local state and are safe against an immutable finalized store. Python Document and TransferSourceSnapshot expose thin dictionary wrappers.

Structured metadata interpretation records: interpret_metadata(...), interpret_metadata_query(...)

openmeta/metadata_interpretation.h

Experimental

Thin structured projection over semantic query candidates. Records carry query class, semantic kind, normalized shape, confidence, source entry ids, and normalized origin/size/rect/margins/value arrays where available. Current scope covers orientation, geometry/crop/border including Fujifilm RAF, Canon, Nikon Capture, and Sony panorama geometry patterns, exposure/gain, color/white-balance/profile/source-color-transform records, lens-correction, RAW/source-processing records including raw value curves, linearity limits, calibration curves, curve control points, computational, thermal, and stitch/panorama subroles, and grouped vendor-family table/vector records where classification supports them. Python Document and TransferSourceSnapshot expose matching dictionary wrappers.

Cross-family concept resolution: resolve_metadata_concepts(...), resolve_metadata_concept(...)

openmeta/metadata_concepts.h

Experimental

First bounded resolver for duplicated host-facing concepts. Current scope reports candidates, candidate source entries, source families, preferred entries, normalized numeric/text keys, full normalized value vectors, transfer hints, RAW applicability states, normalized date/time fields, date/time precision including bounded subsecond digits, timezone kind, normalized geometry fields, normalized exposure values, and same-role conflicts for orientation, date/time, exposure/gain, color/profile/source-color-transform, GPS, descriptive fields, geometry, lens-correction, RAW-processing, and container-graph evidence across EXIF, XMP, IPTC, ICC, PNG text, BMFF fields, and query-backed interpretation records where applicable. Exposure candidates cover exposure time, aperture, ISO sensitivity, exposure bias, exposure program/mode, gain, and raw exposure-adjustment roles across standard EXIF/DNG/XMP evidence and selected decoded vendor/MakerNote exposure names; standard EXIF exposure program/mode and gain-control values plus selected Canon/Nikon/Sony/Fujifilm/Pentax/Olympus/Panasonic/Phase One/Kodak/Minolta/Sigma/Samsung/Ricoh MakerNote values include human-readable labels where stable; capture exposure facts are safe, while raw/DNG exposure adjustments stay rendered-unsafe. Geometry candidates cover crop, active area, border, and sensor geometry with canonical origin, size, rect, and margin fields when available, including normalized DNG, Phase One/Leaf, Fujifilm RAF, Canon, Nikon Capture, and Sony panorama geometry patterns. Candidate transfer hints distinguish safe, source_bound, rendered_unsafe, and requires_target_image_spec evidence, with compatible-file and rendered-image safety booleans. Color/white-balance, source-color-transform, lens-correction, RAW-processing, and container-graph concepts preserve source evidence for host inspection; source-bound color transforms and RAW curve/linearity/calibration roles are marked rendered-unsafe, computational/thermal/stitch RAW-processing roles are marked source-bound, and BMFF whole-scene, primary-component, per-component content-bound metadata / multi-image policy, and derived-image construction fields are marked source-bound. RAW curve/LUT-like concept roles are conservatively marked conditional_on_raw_encoding until a raw data descriptor can confirm whether they affect the stored samples; descriptor-aware overloads accept MetadataRawDataDescriptor and can collapse supported stored-RAW descriptors to applies_to_stored_raw, rendered descriptors to not_applicable_to_stored_raw, compressed-only descriptors to not-applicable when the supplied storage encoding is uncompressed or packed, and primary-plane-only descriptors to not-applicable when the supplied plane index is non-primary. Matching EXIF OffsetTime* and SubSecTime* entries are assembled with DateTime* candidates, offset-aware conflicts compare normalized UTC instants, and missing timezone or subsecond fields remain lower-precision evidence. EXIF and XMP GPS date/time are combined from same-scope GPSDateStamp plus GPSTimeStamp entries, direct XMP GPSDateTime / GPSDateTimeStamp values map to the GPS timestamp role, IPTC digital-creation date/time and XMP DateTimeDigitized map to the Digitized date/time role, and GPS altitude candidates expose altitude-reference code plus below-sea-level state when reference metadata is present. Camera position, EXIF/XMP destination coordinates, and IPTC Extension LocationShown / LocationCreated coordinates use distinct roles. Structured candidates expose location_scope, and conflict/preference handling compares values only within the same scope; metadata_concept_gps_altitude_reference_name(...) provides a stable display token for altitude reference codes. The Descriptive kind reconciles standard title, headline, description, creator, keyword/subject, created/shown location, copyright, rights/license, credit, and source fields. Localized scalars compare per normalized language; creator, keyword, location-identifier, rights-holder, and licensor collections preserve distinct values and select one preferred source per duplicate normalized value. Structured PLUS owner/licensor members expose record_scope so related names and identifiers remain associated. It is intended for inspection UI and host policy decisions; it does not rewrite metadata or hide ambiguity. Python Document and TransferSourceSnapshot expose matching dictionary wrappers, including subsecond, location-scope, record-scope, and language fields and the thin MetadataRawDataDescriptor object with storage, compression, and plane-binding fields.

Transfer concept diagnostics: transfer_concept_diagnostics_from_store(...), transfer_concept_diagnostic_message(...), transfer_concept_diagnostic_token(...), transfer_concept_diagnostic_message_token(...), transfer_concept_diagnostic_message_arguments(...)

openmeta/metadata_transfer.h

Experimental

Preflight view over concept candidates for TransferSafetyMode. Each diagnostic reports concept kind/role, transfer hint, keep/drop/requires-target-image-spec action, reason token, severity token, stable host-facing summary token, stable localization message token, localizable argument tokens, default message text, conflict flag, source entries, structured-location scope, generic structured-record scope, and language where applicable, compatible/rendered safety booleans, RAW applicability state, and GPS altitude-reference presentation fields. Descriptor-aware overloads accept MetadataRawDataDescriptor and make RAW-processing keep/drop decisions reflect the supplied stored-RAW, compressed-only, primary-plane-only, or rendered storage context. PrepareTransferRequest::source_raw_data_descriptor can apply the same coarse rendered-source RAW filtering during prepare_metadata_for_target(...); it is still intentionally conservative and does not prove vendor curve/LUT activity for a specific compression mode or decoder stage. Rendered-transfer drop messages distinguish source color transforms, white balance, lens-correction records, source RAW curves/linearity metadata that still require storage-context confirmation, computational/thermal/stitch source-processing drops, and BMFF container-graph content-bound metadata / multi-image scene / derived-image construction drops from generic source-processing metadata. Python Document and TransferSourceSnapshot expose transfer_concept_diagnostics(...) dictionaries with severity_name, token, message_token, message_arguments, message, location_scope, record_scope, language, and RAW applicability fields, with overloads that accept the thin MetadataRawDataDescriptor object; Python transfer helpers also accept source_raw_data_descriptor for prepare-time filtering.

Vendor RAW-processing summaries: vendor_raw_processing_from_store(...), classify_vendor_raw_processing_field(...)

openmeta/vendor_raw_processing.h

Experimental

Conservative grouped source-RAW/source-processing field summaries for decoded Sony, Canon, Nikon, Fujifilm, Pentax, Panasonic, Olympus, Kodak, Minolta, Sigma, Samsung, Ricoh, Apple, DJI, Google, FLIR, Casio, Sanyo, KyoceraRaw, Reconyx, HP, JVC, GE, Motorola, Nintendo, and Microsoft MakerNotes, including vendor-private, computational, thermal, preview, face-geometry, stitch/panorama, Apple computational capture/HDR/motion, DJI pose/thermal, Google HDR+/shot-log, pixel-shift/multi-shot/composite/auto-lighting/source-style processing, and FLIR radiometric/raw-value buckets. Long-tail aliases cover source color/style, camera-to-XYZ/RGB matrix, white-balance gain, optical/lens correction, dynamic-range, and raw-development terms. Direct field classification also recognizes decoded Phase One/Leaf RAW-processing tags; use the dedicated Phase One/Leaf helpers for normalized geometry and processing summaries. Intended for audit/UI and rendered-transfer safety decisions, not for writing vendor RAW/source-processing values into rendered targets.

Transfer safety audit: transfer_safety_audit_from_store(...)

openmeta/metadata_transfer.h

Experimental

Preflight summary of source entries and entries filtered or invalidated by TransferSafetyMode, including Sony/Canon/Nikon/Fujifilm/Pentax/Panasonic/Olympus/Kodak/Minolta/Sigma/Samsung/Ricoh/Apple/DJI/Google/FLIR/Casio/Sanyo/KyoceraRaw/Reconyx/HP/JVC/GE/Motorola/Nintendo/Microsoft RAW/source-processing buckets. Intended for diagnostics and host UI before preparing rendered-image transfers.

MakerNote transfer audits: makernote_transfer_audit_from_store(...), makernote_layout_transfer_audit_from_store(...)

openmeta/metadata_transfer.h

Experimental

The generic audit reports raw opaque payload and decoded-only entry counts plus current rewrite trust capabilities. The layout audit recognizes canonical Nikon type 1 outer-TIFF-relative notes and type 3 notes with an embedded TIFF at byte 10; bounded embedded-TIFF validation covers standard directory/value offsets only. The writer still cannot reconstruct decoded fields, relocate vendor-private offsets, repair checksums, prove semantic readability, or pass MakerNotes through as raw carriers. Python Document and TransferSourceSnapshot expose matching thin dictionary wrappers.

Raw-carrier passthrough audit: raw_carrier_passthrough_audit_from_snapshot(...)

openmeta/metadata_transfer.h

Experimental

Diagnostic preflight for opt-in raw carriers. Reports candidate carriers and primary block reasons such as missing payload, target incompatibility, safety filtering, content-bound C2PA, explicit profile policy, missing decoded-entry links, or unsupported carrier kind. Hosts can call it directly before enabling snapshot passthrough.

Decoded source snapshot state: TransferSourceSnapshot

openmeta/metadata_transfer.h

Stable v1 profile

Stable decoded-store state for positional read, persistence, and reconciliation. Optional raw-carrier records are preserved as data, but raw-carrier passthrough policy remains experimental. Const reuse is safe when callers do not mutate the snapshot.

File/bytes/build snapshot helpers: read_transfer_source_snapshot_file(...), read_transfer_source_snapshot_bytes(...), build_transfer_source_snapshot(...)

openmeta/metadata_transfer.h

Experimental

Convenience entry points outside the narrow positional Host Adoption Profile.

Versioned source snapshot persistence: serialize_transfer_source_snapshot(...), deserialize_transfer_source_snapshot(...)

openmeta/metadata_transfer.h

Stable v1

Target-neutral canonical v1 representation with transactional bounded parsing and an exact compatibility vector. Preserves store blocks, ordered duplicate entries, typed values, provenance, tombstones, flags, and optional raw-carrier links. Current readers accept v1 and reject unknown versions atomically; persistence does not imply that raw bytes are safe to relocate or rewrite.

Fileless preparation: prepare_metadata_for_target_snapshot(...)

openmeta/metadata_transfer.h

Experimental

Intended for hosts that already decoded metadata and want to prepare transfer artifacts without reopening the source file. TransferRawCarrierPassthroughMode::WhenSafe is an opt-in snapshot mode; the current writer path only reuses eligible non-C2PA JUMBF and draft unsigned C2PA invalidation carriers for JPEG, JXL, and BMFF targets, plus draft unsigned C2PA invalidation carriers for WebP.

Snapshot execution: execute_prepared_transfer_snapshot(...)

openmeta/metadata_transfer.h

Experimental

Intended for deferred save/writeback from a reusable decoded source snapshot.

Bundle execution: execute_prepared_transfer_bundle(...)

openmeta/metadata_transfer.h

Experimental

Intended for hosts that already own a prepared bundle and destination bytes. Treat bundles as immutable except through documented patch helpers.

Typed adapter operation schema: PreparedTransferAdapterOp, TransferAdapterOpKind, kPreparedTransferAdapterContractVersion

openmeta/metadata_transfer.h

Stable v1 schema

Enum-based insertion operations for JPEG, TIFF/DNG, JXL, WebP, PNG, JP2, EXR, and BMFF. Marker/tag/box/chunk/item/property fields are explicit. EXR name/type/value resolution uses get_prepared_transfer_adapter_exr_attribute_view(...); codecs do not parse route strings.

Adapter-view build, validation, and execution: build_prepared_transfer_adapter_view(...), validate_prepared_transfer_adapter_view(...), emit_prepared_transfer_adapter_view(...)

openmeta/metadata_transfer.h

Experimental

Builds and validates the stable v1 operation schema over an experimental prepared bundle. Validation compares every operation with the canonical compiled view before codec handoff.

Persisted prepared payload/package batches: serialize_prepared_transfer_payload_batch(...), deserialize_prepared_transfer_payload_batch(...), serialize_prepared_transfer_package_batch(...), deserialize_prepared_transfer_package_batch(...), replay and view helpers

openmeta/metadata_transfer.h

Experimental

Owned target-specific encoder/package handoff. The current wire formats are versioned and bounded, but route and operation details have not yet graduated to a stable compatibility contract.

Generated transfer payload internals, undocumented route strings, low-level package chunks, and diagnostic counters not covered by a host-facing API row

openmeta/metadata_transfer.h

Internal

These fields may be useful for tests and diagnostics, but they are not a compatibility contract for downstream integrations.

Structured descriptive candidates now expose experimental record_kind, record_scope, and sensitivity fields. Record kinds cover creator contacts, events, people, organizations, products, artwork/objects, rights expressions, rights holders, licensors, licensees, licenses, releases, end users, image creators, image suppliers, image assets, controlled-vocabulary terms, registry entries, image regions, resource references, resource events, manifest items, versions, editorial workflows, source software, editorial contacts, and pantry items, plus legacy IPTC technical-image, audio-asset, and preview-asset records. The IPTC technical records normalize image layout, component count, audio channel/rate/resolution/duration, preview format/version, and bounded binary payload identity without treating IPTC layout as EXIF rotation. Sensitivity is a policy signal independent of technical transfer safety; the same fields are mirrored in transfer diagnostics and thin Python dictionaries. Hosts must not interpret safe as approval to publish personal-contact, person-identity, location, or legal-rights metadata.

Exact descriptive query semantics also cover legacy editorial workflow pairs, non-equivalent IPTC taxonomy and workflow fields, scoped prior-envelope references and originating software, IPTC Core accessibility and taxonomy fields, IPTC Extension registry and image-region entities, resource/document identity and lineage/history, and remaining bounded PLUS party, delivered-asset, and license-policy fields. Legacy IPTC image, audio, and preview datasets use exact technical_image, audio, and preview semantics. Equivalent scalar pairs participate in preference/conflict handling; taxonomy, resource-identifier, and license-document collections remain additive. Document identity/lineage/history, registry, prior-envelope-reference, and source-software records are source-bound for rendered transfer; image-region records require target image specifications. Editorial contacts carry personal-contact sensitivity independently of their technical transfer hint. Technical-image, audio-asset, and preview-asset records are source-bound.

The bounded BMFF tiled-image field contract covers tilC version 0 tile dimensions, up to eight extra dimensions, dref/deti mapping, internal tile_item_type/tipa associations, bounded external URL components, logical offset-table rows, explicit or sequentially inferred tile sizes, and separate core/layout/complete validity. Offset-table validation is capped at 262144 entries, emitted rows at 64, property associations at 64, and retained URL components at 512 bytes. TiledImageConfiguration remains an experimental source-bound concept role exposed unchanged by the thin Python enum.

Practical Guidance

Use stable APIs for normal application integrations. Use experimental APIs when they match a real workflow and the integration can track OpenMeta releases. Avoid internal surfaces unless you are contributing to OpenMeta itself or writing a test that is intentionally tied to implementation details.

High-throughput hosts should use Host Adoption Profile v1 as the compatibility boundary and query format capabilities separately.

page Compatibility Dump Contract

OpenMeta exposes a deterministic text dump for downstream compatibility tests. The goal is to let host projects compare names, value shapes, origins, and transfer decisions without keeping binary metadata packet baselines.

Contract constant:

openmeta::kCompatibilityDumpContractVersion == 1

Python exposes the same version as:

openmeta.COMPATIBILITY_DUMP_CONTRACT_VERSION == 1

Metadata Dump

Use dump_metadata_compatibility(...) for C++:

#include "openmeta/compatibility_dump.h"

openmeta::MetadataCompatibilityDumpOptions options;
options.style = openmeta::ExportNameStyle::FlatHost;

std::string out;
openmeta::dump_metadata_compatibility(store, options, &out);

Python Document and TransferSourceSnapshot expose the same metadata dump:

doc = openmeta.read("source.jpg")
text = doc.compatibility_dump()

The v1 metadata dump is line-oriented ASCII text:

openmeta.compat.metadata version=1 ...
entry index=0 name="Make" key_kind="exif_tag" value_kind="text" ...

Each emitted entry is based on visit_metadata(...), so ordering, duplicate handling, and naming follow the selected ExportNameStyle. By default the dump uses the stable FlatHost contract. BMFF component membership, role, policy, and derived-image construction fields such as bmff:scene.component.item_id, bmff:scene.component.role, bmff:scene.component.metadata_policy, and bmff:scene.component.multi_image_policy, plus bmff:derived_image.construction and bmff:derived_image.construction_valid, bmff:derived_image.graph_valid, and bmff:derived_image.descriptor_reference_depth, are emitted as normal bmff_field entries, so host baselines can verify container-graph evidence without a separate decoder-specific dump format.

Metadata entry lines include:

  • exported name

  • key family

  • value kind

  • scalar or array element type

  • text encoding

  • count

  • optional safe value text

  • optional origin block/order/wire fields

  • optional per-entry flags

Text and byte values are escaped with the same terminal-safe ASCII rules used by other OpenMeta diagnostic output. Large values are bounded by max_value_bytes.

Transfer Dump

Use dump_transfer_compatibility(...) for C++ transfer/writeback decisions:

std::string out;
openmeta::TransferCompatibilityDumpOptions options;
openmeta::dump_transfer_compatibility(result, persisted_or_null, options, &out);

The v1 transfer dump is line-oriented ASCII text:

openmeta.compat.transfer version=1 target_format="png" ...
policy index=0 subject="xmp_iptc_projection" ...
block index=0 kind="xmp" route="png:itxt-xmp" ...
execute edit_requested=true ...
writeback xmp_sidecar_requested=true ...
persist status="ok" ...

Transfer dump lines include:

  • target format and high-level read/prepare status

  • prepared policy decisions

  • prepared block kind, route, order, and payload size

  • execute/edit status and output sizes

  • XMP sidecar request, output, and cleanup decisions

  • optional persisted file/sidecar/cleanup result

The dump intentionally records decisions and sizes, not full binary payloads. This keeps downstream tests stable across equivalent packet serialization changes.

Stability

This is a stable v1 contract. Future releases may add fields or lines, but existing v1 field names and meanings should not change without a new contract version or a documented compatibility path.

page Metadata Creation

openmeta/metadata_creation.h provides the first high-level Creation contract for fresh metadata. A host supplies logical fields rather than EXIF tag IDs or XMP namespace paths. OpenMeta validates the complete request and returns one finalized MetaStore containing canonical portable-XMP entries.

The API is experimental and versioned by kMetadataCreationContractVersion == 1.

C++ Example

#include "openmeta/metadata_creation.h"

#include <array>

const std::array fields = {
    openmeta::make_metadata_creation_text(
        openmeta::MetadataCreationFieldKind::Title, "Evening frame"),
    openmeta::make_metadata_creation_text(
        openmeta::MetadataCreationFieldKind::Creator, "Alice"),
    openmeta::make_metadata_creation_text(
        openmeta::MetadataCreationFieldKind::Keyword, "night"),
    openmeta::make_metadata_creation_u32(
        openmeta::MetadataCreationFieldKind::Orientation, 6),
    openmeta::make_metadata_creation_urational(
        openmeta::MetadataCreationFieldKind::ExposureTime, 1, 125),
};

openmeta::MetadataCreationRequest request;
request.fields = fields;

openmeta::MetaStore store;
const openmeta::MetadataCreationResult result =
    openmeta::create_metadata(request, &store);
if (result.status != openmeta::MetadataCreationStatus::Ok) {
    // result.failed_field_index identifies the rejected field when available.
}

The call is transactional. store is replaced only after every field has passed validation and the new store has been finalized. An empty request creates an empty finalized store.

Current Field Mapping

Logical field

Input type

Canonical portable-XMP property

Notes

Title

Text

dc:title[x-default]

Singleton language alternative

Description

Text

dc:description[x-default]

Singleton language alternative

Creator

Text

dc:creator[n]

Additive ordered sequence

Keyword

Text

dc:subject[n]

Additive unordered bag

Copyright

Text

dc:rights[x-default]

Singleton language alternative

RightsUsageTerms

Text

xmpRights:UsageTerms[x-default]

Singleton language alternative

Credit

Text

photoshop:Credit

Singleton

Source

Text

photoshop:Source

Singleton

CreateDate

Text

xmp:CreateDate

Caller supplies the XMP date lexical value

ModifyDate

Text

xmp:ModifyDate

Caller supplies the XMP date lexical value

Rating

Signed integer

xmp:Rating

-1..5

Label

Text

xmp:Label

Singleton

CameraMake

Text

tiff:Make

Singleton

CameraModel

Text

tiff:Model

Singleton

Software

Text

xmp:CreatorTool

Singleton

DateTimeOriginal

Text

exif:DateTimeOriginal

Caller supplies the XMP date lexical value

Orientation

Unsigned integer

tiff:Orientation

EXIF orientation index 1..8

PixelWidth

Unsigned integer

exif:ExifImageWidth

Must be nonzero

PixelHeight

Unsigned integer

exif:ExifImageHeight

Must be nonzero

ColorSpace

Unsigned integer

exif:ColorSpace

1..65535

ExposureTime

Unsigned rational

exif:ExposureTime

Nonzero numerator and denominator

FNumber

Unsigned rational

exif:FNumber

Nonzero numerator and denominator

IsoSensitivity

Unsigned integer

exif:ISO

Must be nonzero

FocalLength

Unsigned rational

exif:FocalLength

Nonzero numerator and denominator

Creators and keywords may be repeated and retain request order. Every other logical field is a singleton; duplicate singleton fields are rejected rather than silently selecting a winner.

Validation And Limits

Text must be non-empty valid UTF-8 containing only XML 1.0 character data. The current hard maxima are:

  • 1024 fields

  • 1 MiB of UTF-8 text per field

  • 8 MiB of UTF-8 text per request

MetadataCreationRequest::limits may lower but not raise these bounds. Date strings are not parsed or normalized in this milestone; callers must provide valid XMP date lexical values.

Each result identifies its stable status and, when applicable, the rejected field index. Creation uses no global state. Concurrent calls are safe when each call has a distinct output store.

Python

Python owns field text until the C++ request completes and uses the same C++ validation and mapping:

import openmeta

K = openmeta.MetadataCreationFieldKind
document = openmeta.create_metadata([
    openmeta.metadata_creation_text(K.Title, "Evening frame"),
    openmeta.metadata_creation_text(K.Creator, "Alice"),
    openmeta.metadata_creation_u32(K.Orientation, 6),
    openmeta.metadata_creation_urational(K.ExposureTime, 1, 125),
])

packet, result = document.dump_xmp_portable(
    include_exif=False,
    include_iptc=False,
    include_existing_xmp=True,
)

Invalid requests raise ValueError with the C++ status and rejected field index. The returned object is a normal Document: it can be queried, dumped, or converted into a transfer snapshot.

Use the matching transactional Editing API to modify these fields in an existing finalized store. See editing.md.

Scope And Safety

Creation writes canonical portable-XMP entries because that representation can flow through the existing sidecar and transfer writers without requiring an original file layout. Direct EXIF/IPTC projection is a Translation concern and is not implied by this API.

Image-dependent values such as dimensions, orientation, and color space must describe the destination pixels. OpenMeta cannot infer them from an encoder buffer. Do not copy those values from a differently sized, rotated, converted, or color-transformed source image.

This milestone does not yet cover arbitrary custom properties, non-default language alternatives, structured XMP records, binary values, fresh ICC profiles, or direct EXIF/IPTC block construction.

page Canonical EXR Value Encoding in OpenMeta

Status: baseline contract (v1)

Scope

This defines how OpenEXR attribute values should be represented in MetaValue and Origin/WireType so decode/edit/write logic stays deterministic and lossless.

Keying is handled separately by MetaKeyKind::ExrAttribute with:

  • part_index (EXR part id)

  • name (attribute name)

Wire Type Contract

  • Origin::wire_type.family = WireFamily::Other

  • Origin::wire_type.code = exr_attribute_type_t numeric value

  • Origin::wire_count stores raw attribute byte size (current implementation)

For unknown/user-defined EXR attribute types, preserve:

  • raw payload bytes in MetaValueKind::Bytes

  • type string in Origin::wire_type_name (optional decode behavior)

Canonical Mapping Table

  • EXR_ATTR_INT -> Scalar + I32

  • EXR_ATTR_FLOAT -> Scalar + F32

  • EXR_ATTR_DOUBLE -> Scalar + F64

  • EXR_ATTR_RATIONAL -> Scalar + SRational (num, denom)

  • EXR_ATTR_STRING -> Text + Utf8 (best effort, fallback Unknown)

  • EXR_ATTR_STRING_VECTOR -> Bytes (current), planned structured helper API for element iteration

  • EXR_ATTR_V2I/V3I -> Array + I32 (count 2/3)

  • EXR_ATTR_V2F/V3F -> Array + F32 (count 2/3)

  • EXR_ATTR_V2D/V3D -> Array + F64 (count 2/3)

  • EXR_ATTR_M33F -> Array + F32 (count 9, row-major)

  • EXR_ATTR_M33D -> Array + F64 (count 9, row-major)

  • EXR_ATTR_M44F -> Array + F32 (count 16, row-major)

  • EXR_ATTR_M44D -> Array + F64 (count 16, row-major)

  • EXR_ATTR_BOX2I -> Array + I32 (count 4: min.x,min.y,max.x,max.y)

  • EXR_ATTR_BOX2F -> Array + F32 (count 4: min.x,min.y,max.x,max.y)

  • Enum-like attrs (compression, lineorder, envmap, deepImageState) -> Scalar + U8

  • Struct/blob attrs (chlist, preview, bytes, opaque) -> Bytes for lossless core storage; typed helper decode APIs should be layered on top.

  • Current decode additionally normalizes:

    • EXR_ATTR_TIMECODE -> Array + U32 (2 values)

    • EXR_ATTR_KEYCODE -> Array + I32 (7 values)

    • EXR_ATTR_TILEDESC -> Array + U8 (9 raw bytes)

Rationale

  1. Keep MetaStore compact and storage-agnostic.

  2. Guarantee lossless round-trip for all EXR attributes, including unknown ones.

  3. Avoid hard-coding large per-type structs in core until a stable EXR read/write adapter lands.

Open Questions

  1. Whether string_vector should become first-class Array + Text rather than a packed-bytes representation.

  2. Where to attach EXR type_name for unknown/custom attrs without bloating all entries.

  3. Whether chlist should get a dedicated typed view API in v1 or remain bytes in core with helper parsing only.

page Development

See also: docs/metadata_support.md for current container/block/decode support and docs/interpretation_status.md for the semantic interpretation matrix. If you are looking for the shortest practical entry path, start with docs/quick_start.md before this file.

If you already have a host encoder, SDK, or container API, use docs/host_integration.md after the quick start.

OpenMeta Structure

OpenMeta’s public architecture is organized around a small set of user-facing capabilities. Internally some of these split into more stages, but the public model should stay compact:

Area

Purpose

Readiness

Decoding

Find metadata carriers and decode EXIF, XMP, IPTC, ICC, Photoshop IRB, JUMBF/C2PA, EXR, and related blocks into MetaStore entries.

High, about 98-100% for the current target scope.

Interpretation

Normalize names and values, group entries by meaning, and classify source-bound data such as RAW crop, exposure adjustment, color/profile/source-color-transform evidence, RAW curves/linearity metadata with descriptor-backed compressed-storage applicability, lens-correction, sensor, BMFF brand/item-property associations and rollups including avio AVIF brands, item groups, item semantic counts, whole-scene policy hints, graph-component summaries with per-component roles, member item IDs, semantic composition, typed relation counts, bounded grid/iovl/iden construction semantics with recursive item-offset descriptors and graph-cycle/source validation, bounded complete tili configuration/reference/offset-table interpretation, container_graph concepts, primary item properties, primary metadata-carrier flags, primary sidecar and scene summaries, and display-transform summaries, JUMBF labels, Photoshop IRB embedded carriers plus fixed-layout, XML/text, working-path and numbered clipping-path records, byte-count, descriptor-header, scalar/class/alias/enum/reference, and bounded nested list/object summaries, EXIF 3.1 correction/noise labels, version/firmware-style value formatting for selected EXIF/Nikon/Olympus/native RAF contexts, selected Sony ILCE-7RM6 correction-offset routing, Fujifilm flash white-balance naming, Apple/FLIR/JVC/GE/Reconyx/Microsoft/Nintendo/Sanyo scalar MakerNote labels, current Canon RF/Nikon Z lens labels, an ambiguous Pentax Sigma/Samsung/Tokina lens-family label, EXIF/XMP GPS timestamp composites, EXIF OffsetTime*/SubSecTime* date composition with normalized-instant conflict checks, separate camera/destination/shown/created GPS roles with scope-aware structured-location conflicts, language-aware descriptive roles, legacy editorial duplicate reconciliation, non-equivalent IPTC taxonomy/workflow fields, content-location and prior-envelope scopes, editorial release/expiration date-time pairs, source software and editorial contacts, source-bound IPTC technical-image/audio/preview records, accessibility/taxonomy/registry/image-region/document-identity/lineage/history semantics, structured creator-contact/event/person/organization/product/artwork/rights/license/release/end-user/image-creator/image-supplier/image-asset/controlled-vocabulary/registry/image-region/image-region-boundary/resource-reference/resource-event/manifest-item/version/editorial-workflow/source-software/editorial-contact/technical-image/audio-asset/preview-asset/pantry records, bounded standard resource-reference/event/version/manifest structures nested in pantry items, explicit image-region shape and coordinate-unit contracts, independent privacy/policy sensitivity, computational, thermal, stitch/panorama capture state, and vendor-private fields.

High, measured about 99.85% for declared semantic targets.

Query

Find entries by exact name or semantic group, then expose normalized query candidates, structured interpretation records, bounded cross-family concept resolutions, transfer hints, sensitivity, and conflict flags for crop/border/active-area, exposure/gain, color/WB/profile/source-color-transform, orientation, date/time, GPS, descriptive fields including contact/event/person/organization/product/artwork/rights/license/release, editorial, accessibility, taxonomy, registry, image-region, document-identity, document-lineage, document-history, technical-image, audio, and preview semantics, lens-correction, computational/thermal/stitch, RAW/source-processing fields, and BMFF derived-image construction and tiled-image configuration evidence across standard and vendor metadata.

High, measured about 99.77% for declared query targets.

Fuzzy Search

Optionally find misspelled, aliased, or near-match metadata names and property paths with bounded deterministic top-k ranking and explicit exact/alias/fuzzy provenance.

High enough for the current milestone, about 80-85%; the standalone RapidFuzz-backed API, curated positive/adversarial quality gate, bounded ASCII contract, Python wrappers, Release/libc++ CI gate, and opt-in scaling benchmark are implemented.

Creation

Build fresh metadata entries from host-provided values through a transactional, bounded logical-field request that produces a finalized canonical portable-XMP store.

Medium-high, about 70-75%; the v1 C++ contract, common descriptive/capture fields, UTF-8/XML and typed-value validation, resource limits, deterministic collection ordering, portable serialization, semantic-query visibility, and thin Python wrapper are implemented.

Editing

Modify existing logical metadata entries while preserving valid surrounding structure.

Medium-high, about 75-80%; the v1 logical add/set/remove transaction, deterministic occurrence handling, singleton conflict repair, dirty/tombstone behavior, provenance preservation, portable serialization, transfer visibility, and immutable thin Python wrapper are implemented.

Transfer

Move metadata between files using explicit compatible-file or rendered-image safety policies.

Medium-high, about 80-85%.

Translation

Project metadata between families, mainly bounded EXIF/IPTC/XMP portable mappings.

Medium, about 60-70%.

Writing

Serialize metadata and write or rewrite it into target containers.

Medium, about 65-75%.

Adapters

Thin integration layers for host APIs or format-specific ecosystems such as EXR, DNG SDK, LibRaw orientation mapping, and flat host exports.

Medium, about 60-70%.

Utilities

Small standalone helpers such as capability queries, compatibility dumps, safety audits, tag-name lookup, version-value formatting, and orientation conversion.

Medium, about 65-75%.

These measured interpretation and query values use explicit target sets. Fuzzy Search is not included in the 99.77% Query audit; its readiness is a separate architectural estimate. Unknown private numeric IDs and intentionally opaque payloads are tracked separately rather than counted as failed semantics. The remaining measured tail is primarily malformed, undefined, or incomplete metadata. Decoding retains a 98-100% range because not every declared container lane has an independent conformance sample set, even though tracked inputs have explicit read outcomes.

The first Creation and Editing milestones are implemented in and , with their contracts documented in `creation.md` and `editing.md`. The active implementation sequence now advances to Transfer, Translation, and Writing. Creation and Editing resume for arbitrary/custom properties, multilingual alternatives, structured values, direct family projection, structural block operations, and broader cross-family synchronization. Adapters and Utilities remain deferred. Fuzzy Search resumes before those final two stages for independently sourced quality expansion, designed Unicode/transliteration behavior, multilingual gates, and an optional immutable index for repeated searches over large stores.

Query results should expose both inspection-level matches and interpreted candidates. A crop query, for example, may match separate DefaultCropOrigin and DefaultCropSize tags, an ActiveArea rectangle, vendor margin fields, or a raw integer array. OpenMeta should return the source entries, confidence, value shape, match provenance, and any normalized interpretation rather than hiding ambiguity behind a single value.

The first experimental C++ query surface is openmeta/metadata_query.h. It returns both raw matches and normalized candidates for crop/active-area, exposure/gain, white balance, color/profile, lens correction, orientation, descriptive, and RAW-processing queries. Crop queries include DNG crop tags, ActiveArea, Phase One/Leaf raw geometry, Fujifilm RAF raw crop/zoom rectangles, Canon aspect/crop metadata, Nikon Capture crop bounds, Sony panorama crop margins, and crop/border-style XMP property paths. The non-crop queries expose per-entry value candidates and reuse standard tag names, selected DNG tags, matching XMP paths, canonical border-margin parsing, and vendor RAW-processing classification where applicable. They also append grouped candidates for related DNG color matrix/calibration/ reduction/forward matrix tags, DNG white-balance vector tags, and lens-correction table groups. Color queries expose a distinct color_profile semantic for EXIF color-space evidence, ICC header/tag entries, XMP ICC/profile/color-space fields, and PNG profile text carriers. Vendor-classified MakerNote/RAW fields can also form per-family grouped candidates for white balance, color, raw-storage, sensor, computational, thermal, stitch/panorama, source-processing, raw value curve, linearity-limit, calibration-curve, and curve-control-point records. RAW-processing queries add conservative groups for black/white levels, linearization tables, RAW value curves, RAW linearity limits, RAW calibration curves, RAW curve control points, CFA/sensor layout, source geometry, raw-storage identifiers, and source-private processing buckets. Exposure/gain concept resolution promotes exposure time, aperture, ISO, exposure bias, exposure program/mode, gain, and raw exposure-adjustment records into host-visible roles, with raw exposure adjustments kept unsafe for rendered targets. Standard EXIF exposure program/mode and gain-control values and selected Canon/Nikon/Sony/Fujifilm/Pentax/Olympus/Panasonic/Phase One/Kodak/ Minolta/Sigma/Samsung/Ricoh/Apple/FLIR/JVC/GE/Reconyx/Microsoft/Nintendo/ Sanyo MakerNote scalar print conversions are exposed as bounded labels when a stable enum mapping is available. Version/firmware-like fields use exif_tag_numeric_value_format(...) and exif_tag_byte_value_format(...) instead of enum-label lookup where the value is a formatted payload rather than a closed numeric choice. Current source-private aliases include camera-to-XYZ/RGB matrices, creative and picture styles, film simulation, dynamic-range processing, optical/lens correction, white-balance gains, and raw-development terms. Grouped candidates use matrix_set, vector_set, and table value shapes. Color matrix sets, white-balance vector sets, and lens-correction tables are promoted only when the numeric payloads meet conservative minimum shapes; other records stay visible as per-entry matches/candidates. Semantic Query always uses deterministic tag, namespace, and name matching so similar names cannot change classification. Raw matches retain exact_match, fuzzy_match, and fuzzy_score compatibility fields, but tolerant free-text ranking belongs to the separate Fuzzy Search API. Python Document and TransferSourceSnapshot mirror this as thin wrappers returning the same match/candidate dictionary shape.

Fuzzy Search is a separate optional stage layered over Query. See `fuzzy_search.md` for its complete text, ranking, resource, threading, quality, and benchmark contracts. The openmeta/metadata_fuzzy_search.h API searches decoded entry names and property paths with caller-selected score and result bounds. Results are ordered by descending score, then exact/alias/fuzzy provenance, then stable entry id. Search is locale-independent and currently accepts ASCII query text only; non-ASCII queries return an explicit unsupported status rather than performing byte-wise similarity or implicit transliteration. The curated quality gate covers common spelling errors, aliases, metadata-like adversarial negative queries, deterministic top-k truncation, deleted-entry filtering, and ASCII/UTF-8 boundary behavior. An opt-in benchmark confirms linear scaling and supports keeping the scan path for ordinary per-image stores; a reusable immutable index remains deferred for repeated GUI queries or aggregated stores. Builds without RapidFuzz retain exact and semantic Query behavior.

For code that wants an iterable semantic record stream instead of raw query matches, use openmeta/metadata_interpretation.h. It projects query candidates into records with query class, semantic kind, normalized shape, confidence, source entries, and normalized geometry/value arrays where available.

For cross-family duplicated concepts, use openmeta/metadata_concepts.h. It currently resolves orientation, date/time, exposure/gain, color/profile, GPS, descriptive fields, geometry, lens-correction, and RAW-processing into candidate lists with candidate source entries, source families, preferred entries, normalized compare keys, parsed date/time fields, date/time precision, timezone kind, GPS altitude-reference state, distinct destination/shown/created coordinate roles, structured-location scope, normalized descriptive language, additive collection preference, structured record kinds and scopes for editorial, rights, license, release, end-user, image-creator, image-supplier, and image-asset, controlled-vocabulary, registry, image-region, resource-reference, resource-event, technical-image, audio-asset, preview-asset, pantry, and pantry-nested standard XMP MM records, independent policy sensitivity, canonical geometry origin/size/rect/margins, normalized exposure values, full normalized value vectors for grouped matrix/vector/table records, transfer hints, compatible and rendered safety booleans, and same-role conflict flags. This is deliberately an inspection/policy surface; host code still decides whether a conflict should be shown, ignored, or corrected during editing/transfer.

Build Prerequisites

  • CMake >= 3.20

  • A C++20 compiler (Clang is recommended; fuzzing requires Clang)

  • Optional: Ninja (-G Ninja)

OpenMeta discovers optional dependencies via find_package(...). If you install deps into a custom prefix, pass it via CMAKE_PREFIX_PATH (example: -DCMAKE_PREFIX_PATH=/mnt/f/UBSd).

Optional Dependencies (Why They Exist)

OpenMeta’s core scanning and EXIF/TIFF decoding do not require third-party libraries. Some metadata payloads are compressed or structured; these optional dependencies let OpenMeta decode more content:

  • Expat (OPENMETA_WITH_EXPAT): parses XMP RDF/XML packets (embedded blocks and .xmp sidecars). Expat is used as a streaming parser so OpenMeta can enforce strict limits and avoid building a full XML DOM from untrusted input.

  • RapidFuzz (OPENMETA_ENABLE_RAPIDFUZZ): opt-in bounded fuzzy entry search for inspection UI. It is disabled by default; when enabled, CMake requires either a rapidfuzz::rapidfuzz package target or OPENMETA_RAPIDFUZZ_INCLUDE_DIR pointing at headers containing rapidfuzz/fuzz.hpp.

  • zlib (OPENMETA_WITH_ZLIB): inflates Deflate-compressed payloads, including PNG iCCP (ICC profiles) and compressed text/XMP chunks (iTXt, zTXt).

  • Brotli (OPENMETA_WITH_BROTLI): decompresses JPEG XL brob

    ”compressed

    metadata” boxes so wrapped metadata payloads can be decoded.

  • Draft C2PA verify scaffold (OPENMETA_ENABLE_C2PA_VERIFY, OPENMETA_C2PA_VERIFY_BACKEND): enables backend selection/reporting fields (none|auto|native|openssl) and draft verification flow. Native backend availability is platform-based (Windows/macOS), while OpenSSL availability is discovered via find_package(OpenSSL) when needed. Current results are diagnostic only: cryptographic signature success is reported as signature_verified_only and does not establish asset hard binding. Do not use this scaffold as an authenticity or trust gate.

If you link against dependencies that were built with libc++ (common when using Clang), configure OpenMeta with:

-DOPENMETA_USE_LIBCXX=ON

When CTest launches external validation tools from the same dependency prefix, those tools must also be able to find their matching C++ runtime libraries. If the runtime is not discoverable through the system loader, pass an explicit runtime directory:

-DOPENMETA_TEST_RUNTIME_LIBRARY_PATH=/path/to/runtime-libs

Versioning

VERSION is the single source of truth for the project version:

  • CMake reads VERSION and sets PROJECT_VERSION.

  • The Python wheel version is derived from VERSION (via scikit-build-core metadata).

CLI Tools

metavalidate checks decode-status health and DNG/CCM validation:

#Basic validation
./build/metavalidate input.dng

#Strict mode : warnings fail the file
./build/metavalidate --strict input.dng

#Machine - readable JSON output
./build/metavalidate --json input.dng

#Validate with sidecar + MakerNotes + C2PA verify status
./build/metavalidate --xmp-sidecar --makernotes --c2pa-verify input.jpg

#Exercise the draft trusted-chain diagnostic (not an authenticity gate)
./build/metavalidate --c2pa-verify --c2pa-verify-require-trusted-chain input.jpg
metavalidate CLI is a thin wrapper over openmeta::validate_file(...). Machine-readable JSON output includes issue codes suitable for gating, for example xmp/output_truncated and xmp/invalid_or_malformed_xml_text.

metadump is the general dump/save tool:

#Lossless sidecar
./build/metadump --format lossless input.jpg output.xmp

#Portable sidecar
./build/metadump --format portable --portable-include-existing-xmp input.jpg output.xmp

#Portable sidecar with ExifTool GPS time alias compatibility
./build/metadump --format portable --portable-exiftool-gpsdatetime-alias input.jpg output.xmp

#Portable sidecar + draft C2PA verify scaffold status reporting
./build/metadump --format portable --c2pa-verify --c2pa-verify-backend auto input.jpg output.xmp

#Portable sidecar with the draft trusted-chain diagnostic enabled
./build/metadump --format portable --c2pa-verify --c2pa-verify-require-trusted-chain input.jpg output.xmp

#Explicit input / output form
./build/metadump -i input.jpg -o output.xmp

#Extract first embedded preview
./build/metadump --extract-preview --first-only input.jpg preview.jpg

#If multiple previews exist, --out gets auto - suffixed:
#preview_1.jpg, preview_2.jpg, ...
./build/metadump --extract-preview input.arq preview.jpg

Portable sidecar note:

  • exif:GPSTimeStamp is emitted as XMP date-time text (YYYY-MM-DDThh:mm:ssZ) only when GPSDateStamp is available; otherwise it is skipped.

  • Compatibility mode --portable-exiftool-gpsdatetime-alias emits exif:GPSDateTime instead of exif:GPSTimeStamp.

  • Portable IPTC-IIM mapping covers dc:* plus selected photoshop:* and Iptc4xmpCore:* fields (for example city/state/country/headline/credit and location/country-code).

metatransfer is a transfer smoke tool for JPEG/TIFF packaging:

#read -> prepare -> emit simulation
./build/metatransfer input.jpg

#Portable vs lossless transfer-prepared XMP block
./build/metatransfer --format portable input.jpg
./build/metatransfer --format lossless input.jpg

#Write prepared payload bytes for inspection
./build/metatransfer --unsafe-write-payloads --out-dir payloads input.jpg

#Prepare once, emit many times (same bundle)
./build/metatransfer --emit-repeat 100 input.jpg

#Patch prepared EXIF time fields before emit
./build/metatransfer --time-patch DateTimeOriginal="2026:03:06 12:34:56" input.jpg

#Select explicit transfer policy for raw-sensitive families
./build/metatransfer --makernote-policy keep --jumbf-policy drop --c2pa-policy drop input.jpg

#Emit a draft unsigned C2PA invalidation payload for JPEG output
./build/metatransfer --no-exif --no-xmp --no-icc --no-iptc \
  --c2pa-policy invalidate input_with_c2pa.jpg

#Append one logical raw JUMBF payload into a prepared JPEG bundle
./build/metatransfer --no-exif --no-xmp --no-icc --no-iptc \
  --jpeg-jumbf payload.jumbf input.jpg

#Stage externally signed logical C2PA into a JPEG rewrite flow
./build/metatransfer --no-exif --no-xmp --no-icc --no-iptc \
  --jpeg-c2pa-signed signed_c2pa.jumb \
  --c2pa-manifest-output manifest.bin \
  --c2pa-certificate-chain chain.bin \
  --c2pa-key-ref signer-key \
  --c2pa-signing-time 2026-03-09T00:00:00Z \
  -o output.jpg input_with_c2pa.jpg

#Persist the semantic transfer payload batch for cross-process handoff
./build/metatransfer --dump-transfer-payload-batch payloads.omtpld input.jpg

#Load and inspect one persisted semantic transfer payload batch
./build/metatransfer --load-transfer-payload-batch payloads.omtpld

#Persist one final transfer package batch
./build/metatransfer --dump-transfer-package-batch package.omtpkg input.jpg

#Load and inspect one persisted final transfer package batch
./build/metatransfer --load-transfer-package-batch package.omtpkg

#Plan edit strategy without writing output
./build/metatransfer --mode auto --dry-run input.jpg

#Write edited JPEG output (metadata rewrite mode)
./build/metatransfer --mode metadata_rewrite -o output.jpg input.jpg

#Use separate metadata source and JPEG target stream
./build/metatransfer \
  --source-meta source.tif \
  --target-jpeg target.jpg \
  --mode metadata_rewrite \
  -o injected.jpg

#Use separate metadata source and TIFF target stream
./build/metatransfer \
  --source-meta source.jpg \
  --target-tiff target.tif \
  -o injected.tif

#Inject target-owned image facts when source and output pixels differ
./build/metatransfer \
  --target-jpeg target.jpg \
  --target-width 320 --target-height 240 \
  --target-samples-per-pixel 3 --target-bits-per-sample 8 \
  --target-photometric 2 --target-exif-color-space 1 \
  -o injected.jpg source.jpg

metatransfer is a thin CLI wrapper over the public transfer APIs. It uses prepare_metadata_for_target_file(...) for source read/decode plus execute_prepared_transfer(...) for time patching, route compile/emit, and optional JPEG/TIFF edit plan/apply. When --jpeg-jumbf is used, the CLI also calls append_prepared_bundle_jpeg_jumbf(...) before execute. The core also exposes compile_prepared_transfer_execution(...) plus execute_prepared_transfer_compiled(...) for prepare once -> compile once -> patch/emit many workflows. When -o is used, the CLI passes a TransferByteWriter sink into the shared execution path so edited output can stream directly to disk instead of always materializing a full output buffer. The --target-width, --target-height, --target-orientation, --target-samples-per-pixel, --target-bits-per-sample, --target-sample-format, --target-photometric, --target-planar-configuration, --target-compression, and --target-exif-color-space flags populate PrepareTransferRequest::target_image_spec. Current v1 behavior is:

  • JPEG edit output is streamed directly from the shared core path.

  • JPEG metadata-only emit can also stream marker bytes directly through the shared core API.

    • TIFF edit output uses the same sink API and only buffers the appended metadata tail; it no longer materializes a second full-file output buffer.

    • JPEG XL prepare/emit now shares the same transfer contract for backend emitter use:

      • prepare_metadata_for_target(..., TransferTargetFormat::Jxl, ...) currently builds Exif, xml, and bounded jumb box payloads plus the encoder ICC profile from MetaStore

      • compile_prepared_bundle_jxl(...) and emit_prepared_bundle_jxl_compiled(...) provide the same prepare once -> compile once -> emit many shape as JPEG/TIFF

      • execute_prepared_transfer(...) and emit_prepared_transfer_compiled(..., JxlTransferEmitter&) now accept JXL bundles

      • jxl:icc-profile is emitted through JxlTransferEmitter::set_icc_profile(...) and stays separate from the JXL box path

      • file-based prepare can preserve source generic JUMBF payloads and raw OpenMeta draft C2PA invalidation payloads as JXL boxes

      • store-only prepare can project decoded non-C2PA JumbfCborKey roots into generic JXL jumb boxes when no raw source payload is available

      • IPTC requested for JXL is projected into the existing xml XMP box; OpenMeta does not create a raw IPTC-IIM JXL carrier

      • build_prepared_jxl_encoder_handoff_view(...) is the explicit encoder-side ICC handoff contract for JXL, and build_prepared_jxl_encoder_handoff(...) / serialize_prepared_jxl_encoder_handoff(...) add an owned persisted handoff object for cross-process reuse: at most one prepared jxl:icc-profile payload plus the remaining JXL box counts

      • inspect_prepared_transfer_artifact(...) is now the shared inspect entry point across persisted transfer artifacts: payload batches, package batches, persisted C2PA handoff/signed packages, and persisted JXL encoder handoffs

      • the JXL compile/emit path now rejects multiple prepared ICC profiles so the encoder handoff and backend execution contracts match

      • build_prepared_transfer_emit_package(...) plus write_prepared_transfer_package(...) can serialize direct JXL box bytes from prepared bundles, and build_prepared_transfer_package_batch(...) can materialize those bytes into one owned replay batch

      • bounded JXL file edit now uses the same package layer: it preserves the signature and non-managed top-level boxes, replaces only the metadata families present in the prepared bundle, and appends the prepared JXL boxes to an existing JXL container file

      • unrelated source JXL metadata boxes are preserved, and uncompressed source jumb boxes are distinguished as generic JUMBF vs C2PA for that replacement decision

      • when Brotli support is available, the same distinction is applied to compressed brob(realtype=jumb) source boxes before deciding whether to preserve or replace them

      • the package writer remains box-only, so it still rejects jxl:icc-profile; ICC remains encoder-only on JXL

      • CLI/Python metatransfer wrappers now expose this bounded edit path through --target-jxl ... --source-meta ... --output ... when the prepared bundle does not require jxl:icc-profile

      • JXL transfer now supports generated draft C2PA invalidation for content-bound source payloads, plus the bounded external-signer path: sign-request derivation, binding-byte materialization, signed-payload validation, staged jxl:box-jumb apply, and bounded file-helper edit execution

    • WebP prepare/emit now uses the same bounded transfer contract:

      • prepare_metadata_for_target(..., TransferTargetFormat::Webp, ...) currently builds EXIF, XMP, ICCP, and bounded C2PA RIFF metadata chunks from MetaStore

      • WebP EXIF chunk payloads contain direct TIFF bytes and intentionally omit the JPEG APP1 Exif\0\0 preamble

      • compile_prepared_bundle_webp(...) and emit_prepared_bundle_webp_compiled(...) provide the same prepare once -> compile once -> emit many shape as JPEG/TIFF/JXL

      • execute_prepared_transfer(...) and emit_prepared_transfer_compiled(..., WebpTransferEmitter&) now accept WebP bundles

      • IPTC requested for WebP is projected into the existing XMP chunk; OpenMeta does not create a raw IPTC-IIM WebP carrier

      • draft OpenMeta invalidation payloads and generated invalidation output use the C2PA RIFF chunk path

      • build_prepared_transfer_emit_package(...) plus write_prepared_transfer_package(...) can serialize direct WebP chunk bytes from prepared bundles, and build_prepared_transfer_package_batch(...) can materialize those bytes into one owned replay batch

      • full WebP signed C2PA rewrite remains follow-up work

    • ISO-BMFF metadata-item transfer now uses the same bounded contract for HEIF / AVIF / CR3 targets:

      • prepare_metadata_for_target(..., TransferTargetFormat::{Heif,Avif,Cr3}, ...) currently builds bmff:item-exif, bmff:item-xmp, bounded bmff:item-jumb, bounded bmff:item-c2pa, and bmff:property-colr-icc payloads

      • EXIF is prepared as a BMFF item payload with the 4-byte big-endian TIFF-offset prefix plus full Exif\0\0 bytes

      • IPTC requested for BMFF is projected into bmff:item-xmp; OpenMeta does not create a raw IPTC-IIM BMFF carrier

      • ICC requested for BMFF uses the bounded property path: bmff:property-colr-icc carries u32be(‘prof) + <icc-profile>as the payload bytes for acolrproperty, not a BMFF metadata item

      • file-based prepare can preserve source generic JUMBF payloads and raw OpenMeta draft C2PA invalidation payloads as BMFF metadata items

      • store-only prepare can project decoded non-C2PAJumbfCborKeyroots intobmff:item-jumbwhen no raw source payload is available -compile_prepared_bundle_bmff(…), emit_prepared_bundle_bmff(…), emit_prepared_bundle_bmff_compiled(…), and emit_prepared_transfer_compiled(…, BmffTransferEmitter&)provide the reusable item/property-emitter path

      • the shared package-batch persistence/replay layer can own and hand off those stable BMFF item and property payload bytes

      • OpenMeta also supports a bounded BMFF edit path for targets without a foreign top-levelmetabox, or with a prior OpenMeta-authored metadata-onlymetabox from the same bounded contract. It preserves non-metatop-level BMFF boxes and replaces the OpenMeta-authored metadata-onlymetabox with the prepared BMFF items/properties.

      • For targets with a parseable foreign top-levelmetabox, OpenMeta can merge, replace, or strip bounded Exif/XMP/JUMBF/C2PA items by extending iinf,iloc,idat, andirefwithcdscreferences to the primary item. This path requires a single parseableiinf,ilocversion 0/1/2,pitm, and at most oneidat. Inserted item IDs can use the 32-bit item-id space: supportedilocversion 0/1 graphs are upgraded to outputilocversion 2 when needed, and OpenMeta emits wider infe/irefrecords for inserted items that exceed 16 bits. Retained foreign item locations support construction method 0 file offsets and construction method 1idatextents with data reference index 0. Retained construction method 2 item-reference extents are supported when irefilocreferences are parseable by explicit extent index or reference order and referenced items are also retained with supported local locations; missing references, removed referenced items, external data references, and other construction methods fail safely. Bounded ICC transfer removes prior ICCcolr/profandcolr/rICC properties fromiprp/ipco, compacts/remaps existingipma associations, appends the transferredcolr/profproperty, and associates it with the primary item and any retained item that previously referenced a replaced ICC property while preserving the prior essential association bit. Arbitrary BMFF scene/property graph rewrite remains unsupported.

      • CLI/Pythonmetatransferwrappers expose both BMFF summaries and this bounded edit path;&#8212;target-heif,&#8212;target-avif, and&#8212;target-cr3 now accept&#8212;source-meta PATHplus&#8212;output PATHfor metadata transfer onto an existing BMFF target file

      • the same bounded BMFF edit contract now also participates in the core / file-helper C2PA signer path: build_prepared_c2pa_sign_request(…), build_prepared_c2pa_sign_request_binding(…), validate_prepared_c2pa_sign_result(…), and apply_prepared_c2pa_sign_result(…)can reconstruct rewrite binding from preserved source ranges plus one prepared metadata-onlymetabox and can stage validated signed logical C2PA back asbmff:item-c2pa before bounded BMFF edit

      • CLI/Python signer-input options now support JPEG, JXL, and bounded BMFF targets; the legacy option name&#8212;jpeg-c2pa-signedis kept for compatibility even when the target is JXL or BMFF -TransferProfilenow uses explicitTransferPolicyActionvalues for makernote,jumbf, andc2pa. -PreparedTransferBundle::policy_decisionsrecords the resolved per-family transfer decision during prepare.

    • CLI and Python transfer probes now expose those resolved policy decisions directly, and JPEG edit plans report how many existing APP11 JUMBF/C2PA segments will be removed during rewrite.

    • C2PA decisions now expose three explicit fields: -TransferC2paMode -TransferC2paSourceKind -TransferC2paPreparedOutput so callers can tell whether prepare saw decoded-only C2PA, content-bound raw C2PA, or a raw draft invalidation payload, and whether the prepared output was dropped, preserved raw, or generated as a draft invalidation. -PreparedTransferBundle::c2pa_rewriteis the future-facing signer contract forc2pa=rewrite.

Resource Budgets (Draft)

Code Organization (EXIF + MakerNotes)

Tests (GoogleTest)

libFuzzer Targets

Corpus runs (seed corpora)

FuzzTest

Python (nanobind)

Python Wheel

Interop Surfaces

Doxygen (Optional)

Sphinx Docs (Optional)

page Documentation

OpenMeta uses Doxygen for API extraction. For the published site docs, we render Doxygen XML via Sphinx + Breathe.

Requirements

  • doxygen (optional: graphviz for diagrams)

  • For Sphinx docs: Python packages listed in docs/requirements.txt

Generate API docs (CMake)

Enable docs and build:

cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DOPENMETA_BUILD_DOCS=ON
cmake --build build --target openmeta_docs

Output goes to build/docs/doxygen/html/index.html inside the build directory.

When OPENMETA_BUILD_DOCS=ON, docs are also generated during install:

cmake --build build --target install

Generate site docs (Sphinx)

Enable Sphinx docs and build:

cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DOPENMETA_BUILD_SPHINX_DOCS=ON
cmake --build build --target openmeta_docs_sphinx

Output goes to build/docs/html/index.html. Doxygen XML goes to build/docs/doxygen/xml/index.xml.

Publish on GitHub Pages

The repository includes a GitHub Actions workflow at .github/workflows/docs-pages.yml that builds the Sphinx site and publishes it to GitHub Pages.

Recommended setup:

  • In the repository settings, set Pages to GitHub Actions as the source. This is a one-time repository setting.

  • Pull requests build the docs but do not deploy.

  • Pushes to main and tag pushes build and deploy the site.

The workflow only runs when docs inputs change: docs/**, src/include/**, README.md, SECURITY.md, NOTICE.md, CMakeLists.txt, or the workflow itself.

Generate API docs (manual)

From the OpenMeta/ repo root:

doxygen docs/Doxyfile

Output goes to build/docs/doxygen/html/index.html.

What gets documented

  • Markdown: README.md is used as the main page.

  • Public API: everything under src/include/openmeta/.

If you add new public headers or APIs, prefer documenting at the header or type/function level so the docs stay accurate as code moves.

page Metadata Editing

openmeta/metadata_editing.h provides a bounded transactional editing contract for the same logical fields accepted by the high-level Creation API. It edits canonical portable-XMP entries in a finalized MetaStore without requiring a host to work with namespace paths or entry IDs.

The API is experimental and versioned by kMetadataEditingContractVersion == 1.

C++ Example

#include "openmeta/metadata_editing.h"

#include <array>

const std::array operations = {
    openmeta::make_metadata_edit_set(
        openmeta::make_metadata_creation_text(
            openmeta::MetadataCreationFieldKind::Title, "Edited title")),
    openmeta::make_metadata_edit_add(
        openmeta::make_metadata_creation_text(
            openmeta::MetadataCreationFieldKind::Keyword, "approved")),
    openmeta::make_metadata_edit_remove(
        openmeta::MetadataCreationFieldKind::Creator, 0),
};

openmeta::MetadataEditingRequest request;
request.operations = operations;

openmeta::MetaStore edited;
const openmeta::MetadataEditingResult result =
    openmeta::edit_metadata(source, request, &edited);

source must be finalized. The output is replaced only after every operation has passed validation and the entire edit has committed. On failure, edited is unchanged and failed_operation_index identifies the rejected operation when available.

Operation Semantics

Operation

Behavior

Add

Creates an absent singleton or appends a creator/keyword value. Adding an existing singleton is an explicit conflict.

Set

Replaces one active value. Existing key, origin, block, wire provenance, and flags are preserved; Dirty is added.

| Remove | Marks one active value as Deleted | Dirty. The tombstone remains available for writeback and audit behavior. | | RemoveAll | Tombstones every active occurrence. This can repair malformed duplicate singleton fields before a new value is added in the same transaction. |

Operations observe earlier operations in request order. For repeated creators and keywords, occurrence is a zero-based index into the current active logical values. Removing an occurrence shifts later values for subsequent operations. New repeated values receive the next unused canonical property index; existing index gaps are not renumbered.

Singleton fields accept only occurrence zero. If a malformed store contains multiple active copies, single-value Set and Remove return AmbiguousTarget; use RemoveAll followed by Add when that repair is intended. Missing targets are errors rather than silent no-ops.

Provenance And Blocks

Set changes only the value and dirty flag. Remove changes only entry flags. Both therefore retain the original block and wire provenance.

Add emits a new dirty canonical portable-XMP entry. When the store already contains an XMP entry with a valid block, the new entry uses that block and a later deterministic order. A finalized empty store can also be edited; its new entry has no source block because no original carrier exists. Portable XMP and transfer preparation can serialize that entry normally.

Editing does not compact tombstones automatically. Call the lower-level compact(...) helper only when losing deleted-entry identity is appropriate for the host workflow.

Validation And Limits

Add and Set use exactly the Creation field mapping and value validation. Text must be non-empty valid UTF-8 and XML 1.0 character data. Orientation, rating, dimensions, color space, ISO, and rational values use the constraints documented in creation.md.

The hard maxima are:

  • 1024 operations

  • 1 MiB of UTF-8 text per Add or Set operation

  • 8 MiB of UTF-8 text per request

MetadataEditingRequest::limits may lower but not raise these bounds. The implementation keeps no global state. Concurrent calls are safe when callers use distinct output stores and do not mutate the finalized source.

Python

Python operation objects own their text and pass the same request to C++:

import openmeta

K = openmeta.MetadataCreationFieldKind
edited = document.edit_metadata([
    openmeta.metadata_edit_set(
        openmeta.metadata_creation_text(K.Title, "Edited title")),
    openmeta.metadata_edit_add(
        openmeta.metadata_creation_text(K.Keyword, "approved")),
    openmeta.metadata_edit_remove(K.Creator, 0),
])

The method returns a detached edited Document; the original document is not mutated. The result can be queried, dumped as XMP, or converted into a transfer snapshot. Invalid requests raise ValueError with the C++ status and rejected operation index.

Current Scope

This milestone edits the 24 logical fields listed in creation.md. It does not yet provide high-level arbitrary EXIF/IPTC/XMP/custom-key operations, language-alternative selection beyond x-default, structural block editing, a full EXIF/IPTC/XMP synchronization engine, or direct in-place file patching. Lower-level MetaEdit remains available for entry-ID-based host code, while transfer and writer APIs handle container persistence.

page FlatHost Mapping Contract

ExportNameStyle::FlatHost is the stable v1 naming contract for host-owned metadata object models that prefer flat attribute names over OpenMeta’s native key shapes.

Contract constant:

openmeta::kFlatHostExportContractVersion == 1

Scope

The contract covers names emitted by:

openmeta::visit_metadata(store, options, sink)

with:

options.style = openmeta::ExportNameStyle::FlatHost;

Python mirrors this name contract through:

doc.export_names(style=openmeta.ExportNameStyle.FlatHost)

The C++ traversal exposes ExportItem::entry, so C++ hosts can project values from the original Entry::value. Python export_names(...) is name-only.

Typed writeback is available through import_flat_host_metadata(...). It is transactional and returns a detached finalized store; it does not mutate the source store.

Ordering And Duplicates

  • Entries are emitted in MetaStore::entries() order.

  • Deleted entries are skipped.

  • Duplicate names are preserved and emitted separately.

  • OpenMeta does not merge, reconcile, or suffix duplicate FlatHost names.

  • If a host requires unique keys, it must apply its own deterministic collision policy after traversal.

  • Name-based import succeeds only for a unique exported name. A host that must update one duplicate retains the source EntryId and imports by identity.

Value Projection

FlatHost is a naming contract, not a value-conversion contract.

  • C++ receives the original Entry through ExportItem::entry.

  • Entry::value.kind, elem_type, count, and storage are unchanged.

  • Text encoding remains the original decoded TextEncoding.

  • Byte payloads remain byte payloads; unsafe text conversion is not performed by visit_metadata(...).

  • Hosts that need a text-only export should use a safe formatting layer on top of Entry::value.

Namespace Behavior

FlatHost intentionally keeps common camera-style names short while preserving namespace prefixes where ambiguity matters.

Source family

FlatHost rule

TIFF root and preview IFD tags

Use the known tag alias without a prefix, for example Make, ModifyDate, ImageWidth.

EXIF and interoperability IFD tags

Prefix with Exif:, for example Exif:ExposureTime, Exif:ISO, Exif:CreateDate.

GPS IFD tags

Prefix with GPS:, for example GPS:GPSLatitude.

MakerNote IFDs

Emit only when include_makernotes is true, using MakerNote:<ifd>:<tag-name-or-hex>.

XMP simple properties

Emit selected known namespaces as XMP:, TIFF:, Exif:, or DC: plus the simple property name.

ICC header fields and tags

Emit ICC:<field> or ICC:tag:<signature>.

EXR part 0 known aliases

Map selected standard attributes to common host names, for example owner -> Copyright, capDate -> DateTime, expTime -> ExposureTime.

EXR part 0 unknown attributes

Emit openexr:<name>.

EXR non-zero parts

Emit openexr:part:<index>:<name>.

Unsupported key families

Fall back to the canonical OpenMeta name when one exists.

Complex XMP paths are not flattened. XMP properties are emitted only when the property path is a simple token containing letters, digits, _, or -; paths with /, [, ], or other punctuation are skipped by FlatHost.

Name Policy

ExportOptions::name_policy controls tag aliasing:

  • ExportNamePolicy::ExifToolAlias is the default and uses OpenMeta’s ExifTool-compatible aliases where OpenMeta has a clean-room mapping.

  • ExportNamePolicy::Spec preserves native/spec-style tag names where available and uses Tag_0x.... for unknown EXIF tags.

The policy does not change ordering, duplicate preservation, or value projection.

Typed Import

FlatHost names are lossy and are not parsed back into arbitrary keys.

  • FlatHostImportTarget::SourceEntry verifies the original EntryId and its exported name before replacing the typed value.

  • FlatHostImportTarget::UniqueName resolves exactly one exported name and rejects missing or duplicate matches.

  • FlatHostImportTarget::ExplicitKey appends a new entry from a caller-supplied MetaKeyView. This is the path for custom XMP and metadata that did not exist in the source store.

  • FlatHostImportTarget::RemoveSourceEntry and RemoveUniqueName retain the matching source entry as a Dirty | Deleted tombstone. The request value must be empty. Stable entry ids, provenance, and snapshot raw-carrier links are preserved while export, lookup, and transfer omit the deleted value.

  • Values retain scalar/array/bytes/text kind, element type, count, and text encoding. Byte arrays are never converted to text implicitly.

  • One import cannot update and remove the same source entry twice. Duplicate targets fail the complete transaction without changing the source.

  • Import uses local state and is safe to call concurrently against an immutable finalized source store.

Filtering

FlatHost skips:

  • deleted entries

  • EXIF pointer tags under the default alias policy

  • embedded metadata blob tags such as EXIF-stored XMP, ICC, IPTC, Photoshop IRB, and MakerNote blob tags under the default alias policy

  • MakerNote IFDs when include_makernotes is false

  • complex XMP paths and unknown XMP namespaces

  • selected structural EXR header attributes that are not useful as host metadata attributes, such as channels, compression, and data windows

Stability

This is a stable v1 naming contract. Future OpenMeta releases may add mappings for newly decoded metadata families, but existing v1 names should not change without a new contract version or a documented compatibility path.

page Fuzzy Search

Fuzzy Search is an optional inspection layer over decoded metadata entry names and property paths. It is separate from Semantic Query: fuzzy ranking helps a person find likely fields, but it never changes metadata interpretation.

Enable it with:

cmake -S . -B build \
  -DOPENMETA_ENABLE_RAPIDFUZZ=ON \
  -DCMAKE_PREFIX_PATH=/path/to/rapidfuzz/prefix

The public entry point is fuzzy_search_metadata(...) in openmeta/metadata_fuzzy_search.h. Python exposes the same bounded operation through Document.fuzzy_search(...) and TransferSourceSnapshot.fuzzy_search(...).

Ranking Contract

Results use deterministic ordering:

  1. Higher score.

  2. Exact, alias, then general fuzzy provenance.

  3. Lower stable entry ID.

Exact normalized phrases score 100. Exact curated aliases score 96. Misspelled curated aliases use whole-phrase and per-token edit similarity and score at most 95; this prevents a shared word such as sensor or rectangle from making an unrelated phrase look like a known alias. General candidate matching uses RapidFuzz weighted and token similarity.

The default minimum score is 80. Hosts should expose the score and provenance instead of presenting a fuzzy result as an exact metadata meaning.

Text Contract

The current contract is locale-independent ASCII:

  • ASCII case is folded.

  • Punctuation and separators collapse to spaces.

  • Camel-case and acronym-to-word boundaries are split, so GPSLatitude becomes gps latitude.

  • Non-ASCII query bytes return UnsupportedQueryText.

  • Non-ASCII bytes in candidate names act as separators. Searchable ASCII fragments remain visible, but OpenMeta does not claim Unicode equivalence or transliteration.

Unicode normalization, transliteration, and multilingual ranking remain a future milestone. They must not be added as implicit locale-dependent behavior.

Resource And Threading Contract

Query bytes, candidate bytes, and result counts have public hard limits. Deleted entries are skipped and returned name/group strings carry truncation flags. Each call uses only local search state and reads a const MetaStore, so concurrent searches are safe when the finalized store is not being mutated.

The current implementation performs a bounded linear scan. It does not retain references to the store or maintain global caches.

Quality And Performance Gates

The RapidFuzz release gate covers curated spelling errors and aliases across descriptive, capture, geometry, color, RAW-processing, rights, location, and history terminology. It also includes unrelated and metadata-like adversarial negative queries, deterministic top-k behavior, deleted entries, resource bounds, and the ASCII/UTF-8 contract.

Build the informational benchmark with:

cmake -S . -B build-fuzzy-benchmark \
  -DCMAKE_BUILD_TYPE=Release \
  -DOPENMETA_ENABLE_RAPIDFUZZ=ON \
  -DOPENMETA_BUILD_BENCHMARKS=ON
cmake --build build-fuzzy-benchmark \
  --target openmeta_benchmark_fuzzy_search
./build-fuzzy-benchmark/openmeta_benchmark_fuzzy_search

The benchmark validates every result and reports elapsed time, queries per second, and nanoseconds per entry/query. It has no timing pass/fail threshold.

A reference Release/libc++ run measured:

Entries

Approximate time per query

256

2.3 ms

1,024

8.2 ms

4,096

31.7 ms

16,384

129 ms

These values are diagnostic, not a performance guarantee. The near-constant per-entry cost confirms linear scaling.

Indexing Decision

The linear scan remains the default for this milestone. It is simple, bounded, thread-safe for immutable stores, and adequate for ordinary per-image metadata stores and one-off searches.

An immutable reusable index is justified for repeated interactive queries or aggregated stores with many thousands of entries. That work is deferred until Fuzzy Search resumes, before Adapters and Utilities become the active project focus. The index must have explicit ownership, build cost, invalidation rules, memory accounting, and identical deterministic ranking.

Fuzzy Search is considered milestone-ready at about 80-85%. Remaining work is broader independently sourced quality coverage, Unicode/transliteration policy, multilingual ranking gates, and the optional immutable index.

page Host Adoption Profile

Host Adoption Profile v1 is the narrow compatibility boundary for applications that integrate OpenMeta into high-throughput image processing or transcoding. It is host-neutral: the source may be memory, a file handle, a range-backed object, or another synchronous positional I/O service.

The profile separates stable state and I/O contracts from broader transfer implementation details that are still evolving.

Runtime Contract Check

Include openmeta/host_adoption.h and compare the profile compiled into the application with the linked OpenMeta library:

#include "openmeta/host_adoption.h"

if (!openmeta::host_adoption_profile_matches(
        openmeta::kHostAdoptionProfileV1)) {
    // Reject the incompatible OpenMeta runtime before processing assets.
}

HostAdoptionProfile is a trivially copyable, allocation-free version record. It reports API contract versions only. It does not claim that every metadata family is available for every container. Use metadata_capability(...) for format/family support and inspect positional read completeness and diagnostics for each asset.

Stable V1 Boundary

Contract

Stable surface

Positional source

RandomAccessSource, source ranges, caller-owned windows and accounting, exact reads, and kRandomAccessSourceContractVersion

Snapshot read

read_transfer_source_snapshot_random_access(...), its scratch/options/result types, complete(), and kReadTransferSourceSnapshotContractVersion

Read diagnostics

collect_read_transfer_source_diagnostics(...), caller-buffered diagnostic records and names/messages, and kReadTransferSourceDiagnosticsContractVersion

Snapshot state

The decoded-store TransferSourceSnapshot object contract and kTransferSourceSnapshotContractVersion; optional raw-carrier data may be preserved, but passthrough policy is not part of this profile

Snapshot persistence

serialize_transfer_source_snapshot(...), deserialize_transfer_source_snapshot(...), bounded transactional parsing, and canonical wire format v1

Flat host reconciliation

Stable FlatHost + ExportNamePolicy::Spec export names plus typed add/update/remove import, tombstones, transactionality, and kFlatHostImportContractVersion

Codec operation schema

TransferAdapterOpKind, PreparedTransferAdapterOp, explicit target fields, and kPreparedTransferAdapterContractVersion

Breaking any stable v1 shape or semantic requires a new contract version, a compatibility path, or an ABI-major transition. Format support may grow without changing the profile when existing result codes, limits, ownership, ordering, and residual semantics remain compatible.

Supported Reconciliation Sequence

The stable state path is:

  1. Read through read_transfer_source_snapshot_random_access(...).

  2. Require result.complete() when the workflow needs complete metadata, or collect and apply policy to structured diagnostics.

  3. Serialize the snapshot when it must outlive source storage or cross a host object/process boundary.

  4. Deserialize transactionally.

  5. Export FlatHost names with ExportNamePolicy::Spec and retain source entry identities in the host.

  6. Import changed values, explicit typed additions, and removals. Replace the snapshot store only after FlatHostImportResult::ok().

  7. Pass the reconciled snapshot to target preparation.

Import keeps source entry positions stable, represents removals as Dirty | Deleted tombstones, and appends additions. This preserves untouched complex metadata, provenance, duplicate order, and snapshot raw-carrier entry links.

Deliberate Experimental Boundary

Host Adoption Profile v1 does not stabilize:

  • low-level format-specific scan_*_random_access(...), payload extraction, or decoder APIs;

  • file-path, whole-byte-span, or build_transfer_source_snapshot(...) helpers;

  • prepare_metadata_for_target_snapshot(...), PreparedTransferBundle, adapter-view build/validation/emission, or bundle execution;

  • prepared payload/package serialization;

  • raw-carrier passthrough policy or broad byte-preserving carrier transfer.

The typed adapter operation schema is stable so codec integrations do not parse route strings. Its current builders still depend on the experimental prepared bundle model. Hosts using target preparation should pin and test an OpenMeta release until that construction boundary is stabilized separately.

Performance And Concurrency

Positional callbacks are synchronous and must not throw. OpenMeta performs no hidden retry, locking, scheduling, or whole-file materialization in the stable positional read path. Scratch, read windows, limits, and accounting are caller owned. The returned snapshot owns its finalized metadata state.

Independent operations may share an immutable source only when the host sets RandomAccessSource::concurrent_reads and the backing implementation supports concurrent exact reads. Do not share mutable scratch, accounting, import results, prepared bundles, or writers between concurrent operations.

page Host Integration

This guide is for applications that already own the image/container side and want OpenMeta to handle metadata.

OpenMeta is not an image encoder. The usual pattern is:

  • decode metadata from one source file

  • query or edit it in MetaStore

  • hand prepared metadata to your own writer, encoder, or SDK

If you want the shortest end-to-end examples first, start with quick_start.md. For public API adoption status, see api_stability.md. For the narrow stable realtime/transcoding boundary, see host_adoption_profile.md. For the stable flat host naming contract, see flat_host_mapping.md. For deterministic host compatibility baselines, see compatibility_dump.md. For generated XMP merge and writeback precedence, see xmp_sync_policy.md. For per-target writer preserve/replace guarantees, see writer_target_contract.md.

Pick The Integration Path

Use the narrowest public API that matches your host:

Host owns

Use

Existing target file or template

execute_prepared_transfer_file(...) + persist_prepared_transfer_file_result(...)

EXR writer

build_exr_attribute_batch_from_file(...)

Host-owned metadata object model

visit_metadata(...)

Host metadata inspection/search UI

openmeta/metadata_query.h focused query helpers

Structured interpreted metadata records

openmeta/metadata_interpretation.h

Cross-family concept conflicts

openmeta/metadata_concepts.h

User-facing orientation display

openmeta/orientation.h

Common EXIF/TIFF/DNG and selected MakerNote value labels

openmeta/exif_value_names.h

JPEG/JXL/WebP/PNG/JP2/BMFF encoder path

prepare_metadata_for_target_file(...) + adapter view or backend emitter

Adobe DNG SDK objects/files

dng_sdk_adapter.h

For inspection/search UI, prefer the experimental semantic query helpers before building a separate fuzzy layer. They report source entries, confidence, value shape, exact/fuzzy match provenance, and normalized candidates while preserving ambiguity.

For host code that wants a simpler iterable result, use metadata_interpretation.h. It keeps the same semantic vocabulary as query but returns structured records with query class, normalized shape, source entries, confidence, and normalized geometry/value arrays.

For host code that needs to reconcile duplicated concepts across metadata families, use metadata_concepts.h. It reports orientation, date/time, exposure/gain, color/profile, GPS, geometry, lens-correction, and RAW-processing candidates with source families, preferred entries, and same-role conflict flags. Exposure candidates expose capture facts such as exposure time, aperture, ISO, exposure bias, exposure program, and gain as safe transfer facts, while raw/DNG exposure adjustment fields remain unsafe for rendered-image transfer. Geometry candidates expose crop, active-area, border, and sensor-geometry roles with canonical origin, size, rect, and margin fields when available, including known DNG, Phase One/Leaf, Fujifilm RAF, Canon, Nikon Capture, and Sony panorama geometry patterns. Color/white balance, lens-correction, and RAW-processing candidates expose full normalized value vectors for grouped matrix/vector/table records when the source payloads satisfy conservative numeric shape checks. Malformed or text-only source records remain visible as individual metadata, but they are not promoted into normalized grouped color, white-balance, or lens-correction candidates. Date/time candidates include parsed date/time fields when the source value is recognizable, plus precision and timezone-kind fields. Matching EXIF OffsetTime* and SubSecTime* companions are assembled with their DateTime* values; normalized subseconds are bounded to nine decimal digits. Offset-aware candidates are compared as UTC instants, so equivalent timestamps with different written offsets do not conflict. IPTC created date/time, IPTC digital-creation date/time, XMP digitized timestamps, and GPS timestamps are assembled where the source fields provide enough pieces. GPS timestamps combine GPSDateStamp with GPSTimeStamp only within the same XMP property scope, and GPS altitude candidates report whether GPSAltitudeRef marked the height as below sea level. Camera position accepts XMP coordinates only from the EXIF XMP schema. EXIF/XMP destination coordinates and IPTC Extension LocationShown / LocationCreated coordinates use distinct roles, so they are not conflated with camera position. Structured-location candidates carry a location_scope such as LocationShown[1]; conflicts and preference are resolved independently within each scope. Use metadata_concept_gps_altitude_reference_name(...) for a stable display token. Descriptive concepts reconcile standard EXIF, IPTC IIM, Dublin Core, XMP Rights, Photoshop, IPTC Core/Extension, and PLUS title/headline, description, creator, keyword/subject, location, copyright, rights/license, credit, source, creator-contact, event, person, organization, product, artwork/object, encoded-rights-expression, license-constraint, release, legacy editorial, accessibility, taxonomy, resource/document identity, controlled-vocabulary terms, registry entries, image-region entities, document lineage/history, end-user, image-creator, image-supplier, and delivered-image fields. Scalar conflicts are isolated by normalized language and structured location scope; additive collections retain distinct values. Structured members carry both a record_kind and record_scope, such as person plus Person[1], so hosts can keep associated names, identifiers, descriptions, contacts, constraints, and release records together. IPTC image boundaries use the image_region_boundary record kind. A complete boundary adds a region_boundary candidate with explicit image_region_shape and image_region_coordinate_unit fields. Rectangle values use rect as x, y, width, height; circles use a three-value x, y, radius vector; polygons use a flattened x, y vector_set plus scoped vec2 vertex candidates. OpenMeta does not synthesize geometry when the shape, unit, or required coordinates are incomplete, but valid individual numeric fields remain queryable. Pixel and relative coordinates are not interchangeable: hosts must use source and target image specifications to transform or validate them before transfer. Treat this as an inspection and policy input rather than an automatic metadata rewrite decision; source-bound color, lens, and RAW-processing values still need rendered-transfer safety filtering. Document identity, registry, XMP Media Management manifest/version/lineage/history records, and pantry identity are source-bound; image-region records require target image specifications because their meaning is tied to the source image. Each candidate also carries a transfer hint: safe, source_bound, rendered_unsafe, or requires_target_image_spec, plus compatible_file_safe and rendered_image_safe booleans for host UI and preflight policy. For transfer previews, transfer_concept_diagnostics_from_store(...) converts those hints into keep/drop/requires-target-image-spec actions for a selected TransferSafetyMode, plus stable severity tokens, summary tokens, message tokens, argument tokens, and default message text for host UI. If the host knows the source storage context, pass MetadataRawDataDescriptor to the descriptor-aware overload so RAW-processing diagnostics distinguish stored RAW samples from rendered pixels before choosing keep/drop actions. Rendered-transfer drop messages distinguish source color transforms, white balance, lens correction, source RAW curves/linearity metadata, source-bound RAW processing, and target-owned image properties.

sensitivity is a separate policy signal with none, personal_contact, person_identity, location, and legal_rights values. A candidate marked safe can still be privacy- or policy-sensitive. Hosts that publish or share images should review or remove sensitive metadata according to their own user consent, privacy, and rights policies; OpenMeta does not drop it automatically merely because it is sensitive. Hosts can localize or replace the wording, but they do not need to invent the basic safe/drop/rewrite reasons.

Adapter Classes

OpenMeta splits host integration surfaces deliberately:

  • export-only naming/traversal surface: visit_metadata(...) for host-owned metadata mapping layers

  • export-only adapter: build_ocio_metadata_tree(...) for OCIO-style metadata trees

  • host-apply adapter: build_exr_attribute_batch(...) for EXR/OpenEXR header workflows

  • direct bridge: dng_sdk_adapter.h for applications that already use Adobe DNG SDK objects

  • narrow translator: libraw_adapter.h for orientation mapping into LibRaw flip space

  • orientation utility: orientation.h for EXIF/TIFF labels, rotation degrees, mirrored-state checks, and width/height-swap checks

  • value-name utility: exif_value_names.h for common EXIF/TIFF/DNG enum-style numeric labels and selected bounded Canon/Nikon/Sony/Fujifilm/Pentax/Olympus/Panasonic/ Phase One/Kodak/Minolta/Sigma/Samsung/Ricoh MakerNote labels

  • structured interpretation utility: metadata_interpretation.h for query-backed semantic records

  • concept-resolution utility: metadata_concepts.h for cross-family orientation, date/time, color/profile, exposure/gain, GPS, descriptive fields, geometry, lens-correction, and RAW-processing conflict inspection

1. Read Into <tt>MetaStore</tt>

#include "openmeta/simple_meta.h"

#include <array>
#include <cstddef>
#include <span>
#include <vector>

std::vector<std::byte> file_bytes = load_file_somehow("input.jpg");

openmeta::MetaStore store;
std::array<openmeta::ContainerBlockRef, 256> blocks {};
std::array<openmeta::ExifIfdRef, 512> ifds {};
std::vector<std::byte> payload(1 << 20);
std::array<uint32_t, 1024> payload_indices {};

openmeta::SimpleMetaDecodeOptions options;
openmeta::SimpleMetaResult result = openmeta::simple_meta_read(
    std::span<const std::byte>(file_bytes.data(), file_bytes.size()),
    store,
    blocks,
    ifds,
    payload,
    payload_indices,
    options);

store.finalize();

The caller owns the scratch buffers. That is deliberate: the API stays deterministic and easy to reuse in hot paths.

2. Query By Exact Key

#include "openmeta/meta_key.h"

openmeta::MetaKeyView key;
key.kind = openmeta::MetaKeyKind::ExifTag;
key.data.exif_tag.ifd = "ifd0";
key.data.exif_tag.tag = 0x010F;  // Make

for (openmeta::EntryId id : store.find_all(key)) {
    const openmeta::Entry& entry = store.entry(id);
    // Inspect entry.value and entry.origin.
}

Use exact lookup for deterministic key access. For inspection/search UI, prefer openmeta/metadata_query.h before building a separate layer. It returns source entries, confidence, value shape, and normalized candidates. Semantic Query uses built-in tags and conservative namespace/name rules; it intentionally does not use partial matching because near names must not alter classification. Raw matches retain exact_match, fuzzy_match, and fuzzy_score compatibility fields.

For a free-text search box, use openmeta/metadata_fuzzy_search.h instead of merging ranking policy into semantic Query. fuzzy_search_metadata(...) searches decoded names and property paths with explicit score and result bounds. It returns deterministic top-k results with exact, alias, or fuzzy provenance and stable entry-id tie-breaking. The current normalization contract is locale-independent ASCII; non-ASCII queries return UnsupportedQueryText, with no implicit transliteration. Thin Python Document and TransferSourceSnapshot wrappers return the same status, counts, truncation flag, and match fields. Calls keep local state and may run concurrently against an immutable finalized store. The current bounded linear scan is intended for ordinary per-image stores; see fuzzy_search.md for benchmark results and the deferred immutable-index boundary.

3. Generic Host Metadata Traversal

Use the traversal API when your application owns the metadata object model and needs deterministic exported names plus the original Entry.

#include "openmeta/interop_export.h"

class MyMetadataSink final : public openmeta::MetadataSink {
public:
    void on_item(const openmeta::ExportItem& item) noexcept override
    {
        // Map item.name + item.entry into your host metadata object.
    }
};

openmeta::ExportOptions options;
options.style              = openmeta::ExportNameStyle::FlatHost;
options.name_policy        = openmeta::ExportNamePolicy::Spec;
options.include_makernotes = false;

MyMetadataSink sink;
openmeta::visit_metadata(store, options, sink);

This keeps host-specific object ownership and write behavior outside OpenMeta. Use ExportNamePolicy::Spec when the host’s tables use specification names such as Exif:ISOSpeedRatings and Exif:ExposureBiasValue. The default ExifToolAlias policy is intended for ExifTool-compatible display/parity names.

For writeback, import_flat_host_metadata(...) accepts ordered typed values and returns a detached finalized MetaStore. Existing values may be selected by the source EntryId, or by name only when that FlatHost name is unique. Duplicate names are intentionally ambiguous. New custom XMP, EXIF, IPTC, or other entries must include an explicit MetaKeyView; OpenMeta does not guess a namespace or numeric tag from a lossy flat name. RemoveSourceEntry and RemoveUniqueName requests use an empty value and retain a Dirty | Deleted tombstone. This keeps entry ids, provenance, and snapshot raw-carrier links stable while subsequent export and transfer omit the deleted metadata.

Random-Access Source Foundation

For realtime and large-asset pipelines, openmeta/random_access_source.h defines a borrowed fixed-size source with either caller-owned contiguous memory or an exact synchronous read_at(offset, destination) callback. The primitive has no hidden allocation, lock, scheduler, or file-position state. Request count, total-byte, and single-read ceilings are tracked in caller-owned state.

Version 0.4.101 routes classic TIFF, BigTIFF, DNG, RW2, and ORF header/IFD decoding through this contract with caller-owned structural and value scratch. The existing span API is a zero-copy memory-source adapter over the same public entry point. Callback-backed PrintIM, GeoTIFF, Pentax DNG private data, and selected self-contained MakerNotes are supported. Version 0.4.102 adds source-backed Nikon embedded TIFF/type 1, Sony outer-TIFF-relative IFDs, and contained Canon adjusted-base payloads. Version 0.4.103 adds legacy and modern Olympus nested IFDs, Panasonic binary tables, and self-contained Samsung STMN and Type2 derived tables. Version 0.4.104 adds bounded Fujifilm self-relative IFDs and General Imaging Type 2 source windows. Version 0.4.105 adds Kodak fixed-layout records and outer-TIFF-relative Type 8, Type 10, and Type 11 IFDs with vendor subtables. Version 0.4.106 adds Ricoh, Nintendo, Casio, Minolta, and FLIR callback parity. Version 0.4.107 adds bounded leading JPEG metadata-segment scanning with 512-byte caller scratch and no entropy-data reads. Version 0.4.108 adds positional PNG/WebP chunk scanning and JP2/JXL/ISO-BMFF structural and metadata-item traversal while skipping image/media payloads. Version 0.4.109 adds positional GIF extension scanning, EXR header traversal, bounded logical payload fetching, and decoded snapshot assembly through read_transfer_source_snapshot_random_access(...). Scanner, decoder, and payload workspaces remain caller-owned; the returned snapshot owns its finalized store. Aggregate source limits cover every phase, and ordinary decoded assembly does not retain the whole file. Version 0.4.111 adds native positional RAF, X3F, and CRW/CIFF metadata traversal and allocation-free structured read diagnostics. Version 0.4.112 adds bounded traversal and decode of declared RAF preview-JPEG/FujiIFD metadata and X3F section-JPEG metadata without reading JPEG entropy or RAW image payloads. Unconverted Canon derived subtables outside the declared payload and unknown vendor layouts remain explicit residuals through ExifRandomAccessDecodeResult::nested_payloads_skipped; hosts must check complete() before claiming full nested parity. Undeclared source-wide fallback searches, selected BMFF enrichment, and whole-file raw carriers also remain explicit positional residuals. Use collect_read_transfer_source_diagnostics(...) to project bounded severity, code, family, source-offset/sizing, MakerNote, and residual details. See random_access_input.md for buffer sizing, lifetime, short-read, concurrency, and performance requirements.

4. Build An EXR Attribute Batch

This is the cleanest host-adapter path in OpenMeta today.

#include "openmeta/exr_adapter.h"

openmeta::ExrAdapterBatch batch;
openmeta::BuildExrAttributeBatchFileOptions options;

openmeta::BuildExrAttributeBatchFileResult result =
    openmeta::build_exr_attribute_batch_from_file(
        "source.jpg", &batch, options);

for (const openmeta::ExrAdapterAttribute& attr : batch.attributes) {
    // Forward attr.name, attr.type_name, and attr.value to your EXR writer.
}

OpenMeta does not need OpenEXR headers for this path. It exports a neutral batch of EXR-style attributes that your host can apply through OpenEXR or its own EXR writer.

5. Feed A Host-Owned JPEG Or JXL Encoder

There are two public patterns for encoder-owned output:

  • implement a backend emitter such as JpegTransferEmitter or JxlTransferEmitter

  • build an adapter view and consume one normalized list of operations

Adapter-View Pattern

Use this when you want one target-neutral operation list.

#include "openmeta/metadata_transfer.h"

class MySink final : public openmeta::TransferAdapterSink {
public:
    openmeta::TransferStatus
    emit_op(const openmeta::PreparedTransferAdapterOp& op,
            std::span<const std::byte> payload) noexcept override
    {
        // Dispatch on op.kind and forward payload into your backend.
        return openmeta::TransferStatus::Ok;
    }
};

openmeta::PrepareTransferFileOptions prepare;
prepare.prepare.target_format = openmeta::TransferTargetFormat::Jxl;

openmeta::PrepareTransferFileResult prepared =
    openmeta::prepare_metadata_for_target_file("source.jpg", prepare);

openmeta::PreparedTransferAdapterView view;
openmeta::build_prepared_transfer_adapter_view(
    prepared.bundle, &view, openmeta::EmitTransferOptions {});
openmeta::validate_prepared_transfer_adapter_view(prepared.bundle, view);

MySink sink;
openmeta::emit_prepared_transfer_adapter_view(prepared.bundle, view, sink);

This is a good fit when your host already has its own abstraction for “metadata op + bytes”. kPreparedTransferAdapterContractVersion versions the codec-facing operation schema independently from internal route strings. The operation schema is stable v1; adapter-view construction, validation, and emission remain experimental because they expose the prepared-bundle model.

Operation kind

Insertion fields

JpegMarker

jpeg_marker_code and marker payload

TiffTagBytes

tiff_tag and tag value bytes

JxlBox / JxlIccProfile

box_type, compress, or direct ICC payload

WebpChunk / PngChunk

chunk_type and chunk payload

Jp2Box

box_type and box payload

BmffItem / BmffProperty

item/property type, subtype, MIME-XMP flag, and payload

ExrAttribute

call get_prepared_transfer_adapter_exr_attribute_view(...) for borrowed name, type, and value

validate_prepared_transfer_adapter_view(...) rebuilds the canonical operation list and compares every kind-specific field. Hosts should validate cached or cross-layer views before codec handoff. Payload spans passed to TransferAdapterSink::emit_op(...) are borrowed for that call. The typed EXR view borrows from the unchanged source bundle.

Backend-Emitter Pattern

Use this when your host already looks like one OpenMeta backend.

#include "openmeta/metadata_transfer.h"

class MyJpegEmitter final : public openmeta::JpegTransferEmitter {
public:
    openmeta::TransferStatus
    write_app_marker(uint8_t marker_code,
                     std::span<const std::byte> payload) noexcept override
    {
        // Write one APPn marker into your JPEG output path.
        return openmeta::TransferStatus::Ok;
    }
};

openmeta::PrepareTransferFileOptions prepare;
prepare.prepare.target_format = openmeta::TransferTargetFormat::Jpeg;

openmeta::PrepareTransferFileResult prepared =
    openmeta::prepare_metadata_for_target_file("source.jpg", prepare);

openmeta::PreparedTransferExecutionPlan plan;
openmeta::compile_prepared_transfer_execution(
    prepared.bundle, openmeta::EmitTransferOptions {}, &plan);

MyJpegEmitter emitter;
openmeta::emit_prepared_transfer_compiled(prepared.bundle, plan, emitter);

For JXL, implement JxlTransferEmitter::set_icc_profile(...), add_box(...), and close_boxes(...).

OpenMeta does not ship a TurboJPEG-specific wrapper yet. The intended integration path is still through JpegTransferEmitter or the adapter view.

6. Edit An Existing Target File

If your host already has a target file or template on disk, use the file helper instead of building your own writer path.

#include "openmeta/metadata_transfer.h"

openmeta::ExecutePreparedTransferFileOptions exec_options;
exec_options.prepare.prepare.target_format =
    openmeta::TransferTargetFormat::Tiff;
exec_options.edit_target_path = "rendered.tif";

openmeta::ExecutePreparedTransferFileResult exec =
    openmeta::execute_prepared_transfer_file("source.jpg", exec_options);

openmeta::PersistPreparedTransferFileOptions persist;
persist.output_path = "rendered_with_meta.tif";
persist.overwrite_output = true;

openmeta::PersistPreparedTransferFileResult saved =
    openmeta::persist_prepared_transfer_file_result(exec, persist);

This path is usually simpler than a custom adapter when the container already exists.

Read Once, Save Later

If your host already decoded source metadata during the initial load, keep a decoded source snapshot and execute the later save without reopening the source file:

#include "openmeta/metadata_transfer.h"

const openmeta::ReadTransferSourceSnapshotFileResult snapshot =
    openmeta::read_transfer_source_snapshot_file("source.jpg");

openmeta::ExecutePreparedTransferSnapshotOptions options;
options.prepare.target_format = openmeta::TransferTargetFormat::Tiff;
options.edit_target_path      = "target.tif";
options.execute.edit_apply    = true;

openmeta::ExecutePreparedTransferFileResult result =
    openmeta::execute_prepared_transfer_snapshot(
        snapshot.snapshot, options);

Python mirrors that same host-facing snapshot flow:

from pathlib import Path

import openmeta

snapshot_info = openmeta.read_transfer_source_snapshot_file("source.jpg")
snapshot = snapshot_info["snapshot"]

result = openmeta.transfer_snapshot_file(
    snapshot,
    target_format=openmeta.TransferTargetFormat.Tiff,
    edit_target_path="target.tif",
    target_bytes=Path("target.tif").read_bytes(),
    output_path="edited.tif",
)

Current source snapshots are decoded-store-backed by default. They are intended for the normal EXIF/XMP/ICC/IPTC transfer flow, where OpenMeta re-emits decoded metadata after applying the selected safety policy. If a host needs source carrier provenance for diagnostics or a later passthrough policy decision, enable ReadTransferSourceSnapshotFileOptions::preserve_raw_carriers or pass ReadTransferSourceSnapshotOptions with preserve_raw_carriers set. Each raw carrier records its route, semantic kind, payload bytes, and snapshot-local decoded entry ids attributed to that carrier. Call raw_carrier_passthrough_audit_from_snapshot(...) before any host-owned passthrough decision. The audit reports candidate carriers and primary block reasons such as missing payload, target incompatibility, safety filtering, content-bound C2PA, explicit profile policy, missing decoded entry links, or unsupported carrier kind. Python exposes the same check as snapshot.raw_carrier_passthrough_audit(...). Snapshot preparation defaults to decoded re-emission. Hosts that need bounded raw reuse can set PrepareTransferRequest::raw_carrier_passthrough_mode to TransferRawCarrierPassthroughMode::WhenSafe, or pass raw_carrier_passthrough_mode=openmeta.TransferRawCarrierPassthroughMode.WhenSafe to Python snapshot transfer helpers. The current passthrough path is limited to eligible non-C2PA JUMBF and OpenMeta draft unsigned C2PA invalidation carriers for JPEG, JXL, and BMFF targets, plus draft unsigned C2PA invalidation carriers for WebP. EXIF/XMP/ICC/IPTC remain decoded re-emitted. For hosts that still own the bundle/execution split, the lower-level prepare_metadata_for_target_snapshot(...) entry point remains available. If the host already has a decoded MetaStore, build a reusable snapshot with build_transfer_source_snapshot(store). If it already owns the source bytes in memory, use read_transfer_source_snapshot_bytes(bytes) instead of the file-path reader. In Python, a previously decoded Document can be turned into a reusable snapshot through doc.build_transfer_source_snapshot() or openmeta.build_transfer_source_snapshot(doc). If it also owns the destination bytes in memory, call the overload execute_prepared_transfer_snapshot(snapshot, target_bytes, options). If it already holds a prepared bundle, use execute_prepared_transfer_bundle(bundle, target_bytes, options) instead. Snapshots can cross a process or host-object boundary without retaining their source storage:

std::vector<std::byte> persisted;
openmeta::serialize_transfer_source_snapshot(snapshot.snapshot, &persisted);

openmeta::TransferSourceSnapshot restored;
openmeta::deserialize_transfer_source_snapshot(persisted, &restored);

The parser is transactional and bounded by TransferSourceSnapshotIoOptions. Serialization preserves raw carrier bytes only when they were captured in the snapshot; it does not make those bytes safe to relocate or rewrite. The canonical v1 wire representation is compatibility-locked. Current readers accept v1 and reject unknown versions without changing the output snapshot.

Reconcile Host Attributes After Deserialization

The supported deferred-edit sequence is:

  1. Deserialize the source snapshot.

  2. Compare the host’s current FlatHost attributes with its saved export.

  3. Import changed values, explicit additions, and removals.

  4. Replace only the snapshot store after a successful transaction.

  5. Prepare target-specific payloads from the reconciled snapshot.

openmeta::TransferSourceSnapshot snapshot;
openmeta::deserialize_transfer_source_snapshot(persisted, &snapshot);

std::vector<openmeta::FlatHostImportItem> changes = host_changes();
openmeta::FlatHostImportOptions import_options;
import_options.name_policy = openmeta::ExportNamePolicy::Spec;

openmeta::FlatHostImportResult imported =
    openmeta::import_flat_host_metadata(snapshot.store, changes,
                                        import_options);
if (imported.ok()) {
    snapshot.store = std::move(imported.store);
}

openmeta::PrepareTransferRequest request;
request.target_format = openmeta::TransferTargetFormat::Webp;
openmeta::PreparedTransferBundle bundle;
openmeta::prepare_metadata_for_target_snapshot(snapshot, request, &bundle);

Import preserves every source entry position and appends additions, so raw carrier decoded_entry_ids remain valid. Tombstones preserve removed-entry identity. Untouched complex metadata and optional raw carriers remain in the snapshot; normal target safety and serialization policy still decides what is emitted. Snapshot execution supports the same existing-sidecar merge and destination carrier-precedence controls as the file helper; when loading an existing sidecar it defaults to edit_target_path unless xmp_existing_sidecar_base_path is set explicitly. For embedded-only writeback with sidecar cleanup and no filesystem path, set xmp_existing_destination_sidecar_state explicitly so OpenMeta can return a cleanup decision without guessing a sidecar location. Python now exposes those same split path/state controls directly: xmp_existing_sidecar_base_path, xmp_sidecar_base_path, xmp_existing_destination_embedded_path, and xmp_existing_destination_sidecar_state.

The CLI and Python command-line wrapper do not implement their own transfer semantics. They map flags onto the same file-helper contract:

  • --output is the sidecar base for sidecar and embedded_and_sidecar writeback, so the generated sidecar is output-stem.xmp.

  • --xmp-writeback sidecar suppresses generated embedded XMP.

  • --xmp-writeback embedded_and_sidecar writes generated XMP to both the edited output and the generated sidecar.

  • embedded-only writeback preserves an existing destination sidecar unless --xmp-destination-sidecar strip_existing is selected.

  • sidecar-only writeback preserves existing destination embedded XMP unless --xmp-destination-embedded strip_existing is selected.

  • --force maps to the C++ persistence overwrite flags for the primary output and generated sidecar.

7. Query Runtime Capabilities

Hosts can ask OpenMeta what the current build supports before wiring format menus, warnings, or integration feature flags.

#include "openmeta/metadata_capabilities.h"

openmeta::MetadataCapability cap = openmeta::metadata_capability(
    openmeta::TransferTargetFormat::Avif,
    openmeta::MetadataCapabilityFamily::Xmp);

if (openmeta::metadata_capability_available(cap.target_edit)) {
    // The current build can edit AVIF XMP within the reported support level.
}

Each operation reports one of unsupported, supported, bounded, or disabled. bounded means the capability exists within OpenMeta’s documented contract, not that it is arbitrary metadata-editor parity. disabled is used for compile-time-disabled support such as XMP decode when XML support is not available.

Python exposes the same query:

cap = openmeta.metadata_capability(
    openmeta.TransferTargetFormat.Avif,
    openmeta.MetadataCapabilityFamily.Xmp,
)
print(cap["target_edit_name"])

8. Use The Optional Adobe DNG SDK Bridge

If OpenMeta was built with OPENMETA_WITH_DNG_SDK_ADAPTER=ON, you can use the optional SDK bridge in two ways.

Update An Existing DNG File

#include "openmeta/dng_sdk_adapter.h"

openmeta::ApplyDngSdkMetadataFileResult result =
    openmeta::update_dng_sdk_file_from_file("source.jpg", "target.dng");

Apply Onto Existing SDK Objects

#include "openmeta/dng_sdk_adapter.h"
#include "openmeta/metadata_transfer.h"

openmeta::PrepareTransferFileOptions prepare;
prepare.prepare.target_format = openmeta::TransferTargetFormat::Dng;

openmeta::PrepareTransferFileResult prepared =
    openmeta::prepare_metadata_for_target_file("source.jpg", prepare);

openmeta::DngSdkAdapterOptions adapter;
openmeta::apply_prepared_dng_sdk_metadata(
    prepared.bundle, host, negative, adapter);

This bridge is for applications that already use the Adobe DNG SDK. OpenMeta still does not encode pixels or invent raw-image structure.

Host-Owned Image Specs

If a transfer target is produced from a different image buffer than the source, the host writer owns the target image facts: dimensions, channel count, sample type, compression, orientation, colorspace, ICC profile, and TIFF strip/tile storage. OpenMeta does not infer those values from copied metadata. During prepared transfer it filters source EXIF/XMP image-layout fields so stale source properties are not written into a different output image.

Host code that encodes pixels should keep those fields from the target container or inject values derived from the actual output buffer. Enable source ICC transfer only when the host has verified that the profile matches the target pixel buffer; otherwise preserve or write the target profile.

Use TransferProfile::safety for the broad source/destination relationship:

Mode

Use when

Transfer policy

CompatibleFile

Metadata is repackaged or recompressed into a compatible file/pixel representation

Preserve source camera, color, ICC, and camera-specific data except target-owned image-layout fields

RenderedImage

Pixels may have changed, especially RAW-to-JPEG/PNG/WebP/JXL/HEIF/AVIF export

Keep general/time/GPS/IPTC/portable XMP; drop source raw color calibration, profile/gain tables, raw digests/storage identifiers, linearization/crop/correction metadata, vendor RAW/source-processing geometry/color/correction/thermal/computational/private/stitch fields, camera raw settings XMP, source ICC, opaque MakerNotes, and non-C2PA JUMBF

See writer_target_contract.md for the detailed per-group transfer matrix.

openmeta::PrepareTransferRequest request;
request.target_format = openmeta::TransferTargetFormat::Jpeg;
request.profile.safety = openmeta::TransferSafetyMode::RenderedImage;

request.target_image_spec.has_dimensions = true;
request.target_image_spec.width = encoded_width;
request.target_image_spec.height = encoded_height;

request.target_image_spec.has_samples_per_pixel = true;
request.target_image_spec.samples_per_pixel = 3;
request.target_image_spec.bits_per_sample_count = 1;
request.target_image_spec.bits_per_sample[0] = 8;
request.target_image_spec.has_photometric_interpretation = true;
request.target_image_spec.photometric_interpretation = 2; // RGB
request.target_image_spec.has_exif_color_space = true;
request.target_image_spec.exif_color_space = 1; // sRGB

Python exposes the same structure as openmeta.TransferTargetImageSpec and the command-line wrappers pass it through without a separate policy layer:

spec = openmeta.TransferTargetImageSpec()
spec.has_dimensions = True
spec.width = encoded_width
spec.height = encoded_height
spec.has_samples_per_pixel = True
spec.samples_per_pixel = 3
spec.bits_per_sample = [8]
spec.has_photometric_interpretation = True
spec.photometric_interpretation = 2
spec.has_exif_color_space = True
spec.exif_color_space = 1

For smoke testing the file-helper path, metatransfer and python -m openmeta.python.metatransfer expose equivalent flags:

metatransfer --target-jpeg target.jpg -o output.jpg \
  --target-width 320 --target-height 240 \
  --target-samples-per-pixel 3 --target-bits-per-sample 8 \
  --target-photometric 2 --target-exif-color-space 1 \
  source.jpg

9. Query Phase One RAW Processing Metadata

After decoding MakerNotes, hosts can query Phase One/Leaf RAW processing data without depending on private MakerNote tag layout. The helper reports presence and normalized values for color matrices, WB RGB levels, black level, sensor temperatures, raw-data/storage byte counts, and sensor-calibration summaries. These values are source-RAW processing metadata; do not write them into rendered outputs unless the destination is a compatible RAW-style target.

#include "openmeta/phaseone_geometry.h"

openmeta::PhaseOneRawGeometryResult geometry =
    openmeta::phaseone_raw_geometry_from_store(store);
openmeta::PhaseOneRawProcessingResult raw =
    openmeta::phaseone_raw_processing_from_store(store);

if (raw.status == openmeta::PhaseOneRawProcessingStatus::Ok &&
    raw.info.has_color_matrix1) {
    const double m00 = raw.info.color_matrix1[0];
    (void)m00;
}

Python exposes the same normalized queries on decoded documents and reusable transfer snapshots:

doc = openmeta.read("source.iiq", decode_makernote=True)
geometry = doc.phaseone_raw_geometry()
raw = doc.phaseone_raw_processing()

if (raw["status"] == openmeta.PhaseOneRawProcessingStatus.Ok and
        raw["has_color_matrix1"]):
    m00 = raw["color_matrix1"][0]

The metaread command prints compact phaseone_raw_geometry=... and phaseone_raw_processing=... summaries when those decoded fields are present.

10. Query Vendor RAW Processing Metadata

For Sony, Canon, Nikon, Fujifilm, Pentax, Panasonic, Olympus, Kodak, Minolta, Sigma, Samsung, Ricoh, Apple, DJI, Google, FLIR, Casio, Sanyo, KyoceraRaw, Reconyx, HP, JVC, GE, Motorola, Nintendo, and Microsoft, OpenMeta exposes a conservative grouped summary instead of vendor-specific decoded values. The helper reports whether decoded MakerNote fields look like source RAW color/WB, geometry/storage, lens correction, raw-data, sensor-calibration, computational, thermal, preview/face geometry, stitch/panorama geometry, or vendor-private table metadata. Use it to audit transfer safety decisions and host UI, not as a rendered-output write source. The same classification feeds semantic query and interpretation records as per-family grouped table/vector candidates when multiple related vendor fields are present.

#include "openmeta/vendor_raw_processing.h"

openmeta::VendorRawProcessingSummary sony =
    openmeta::vendor_raw_processing_from_store(
        store, openmeta::VendorRawProcessingFamily::Sony);

if (sony.fields_seen > 0) {
    const uint32_t unsafe_for_rendered = sony.color_fields +
        sony.white_balance_fields + sony.lens_correction_fields;
    (void)unsafe_for_rendered;
}

openmeta::TransferSafetyAudit audit =
    openmeta::transfer_safety_audit_from_store(
        store, openmeta::TransferSafetyMode::RenderedImage);

if (audit.filtered_raw_color_calibration > 0 ||
    audit.filtered_icc_profiles > 0 ||
    audit.filtered_makernotes > 0) {
    // Show the host/user which source-bound metadata will not be transferred.
}

openmeta::TransferConceptDiagnostics diagnostics =
    openmeta::transfer_concept_diagnostics_from_store(
        store, openmeta::TransferSafetyMode::RenderedImage);

openmeta::MetadataRawDataDescriptor raw_descriptor;
raw_descriptor.encoding = openmeta::MetadataRawDataEncoding::Rendered;
openmeta::TransferConceptDiagnostics descriptor_diagnostics =
    openmeta::transfer_concept_diagnostics_from_store(
        store, openmeta::TransferSafetyMode::CompatibleFile, raw_descriptor);

for (size_t i = 0U; i < diagnostics.diagnostics.size(); ++i) {
    const openmeta::TransferConceptDiagnostic& item =
        diagnostics.diagnostics[i];
    const char* action =
        openmeta::transfer_concept_diagnostic_action_name(item.action);
    const char* reason =
        openmeta::transfer_concept_diagnostic_reason_name(item.reason);
    const char* severity =
        openmeta::transfer_concept_diagnostic_severity_name(item.severity);
    const char* message =
        openmeta::transfer_concept_diagnostic_message(item);
    const std::string token =
        openmeta::transfer_concept_diagnostic_token(item);
    const std::string message_token =
        openmeta::transfer_concept_diagnostic_message_token(item);
    const std::vector<std::string> message_arguments =
        openmeta::transfer_concept_diagnostic_message_arguments(item);
    (void)action;
    (void)reason;
    (void)severity;
    (void)message;
    (void)token;
    (void)message_token;
    (void)message_arguments;
}

If a decoder exposes a curve/LUT metadata entry that only affects compressed RAW storage, set raw_descriptor.requires_compressed_raw_encoding = true for the descriptor-aware diagnostics call. OpenMeta will then treat that curve as not applicable for uncompressed or packed raw buffers instead of assuming the metadata is active.

If the decoder also knows that the curve/LUT only affects the primary raw plane, set raw_descriptor.requires_primary_raw_plane = true and provide raw_descriptor.has_plane_index = true plus raw_descriptor.plane_index for the raw buffer being checked. Non-primary planes are then reported as not applicable; unknown plane selection remains conditional.

Python uses the same family enum:

summary = doc.vendor_raw_processing(openmeta.VendorRawProcessingFamily.Nikon)
if summary["fields_seen"]:
    print(summary["lens_correction_fields"])

audit = doc.transfer_safety_audit(openmeta.TransferSafetyMode.RenderedImage)
print(audit["filtered_raw_color_calibration"])

diagnostics = doc.transfer_concept_diagnostics(
    openmeta.TransferSafetyMode.RenderedImage
)
raw_descriptor = openmeta.MetadataRawDataDescriptor()
raw_descriptor.encoding = openmeta.MetadataRawDataEncoding.Rendered
descriptor_diagnostics = doc.transfer_concept_diagnostics(
    openmeta.TransferSafetyMode.CompatibleFile,
    raw_descriptor,
)
for item in diagnostics["diagnostics"]:
    print(
        item["kind_name"],
        item["role_name"],
        item["action_name"],
        item["severity_name"],
        item["token"],
        item["message_token"],
        item["message_arguments"],
        item["message"],
    )

metaread prints vendor_raw_processing[sony|canon|nikon|fujifilm|pentax|panasonic|olympus|kodak|minolta|sigma|samsung|ricoh|apple|dji|google|flir|casio|sanyo|kyoceraraw|reconyx|hp|jvc|ge|motorola|nintendo|microsoft]=... summaries when matching decoded fields are present. Live-vendor source-processing coverage currently includes Apple computational capture/HDR/motion fields, DJI pose and thermal fields, Google HDR+/shot-log fields, and FLIR radiometric/raw-value/geometry fields. These buckets are used by rendered-image safety filtering; they are not target-owned metadata for rendered outputs.

11. Build <tt>MetaStore</tt> Yourself

If your application creates metadata directly, build the store first and then reuse the same export and transfer APIs.

#include "openmeta/meta_key.h"
#include "openmeta/meta_store.h"
#include "openmeta/meta_value.h"

openmeta::MetaStore store;
const openmeta::BlockId block = store.add_block(openmeta::BlockInfo {});

openmeta::Entry entry;
entry.key = openmeta::make_exif_tag_key(store.arena(), "ifd0", 0x010F);
entry.value = openmeta::make_text(
    store.arena(), "Vendor", openmeta::TextEncoding::Ascii);
entry.origin.block = block;
entry.origin.order_in_block = 0;

store.add_entry(entry);
store.finalize();

Related Docs

page Interpretation Status

This page tracks how far OpenMeta has moved beyond raw metadata decoding into meaningful interpretation. Interpretation means that decoded entries have stable names, typed values, semantic groups, query shapes, and transfer-safety classification that host applications can use directly.

Current overall status: high, measured above 99% for the public target scope. This is intentionally lower than decode coverage. Decode parity only proves that metadata carriers and entries are visible; interpretation also requires human-readable meaning and safe cross-format behavior.

100% Acceptance Gates

For the declared target scope, an entry counts as covered when it has one explicit outcome:

Gate

Requirement

Decoded

The carrier and entry are visible in MetaStore, or the decoder reports an explicit unsupported/limit/malformed reason.

Named

The entry has a stable public name, or it is deliberately exposed as an unknown numeric/private field.

Typed

The raw value shape is preserved as scalar, vector, matrix, table, bytes, text, or opaque blob.

Interpreted

Known enum-like values, orientation states, geometry, exposure/gain, color, white-balance, lens-correction, RAW-processing, and source-private meanings are projected into public helpers or query candidates.

Classified

Source-bound data is classified as portable, target-owned, source RAW-specific, vendor-private, computational, thermal, preview/face/stitch metadata, or opaque/lossless.

Queryable

Host/UI workflows can find the interpreted meaning through focused query helpers with source entries, confidence, value shape, and normalized fields where available.

Fuzzy-searchable

Optional search can tolerate bounded spelling and property-path near misses while reporting similarity and exact/fuzzy provenance without silently changing interpretation.

Structured

Host code can consume query-backed interpretation records without reassembling raw query candidates manually.

Conflict-aware

Duplicated cross-family concepts either have a documented precedence rule or surface enough source information for host conflict handling.

Measured Target Audit

The current target audit measures 99.85% interpretation coverage and 99.77% query coverage. The denominator contains only explicitly declared semantic targets. Unknown private numeric IDs and intentionally opaque payloads are reported separately, while malformed, undefined, and incomplete values remain visible as residual gaps instead of receiving guessed meanings. Fuzzy Search is measured separately and is not part of the query percentage.

Coverage Matrix

Area

Current coverage

Readiness

Main remaining gap

Standard EXIF/TIFF/DNG tag names and typed values

Standard tag names, common scalar/vector values, DNG crop/color/exposure/RAW-processing fields, GeoTIFF key names, EXIF 3.1 learning/development/correction/noise tag names, and common EXIF/TIFF/DNG numeric value-name helpers are available. Exposure time, aperture, ISO sensitivity, exposure bias, exposure program/mode, gain, YCbCr positioning, sensitivity type, focal-plane unit, sensing method, file source, scene type, rendering controls, subject-distance range, compression, photometric, flash, correction/noise status values, and raw exposure-adjustment records now flow into concept candidates or stable display helpers where appropriate. Valid ASCII-byte EXIF dates and GPS references are normalized without changing stored bytes.

High, above 99% for declared enum targets.

Undefined enum codes and malformed field encodings intentionally remain raw.

ICC profiles

ICC header/tag table decode plus interpreted desc, text, signatures, XYZ, curves, named-color, measurement, viewing-condition, MFT/MAB/MBA, numeric array, and malformed/limit handling.

High, about 90-95%.

Full color-management policy remains host-owned; OpenMeta interprets profile metadata, not rendered color transforms.

IPTC-IIM and portable XMP

IPTC datasets and XMP properties decode into typed entries, bounded EXIF/IPTC-to-XMP projection exists for transfer/writeback, and common descriptive EXIF/IPTC/XMP concepts such as title/headline, description/caption, creator/author, keywords/subject, rights/license, credit/source, IPTC created date/time, and IPTC digital-creation date/time are queryable with source-entry provenance. The Descriptive concept also reconciles equivalent legacy IPTC/Photoshop fields; preserves non-equivalent object-type, object-attribute, and subject references; scopes editorial status/update/action/cycle/language/fixture fields, content locations, prior-envelope references, originating software, and editorial contacts; and normalizes editorial release/expiration date-time pairs. Legacy image type/layout, rasterized caption, audio type/channel/content/rate/resolution/duration/outcue, and object-preview format/version/data datasets are interpreted as source-bound technical records; IPTC image layout is not conflated with EXIF rotation orientation. It also interprets IPTC Core accessibility/taxonomy fields, IPTC Extension controlled-vocabulary, registry, image-region entity records, and rectangle/circle/polygon boundary geometry with explicit pixel/relative units, XMP document identity, XMP CreatorTool source software, exact Camera Raw Settings source processing, and XMP Media Management resource-reference, ingredient, history, manifest-item/reference, version/event, and bounded pantry records including standard nested resource-reference, manifest-reference, history-event, and version structures with pantry-qualified scopes; and groups structured creator contacts, events, people, organizations, products, artwork/objects, encoded rights expressions, PLUS parties/assets/license policy, and model/property releases with record kind, record scope, language, transfer hint, and independent sensitivity. Unknown nested XMP namespaces retain full URI identity in a collision-safe nsu_<namespace-uri-hex>: path segment and are not promoted as standard pantry structures.

High, about 99%.

Deliberately unmodeled arbitrary pantry payloads and undocumented extension datasets remain bounded raw metadata.

Orientation

EXIF/TIFF orientation query, LibRaw flip mapping, generic orientation helpers for index, rotation degrees, mirrored state, dimension swap, rotation-only fallback, human-readable labels, and EXIF-vs-XMP conflict reporting in the LibRaw bridge.

High, about 90-95%.

Higher-level policy for resolving container and host pixel-orientation state remains host-specific.

Geometry, crop, active area, and borders

DNG crop/active-area/masked-area tags, Phase One/Leaf geometry, Fujifilm RAF raw crop/zoom rectangles, Canon aspect/crop metadata, Nikon Capture crop bounds, Sony panorama crop margins, canonical border margins, vendor RAW-processing geometry buckets, and crop/border-style paths are queryable.

High, about 88-92%.

More vendor-specific normalized rectangles and stronger output contracts for ambiguous multi-tag geometry.

Exposure and gain

Standard EXIF exposure time, f-number, exposure program/mode, photographic sensitivity, exposure bias, exposure index, gain control, selected DNG baseline/raw-preview gain fields, matching XMP paths, and selected decoded vendor/MakerNote exposure names are queryable and promoted into cross-family exposure roles. Standard EXIF exposure program/mode and gain-control values plus selected Canon/Nikon/Sony/Fujifilm/Pentax/Olympus/Panasonic/Phase One/Kodak/Minolta/Sigma/Samsung/Ricoh MakerNote values carry human-readable labels where stable. Capture exposure facts are marked safe, while raw/DNG exposure adjustments are marked unsafe for rendered-image transfer.

Medium-high, about 91-94%.

More vendor MakerNote exposure print conversions and richer per-vendor exposure/gain labels.

Color, white balance, profiles, and matrices

DNG color/calibration/reduction/forward matrix groups, white-balance vector groups, EXIF color-space evidence, ICC header/tag entries, XMP ICC/profile fields, PNG profile text carriers, RAW color/source-processing safety buckets, transfer hints, per-family grouped vendor color/WB candidates, long-tail camera-to-XYZ/RGB, Canon ColorData source-color tables, style/color, and white-balance gain aliases, and cross-family concept candidates with full grouped value vectors are identified. ICC/profile and color-space records have a distinct color_profile semantic role, while camera RAW profile/look/tone-curve/style fields and vendor source color tables have a separate source_color_transform role marked unsafe for rendered-image transfer. Matrix/vector groups require numeric payloads with conservative minimum shapes before promotion.

Medium-high, about 86-92%.

Deeper camera/vendor color science interpretation is intentionally conservative, especially for rendered-image transfer.

Lens correction and RAW processing

Lens-correction groups, black/white levels, linearization, RAW value curves, RAW linearity limits, RAW calibration curves, RAW curve control points, CFA/sensor layout, raw-storage identifiers, vendor RAW/source-processing buckets, creative/picture style, film simulation, dynamic-range, optical correction, raw-development, computational, thermal, and stitch/panorama aliases, per-family vendor raw-storage/sensor/computational/thermal/stitch/source-processing table candidates, transfer hints, transfer diagnostics, and concept candidates with grouped table/vector values are classified for query and transfer safety. Current public RAW curve coverage includes DNG linearization/linearity-limit tags plus conservative Sony, Nikon, Kodak, Panasonic, and Phase One/Leaf-style curve or calibration names where decoded metadata is visible. Sony model-specific correction-offset routing includes the current ILCE-7RM6 Tag9416 offsets where the decoded payload exposes numeric correction arrays. RAW concept candidates now expose a conservative RAW applicability state; descriptor-aware concept-resolution overloads let a host or decoder provide a MetadataRawDataDescriptor so curve/LUT-like entries can remain conditional, apply to stored RAW samples, require compressed RAW storage, require the primary RAW plane, or be marked not applicable for rendered, uncompressed, packed, or non-primary-plane data. Transfer preparation can also consume the descriptor and drop RAW-processing metadata when source pixels are already rendered. Lens-correction grouped tables require numeric payloads before promotion.

Medium-high, about 90-94%.

Long-tail per-model correction tables, exact blob/decoder-stage applicability, and richer numeric normalization.

Vendor MakerNotes

Broad MakerNote naming and source-processing classification exists for common vendors and several live computational/thermal vendors. Unknown entries remain lossless and source-private subgroups distinguish preview, face geometry, computational, thermal, stitch/panorama, pixel-shift, multi-shot, composite, auto-lighting, RAW crop/active-area, source color-transform, source style/rendering aliases, lens-correction, raw-level processing data, and Phase One/Leaf RAW-processing fields handled by direct classification plus dedicated normalized helpers. Classified multi-field vendor groups now surface as grouped query/interpretation candidates where safe to expose structurally. Selected Canon/Nikon/Sony/Fujifilm/Pentax/Olympus/Panasonic/Casio/Phase One/Kodak/Minolta/Sigma/Samsung/Ricoh/Apple/FLIR/JVC/GE/Reconyx/Microsoft/Motorola/Nintendo/Sanyo print conversions expose bounded human-readable labels, including expanded Canon sub-IFDs and CanonCustom fields, Canon ColorData source color-transform aliases, Nikon sub-IFDs and NikonSettings fields, NikonSettings source-processing aliases, NikonSettings On/Off residual labels, Nikon Active D-Lighting labels, decoded Fujifilm mk_fuji* including flash white-balance naming, native RAF firmware naming, Pentax sub-IFDs, Olympus main/focus/equipment fields, Casio Type2 fields, Panasonic long-tail main-table fields, Apple AE/AF/HDR/capture/camera-type fields, FLIR GPS-valid state, JVC quality, General Imaging macro state, Reconyx moon phase/weekday/flash/illumination/battery/trigger labels, Microsoft stitch camera-motion/map-type labels, Motorola CustomRendered labels, Nintendo category labels, Sanyo main/MOV public-context scalar labels, current Canon RF lens-type labels, current Nikon Z LensData0800 LensID labels, and an ambiguous Pentax Sigma/Samsung/Tokina lens-family label. Version/firmware payloads have a separate bounded formatter path for selected standard EXIF byte-version fields, Nikon version-like contexts, Olympus packed firmware fields, and native RAF firmware fields so formatted versions are not confused with enum labels. Canon AF micro-adjustment fields are classified for lens-correction search, and Canon ambience-selection fields are classified as source-processing metadata. Ambiguous per-model, per-version, text/count, measurement, MP4 numeric, or value-type-dependent labels intentionally remain empty instead of guessing.

Medium-high, about 97%.

Remaining encrypted/custom settings, per-model private tables, remaining live-vendor scalar/string-coded fields, and per-model firmware formulas outside currently supported contexts.

BMFF item graph, HEIF/AVIF/CR3, JUMBF, and C2PA

BMFF derived fields expose AVIF-compatible brands, item-info and semantic rows, bounded scene/component graph summaries, direction-correct typed relations, semantic item groups, iloc/idat layouts, item-property associations, primary item/display/color summaries, JUMBF/C2PA structure, and bounded grid/iovl/iden construction descriptors. Derived descriptor reads support method-0 file extents, method-1 idat extents, and recursive method-2 item-offset chains with fixed depth, overflow/range/index checks, no complete-item copies, descriptor-reference depth, and graph cycle/missing-source/truncated-reference validity. tili image items expose bounded tilC version-0 dimensions, extra dimensions, property relationships, tile grids, expected tile counts, dref/deti mapping, internal tile_item_type/tipa associations, external URL state, logical offset tables, explicit or sequentially inferred tile sizes, empty-tile state, separate core/layout/complete validity, and a source-bound container-graph concept.

High, about 98%.

Independently authored tiled-image conformance files and full C2PA manifest/policy semantics.

Photoshop IRB

Raw resources are preserved and a bounded interpreted subset is decoded for fixed-layout resources, including Photoshop 2 info/color-table summaries, resolution/version/print data, print-flag bytes, border/background/effective-BW data, display info, grid/guide info, color sampler headers/records, descriptor-header summaries plus safe descriptor class-name/class-ID/item-count fields, bounded descriptor item bodies (bool, long, comp, doub, UntF, TEXT, enum, type, GlbC, opaque alis and tdta byte counts) with type-name/type-code fields, parsed maximum depth, and parsed per-type counters, ordered bounded obj reference streams for property, class, enumerated, offset, identifier, index, and name forms with reference paths, depths, indices, values, and aggregate counters, empty and non-empty nested object/list summaries with item paths, depths, list indices, and parsed-value counts, for resources including layer comps, measurement scale, timeline info, sheet disclosure, HDR toning, print info, onion skins, count info, print info/style, path selection state, and origin path info, working-path and numbered clipping-path byte-count / record summaries, alpha names/identifiers, captions, QuickMask info, URL/list data, autosave strings, XMLData, ImageReady XML text, Lightroom workflow text, thumbnail headers, channel options, clipping-path names, MacintoshPrintInfo, Macintosh NSPrintInfo, Windows DEVMODE, AlternateDuotoneColors, AlternateSpotColors, and obsolete Photoshop tag byte counts, legacy halftone/transfer/duotone/EPS byte summaries, embedded IPTC/ICC/XMP/EXIF resource byte counts, and embedded IPTC/XMP/ICC payload decode where enabled.

Medium-high, about 90-94%.

Full Photoshop action execution semantics, opaque alias/raw payload interpretation, and long-tail resource interpretation.

Semantic query and records

Query helpers expose raw matches, confidence, provenance, value shapes, normalized candidates, canonical crop/active-area rectangles, exposure/gain and vendor records, exact structured descriptive semantics for contacts, events, people, organizations, products, artwork, rights expressions, licenses, releases, editorial workflow, accessibility, taxonomy, registry, image regions, document identity, lineage, history, technical image layout, audio, and preview data, explicit color/profile/RAW/source-processing/container-graph concepts, and bounded cross-family concept resolution. Candidates preserve source entries, normalized values, language, location scope, record kind/scope, transfer hints, RAW applicability, independent sensitivity, safety booleans, and conflict state.

High, measured about 99.77% for declared targets.

Incomplete GPS tuples, malformed dates, and undefined values remain inspection data rather than normalized candidates.

Fuzzy Search

Optional fuzzy_search_metadata(...) searches decoded names and property paths with bounded score/result options, deterministic top-k ordering, stable ties, exact/alias/fuzzy provenance, curated positive/adversarial quality gates, and an opt-in scaling benchmark. Python snapshot/document wrappers preserve the same result shape.

High enough for the current milestone, about 80-85%.

Broaden independently sourced quality coverage, then design Unicode normalization, transliteration, multilingual ranking, and an optional immutable index for repeated large-store searches.

Transfer-safety classification

Compatible-file versus rendered-image safety policies classify source-specific image geometry, color/profile, RAW curves/linearity metadata, RAW-processing, MakerNote, BMFF content-bound/multi-image/derived-construction/tiled-image policy, JUMBF/C2PA, and vendor-private data, with concept-level diagnostics that report keep/drop/requires-target-image-spec actions, severity, stable summary/message tokens, localizable argument tokens, RAW applicability, and role-specific default message text before prepare. Source-processing diagnostics distinguish computational, thermal, and stitch/panorama message tokens; container-graph diagnostics distinguish content-bound metadata, multi-image scene, derived-image construction, and tiled-image configuration message tokens. Descriptor-aware diagnostics can also mark curve/LUT-like RAW roles as compressed-storage-only or primary-plane-only. PrepareTransferRequest can carry a MetadataRawDataDescriptor; when it marks source pixels as rendered, RAW-processing metadata is filtered even under compatible-file safety.

High, about 94-96%.

More per-family policy tests and broader per-family policy coverage.

Competitor Position

ExifTool remains the practical reference for long-tail tag names, MakerNote tables, and human-readable print conversions. OpenMeta is now close on decode visibility for the current target scope, but interpretation still trails ExifTool in per-model private meanings.

Exiv2 is strong for common EXIF/IPTC/XMP workflows. OpenMeta’s differentiator is the explicit safe-transfer and host-query model: it classifies whether data is portable, target-owned, source RAW-specific, or unsafe to move into rendered outputs.

Active Project Sequence

The first bounded Creation and Editing milestones are complete. The current implementation focus advances to Transfer, Translation, and Writing. Adapters and Utilities remain deferred. Creation and Editing resume for custom, multilingual, structured, direct-family output, structural block operations, and broader synchronization; Fuzzy Search resumes before those final two stages for its Unicode/multilingual and optional-index milestones.

Interpretation Maintenance Priorities

  1. Validate the complete bounded BMFF tiled-image contract against independently authored conformance files as they become available.

  2. Broaden transfer diagnostic policy coverage now that stable message tokens and localizable argument tokens are available for GUI workflows.

  3. Extend pantry payload semantics only when another stable, bounded schema is validated; keep arbitrary payloads raw and source-bound.

  4. Expand the remaining unambiguous MakerNote long tail: encrypted/custom settings, per-model firmware formulas outside currently supported formatter contexts, remaining live-vendor scalar/string-coded fields, and per-model tables only where context is strong enough to avoid wrong labels.

  5. Keep transfer-safety classification conservative when interpretation is incomplete.

page Metadata Backend Matrix (Draft)

Date: March 5, 2026

Goal

Define one OpenMeta write/transfer contract that can target multiple container backends without per-backend metadata logic duplication.

For the public per-target preserve/replace guarantees, see writer_target_contract.md.

Capability Matrix

Backend

Native metadata write primitives

Best use in OpenMeta

libjpeg-turbo

jpeg_write_marker, jpeg_write_m_header, jpeg_write_m_byte, jpeg_write_icc_profile

Primary JPEG metadata emitter (APP1/APP2/APP13 direct control)

libtiff

TIFFSetField, TIFFCreateEXIFDirectory, TIFFCreateGPSDirectory, TIFFWriteCustomDirectory, TIFFMergeFieldInfo

Primary TIFF metadata emitter (native tag and IFD path)

libjxl

JxlEncoderUseBoxes, JxlEncoderAddBox, JxlEncoderCloseBoxes, JxlEncoderSetICCProfile

Primary JXL metadata emitter (Exif, xml, jumb, optional brob) plus encoder ICC profile

OpenEXR

Header::insert, typed attributes, OpaqueAttribute for unknown attr types

EXR header attribute path (not EXIF block packaging)

Container-Level Notes

JPEG (libjpeg-turbo)

  • Write EXIF as APP1 (Exif\\0\\0 + TIFF payload).

  • Write XMP as APP1 (\\0 + packet).

  • Write IPTC/IRB as APP13 (Photoshop 3.0 resource block layout).

  • Write ICC as APP2 chunk chain (ICC_PROFILE header + sequence index/count).

  • OpenMeta should own marker ordering policy and payload splitting limits.

TIFF (libtiff)

  • EXIF/GPS should be written as directories and linked from root IFD pointers.

  • XMP uses TIFFTAG_XMLPACKET (700).

  • IPTC uses TIFFTAG_RICHTIFFIPTC / TIFFTAG_EP_IPTC_NAA (33723 alias).

  • Photoshop IRB uses TIFFTAG_PHOTOSHOP (34377).

  • ICC uses TIFFTAG_ICCPROFILE (34675).

  • OpenMeta should own EXIF serializer policy before TIFFSetField.

  • Public OpenMeta fast path is backend-emitter or rewrite/edit based: emit_prepared_transfer_compiled(..., TiffTransferEmitter&) or write_prepared_bundle_tiff_edit(...).

  • TIFF intentionally does not expose a metadata-only byte-writer emit API.

JXL (libjxl)

  • Metadata requires container boxes enabled.

  • Add Exif, xml, jumb boxes through JxlEncoderAddBox.

  • Set ICC through JxlEncoderSetICCProfile; ICC is not a JXL metadata box.

  • Exif box content must include the 4-byte TIFF header offset prefix.

  • Optional Brotli-compressed box storage (brob) is backend-controlled.

  • OpenMeta should prepare box payloads once and reuse in emit path.

  • Current OpenMeta transfer support on this path is intentionally bounded: EXIF/XMP are prepared and emitted through JxlTransferEmitter, ICC is prepared as jxl:icc-profile and emitted through the encoder ICC path, file-based prepare can preserve source generic JUMBF payloads and raw OpenMeta draft C2PA invalidation payloads as JXL boxes, can generate a draft unsigned invalidation payload for content-bound source C2PA, and store-only prepare can project decoded non-C2PA JumbfCborKey roots into generic JXL jumb boxes. IPTC requested for JXL is projected into the xml XMP box; there is no raw IPTC-IIM JXL route. build_prepared_jxl_encoder_handoff_view(...) is the explicit OpenMeta encoder-side ICC contract for JXL, and build_prepared_jxl_encoder_handoff(...) / serialize_prepared_jxl_encoder_handoff(...) add the owned persisted form of that handoff: one optional jxl:icc-profile payload plus the remaining JXL box counts. The JXL compile/emit path rejects multiple prepared ICC profiles so that handoff contract matches backend execution. inspect_prepared_transfer_artifact(...) is the shared persisted-artifact inspect path across payload batches, package batches, persisted C2PA handoff/signed packages, and persisted JXL encoder handoffs. build_prepared_transfer_emit_package(...) plus write_prepared_transfer_package(...) can also serialize direct JXL box bytes from prepared bundles, and execute_prepared_transfer(...) can use that same box-only serializer through emit_output_writer. OpenMeta also supports a bounded file-level JXL edit path that preserves the signature and non-managed top-level boxes, replaces only the metadata families present in the prepared bundle, and appends the prepared JXL boxes to an existing container file. Unrelated source JXL metadata boxes are preserved, and uncompressed source jumb boxes are distinguished as generic JUMBF vs C2PA for that replacement decision. When Brotli support is available, the same family check also covers compressed brob(realtype=jumb) source boxes. The byte-writer/file-edit path still does not serialize jxl:icc-profile; ICC remains encoder-only. The bounded external-signer path now also supports JXL jumb staging for content-bound C2PA rewrite on top of that edit path; full in-process re-sign remains out of scope.

WebP (RIFF metadata chunks)

  • Metadata is carried as RIFF chunks, not TIFF tags or BMFF boxes.

  • Standard chunk carriers:

    • EXIF

    • XMP

    • ICCP

    • bounded C2PA

  • The prepared EXIF chunk payload is the TIFF byte stream only. It does not include the JPEG APP1 Exif\0\0 preamble.

  • OpenMeta now has a bounded WebP transfer path on the core transfer API: prepare_metadata_for_target(..., TransferTargetFormat::Webp, ...), compile_prepared_bundle_webp(...), emit_prepared_bundle_webp(...), emit_prepared_bundle_webp_compiled(...), and emit_prepared_transfer_compiled(..., WebpTransferEmitter&).

  • IPTC requested for WebP is projected into the existing XMP chunk; OpenMeta does not create a raw IPTC-IIM WebP carrier.

  • build_prepared_transfer_emit_package(...) plus write_prepared_transfer_package(...) can serialize direct WebP chunk bytes from prepared bundles, and the owned package batch/replay path can persist or hand off those bytes without keeping the source bundle alive.

  • The file edit path rewrites managed metadata chunks and patches existing VP8X feature bits. It does not synthesize a missing VP8X chunk.

  • Full WebP signed C2PA rewrite/re-sign is still outside the current WebP transfer contract.

ISO-BMFF metadata items (HEIF / AVIF / CR3)

  • This bounded transfer path is metadata-item/property oriented. OpenMeta also supports a bounded BMFF metadata edit path over an existing BMFF target file.

  • Current prepared item routes:

    • bmff:item-exif

    • bmff:item-xmp

    • bmff:item-jumb

    • bmff:item-c2pa

  • Current prepared property routes:

    • bmff:property-colr-icc

  • EXIF item payloads use the BMFF Exif item shape:

    • 4-byte big-endian TIFF offset prefix

    • followed by full Exif\0\0 bytes

  • IPTC requested for BMFF is projected into bmff:item-xmp; OpenMeta does not create a raw IPTC-IIM BMFF carrier.

  • ICC requested for BMFF uses the bounded property path:

    • bmff:property-colr-icc

    • payload bytes are u32be(‘prof) + <icc-profile>

    • this is acolrproperty payload, not a metadata item

  • File-based prepare can preserve source generic JUMBF payloads and raw OpenMeta draft C2PA invalidation payloads as BMFF metadata items.

  • Store-only prepare can project decoded non-C2PAJumbfCborKeyroots into bmff:item-jumbwhen no raw source payload is available.

  • Core emitter surface: -compile_prepared_bundle_bmff(…) -emit_prepared_bundle_bmff(…) -emit_prepared_bundle_bmff_compiled(…) -emit_prepared_transfer_compiled(…, BmffTransferEmitter&) -build_prepared_transfer_emit_package(…)plus write_prepared_transfer_package(…)can serialize direct BMFF item and property payload bytes from prepared bundles. This is a host/adapter payload handoff, not a standalone BMFF file rewrite. -execute_prepared_transfer(…)exposes that same bounded payload sequence throughExecutePreparedTransferOptions::emit_output_writer, with capacity preflight and BMFF item/property summaries. The output remains a host handoff, not a standalone BMFF container.

  • The shared package-batch persistence/replay layer can own and hand off stable BMFF item and property payload bytes. -metatransfer/openmeta.transfer_probe(…)expose BMFF summaries, includingbmff_item mime/xmp …andbmff_property colr/prof …. -metatransfer &#8212;target-heif|&#8212;target-avif|&#8212;target-cr3 &#8212;source-meta … -o … performs bounded metadata edits for targets with no foreign top-levelmeta box, with a prior OpenMeta-authored metadata-onlymetabox from the same bounded contract, or with a parseable foreign top-levelmetaitem graph. The foreign-metapath merges, replaces, or strips bounded Exif/XMP/JUMBF/C2PA metadata items by extendingiinf,iloc,idat, and irefwithcdscreferences to the primary item. It requires a single parseableiinf,ilocversion 0/1/2,pitm, and at most oneidat. Inserted item IDs can use the 32-bit item-id space: supportedilocversion 0/1 graphs are upgraded to outputilocversion 2 when needed, and OpenMeta emits widerinfe/irefrecords for inserted items that exceed 16 bits. Newly inserted metadata item records keepilocconstruction method 0 and use absolute file-offset extents for broad reader compatibility. When retained self-contained records can be represented that way, the rebuiltilocalso compacts the base-offset field width to zero. Retained foreign item locations are supported for construction method 0 file-offset extents and construction method 1 extents into an existing idat, with data reference index 0. Construction method 2 is supported only when the retained item has parseableirefilocreferences, using explicit extent indexes or reference order, and every referenced item is also retained with a supported local location. External data references, missing method-2 references, removed referenced items, and other construction methods fail safely.

  • Foreign-metaICC property merge is bounded to bmff:property-colr-icc. OpenMeta removes prior ICCcolr/profand colr/rICCproperties fromiprp/ipco, compacts/remaps existingipma associations, appends the transferredcolr/profproperty, and associates it with the primary item and any retained item that previously referenced a replaced ICC property while preserving the prior essential association bit. Broader non-ICC property replacement and arbitrary scene/property-graph rewrites remain out of scope for the current contract.

  • Embedded-XMP strip mode removes XMP from OpenMeta-authored metadatameta boxes and from parseable foreign top-levelmetaitem graphs that satisfy the same bounded merge contract. Foreign graphs without a primary item relationship (pitm) or outside the supportediinf/iloc/idat/iref` shape still fail explicitly instead of silently claiming removal.

  • The same bounded BMFF edit contract now also participates in the core / file-helper C2PA signer path:

    • sign-request derivation

    • binding-byte materialization

    • signed-payload validation

    • staged bmff:item-c2pa apply before bounded metadata-only edit

  • Out of scope for the current BMFF contract:

    • thin CLI/Python signer-input exposure for BMFF

    • arbitrary rewrite of foreign top-level BMFF scene/property graphs

    • full BMFF signed rewrite/re-sign beyond the bounded metadata-only edit path

EXR (OpenEXR)

  • EXR metadata is typed header attributes, not EXIF/TIFF IFD blocks.

  • Use typed attributes for semantic fields.

  • Unknown attribute types can be preserved as opaque attributes.

  • OpenMeta EXR path should remain an attribute adapter, not block repackaging.

  • Current public EXR bridge:

    • build_exr_attribute_batch(...) exports one owned per-part attribute list from MetaStore

    • build_exr_attribute_part_spans(...) groups that batch into contiguous per-part spans

    • build_exr_attribute_part_views(...) exposes zero-copy grouped per-part views over the same batch

    • replay_exr_attribute_batch(...) replays the grouped batch through explicit host callbacks

    • known scalar/vector EXR types are re-encoded into deterministic EXR attribute bytes

    • unknown/custom attrs are preserved as opaque raw bytes when Origin::wire_type_name is available

    • ambiguous attrs without a stable wire-type contract fail closed or can be skipped explicitly

Unified Workaround (Single Contract)

Use one two-phase pipeline for all backends:

  1. prepare_metadata_for_target(source_store, target_format, profile)

    • Build target-ready block payloads once.

    • Build deterministic write order.

    • Build optional fixed-size patch map for per-frame time fields.

  2. emit_prepared_bundle(bundle, writer_target, frame_patch)

    • Emit prebuilt payloads through backend-specific write calls.

    • Apply optional fixed-width time patch before final write.

This keeps heavy work out of hot per-frame loops.

Backend Interface Shape (Draft)

Define narrow backend interfaces:

  • JpegWriterBackend::write_app_block(app_marker, bytes)

  • TiffWriterBackend::set_tag(tag_id, bytes_or_scalar) plus commit_exif_directory(offset_ref)

  • JxlWriterBackend::add_box(type4cc, bytes, compress)

  • ExrWriterBackend::set_attribute(name, typed_or_opaque_value)

OpenMeta core emits backend-neutral prepared payloads. Backends only perform container call mapping.

Policy Defaults (Draft)

  • No-edits transfer mode: preserve payloads when legal for target container.

  • EXIF pointer tags are regenerated for target container layout.

  • MakerNote and C2PA/JUMBF transfer policy is explicit and deterministic.

  • Current JPEG/TIFF prepare behavior:

    • MakerNote: Keep default, Drop supported, Invalidate currently resolves to Drop, and unavailable Rewrite resolves to Drop rather than silently preserving raw bytes. Keep carries the original opaque payload, but does not relocate vendor-private offsets, repair checksums, or prove semantic readability after the surrounding EXIF layout changes. Use makernote_transfer_audit_from_store(...) for the generic machine-readable trust boundary and makernote_layout_transfer_audit_from_store(...) for bounded Nikon type 1/type 3 offset-layout evidence. Type 3 structural validation covers standard embedded-TIFF offsets, not vendor-private binary offsets or checksums.

    • JUMBF: file-based JPEG prepare can preserve source payloads by repacking them into APP11 segments; store-only JPEG prepare can project decoded non-C2PA JumbfCborKey roots into generic APP11 JUMBF payloads; explicit raw JUMBF -> JPEG APP11 append is available through append_prepared_bundle_jpeg_jumbf(...); and JPEG rewrite/edit removes existing APP11 JUMBF when the resolved policy is Drop. Ambiguous numeric map keys and decoded-CBOR bool/simple/sentinel/large-negative fallback forms in projected JUMBF are rejected; tagged CBOR values are preserved.

    • C2PA: Invalidate on JPEG now emits a draft unsigned APP11 C2PA invalidation payload.

      • PreparedTransferPolicyDecision exposes mode, source_kind, and prepared_output so adapters can branch without parsing free-form messages.

      • PreparedTransferBundle::c2pa_rewrite exposes the separate rewrite-prerequisites contract for future signing flows: current rewrite state, source kind, existing carrier segment count, and whether manifest builder, content binding, certificate chain, private key, and signing time are still required.

      • For JPEG it exposes content_binding_chunks as preserved source ranges plus prepared JPEG segments; for the bounded BMFF edit path it uses preserved source ranges plus one prepared metadata-only meta box.

      • build_prepared_c2pa_sign_request(...) derives the external signer view from that same data without changing the bundle contract.

      • build_prepared_c2pa_sign_request_binding(...) materializes the exact content-binding bytes from that request and the target container input. Current bounded targets are JPEG and BMFF.

      • build_prepared_c2pa_handoff_package(...) combines the signer request and exact binding bytes into one public handoff object.

      • serialize_prepared_c2pa_handoff_package(...) and deserialize_prepared_c2pa_handoff_package(...) persist that object.

      • build_prepared_c2pa_signed_package(...) combines the sign request and signer-returned material into one persisted signed package.

      • serialize_prepared_c2pa_signed_package(...) and deserialize_prepared_c2pa_signed_package(...) persist that package.

      • Thin wrappers expose that as CLI dump output and Python unsafe raw bytes for JPEG without duplicating the reconstruction logic. BMFF uses the same core helper without separate wrapper flags yet.

      • validate_prepared_c2pa_sign_result(...) validates a returned signed logical C2PA payload before bundle mutation and reports staged carrier size and segment count.

      • Current JPEG validation also checks semantic manifest/claim/signature consistency, resolved explicit references, request-aware manifest count / claim_generator requirements, decoded-assertion presence when content binding is required, the primary signature linking back to the prepared primary claim under that same content-binding contract, no primary-signature explicit-reference ambiguity under that same request, no multi-signature drift where the primary claim is referenced by more than one signature under the current sign request, and no extra linked signatures beyond the prepared sign request, manifest/claim/signature projection shape under the prepared manifest contract, exact primary manifest-CBOR equality against manifest_builder_output, staged APP11 sequence order, and exact logical-payload reconstruction. Final JPEG emit/write also rejects prepared APP11 C2PA carriers with non-contiguous sequence numbers, inconsistent repeated headers, invalid logical root type, or BMFF declared-size drift before backend bytes are written.

      • Final JPEG emit/write also rejects prepared APP11 C2PA carriers that violate the resolved bundle contract: missing required carriers, draft-invalidated carriers under a signed rewrite contract, signed-rewrite carriers under a draft contract, and Ready rewrite state without SignedRewrite prepared output.

      • apply_prepared_c2pa_sign_result(...) accepts the external signer output and stages a content-bound logical C2PA payload back into prepared JPEG APP11 blocks, JXL jumb boxes, or bounded BMFF bmff:item-c2pa items after strict request validation.

      • The file-level execution helper can now validate that stage step, apply it, and continue into normal JPEG emit/edit, bounded JXL edit, or bounded BMFF edit flow. Thin CLI/Python signer-input wrappers now cover JPEG, JXL, and bounded BMFF targets. The option name --jpeg-c2pa-signed remains for compatibility.

      • PreparedTransferPackagePlan now provides the shared final-output package contract for current JPEG/TIFF rewrite paths plus direct JPEG/JXL emit packaging: deterministic source ranges, prepared direct blocks, prepared JPEG segments, and inline generated bytes can be written through one generic package writer.

      • PreparedTransferPackageBatch is the owned replay form of that same contract: each package chunk is materialized into stable bytes so the final metadata package can be cached or handed off without the original input stream or prepared bundle storage.

      • serialize_prepared_transfer_package_batch(...) and deserialize_prepared_transfer_package_batch(...) persist that owned batch so host layers can move it across process or integration boundaries without reopening the source file or rebuilding the bundle.

      • collect_prepared_transfer_payload_views(...) and build_prepared_transfer_payload_batch(...) now provide the matching target-neutral semantic payload surface directly over prepared bundles.

      • serialize_prepared_transfer_payload_batch(...) and deserialize_prepared_transfer_payload_batch(...) persist that earlier semantic payload batch for cross-process or cross-layer handoff before final package materialization.

      • Host metadata tables that use specification naming should export with ExportNameStyle::FlatHost plus ExportNamePolicy::Spec. This preserves names such as Exif:ISOSpeedRatings and Exif:ExposureBiasValue instead of applying the default ExifTool-compatible aliases.

      • serialize_transfer_source_snapshot(...) now persists the target-neutral decoded source state for later editing and preparation when the output format is not yet known. This is distinct from target-specific payload and package batches.

      • import_flat_host_metadata(...) provides bounded typed writeback by exact source identity or unique exported name, with explicit keys required for new custom metadata. Remove-by-identity and remove-by-unique-name preserve stable tombstones; duplicate flat names are never collapsed implicitly.

      • collect_prepared_transfer_package_views(...) is the target-neutral semantic package surface above that persisted batch.

      • replay_prepared_transfer_package_batch(...) is the target-neutral callback replay surface above that same persisted batch.

      • OpenMeta no longer ships an in-library host-specific payload/package bridge above these target-neutral package views and replay APIs.

      • build_prepared_transfer_adapter_view(...) now provides the parallel target-neutral adapter view for JPEG/TIFF/JXL/WebP/PNG/JP2/EXR/BMFF host integrations that want explicit compiled operations without route parsing. The v1 operation schema has a dedicated contract version and canonical validation; EXR name/type/value uses a typed accessor.

      • emit_prepared_transfer_adapter_view(...) replays that compiled view through one generic host sink.

      • replay_prepared_transfer_payload_batch(...) now reuses that same earlier persisted semantic payload stage directly, before final package materialization.

      • File-based JPEG prepare can preserve an existing OpenMeta draft invalidation payload as raw APP11 C2PA (TransferC2paMode::PreserveRaw).

      • Content-bound Keep still resolves to Drop.

      • Rewrite resolves to Drop with explicit SignedRewriteUnavailable until re-sign support exists, but externally signed payload staging is now available once a signer has consumed the request.

      • JPEG content-changing rewrite/edit removes existing APP11 C2PA from the target before inserting the new prepared payload.

  • Safety limits are enforced before backend calls (size, truncation, malformed).

Recommended Integration Order

  1. JPEG and TIFF direct backends (highest transfer value).

  2. JXL box emitter parity for EXIF/XMP plus bounded JUMBF/C2PA preserve or projection.

  3. If a future host-specific bridge needs persistence or replay formats, build that on top of the target-neutral package and adapter surfaces rather than adding a host-specific wrapper inside OpenMeta.

  4. Extend the current EXR attribute batch bridge if host-side replay or persistence formats are needed.

This order aligns with fast transfer requirements and minimal overhead in high-FPS pipelines.

page Metadata Support Matrix (Draft)

This document summarizes the current metadata read-path coverage in OpenMeta. OpenMeta does not decode, decompress, demosaic, or render image pixels.

It is meant to answer four basic questions:

  • which containers are scanned

  • which metadata families are decoded into MetaStore

  • where display-name mapping exists

  • what can be dumped or exported today

Status Labels

  • Yes: supported in current code

  • Partial: supported, but still bounded or best-effort

  • No: not supported yet

Host integrations can query the same kind of runtime support information with openmeta/metadata_capabilities.h. That API reports read, structured decode, transfer preparation, target edit, and raw-preservation support by target format and metadata family.

Some capabilities depend on build-time discovery. Structured XMP requires Expat, Deflate-compressed metadata requires zlib, JPEG XL brob metadata requires Brotli, and ranked fuzzy search requires explicitly enabling and finding RapidFuzz C++. The configured build report and runtime capability API are authoritative for a particular binary.

For the public camera RAW read-depth plan against ExifTool-style coverage, see raw_read_parity_plan.md.

Coverage Snapshot

Current tracked-gate status:

  • EXIF tag-id compare gates are passing on tracked HEIC/HEIF, CR3, and mixed RAW corpora.

  • Standalone EXIF/TIFF payload recovery is covered for files with a short non-TIFF prefix or a malformed JPEG prefix before the Exif preamble.

  • EXR header metadata compare is passing for the documented name/type/value-class contract.

  • Sidecar export paths (lossless and portable) are covered by baseline and smoke tests.

  • MakerNote coverage is tracked by baseline gates with broad vendor support; unknown vendor tags are preserved as raw metadata for lossless workflows. Current public naming includes Fujifilm flash white-balance and native RAF firmware fields, plus selected model-specific Sony correction-offset routes.

  • Decoded vendor MakerNote sub-IFDs are interpreted/query metadata. Writers do not reconstruct MakerNote blobs from those decoded fields. Compatible-file Keep preserves the original raw payload as unverified opaque bytes; it does not relocate nested offsets, repair vendor checksums, or prove semantic readability after repacking. Explicit Rewrite drops when those operations are unavailable. Hosts can inspect this boundary with makernote_transfer_audit_from_store(...). The separate makernote_layout_transfer_audit_from_store(...) recognizes canonical Nikon type 1/type 3 offset layouts and validates standard embedded-TIFF structure for type 3 without claiming vendor-private offset or checksum validation.

  • Metadata-family presence gates for XMP, ICC, IPTC-IIM, Photoshop IRB, and JUMBF/C2PA are clean on the tracked still-image corpus. Current read coverage includes EXIF/TIFF-carried ICC/IPTC payloads, bare JPEG APP1 XMP packets, and XMP packets using alternate xmpmeta namespace prefixes.

  • BMFF edge-path tests include iloc construction-method-2 relation variants and safe-skip handling for invalid references.

  • Dedicated synthetic read-release gates decode metadata from AVIF, GIF, and JXL containers. Separate SR2/SRF gates exercise their shared TIFF metadata carrier only; they do not claim native legacy SR2/SRF private-structure coverage.

Container Coverage

Container / input type

Block discovery

Structured decode in simple_meta_read(...)

Notes

JPEG

Yes

Yes

EXIF, standard and bare APP1 XMP, extended XMP, ICC, MPF, Photoshop IRB, comments, vendor APP blocks, and bounded JUMBF/C2PA; leading-segment scan supports bounded positional callbacks without reading entropy data

PNG

Yes

Yes

EXIF, XMP, ICC, structured PNG text, and bounded JUMBF/C2PA; chunk scan supports bounded positional callbacks without reading pixel payloads

WebP

Yes

Yes

EXIF, XMP, ICC, and bounded JUMBF/C2PA; chunk scan supports bounded positional callbacks without reading image payloads

GIF

Yes

Partial

XMP, ICC, and structured comments; extension scan and payload fetch support bounded positional callbacks without reading raster sub-block payloads

TIFF / DNG / TIFF-based RAW

Yes

Yes

EXIF, MakerNote, XMP, IPTC, Photoshop IRB, ICC, GeoTIFF, and bounded JUMBF/C2PA

CRW / CIFF

Yes

Partial

Recursive CIFF directories, stable scalar/subtable decode, derived EXIF bridge, and bounded native Canon CIFF naming/projection

RAF / X3F

Partial

Partial

RAF includes header-declared preview-JPEG EXIF/XMP discovery, FujiIFD/TIFF follow path, native RAF header/directory geometry tags, RAFData geometry projection, and standalone XMP fallback; X3F includes header fields, known PROP properties, section-directory JPEG metadata follow path, and legacy embedded-EXIF fallback

JP2

Yes

Yes

EXIF, XMP, IPTC, ICC, and GeoTIFF; box scan supports bounded positional callbacks without reading codestream payloads

JXL

Yes

Yes

EXIF, XMP, and bounded JUMBF/C2PA; supported brob wrapped metadata is decoded and box scan supports bounded positional callbacks

HEIF / AVIF / CR3

Yes

Partial

EXIF, XMP, ICC, CR3 maker blocks, BMFF derived fields including avif/avis/avio AVIF brands, and bounded JUMBF/C2PA; structural/item scan supports bounded positional callbacks without reading mdat payloads

EXR

n/a via scan_auto(...)

Yes

Header attributes only; bounded positional header traversal stops before pixel/chunk data; no pixel decode

Camera RAW Support Tiers

Camera RAW extensions are not equivalent to independent complete decoders. Several families use the shared TIFF/EXIF path, and structured decode depth can differ from raw block preservation.

Camera RAW lane

Metadata read

Vendor-private interpretation

Metadata write / transfer

DNG

Strong TIFF/EXIF/DNG baseline

DNG tags plus available MakerNote interpretation

Bounded TIFF-backed DNG target; not a RAW pixel writer

CR2, NEF/NRW, ARW, RW2, ORF, PEF, and other TIFF-based RAW

Yes through the shared TIFF/EXIF carrier

Varies by vendor, model, MakerNote version, and private table

No general native vendor-RAW writer

Legacy Sony SR2/SRF

Shared TIFF metadata carrier covered

Older native private structures remain partial

No native writer

CR3

Yes through the dedicated ISO-BMFF lane

Bounded metadata graph, EXIF/XMP/ICC, and Canon maker metadata

Bounded metadata graph edit; not a CR3 image encoder

CRW/CIFF

Yes through a dedicated native lane

Partial

No native writer

RAF and X3F

Partial dedicated native lanes

Partial

No native writer

Vendor metadata for Phase One/Leaf, Panasonic, Olympus, Pentax, Kodak, Minolta, Samsung, Ricoh, Apple, DJI, Google, FLIR, and other families is interpreted where layouts are stable and testable. This is not a claim that every model or private table is decoded. For the detailed family gaps, see raw_read_parity_plan.md.

Metadata Family Coverage

Metadata family

Decode

Name mapping

Dump / export

Notes

EXIF (MetaKeyKind::ExifTag)

Yes

Yes

Yes

Standard EXIF plus pointer IFDs, including current EXIF 3.1 learning/development/correction/noise tag names and bounded correction/noise value labels

MakerNote

Partial / Yes

Partial / Yes

Lossless yes; portable limited

Broad vendor coverage; unknown tags may remain raw; selected version/firmware payloads, live-vendor scalar fields, Fujifilm flash white-balance and native RAF firmware names, selected Sony correction-offset routes, Reconyx scalar/string-coded fields, Microsoft stitch fields, Nintendo category fields, Sanyo public-context scalar fields, current Canon RF/Nikon Z lens labels, and an ambiguous Pentax Sigma/Samsung/Tokina lens-family label have bounded display helpers

XMP (MetaKeyKind::XmpProperty)

Yes

Native schema/path

Yes

Requires Expat at build time; known nested namespaces use portable prefixes and unknown nested namespaces use a collision-safe nsu_<namespace-uri-hex>: segment that preserves full namespace identity

ICC (IccHeaderField, IccTag)

Yes

Yes

Yes

Header fields plus tag table; raw tag payload preserved

IPTC-IIM (IptcDataset)

Yes

Yes

Yes

Raw dataset bytes preserved

Photoshop IRB (PhotoshopIrb)

Yes

Partial / Yes

Yes

Raw resources preserved, bounded interpreted subset, fixed-layout, Lightroom workflow, IPTC-NAA byte count, working-path and numbered clipping-path record summaries, descriptor-header, scalar/class/alias/reference, enum, and nested list/object summaries, embedded IPTC/XMP/ICC decode

MPF

Yes

Yes

Yes

Basic TIFF-IFD decode

GeoTIFF (GeotiffKey)

Yes

Yes

Yes

GeoKeyDirectoryTag decode

BMFF derived fields (BmffField)

Yes

Yes

Yes

ftyp brand names including avif/avis/avio AVIF-compatible brands, item-info, ipco, ipma, iref, grpl, iloc/idat, bounded grid/iovl/iden construction semantics, graph summaries with component roles, member item IDs, semantic/relation counts and policy hints, aux semantics, primary item properties, primary metadata-carrier flags, primary sidecar summaries, primary-scene summaries, and bounded primary-linked image roles

JUMBF / C2PA (JumbfField, JumbfCborKey)

Partial

Yes

Yes

Draft structural and semantic layer with box labels; not full conformance

EXR attributes (ExrAttribute)

Yes

Native names

Yes

Header attributes only

Important Bounded Areas

CRW / CIFF

OpenMeta now does more than a pure derived-EXIF bridge:

  • common native CIFF tags are named

  • a bounded set of native subtables is projected

  • stable scalar native CIFF fields are decoded where the layout is clear

It is still a partial lane compared to the deepest legacy Canon tooling.

RAF

OpenMeta now follows both RAF metadata carriers that matter for common camera files:

  • the header-declared preview JPEG is scanned for standard EXIF/XMP-style metadata

  • the header-declared FujiIFD/TIFF area is scanned for native RAF/raw fields

  • native RAF header, directory, and RAFData-derived fields are classified as source-specific metadata for rendered-transfer safety

Deeper model-specific RAF sections remain a partial lane.

X3F

OpenMeta now has a bounded native Sigma X3F lane:

  • common X3F header fields are decoded as x3f_header

  • stable header-extension adjustment fields are decoded as x3f_header_ext

  • known PROP properties are decoded as x3f_prop

  • section-directory JPEG metadata is followed for embedded EXIF/XMP-style metadata blocks, with the older embedded-EXIF scan kept as fallback

Deeper image-processing/compression sections remain partial and should only be promoted when fields can be typed, named, and safety-classified.

Photoshop IRB

OpenMeta preserves raw IRB resources and also decodes a bounded interpreted subset. That subset includes common fixed-layout resources and descriptor-header summaries such as:

  • Photoshop2Info

  • Photoshop2ColorTable

  • ResolutionInfo

  • AlphaChannelsNames

  • DisplayInfo

  • PStringCaption

  • BorderInformation

  • BackgroundColor

  • VersionInfo

  • PrintFlags

  • print-flag byte fields

  • EffectiveBW

  • QuickMaskInfo

  • RawImageMode

  • JPEG_Quality

  • GridGuidesInfo

  • legacy halftone, transfer-function, duotone-image, and EPS byte summaries

  • PhotoshopBGRThumbnail / PhotoshopThumbnail headers

  • SpotHalftone

  • UnicodeAlphaNames

  • AlphaIdentifiers

  • JumpToXPEP

  • PrintScaleInfo

  • PixelInfo

  • AutoSaveFilePath

  • AutoSaveFormat

  • XMLData

  • ImageReadyVariables

  • ImageReadyDataSets

  • LightroomWorkflow

  • IPTCDataBytes

  • ColorSamplersResource / ColorSamplersResource2 headers and records

  • WorkingPath and numbered path resources as byte counts plus record counts/selectors

  • descriptor-header summaries, bounded scalar, class, alias, enum, and obj reference item bodies, raw-data descriptor byte counts, and bounded nested list/object traversal with item paths, depths, list indices, and parsed-value counts for resources such as LayerComps, MeasurementScale, HDRToningInfo, PrintInfo, TimelineInfo, SheetDisclosure, OnionSkins, CountInfo, PrintInfo2, PrintStyle, PathSelectionState, and OriginPathInfo

  • ChannelOptions

  • PrintFlagsInfo

  • ClippingPathName

  • MacintoshPrintInfo, MacintoshNSPrintInfo, WindowsDEVMODE, AlternateDuotoneColors, AlternateSpotColors, ObsoletePhotoshopTag1, ObsoletePhotoshopTag2, and ObsoletePhotoshopTag3 byte counts

  • embedded IPTC-NAA, ICC, EXIF, EXIF2, and XMP resource byte counts

When enabled, embedded IPTC-IIM, XMP, and ICC payloads in IRB resources are also decoded into their regular OpenMeta entry families.

Current Photoshop IRB interpretation status:

Resource area

Status

Notes

Raw IRB resources

Preserved

Every accepted resource keeps a lossless PhotoshopIrb raw entry.

Embedded IPTC/XMP/ICC/EXIF carriers

Interpreted where enabled

Payload bytes remain preserved; enabled decoders also emit regular family entries.

Fixed-layout scalar/string resources

Interpreted

Resolution, alpha/caption strings, version, print flags, quick mask, JPEG quality, URL/list, pixel info, autosave strings, XMLData, ImageReady text, Lightroom workflow text, and similar bounded fields.

Geometry/display/color-sampler/path headers

Interpreted / record-summary

Display/grid/thumbnail/color-sampler headers are decoded; path resources expose byte counts, record counts, and selectors without interpreting Bezier payloads.

Descriptor-backed Photoshop resources

Descriptor header plus bounded item summaries

Descriptor version, remaining byte count, class ID/name, item count, complete value bodies for bool, long, comp, doub, UntF, TEXT, enum, type, and GlbC, opaque byte counts for alis and tdta, nested object/list paths, depths, list indices, list/object counts, and parsed-value count fields are emitted. Bounded obj streams expose ordered property, class, enumerated, offset, identifier, index, and name references with paths, depths, indices, class IDs/names, subtype values, and parsed counters. Alias/raw payload contents and full Photoshop action execution semantics remain out of scope for this subset.

Legacy halftone/transfer/duotone/EPS resources

Header / byte-count only

OpenMeta emits byte counts and first header words where safe, without claiming full Photoshop semantics.

Proprietary, obsolete, or OS-specific resources

Raw-preserved, selected byte counts

Kept losslessly; selected stable resource IDs expose byte counts without claiming payload semantics.

This is useful, but it is still not full Photoshop-resource parity.

Descriptor reference traversal accepts at most 64 items in one obj value and 128 reference items across one descriptor. Unknown, incomplete, or excess reference data stops traversal and emits DescriptorItemParseTruncated; a partially decoded reference element is never emitted.

BMFF (<tt>HEIF</tt> / <tt>AVIF</tt> / <tt>CR3</tt>)

OpenMeta now has a bounded semantic model on top of raw item discovery:

  • ftyp.*, including brand names and compatible-brand counts

  • primary item properties, primary metadata-carrier flags, primary sidecar counts/flags for linked metadata and image sidecars, content-bound C2PA/JUMBF sidecar policy hints, and compact primary-scene node/edge summaries

  • ipco property-container summaries with total, known, unknown, and per-known-type property counts

  • ipma item-property association rows with item ids, property indices, essential flags, and known property type names

  • per-known-property ipma.<type> association, primary-association, and essential-count rollups for common primary-item properties

  • iinf/infe item-info rows

  • item type-name and semantic labels for EXIF, XMP, JUMBF, C2PA, ICC profile, image, URI, auxiliary, thumbnail, derived-image, and content-description items

  • aggregate item semantic counters for known, metadata, image, EXIF, XMP, JUMBF, C2PA, ICC profile, auxiliary, derived, thumbnail, content-description, URI, and JSON roles

  • whole-scene item graph counters for known items, image/metadata/content-bound metadata nodes, selected image-role nodes, relation edges, item groups, and conservative content-bound metadata / multi-image policy hints including explicit multi-image policy text

  • bounded scene graph component counters for observed relation graph nodes, connected components, image and multi-image components, isolated image nodes, components with content-bound metadata, per-component role text, ordered member item IDs, known/unknown and semantic node counts, isolated state, typed auxiliary/derived/thumbnail/content-description edge counts, alpha/depth/disparity/matte auxiliary edge counts, primary graph-component nodes/edges, primary component content-bound flags, primary component multi-image candidates and policy text, and primary component content-bound metadata policy

  • typed iref.<type>.* rows, including direction-correct endpoint roles and named item-id aliases for auxl, dimg, thmb, and cdsc; literal from_item_id and to_item_id rows remain unchanged

  • bounded grpl item-group rows and per-group-type summaries, including group semantics and ordered entity roles for altr, ster, and pymd

  • bounded iloc/idat item-data layout summaries, including construction methods, extent counts, total extent byte counts, idat byte counts, and primary-item location aliases

  • bounded grid, iovl, and iden derived-image construction rows with ordered dimg source IDs, descriptor/source/construction validity, grid rows, columns, tile coordinates and output size, overlay canvas/background and signed source offsets, identity sources, primary aliases, bounded method-2 item-offset descriptor chains, descriptor reference depth, derived-graph cycle/missing-source/truncated-reference validation, and a source-bound container_graph concept for query/transfer diagnostics

  • tili tiled-image items and bounded tilC version-0 configuration fields, including tile width/height, up to eight extra dimensions, required single-ispe/single-tilC association checks, ceil-divided tile rows/columns, overflow-checked expected tile counts, dinf/dref/deti mapping, internal tile_item_type and nested tipa associations, bounded external URL components, logical-iloc offset tables, explicit or sequentially inferred tile sizes, empty-tile state, complete-configuration validity, and source-bound query/transfer diagnostics

  • graph summaries

  • auxC-typed auxiliary semantics

  • bounded primary-linked image-role fields, separate primary inbound derived-image and outbound derived-source summaries, compact primary sidecar aggregate fields, and compact primary-scene aggregate fields

  • primary colr summaries for nclx/nclc color fields and ICC profile-size carriers

  • primary pasp, pixi, and clap item-property summaries for pixel aspect ratio, pixel component bit depth, and clean aperture

This is intentionally smaller than a full QuickTime/BMFF semantic model. Derived descriptors are interpreted from complete method-0 file extents, method-1 idat extents, and bounded method-2 item-offset chains. Method-2 resolution follows ordered iref iloc references, rejects reserved or out-of-range indexes, detects recursion cycles, validates every source range, and never materializes a complete logical item. External data references other than bounded tiled-image deti URL state and incomplete extent inventories remain structural-only. Tiled-image offset-table validation scans at most 262144 entries and emits at most 64 rows; URL components retain at most 512 bytes for field output. Larger valid structures remain visible through counts and truncation fields but do not receive complete-configuration validity.

JXL

OpenMeta decodes:

  • direct Exif

  • direct xml

  • direct jumb

  • direct c2pa

  • wrapped brob forms for those same realtypes

Other brob realtypes are still out of scope.

JUMBF / C2PA

Current support is intentionally draft:

  • structural BMFF box decode

  • JUMBF box labels from parsed jumd boxes

  • bounded CBOR traversal

  • draft c2pa.semantic.* projection

  • optional signature and certificate-chain diagnostic scaffolding

What this means in practice:

  • OpenMeta can expose useful manifest / claim / signature / ingredient shape information

  • the current verification result must not be used as an asset-authenticity or trust gate: it does not establish the manifest’s hard binding to the complete asset; cryptographic signature success is reported as signature_verified_only

  • verify_require_trusted_chain and --c2pa-verify-require-trusted-chain additionally require a trusted chain bound to the signature key, but do not establish asset binding

  • OpenMeta does not claim full C2PA manifest semantics, asset binding, or policy validation

Structural JUMBF and C2PA metadata decode remains available independently of the optional verification scaffold.

Tool-Level Behavior

Tool

Purpose

Current state

metaread

Human-readable metadata listing

Shows decoded entries with mapped names where available

metavalidate

Metadata validation

Reports decode-status and validation issues with machine-readable issue codes

metadump

Sidecar and preview dump tool

Supports lossless and portable sidecar output plus preview extraction

thumdump

Preview extractor

Extracts embedded preview candidates

metatransfer

Transfer/edit smoke tool

Exercises the transfer core for supported target families

Main Current Gaps

  • independently authored conformance-file validation for the recently standardized BMFF tiled-image layout

  • additional JXL brob realtypes beyond Exif, xml, jumb, and c2pa

  • full JUMBF/C2PA semantics and policy validation

  • deeper RAF model-specific native tables and X3F image-processing sections beyond the current bounded carrier/header/property lanes

  • full Photoshop action execution semantics, opaque alias/raw descriptor payload interpretation, and broader IRB interpretation beyond the current subset

Related Docs

page Metadata Transfer Plan (Draft)

Date: March 5, 2026

Related:

Goal

The transfer core is for metadata-only workflows:

  • source: camera RAW and other supported inputs

  • target: export-oriented container metadata

  • scope: prepare once, then emit or edit many times

Pixel transcoding is out of scope.

Design Rule

Transfer should not bottleneck high-throughput pipelines.

The core rule is:

  • do the expensive work once during prepare

  • reuse prebuilt metadata payloads during compile and emit

  • keep per-frame work limited to optional time patching plus final container write calls

Current Status

Current planning estimate for this lane: about 80-85%.

Source-side readiness is already strong:

  • tracked EXIF read gates are green on HEIC/HEIF, CR3, and mixed RAW corpora

  • tracked MakerNote gates are green

  • portable XMP gates are green

  • EXR header interop gates are green

The main remaining work is now on the target side.

The first public write-side sync controls are also in place:

  • generated XMP can explicitly suppress EXIF-derived projection

  • generated XMP can explicitly suppress IPTC-derived projection

  • TransferProfile::safety can distinguish compatible metadata repackage/recompression from rendered-image export, so callers can select a safe coarse policy without hand-picking individual tags

  • prepared bundles record those resolved projection decisions alongside the existing preservation policies

Logical metadata edits are covered through preparation and typed backend execution for every public target: JPEG, TIFF/DNG, JXL, WebP, PNG, JP2, HEIF, AVIF, CR3, and EXR. The regression verifies an edited safe camera descriptor reaches every target, while title, creator, and keyword edits reach every XMP-capable target and replaced or removed values are not serialized again. TIFF/DNG and EXR execution intentionally uses their typed writer or adapter contracts rather than a generic byte stream. EXR does not embed XMP, so its safe string-attribute projection is intentionally narrower than the XMP-capable targets.

Target Status Matrix

Target

Status

Current shape

Main limits

JPEG

First-class

Prepared bundle, compiled emit, byte-writer emit, edit planning/apply, file helper, bounded JUMBF/C2PA staging

Not a full arbitrary metadata editor yet

TIFF

First-class

Prepared bundle, compiled emit, classic-TIFF and BigTIFF edit planning/apply, bounded preview-page chain rewrite (ifd1, ifd2, and preserved downstream tails), bounded SubIFD rewrite with preserved downstream auxiliary tails and preserved trailing existing children when only the front subset is replaced, bounded ExifIFD -> InteropIFD preservation when a replaced ExifIFD omits its own interop child, file helper, streaming edit path

Broader TIFF rewrite coverage is still narrower than JPEG

DNG

First-class

Dedicated public target layered on the TIFF backend; prepared bundle, compiled emit, minimal DNGVersion synthesis when missing, bounded DNG preview/aux merge policy, read-backed file-helper roundtrip, and the same bounded SubIFD/preview-tail/interop preservation contract as TIFF

Not a full DNG-specific rewrite engine or broad DNG policy surface

PNG

Bounded but real

Prepared bundle, compiled emit, bounded chunk rewrite/edit, file-helper roundtrip

Not a general PNG chunk editor

WebP

Bounded but real

Prepared bundle, compiled emit, bounded chunk rewrite/edit, file-helper roundtrip

Not a general WebP chunk editor

JP2

Bounded but real

Prepared bundle, compiled emit, bounded box rewrite/edit, file-helper roundtrip

jp2h synthesis is still out of scope

JXL

Bounded but real

Prepared bundle, compiled emit, bounded box rewrite/edit, file-helper roundtrip

Still narrower than JPEG/TIFF

HEIF / AVIF / CR3

Bounded but real

Prepared bundle, compiled emit, direct prepared item/property payload byte-writer handoff, OpenMeta-managed BMFF item/property edit, constrained foreign-meta item merge/replacement/strip, managed item-ID remapping across iref/version-0 grpl/ipma, plus bounded ICC property merge, file-helper roundtrip

Direct payload output is a host handoff rather than a standalone BMFF file; arbitrary foreign meta scene/property-graph rewrite is still unsupported

EXR

Bounded but real

Prepared bundle, compiled emit, direct backend attribute emit, prepared-bundle to ExrAdapterBatch bridge, CLI/Python transfer surface

No file rewrite/edit path yet; current transfer payload is safe string attributes only

What Is Already Implemented

Core API

The shared transfer core already provides:

  • prepare_metadata_for_target(...)

  • prepare_metadata_for_target_file(...)

  • compile_prepared_transfer_execution(...)

  • execute_prepared_transfer(...)

  • execute_prepared_transfer_compiled(...)

  • execute_prepared_transfer_file(...)

This supports both:

  • prepare -> compile -> emit

  • prepare -> compile -> patch -> emit/edit

Core Utility Layers

These support the public transfer flow:

  • TransferByteWriter

  • SpanTransferByteWriter

  • prepared payload and package batch persistence

  • adapter views for host integrations

  • explicit time-patch support for fixed-width EXIF date/time fields

  • transfer-policy decisions for MakerNote, JUMBF, C2PA, EXIF-to-XMP projection, and IPTC-to-XMP projection

Current File-Helper Regression Coverage

OpenMeta now has explicit end-to-end read-backed transfer tests for:

  • source JPEG -> JPEG edit/apply -> read-back

  • source JPEG -> TIFF edit/apply -> read-back

  • source JPEG -> DNG edit/apply -> read-back

  • source JPEG -> TIFF edit/apply with bounded preview-page chain -> read-back

  • source TIFF/BigTIFF with existing multi-page preview chain -> replace the front preview pages and preserve downstream tails

  • source DNG-like TIFF with subifd0 + ifd1 -> TIFF edit/apply -> read-back

  • source DNG-like TIFF with subifd0 + ifd1 -> BigTIFF edit/apply -> read-back

  • source DNG-like TIFF with subifd0 + ifd1 -> DNG edit/apply -> read-back

  • source TIFF/BigTIFF with existing subifd0 -> next auxiliary chain -> replace subifd0 -> preserve downstream auxiliary tail

  • source JPEG -> PNG edit/apply -> read-back

  • source JPEG -> WebP edit/apply -> read-back

  • source JPEG -> JP2 edit/apply -> read-back

  • source JPEG -> JXL edit/apply -> read-back

  • source JPEG -> bounded HEIF edit/apply -> read-back

  • source JPEG -> bounded AVIF edit/apply -> read-back

  • source JPEG -> bounded CR3 edit/apply -> read-back

  • source ICC -> bounded BMFF ICC property edit/apply -> read-back and external validation when local HEIF/AVIF/CR3 encoders can create usable targets

  • direct BMFF package planning/writing for prepared metadata items and bounded ICC colr/prof property payloads, high-level byte-writer handoff with capacity preflight and item/property summaries, plus owned package replay for constrained foreign-meta graph merges

  • source XMP -> bounded BMFF XMP item edit/apply -> read-back and external validation on configured HEIF/AVIF/CR3 targets where local tools expose the transferred XMP payload

  • source EXIF -> bounded BMFF Exif item edit/apply -> explicit ExifTool reader-layout regression check on configured HEIF/AVIF/CR3 targets

That does not make all targets equally mature, but it does mean the transfer core has real roundtrip regression gates across the primary supported export families.

The primary writer family is also covered by a deterministic compatibility-dump gate for JPEG, TIFF, DNG, PNG, WebP, JP2, JXL, and bounded HEIF, AVIF, and CR3 item metadata edits. That gate checks the prepared EXIF/XMP routes, edit/apply status, dual-write XMP writeback summary, and decoded metadata dump for the managed source fields. Additional compatibility-dump gates cover sidecar-only writeback with explicit sidecar-base overrides and embedded-only writeback with destination-sidecar cleanup through persisted output.

There is now also a named in-tree transfer release gate:

  • openmeta_gate_transfer_release

  • openmeta_transfer_release_gate

In a non-Python test tree it runs:

  • MetadataTransferApi.*

  • XmpDump.*

  • ExrAdapter.*

  • DngSdkAdapter.*

  • openmeta_cli_metatransfer_smoke

In a Python-enabled test tree it also runs:

  • openmeta_python_transfer_probe_smoke

  • openmeta_python_metatransfer_edit_smoke

The external image-usability gate can use optional configured HEIF, AVIF, and CR3 target files via CMake cache paths when local tools cannot create those formats. Configured BMFF targets exercise ICC property, XMP item, MakerNote, and EXIF image-property transfer/read-back routes. For real configured targets, the gate infers target-owned image dimensions, channel count, bit depth, sample format, and photometric layout before transfer, so OpenMeta does not write the synthetic fixture geometry into the destination metadata. ExifTool is used when available for BMFF EXIF/XMP/ICC reader compatibility checks.

Per-Target Notes

JPEG

Strongest current target.

Implemented:

  • EXIF as APP1

  • XMP as APP1

  • ICC as APP2

  • IPTC as APP13

  • edit planning and apply

  • byte-writer emit

  • bounded JUMBF/C2PA staging

TIFF

Also a first-class target.

Implemented:

  • EXIF, XMP, ICC, and IPTC transfer

  • edit planning and apply

  • classic-TIFF and BigTIFF rewrite support

  • bounded ifd1 chain rewrite support, including preserving an existing downstream page tail when ifd1 is replaced

  • bounded TIFF/DNG-style SubIFD rewrite support, including preserving an existing downstream auxiliary tail when subifdN is replaced

  • bounded front-subset SubIFD replacement that preserves trailing existing children from the target file

  • bounded ExifIFD replacement that preserves an existing target InteropIFD when the source replacement omits its own interop child

  • target-owned root image layout and target-local TIFF storage pointers: source EXIF cannot replace the active target root image width/height, sample layout, compression, orientation, strip/tile offsets, strip/tile byte counts, or JPEG interchange offsets; replaced preview/SubIFD structures also drop source-local storage offsets and preserve matching target-local storage fields where available

  • target-owned image-dependent metadata filtering across prepared transfer: EXIF/XMP image dimensions, channel/layout fields, source-local storage offsets, color-space aliases, and similar source image-buffer facts are omitted before packaging metadata for JPEG, TIFF/DNG, PNG, WebP, JP2, JXL, BMFF-family targets, and EXR string attributes. Host writers that change pixels must provide target image buffer specs and target-correct values instead of relying on copied source image properties. C++ callers can set PrepareTransferRequest::target_image_spec to inject target dimensions, orientation, samples-per-pixel, bit depth, sample format, photometric interpretation, planar configuration, compression, and EXIF color space after source image-layout fields have been filtered. The Python binding and both command-line transfer wrappers now expose the same target image spec surface for file-helper integration tests.

  • rendered-output safety mode: TransferProfile::safety = TransferSafetyMode::RenderedImage additionally drops source raw color calibration, profile/gain tables, raw digests/storage identifiers, linearization/crop/correction metadata, vendor RAW geometry/color/correction/thermal/computational/private/stitch fields, camera raw settings XMP, source ICC profiles, MakerNotes, and non-C2PA JUMBF data. It is intended for RAW-to-rendered or otherwise pixel-changing exports where host code must provide target-correct color/profile data.

  • concept-level BMFF diagnostics treat tiled_image.configuration as source-container-bound: compatible-file mode can keep the evidence, while rendered-image mode reports drop.tiled_image_configuration. This diagnostic does not authorize copying source tilC bytes into a rewritten destination item graph.

  • safety regression coverage now checks both sides of that boundary: compatible-file mode keeps serializable source RAW/camera-specific metadata, while rendered-image mode drops the same source-specific data and injects host-provided target dimensions, channel count, bit depth, sample format, photometric interpretation, and orientation.

  • current writer limits still apply after safety filtering: some compatible source metadata can be retained in the decoded MetaStore and audit, but may not yet serialize through every target writer path. Adobe DNG XMP properties (dng:*) are now emitted by the portable XMP writer when retained by compatible-file safety. The remaining writer gap is mainly reconstructed vendor-private MakerNote sub-IFDs and unknown/custom XMP namespaces that do not have a declared portable writer contract. OpenMeta preserves the raw ExifIFD:MakerNote payload when it is present, but decoded-only vendor MakerNote sub-IFD fields are reported as non-serializable and are not used to synthesize a new MakerNote blob.

  • bounded DNG-style merge policy in the file-helper path: source-supplied preview/aux front structures replace the target front structures, while existing target page tails and trailing auxiliary children are preserved

  • file-based helper flow

  • streaming edit output

DNG

Implemented as a dedicated public target on top of the TIFF backend.

Implemented:

  • EXIF, XMP, ICC, and IPTC transfer through the TIFF-family backend

  • read-backed file-helper roundtrip for JPEG-source and DNG-like-source input

  • minimal DNGVersion synthesis when the source metadata lacks it

  • explicit public target modes:

    • ExistingTarget

    • TemplateTarget

    • MinimalFreshScaffold

  • bounded preview-page chain rewrite/merge

  • bounded raw-image SubIFD rewrite/merge

  • preservation of existing target DNG core tags when a non-DNG source is merged into an existing DNG target

  • preserved downstream page tails and downstream auxiliary tails

  • preserved trailing existing auxiliary children when only the front subset is replaced

  • bounded ExifIFD replacement that preserves an existing target InteropIFD when the source replacement omits its own interop child

Current limits:

  • still a bounded DNG policy layer, not a full DNG-specific rewrite engine

  • broader arbitrary nested-IFD graph rewrite is still out of scope

  • in the file-helper path, ExistingTarget and TemplateTarget now require an explicit target path; only MinimalFreshScaffold keeps the metadata-only prepare/emit path available without a backing DNG container

Optional host bridge:

  • When OpenMeta is built with OPENMETA_WITH_DNG_SDK_ADAPTER=ON and a dng_sdk package is discoverable, openmeta/dng_sdk_adapter.h exposes a bounded Adobe DNG SDK bridge for:

    • applying prepared OpenMeta DNG bundles onto dng_negative

    • updating an existing dng_stream via the SDK’s metadata-update path

    • a direct file-helper for source file -> existing DNG file in-place update

    • a matching direct Python binding over that file-helper

    • a thin CLI wrapper via metatransfer --update-dng-sdk-file

  • This adapter is optional. Core Dng transfer support remains available without the Adobe SDK.

  • The OpenMeta build must use a C++ runtime/standard library compatible with the discovered dng_sdk package.

  • Public automated CI intentionally excludes this SDK-backed lane because the Adobe DNG SDK is not part of the public dependency/distribution story. Treat it as a maintainer or release-validation path rather than a default GitHub Actions requirement.

PNG

Implemented as a bounded chunk target:

  • eXIf

  • XMP iTXt

  • iCCP

  • bounded rewrite/edit for managed metadata chunks

WebP

Implemented as a bounded RIFF metadata target:

  • EXIF

  • XMP

  • ICCP

  • bounded C2PA

  • bounded rewrite/edit for managed metadata chunks

  • EXIF chunk payloads use direct TIFF bytes, without the JPEG APP1 Exif\0\0 preamble

JP2

Implemented as a bounded box target:

  • Exif

  • xml

  • bounded jp2h / colr

  • bounded rewrite/edit for top-level managed metadata

  • replacement of managed colr in an existing jp2h

JXL

Implemented as a bounded box target:

  • Exif

  • xml

  • bounded jumb

  • bounded c2pa

  • encoder ICC handoff

  • bounded box-based edit path

HEIF / AVIF / CR3

Implemented as a bounded BMFF target family:

  • bmff:item-exif

  • bmff:item-xmp

  • bounded bmff:item-jumb

  • bounded bmff:item-c2pa

  • bounded bmff:property-colr-icc

  • bounded OpenMeta-managed metadata-only meta rewrite path

  • constrained foreign top-level meta item merge for parseable iinf, iloc version 0/1/2, pitm, optional single idat, and primary-item cdsc references

  • bounded 32-bit item-id insertion for foreign item graphs, including automatic iloc version 2 upgrade when an otherwise supported iloc version 0/1 graph exhausts the 16-bit item-id space

  • inserted metadata item records keep iloc construction method 0 and use absolute file-offset extents for broad reader compatibility

  • retained foreign item locations support construction method 0 file offsets and construction method 1 idat extents with data reference index 0 or an explicitly self-contained version-0 dinf/dref url or urn entry

  • retained construction method 2 item-reference extents are supported when iref iloc references are parseable by explicit extent index or reference order and referenced items are also retained with supported local locations; its referenced target records remain limited to data reference index 0; missing references, removed referenced items, non-self-contained data references, and other construction methods fail safely

  • unambiguous one-old-to-one-new managed Exif, XMP, JUMBF, and C2PA item replacement remaps retained iref endpoints, version-0 grpl item-group members, and ipma item associations; strip and ambiguous replacement paths remove references to deleted managed item IDs instead of leaving them stale

  • rebuilt foreign iloc graphs compact foldable self-contained base offsets to a zero-width base-offset field when safe

  • bounded foreign top-level meta ICC property merge by replacing prior ICC colr/prof and colr/rICC properties, remapping ipma, and associating the transferred colr/prof property with the primary item and any retained item that previously referenced a replaced ICC property while preserving the prior essential association bit

  • bounded foreign top-level meta XMP replacement and strip support for parseable item graphs that satisfy the same primary-item contract

  • fail-safe rejection for unsupported foreign top-level meta shapes and broader BMFF item/property graph rewrite shapes outside the bounded contract

EXR

Implemented today as a bounded first-class target:

  • prepare_metadata_for_target(...)

  • prepare_metadata_for_target_file(...)

  • compile_prepared_transfer_execution(...)

  • emit_prepared_bundle_exr(...)

  • emit_prepared_transfer_compiled(...)

  • public CLI/Python --target-exr transfer surface

It still keeps the older integration bridge:

  • build_exr_attribute_batch(...)

  • build_exr_attribute_part_spans(...)

  • build_exr_attribute_part_views(...)

  • replay_exr_attribute_batch(...)

The transfer lane now also exposes:

  • build_prepared_exr_attribute_batch(...)

  • build_exr_attribute_batch_from_file(...)

  • Python build_exr_attribute_batch_from_file(...) for direct file-to-batch host-side inspection without going through the generic transfer probe

  • Python helper wrappers: openmeta.python.probe_exr_attribute_batch(...) and openmeta.python.get_exr_attribute_batch(...)

That keeps EXR host integrations on the transfer path: callers can prepare one TransferTargetFormat::Exr bundle, then materialize a native ExrAdapterBatch without re-projecting from the source MetaStore.

Current EXR transfer scope is intentionally conservative:

  • safe flattened string header attributes

  • backend emission through ExrTransferEmitter

  • no general file-based EXR metadata rewrite/edit path yet

  • no typed EXR attribute synthesis beyond the current safe string projection

Important user use case to keep visible:

  • A tile/region streaming EXR writer may know some metadata only after all pixel chunks are written, for example total_compute_time.

  • The practical fast path for that use case is not a general variable-length header rewrite. It is a fixed-size reservation/patch contract: declare a fixed-width attribute, such as a double, before opening the EXR writer, write pixel chunks normally, then patch only the reserved value bytes after close.

  • OpenMeta does not expose that late-bound EXR patch plan yet. If EXR depth is expanded, the first useful scope should be a bounded fixed-size patch API with offset discovery, type/size validation, and a decode-after-patch verification gate.

Transfer Policies

The public transfer contract now models five policy subjects:

  • MakerNote

  • JUMBF

  • C2PA

  • XMP EXIF projection

  • XMP IPTC projection

Each uses explicit TransferPolicyAction values:

  • Keep

  • Drop

  • Invalidate

  • Rewrite

Prepared bundles also record the resolved policy decisions and reasons so callers do not have to infer behavior from warning text alone.

For the XMP projection subjects, the current public knobs are intentionally simple:

  • EXIF-derived properties can be mirrored into generated XMP or suppressed

  • IPTC-derived properties can be mirrored into generated XMP or suppressed

  • generated portable XMP can choose how existing decoded XMP conflicts with generated EXIF/IPTC mappings

This gives callers stable write-side control over the most important projection behavior without forcing them to reverse-engineer the transfer output.

Write-Side Sync Controls

OpenMeta now has a bounded public sync-policy layer for generated XMP.

Current controls:

  • xmp_project_exif

  • xmp_project_iptc

  • xmp_existing_namespace_policy

    • KnownPortableOnly

    • PreserveCustom

  • xmp_conflict_policy

  • xmp_existing_sidecar_mode on the file-read/prepare path:

    • Ignore

    • MergeIfPresent

  • xmp_existing_sidecar_precedence on the file-read/prepare path:

    • SidecarWins

    • SourceWins

  • xmp_existing_destination_embedded_mode on the file-read/prepare and file-helper execution paths:

    • Ignore

    • MergeIfPresent

  • xmp_existing_destination_embedded_precedence on the file-read/prepare and file-helper execution paths:

    • DestinationWins

    • SourceWins

  • xmp_writeback_mode on the file-helper execution path:

    • EmbeddedOnly

    • SidecarOnly

    • EmbeddedAndSidecar

  • xmp_destination_embedded_mode on the file-helper execution path:

    • PreserveExisting

    • StripExisting

  • CLI:

    • --xmp-include-existing-sidecar

    • --xmp-existing-sidecar-precedence <sidecar_wins|source_wins>

    • --xmp-include-existing-destination-embedded

    • --xmp-existing-destination-embedded-precedence <destination_wins|source_wins>

    • --xmp-no-exif-projection

    • --xmp-no-iptc-projection

    • --xmp-conflict-policy <current|existing_wins|generated_wins>

    • --xmp-writeback <embedded|sidecar|embedded_and_sidecar>

    • --xmp-destination-embedded <preserve_existing|strip_existing>

    • --xmp-destination-sidecar <preserve_existing|strip_existing>

Current bounded writeback contract:

xmp_writeback_mode

Edited file

Sibling .xmp

Default cleanup behavior

EmbeddedOnly

Keep generated XMP in the managed embedded carrier

No generated sidecar output

Preserve any existing sibling .xmp unless xmp_destination_sidecar_mode=StripExisting

SidecarOnly

Suppress generated embedded XMP carriers

Return generated sidecar output

Preserve existing embedded XMP unless xmp_destination_embedded_mode=StripExisting

EmbeddedAndSidecar

Keep generated XMP in the managed embedded carrier

Return the same generated XMP as sibling .xmp output

No sidecar cleanup path is requested

Current behavior:

  • existing XMP can still be included independently

  • EXIF payload emission stays independent from EXIF-to-XMP projection

  • IPTC native carrier emission stays independent from IPTC-to-XMP projection

  • portable generated XMP can keep the historical mixed order, prefer existing decoded XMP, or prefer generated EXIF/IPTC mappings when the same portable property would collide

  • existing sibling .xmp sidecars from the destination path can be merged into generated portable XMP before transfer packaging when explicitly requested

  • that sidecar merge path now has explicit precedence against source-embedded existing XMP instead of relying on implicit decode order

  • existing embedded XMP from the destination file can also be merged into generated portable XMP on the file-read/prepare path and on the file-helper path when explicitly requested

  • that destination-embedded merge path has its own explicit precedence against source-embedded existing XMP instead of relying on implicit decode order

  • some targets without a native IPTC carrier can still use XMP as the bounded fallback carrier when IPTC projection is enabled

  • file-helper export can now strip prepared embedded XMP blocks and return canonical sidecar output guidance instead

  • file-helper export can also keep generated embedded XMP while emitting the same generated packet as a sibling .xmp sidecar

  • the public metatransfer CLI and Python transfer wrapper can now persist that generated XMP as a sibling .xmp sidecar when sidecar or dual-write XMP writeback is selected

  • the public metatransfer CLI and Python transfer wrapper now also expose the bounded destination-embedded merge and precedence controls directly

  • sidecar-only writeback now has an explicit destination embedded-XMP policy:

    • preserve existing embedded XMP by default

    • strip existing embedded XMP for jpeg, tiff, png, webp, jp2, and jxl

  • embedded-only writeback now has an explicit destination sidecar policy:

    • preserve an existing sibling .xmp by default

    • strip an existing sibling .xmp when explicitly requested

  • the C++ API now also has a bounded persistence helper for execute_prepared_transfer_file(...) results, so applications can write the edited file, write the generated .xmp sidecar, and remove a stale sibling .xmp without reimplementing wrapper-side file logic

  • the Python binding now exposes the same persistence path through transfer_file(...) and unsafe_transfer_file(...), and the public Python wrapper uses that core helper instead of maintaining its own sidecar write and cleanup implementation

  • the Python binding now also exposes the reusable decoded-source path through read_transfer_source_snapshot_file(...), read_transfer_source_snapshot_bytes(...), Document.build_transfer_source_snapshot(), and transfer_snapshot_probe(...) / transfer_snapshot_file(...)

  • public API regression coverage now asserts dual-write roundtrip and persistence behavior across jpeg, tiff, dng, png, webp, jp2, jxl, heif, avif, and cr3

This is deliberately narrower than a full sync engine. It does not yet define:

  • full EXIF vs XMP precedence rules

  • MWG-style reconciliation

  • full destination embedded-vs-sidecar reconciliation policy beyond the current bounded merge, precedence, carrier-mode, and strip rules

  • namespace-wide deduplication and normalization rules beyond the current generated-XMP path

Time Patch Plan

Time patching is intentionally narrow and fixed-width.

Current model:

  • build EXIF payloads once

  • record patch slots in the bundle

  • patch only the affected bytes during execution

Primary fields:

  • DateTime

  • DateTimeOriginal

  • DateTimeDigitized

  • SubSecTime*

  • OffsetTime*

This is meant for fast repeated transfer, not general metadata editing.

Main Blockers

1. General edit UX

OpenMeta still does not present one fully mature, general-purpose metadata editor across all formats. The current transfer core is real, but still more bounded than ExifTool or Exiv2.

2. Broader EXIF / IPTC / XMP sync policy

This remains one of the biggest product gaps for writer adoption, even though the first public projection controls now exist.

Missing pieces include:

  • conflict resolution rules

  • broader sidecar vs embedded policy beyond the current bounded writeback mode

  • canonical writeback policy

  • broader namespace reconciliation behavior beyond the current bounded custom-namespace preservation control

3. MakerNote-safe rewrite expectations

Read parity is strong, but broad rewrite guarantees for vendor metadata are not yet at the level of mature editing tools. The generic trust boundary is now explicit: decoded-only fields are not serialized, Keep means unverified opaque byte carry-forward, and unavailable Rewrite fails closed to Drop. The generic public audit reports that nested-offset relocation, vendor checksum repair, semantic validation, and raw-carrier passthrough are unavailable. The first vendor-layout audit now distinguishes canonical Nikon type 1 notes, whose offsets depend on the outer TIFF, from type 3 notes with an embedded TIFF at byte 10. Bounded validation can prove that a type 3 embedded TIFF’s standard directory/value offsets remain inside the opaque payload; it does not prove vendor-private binary offsets, checksum validity, or semantic readability.

Preserving a destination MakerNote while editing unrelated target metadata is a different operation from moving a source MakerNote into newly serialized EXIF. The former can retain the target’s established layout; the latter may invalidate outer-TIFF-relative offsets even when the 0x927C payload bytes are unchanged. Synthetic JPEG/TIFF transfer tests now prove byte-identical type 3 payload preservation and selected Nikon field readability after repacking. Remaining work is the broader vendor/version-specific offset-base and integrity inventory, followed by rewrite lanes only where relocation rules are fully understood.

4. EXR depth

The architectural question is now how far to deepen the current bounded EXR target:

  • keep EXR as a backend-emitter target plus bridge helpers, or

  • add a broader EXR file rewrite/edit path

Recommended Next Priorities

  1. Keep transfer ahead of further read-breadth work.

  2. Stabilize the current target family:

    • JPEG

    • TIFF

    • PNG

    • WebP

    • JP2

    • JXL

    • bounded BMFF

  3. Decide how deep EXR should go beyond the current bounded target.

  4. Add more transfer-focused roundtrip and compare gates where they improve confidence for adopters.

  5. Add an explicit EXIF / IPTC / XMP sync policy.

Three-Phase Writer Confidence Roadmap

This is the public roadmap for closing the main read/transfer/write gaps against mature metadata tools without expanding the project scope into full pixel editing or unbounded arbitrary metadata editing.

Working Rule

For the current milestone:

  • do not add broad new read families before the current writer target family is stable

  • every new writer behavior should ship with explicit roundtrip and compare gates

  • prefer one documented bounded contract per target over format-specific hidden behavior

Phase 1: Writer Confidence Baseline

Goal:

  • restore a fully green public tree

  • make current bounded writer behavior explicit and regression-gated

  • remove adoption risk caused by ambiguous sync and preservation behavior

Cross-cutting deliverables:

  • fix all public unit and regression failures before adding further writer breadth

  • publish one explicit EXIF / IPTC / XMP writeback policy for:

    • source-embedded vs destination-embedded precedence

    • source-embedded vs destination-sidecar precedence

    • canonical generated-XMP writeback rules

    • namespace preservation and canonicalization rules

  • add compare-backed release validation for the current primary target family

  • document unmanaged-metadata preservation rules for each writer target

Exit criteria:

  • public test tree is green

  • public release gates cover read-back plus compare-style validation for the primary target family

  • writer-side XMP behavior is explicit instead of implementation-defined

Phase 2: Stable First-Class Writer Set

Goal:

  • make the current target family feel consistent across C++, CLI, and Python

  • raise bounded edit paths into stable first-class writer contracts

  • improve rewrite safety for vendor metadata without claiming full arbitrary edit parity

Cross-cutting deliverables:

  • one stable user-facing edit/transfer surface across C++, CLI, and Python

  • one policy surface for MakerNote, JUMBF, C2PA, EXIF projection, IPTC projection, and XMP carrier behavior

  • stronger rewrite guarantees for preserve-vs-replace behavior on existing target metadata

  • compare and roundtrip gates promoted from smoke coverage into release-facing validation for the first-class target family

Exit criteria:

  • the first-class target family has documented write guarantees and matching regression gates

  • major host surfaces expose the same bounded policy controls

  • target maturity differences are reduced to known documented limits instead of accidental behavior

Phase 3: Deeper Parity and Read-Depth Follow-Through

Goal:

  • close the most visible remaining competitor gaps after the primary writer contract is stable

  • deepen read semantics only where they materially improve writer confidence or interop parity

Cross-cutting deliverables:

  • deeper modern-container semantics where current bounded projections are too small for parity workflows

  • long-tail read-depth work for formats that still rely mainly on embedded-TIFF follow paths

  • broader compare gates for newer target families and long-tail metadata structures

Exit criteria:

  • remaining gaps are mostly strategic out-of-scope items rather than missing baseline format behavior

  • OpenMeta can defend a clear public answer for which targets are first-class, bounded, or read-only

Per-Target Deliverables

Target family

Phase 1 deliverable

Phase 2 deliverable

Phase 3 follow-up

JPEG

Lock explicit sync/writeback defaults for APP1/APP2/APP13, add compare-backed read-back gates for edit/apply, and document unmanaged-marker preservation

Promote JPEG from strongest target to reference writer contract for other backends, including clearer preserve/replace guarantees for existing metadata carriers

Expand parity coverage for more mixed metadata bundles and signed/unsigned JUMBF handoff workflows where still bounded

TIFF

Lock rewrite guarantees for root IFD, ExifIFD, preview-page chains, and bounded SubIFD replacement; add compare-backed roundtrip gates for classic TIFF and BigTIFF

Raise current bounded rewrite behavior into a stable first-class contract, including clearer preserve/replace rules for existing auxiliary chains and downstream tails

Broaden nested-IFD graph handling only where it improves practical export parity without claiming arbitrary graph rewrite

DNG

Lock explicit behavior for ExistingTarget, TemplateTarget, and MinimalFreshScaffold; add compare-backed roundtrip gates for DNGVersion, preview chains, and raw SubIFD merge behavior

Stabilize the DNG policy layer so hosts can rely on predictable preserve/merge behavior without the Adobe SDK path

Decide whether any additional DNG-specific rewrite depth is worth public contract expansion beyond the TIFF-derived bounded model

PNG

Lock chunk replacement rules for eXIf, XMP iTXt, and iCCP; add compare-backed roundtrip gates for embedded-only, sidecar-only, and dual-carrier XMP flows where applicable

Promote the current bounded chunk path into a stable managed-metadata editor with explicit preservation rules for unrelated chunks

Add deeper parity only if compare workflows show recurring gaps against major tools

WebP

Lock replacement rules for EXIF, XMP, ICCP, and bounded C2PA; add compare-backed roundtrip gates

Promote the current bounded RIFF metadata path into a stable managed-metadata editor with explicit preservation guarantees for unrelated chunks

Extend only where public parity data shows material gaps for common WebP metadata workflows

JP2

Lock top-level managed-box rewrite rules and colr replacement behavior; add compare-backed roundtrip gates

Promote bounded box rewrite into a stable JP2 metadata contract with explicit preserve/replace guarantees for unmanaged boxes

Revisit jp2h synthesis only if it becomes necessary for common export parity

JXL

Lock current box rewrite rules for Exif, xml, jumb, bounded c2pa, and encoder-side ICC handoff; add compare-backed roundtrip gates for edit/apply paths

Promote JXL from bounded but real to a stable first-class metadata target with explicit unmanaged-box preservation rules and clearer encoder/file-edit split

Add more brob realtype coverage only after the current direct and bounded compressed routes are stable

HEIF / AVIF / CR3

Lock the bounded metadata-only meta edit contract, item/property preservation rules, and compare-backed roundtrip gates

Stabilize the bounded BMFF writer contract for metadata items, ICC property handling, and existing OpenMeta-authored meta replacement

Deepen BMFF scene semantics and relation modeling where current bounded fields are too small for parity workflows

EXR

Decide whether the public target remains an attribute-emitter contract or grows into a file rewrite/edit path; add compare-backed gates for the chosen contract

If EXR stays bounded, make that contract final and explicit across C++, CLI, and Python; if it grows, define one narrow first-class rewrite scope and gate it

Add depth only after the architectural choice is settled; avoid half-bounded expansion

RAF / X3F

Keep RAF header-declared preview-JPEG EXIF/XMP discovery, FujiIFD/TIFF follow path, RAF header/directory geometry decode, RAFData geometry projection, standalone XMP fallback, rendered-transfer dropping of native RAF source fields, and X3F header/PROP/section-JPEG reads stable with focused compare coverage

Only add read depth that directly improves downstream transfer/export confidence

Deepen remaining RAF model-specific tables and X3F image-processing sections if parity evidence shows real user-facing gaps

CRW / CIFF

Keep the current bounded native CIFF projection stable and well-gated

Improve only the parts that materially affect interop or transfer workflows

Revisit deeper native legacy coverage if it becomes a recurring parity blocker

Photoshop IRB

Keep raw preservation stable and add compare coverage for the current interpreted subset

Expand interpreted subset only where it improves practical writer parity

Revisit broader Photoshop-resource parity after the first-class writer set is stable

JUMBF / C2PA

Keep bounded preserve/invalidate behavior deterministic and regression-gated

Improve public signer-handoff and bounded rewrite workflows without claiming full trust-policy parity

Revisit deeper semantics and signed rewrite coverage after the main writer contract is stable

Phase Ordering Summary

  1. Fix public regressions and lock the sync/writeback contract.

  2. Turn the current target family into a stable first-class writer set.

  3. Spend follow-up effort on deeper parity lanes only after the writer baseline is trustworthy.

Competitor Parity Checklist

This section is a practical tracking view for the remaining gap against general-purpose metadata competitors.

Estimated remaining work packages:

  • to reach normal still-image workflow parity close to Exiv2: about 8 major work packages

  • to reach broader overall parity closer to ExifTool: about 12-15 major work packages

These are not release-percentage numbers. They are rough planning counts for distinct parity workstreams that still matter after the current public writer contract work.

Package Status

Status legend:

  • Done: public contract and regression coverage are good enough that this is no longer a primary parity blocker

  • Partial: real support exists, but competitor-visible limits still remain

  • Missing: still a clear parity gap

Work package

Why it matters for parity

Status

Remaining package count

Main target families

Public writer contract for primary targets

Competitors feel predictable on preserve/replace behavior; OpenMeta still needs that same trust level across all first-class targets

Partial

1

TIFF, DNG, PNG, WebP, JP2, JXL, HEIF/AVIF/CR3

General EXIF / IPTC / XMP sync engine

One of the biggest remaining gaps for general editing adoption

Partial

1-2

Cross-cutting

Compare-backed release validation

Needed to defend parity claims with repeatable read-back and compare gates

Partial

1

Cross-cutting

MakerNote rewrite trust

Generic preserve/rewrite/drop trust is explicit; Nikon type 1/type 3 layout evidence and type 3 JPEG/TIFF preservation regressions are present, but vendor-private relocation, checksum repair, and semantic guarantees still trail mature tools

Partial

1

JPEG, TIFF, DNG, RAW-derived lanes

TIFF / DNG deeper rewrite guarantees

Important for serious export/edit trust on camera-originated files

Partial

1

TIFF, DNG

BMFF writer depth beyond current bounded contract

Needed for stronger HEIF/AVIF/CR3 parity beyond the current metadata-only meta model

Partial

1

HEIF, AVIF, CR3

Modern container read-depth follow-through

Remaining visible read gaps are mostly here

Partial

1

HEIF/AVIF, JXL

Long-tail native format semantics

Matters more against ExifTool than against Exiv2

Partial

2-3

RAF, X3F, CRW/CIFF, Photoshop IRB

EXR target decision

Current EXR target is real but still architecturally bounded

Partial

1

EXR

JUMBF / C2PA deeper semantics

Current support is bounded and useful, but not full trust-policy parity

Partial

1-2

JPEG, PNG, WebP, JXL, BMFF

Full arbitrary metadata editing parity

Mature competitors expose a broader open-ended editor surface

Missing

Strategic / out of scope

Cross-cutting

Format-Family Gap Map

This map is intentionally coarse. It answers where the main remaining work still sits after the current public regression and writer-contract work.

Format family

Read parity

Transfer/write parity

Main remaining competitor gap

JPEG

Strong

Strong

needs continued compare-backed hardening and deeper mixed-bundle parity, not a new baseline writer

TIFF

Strong

Partial

deeper rewrite guarantees for more existing-graph and tail-preservation cases

DNG

Strong

Partial

more predictable preserve/merge behavior across target modes and raw SubIFD chains

PNG

Strong

Partial

stable unmanaged-chunk preservation contract and broader compare-backed validation

WebP

Strong

Partial

stable unrelated-chunk preservation contract and broader compare-backed validation

JP2

Strong

Partial

stronger managed-box preservation guarantees and more roundtrip validation

JXL

Strong on current lanes

Partial

more explicit box-preservation guarantees and deeper brob realtype follow-through

HEIF / AVIF / CR3

Strong on tracked lanes

Partial

BMFF writer depth and deeper scene/relation semantics beyond the bounded current model

EXR

Bounded but real

Bounded but real

still needs an explicit long-term decision between stable bounded target vs rewrite/edit path

RAF / X3F

Partial

not a main writer lane

deeper RAF model-specific native tables and X3F image-processing sections beyond current carrier/header/property lanes

CRW / CIFF

Partial

bounded

legacy native depth still trails mature tools

Photoshop IRB

Partial

bounded preservation

interpreted subset still smaller than mature tools

JUMBF / C2PA

Partial

bounded

deeper semantics, trust-policy behavior, and signed rewrite parity remain out of scope

Practical Readout

If OpenMeta stops after the current writer-contract work, it can already argue that it is close to competitor parity on the main tracked still-image targets.

The latest read-gap closure added RAF preview-JPEG EXIF/XMP discovery before the native FujiIFD/raw section and kept native RAF fields in the rendered-image safety drop set. This closes a common competitor-visible RAF read gap without making RAF a rendered-output writer lane.

To get materially closer to Exiv2, the remaining work is mostly:

  • finish stable writer guarantees for the first-class target family

  • finish the broader sync policy

  • harden compare-backed release validation

  • improve TIFF/DNG/BMFF rewrite trust

To get materially closer to ExifTool, OpenMeta also needs:

  • more long-tail native format depth

  • broader general editing behavior

  • deeper JUMBF/C2PA semantics

  • a clearer answer for EXR

Execution Order

Use this as the practical delivery order for the remaining parity work.

Priority legend:

  • Now: should be in the next active delivery slice

  • Next: should start after the Now slice is stable

  • Later: important for broader parity, but not the next blocker

Work package

Priority

Why this order

Public writer contract for primary targets

Now

This is the core trust gap that still keeps OpenMeta below mature writer parity

General EXIF / IPTC / XMP sync engine

Now

This is still one of the biggest adoption blockers for general edit workflows

Compare-backed release validation

Now

Parity claims remain weaker until compare-backed gates are release-facing instead of mostly API-facing

TIFF / DNG deeper rewrite guarantees

Now

This is the highest-risk writer lane for serious still-image export confidence

BMFF writer depth beyond current bounded contract

Next

HEIF/AVIF/CR3 are already real targets, but the bounded writer model still needs more depth for stronger parity

MakerNote rewrite trust

In progress

Generic behavior fails closed; the Nikon layout inventory has started with type 1/type 3 evidence, while vendor-private relocation and integrity lanes remain

Modern container read-depth follow-through

Next

Visible gap, but less urgent than finishing the current writer baseline

EXR target decision

Next

Needs an explicit product choice, but should follow the main writer-contract stabilization work

RAW curve/data applicability model

In progress

Coarse descriptor-backed rendered-source filtering is now available in prepare; precise RAW interpretation still needs curve/LUT metadata tied to the actual raw data storage path before it is called active

Long-tail native format semantics

Later

Matters more for broad ExifTool parity than for the first still-image writer milestone

JUMBF / C2PA deeper semantics

Later

Current bounded behavior is already useful; deeper trust semantics should wait until the core writer contract is stable

Full arbitrary metadata editing parity

Later

Strategic follow-up, not part of the next parity-closing milestone

Suggested delivery sequence:

  1. Finish the stable writer contract for the first-class target family.

  2. Finish the broader sync-policy layer and compare-backed release validation.

  3. Harden the two highest-risk writer lanes: TIFF/DNG and bounded BMFF.

  4. Continue the Nikon inventory beyond standard embedded-TIFF offsets, then apply the same vendor/version-specific offset and integrity evidence pattern to Canon, Olympus, and Sony; enable rewrite only for fully verified lanes.

  5. Spend follow-up time on modern-container depth, EXR, and long-tail native semantics only after the main writer baseline is defendable.

Now Slice Implementation Board

This board turns the current Now slice into concrete delivery checklists.

The sync item here means the bounded next-slice policy completion needed for practical writer parity. It does not mean full arbitrary EXIF/IPTC/XMP sync parity across every workflow.

1. Public Writer Contract For Primary Targets

  • [x] document final preserve-vs-replace behavior for existing embedded XMP on TIFF, DNG, PNG, WebP, JP2, JXL, and bounded BMFF

  • [x] document final preserve-vs-replace behavior for destination sidecars across embedded-only, sidecar-only, and dual-write flows

  • [x] lock explicit unmanaged-metadata preservation rules for unrelated chunks, boxes, items, and tails per target family

  • [x] add compare-backed read-back gates for each first-class target instead of relying mainly on API-shape regression coverage

  • [x] make CLI and Python surfaces describe the same writeback behavior and path-derivation rules as the C++ helper

  • [x] reduce remaining target differences to documented limits instead of accidental implementation details

Evidence: docs/writer_target_contract.md defines per-target preserve/replace rules and the remaining bounded limits. The BMFF section now makes the item-id width rule explicit: supported foreign iloc version 0/1 graphs can be upgraded to output iloc version 2 when inserted metadata needs 32-bit item IDs, while unsupported graph shapes or exhausted 32-bit ID space still fail safely.

2. Bounded EXIF / IPTC / XMP Sync Layer

  • [x] publish one final precedence table for source embedded XMP, destination embedded XMP, and destination sidecar XMP

  • [x] lock conflict behavior for generated EXIF-to-XMP and IPTC-to-XMP projections when existing XMP is also present

  • [x] lock canonical generated-XMP writeback behavior for embedded-only, sidecar-only, and dual-write flows

  • [x] lock namespace preservation and canonicalization rules for managed vs unmanaged XMP content

  • [x] add regression cases for mixed embedded-plus-sidecar destination states across the primary target family

  • [x] document the explicit non-goals of this bounded sync layer so it is not confused with full arbitrary sync parity

Evidence: docs/xmp_sync_policy.md now defines the bounded public policy, including carrier precedence, generated-vs-existing conflict behavior, writeback modes, namespace handling, and non-goals. The release-facing transfer tests cover source/destination carrier precedence, generated EXIF/IPTC versus existing XMP conflicts, canonical managed namespace replacement, and persisted embedded/sidecar writeback across the primary writer target family.

3. Compare-Backed Release Validation

  • [x] promote the current primary-target roundtrip checks into explicit release-facing compare gates

  • [x] add compare-backed validation for TIFF, DNG, PNG, WebP, JP2, JXL, and bounded BMFF target outputs, including fail-safe rejection for unsupported foreign top-level meta BMFF shapes

  • [x] cover embedded-only, sidecar-only, and dual-write XMP flows in release-facing compare validation

  • [x] add compare-backed validation for explicit sidecar-base overrides and destination-sidecar cleanup behavior

  • [x] gate the primary writer family on deterministic read-back of managed metadata after edit/apply

  • [x] keep public parity claims tied to compare-backed evidence instead of only unit or smoke coverage

Evidence: this plan keeps parity language at the supported-lane level and ties release claims to openmeta_gate_transfer_release, compatibility-dump read-back, and image-usability gates. BMFF high-item-ID insertion is covered by a release-gated API roundtrip that writes into an iloc v2 graph and scans the result back as one Exif item and one XMP item.

4. TIFF / DNG Deeper Rewrite Guarantees

  • [x] lock rewrite guarantees for classic TIFF and BigTIFF root IFD, ExifIFD, preview chains, and bounded SubIFD replacement

  • [x] lock explicit DNG behavior for ExistingTarget, TemplateTarget, and MinimalFreshScaffold

  • [x] add compare-backed roundtrip gates for preview chains, raw SubIFD merge behavior, and DNGVersion persistence

  • [x] document preserve-vs-replace guarantees for existing auxiliary IFD chains and downstream tails

  • [x] harden read-back and rewrite tests around mixed existing metadata carriers on camera-like TIFF/DNG files

  • [x] define the bounded edge of TIFF/DNG rewrite depth clearly enough that hosts know what is guaranteed and what is not

Evidence: docs/writer_target_contract.md defines the bounded TIFF/DNG rewrite contract and DNG target-mode behavior. Release-facing compatibility-dump tests now cover classic TIFF, DNG, and BigTIFF DNG-style merge outputs with preview-tail preservation, SubIFD auxiliary-tail preservation, existing root/preview/SubIFD XMP carrier replacement, embedded-versus-sidecar precedence, and DNGVersion read-back.

Done-When Readout

  • [x] the first-class target family has one explicit public writer contract

  • [x] the bounded sync-policy layer is documented and regression-gated

  • [x] release-facing compare validation covers the main still-image writer set

  • [x] TIFF/DNG rewrite guarantees are strong enough to stop being a primary parity blocker

  • [x] the next work slice can move to bounded BMFF depth instead of still backfilling the writer baseline

Host Integration And Adoption Backlog

This backlog captures adoption-oriented work that supports host projects with flat metadata models and deferred output writes. It should not replace the writer-confidence slice above; it should be sequenced around it.

Near-Term Host Contract Work

  • [x] publish Host Adoption Profile v1 as the narrow stable contract for positional snapshot read, structured diagnostics, snapshot persistence, FlatHost reconciliation, and the typed codec-operation schema; keep prepared bundle construction/execution outside the profile

  • [x] add a small runtime capability query API for read, structured decode, transfer preparation, and target edit support by format and metadata family

  • [x] mark public host-facing APIs with stability levels such as stable, experimental, or internal; start with visit_metadata(...), snapshot read/build, fileless execution, and bundle execution

  • [x] publish the generic FlatHost mapping contract: name style, duplicate handling, type projection, deterministic ordering, and namespace behavior

  • [x] add a deterministic compatibility dump for names, values, scalar types, origins, and transfer/writeback decisions so downstream tests can avoid binary-packet baselines

  • [x] document final conflict and precedence decisions for generated EXIF/XMP, IPTC/XMP, source embedded XMP, destination embedded XMP, and destination sidecar XMP

Medium-Term Fidelity Work

  • [x] add an opt-in raw-preserving TransferSourceSnapshot mode that keeps original carrier provenance and bounded payload bytes alongside decoded MetaStore state

  • [x] preserve bounded per-carrier provenance in raw snapshots: container type, block kind, byte range, original order, and route identity

  • [x] connect decoded entries back to the raw carrier records they were derived from, using snapshot-local decoded entry ids

  • [x] define policy choices for raw passthrough vs decoded re-emission when the destination container can safely accept either form

  • [x] add a diagnostic raw-carrier passthrough audit that reports candidate carriers and primary block reasons before any raw passthrough writer path is enabled

  • [x] add the first opt-in snapshot raw passthrough writer path for eligible non-C2PA JUMBF and draft unsigned C2PA invalidation carriers

  • [x] provide versioned, bounded target-neutral snapshot serialization after settling the first raw/provenance model; preserve store identity, duplicate order, typed values, origins, flags, carriers, and decoded-entry links

  • [x] provide transactional typed FlatHost import by exact source identity, unique exported name, or explicit MetaKeyView; reject ambiguous name-only inverse mapping

  • [x] add FlatHost remove-by-identity and remove-by-unique-name operations that preserve stable Dirty | Deleted tombstones and raw-carrier entry links

  • [x] document and test the deferred reconciliation sequence: deserialize snapshot, import changed/add/remove FlatHost records, retain untouched metadata, then prepare target payloads

  • [x] compatibility-lock the canonical snapshot v1 bytes with exact decode and re-encode coverage plus atomic rejection of unknown versions

  • [x] define the typed adapter operation schema as a dedicated v1 contract, validate every kind-specific field against a canonical rebuild, and expose EXR name/type/value without route parsing

  • [ ] provide full prepared-bundle serialization only if a concrete host needs more than the existing snapshot and prepared payload/package persistence

Supporting Work

  • [x] improve structured diagnostics with severity, stable code, carrier/family, offset or byte range where available, and short host-facing messages

  • [ ] extend resource accounting beyond current hard limits with preflight estimates for prepared transfers, sidecar output, and serialized snapshots

  • [x] add clean-room public micro fixtures for host integration tests; do not vendor large binary assets, third-party source drops, or scraped/spec text

  • [ ] add examples for read bytes -> snapshot -> target bytes -> edited bytes and visit_metadata(...) -> flat host attribute list

  • [x] add the allocation-free bounded random-access source foundation with exact reads, short-read/I/O/source-change results, and caller-owned request and byte accounting; format support still requires the scanner and decoder work below and must not silently materialize the complete source

  • [x] keep OpenMeta C++20-only; C++17 consumers own any dedicated private wrapper, and no C++17 bridge is planned in this repository

Random-Access Read Work Packages

The host contract is a source size plus exact positional reads. It must be implementable by file handles, network/range-backed storage, and host I/O proxies without an OpenMeta dependency on any one host library.

  1. [complete in 0.4.100] Define a borrowed size + read_at(offset, destination) source contract with exact-read, short-read, overflow, request-count, byte-budget, and source-size consistency failures. Concurrent calls against an immutable source must not share mutable decoder state.

  2. [partial in 0.4.106] Refactor TIFF/DNG and TIFF-based camera RAW header/IFD traversal first. Classic TIFF, BigTIFF, DNG, RW2, and ORF structural/value decoding now uses caller-owned windows after type/count/range validation. PrintIM, GeoTIFF, Pentax DNG private data, selected self-contained MakerNotes, Nikon embedded TIFF/type 1, Sony outer-TIFF-relative IFDs, and contained Canon adjusted-base payloads are converted. Olympus outer-relative and modern nested IFDs, Panasonic binary tables, and Samsung STMN/Type2 derived tables are also converted. Fujifilm self-relative and General Imaging Type 2 source layouts are converted. Kodak fixed-layout records and outer-TIFF-relative Type 8, Type 10, and Type 11 IFDs plus their vendor subtables are converted. Mixed-base Ricoh, Nintendo, Casio, Minolta, and FLIR paths are converted; Canon external derived subtables and unknown vendor layouts stay explicit residuals.

  3. [complete in 0.4.109] Refactor shallow sequential container scanners and payload extraction for JPEG, PNG, WebP, GIF, and EXR, then bounded box traversal for BMFF, JP2, and JXL. JPEG, PNG, WebP, JP2, JXL, and ISO-BMFF scanning now has callback/span descriptor parity, caller-owned read windows, explicit source failures, and no image/media-payload reads. BMFF parity includes brands, item tables/references, ICC properties, and nested CR3 metadata wrappers. GIF extension scanning, EXR header traversal, bounded logical-payload fetching, and reusable decoded snapshot assembly are also positional. Snapshot assembly aggregates source limits across phases and reports unconverted enrichment paths as explicit residuals.

  4. [complete in 0.4.112] Refactor native RAF, X3F, and CRW paths and declared embedded-container recursion. Native RAF header/directories, X3F header/section-directory/PROP, and CRW/CIFF directory/value traversal are positional. RAF preview-JPEG/FujiIFD and X3F section-JPEG enrichment now follows declared ranges without reading JPEG entropy or RAW image payloads. Undeclared source-wide compatibility searches remain bounded residual work.

  5. Gate each format on byte-span versus random-reader compatibility dumps, malformed/short-read tests, request/byte ceilings, and real-corpus parity before advertising that format as random-access capable. JPEG, PNG, WebP, GIF, JP2, JXL, ISO-BMFF, TIFF/DNG, and EXR positional decode/snapshot paths, malformed/I/O behavior, payload-skip checks, and cumulative request/byte ceilings are covered through 0.4.109; native RAF/X3F/CRW parity, denied image-payload ranges, malformed offsets, scratch sizing, and cumulative request ceilings are covered in 0.4.111. RAF preview/FujiIFD and X3F section-JPEG callback/span discovery parity, nonzero range offsets, entropy-denied reads, decode assembly, malformed ranges, and request limits are covered in 0.4.112. Undeclared source-wide searches and selected source-wide BMFF enrichment remain explicit work.

Raw Snapshot Emission Policy

Raw carriers are preserved for provenance, diagnostics, and opt-in bounded passthrough decisions. Transfer preparation still defaults to decoded re-emission from MetaStore.

raw_carrier_passthrough_audit_from_snapshot(...) is the current diagnostic bridge between preserved carriers and emission policy. It reports whether each preserved carrier is a passthrough candidate for a target format, or blocked by missing payload bytes, target carrier incompatibility, active safety filtering, content-bound C2PA, explicit profile policy, missing decoded entry links, or unsupported carrier kind. The audit itself does not change bundle preparation; it is a preflight tool for host UI and test coverage.

The planned policy choices are:

  • DecodedReemit: current behavior; OpenMeta decodes entries, applies safety filtering, and emits freshly prepared EXIF/XMP/ICC/IPTC/JUMBF carriers.

  • RawPassthroughWhenSafe: opt-in behavior through TransferRawCarrierPassthroughMode::WhenSafe; OpenMeta may reuse a preserved raw carrier only when the target accepts the same carrier family, the payload was preserved in the snapshot, and the active transfer safety/profile does not require filtering, invalidation, or target-owned image-property rewrite. The current writer path is intentionally narrow: non-C2PA JUMBF and OpenMeta draft unsigned C2PA invalidation carriers can be reused for JPEG, JXL, and BMFF targets, and draft unsigned C2PA invalidation carriers can be reused for WebP. EXIF/XMP/ICC/IPTC still use decoded re-emission.

  • HostOwnedPassthrough: current integration escape hatch; hosts may inspect TransferSourceSnapshot::raw_carriers and implement their own passthrough outside OpenMeta’s writer path.

Rendered-image transfer keeps using decoded re-emission plus safety filtering. Opaque MakerNotes, content-bound C2PA, source ICC profiles, raw color calibration, and target-owned image properties are not raw-passthrough candidates for rendered exports.

Postponed Work

Still out of scope for the current milestone:

  • full arbitrary metadata editing parity

  • full C2PA signed rewrite / trust-policy parity

  • full EXIF / IPTC / XMP sync engine

  • broad TIFF/DNG and BMFF rewrite parity beyond the bounded current targets

  • mandatory raw-passthrough snapshots or snapshot serialization in the default read path

  • C ABI / opaque-handle stability commitments

Practical Summary

OpenMeta is no longer blocked by read-path quality for adoption-oriented transfer work.

The main opportunity now is to make the current bounded transfer core easier to use and easier to trust across the primary export targets, instead of continuing to expand read-only surface area first.

page Quick Start

This guide is for the normal OpenMeta use case: a C++ application that needs to read, query, prepare, and transfer image metadata.

OpenMeta is a metadata engine, not an image encoder. In practice that means:

  • read metadata from an existing file

  • query it through MetaStore

  • build new metadata entries when needed

  • inject metadata into an existing target file or template

  • prepare metadata artifacts for a host API such as EXR or another host-owned metadata layer

If you need the full support matrix, see metadata_support.md. If you need the detailed target contract, see metadata_transfer_plan.md.

If you already own the encoder or host API, see host_integration.md. For the narrow stable high-throughput integration boundary, see host_adoption_profile.md. For public API adoption status, see api_stability.md. For the stable flat host naming contract, see flat_host_mapping.md. For deterministic host compatibility baselines, see compatibility_dump.md. For generated XMP merge and writeback precedence, see xmp_sync_policy.md. For per-target writer preserve/replace guarantees, see writer_target_contract.md.

1. Add OpenMeta To Your CMake Project

If OpenMeta is installed as a package:

find_package(OpenMeta CONFIG REQUIRED)

add_executable(my_app main.cc)
target_link_libraries(my_app PRIVATE OpenMeta::openmeta)

If you build OpenMeta from source in the same workspace, any normal add_subdirectory(...) or install-and-find-package workflow is fine. The public target alias is OpenMeta::openmeta.

2. Build OpenMeta

Library and tools:

cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build

Tests:

cmake -S . -B build-tests -G Ninja \
  -DCMAKE_BUILD_TYPE=Release \
  -DOPENMETA_BUILD_TESTS=ON
cmake --build build-tests
ctest --test-dir build-tests

If your optional dependencies live in a custom prefix, pass that prefix through CMAKE_PREFIX_PATH.

Optional Adobe DNG SDK bridge:

cmake -S . -B build-dng -G Ninja -DCMAKE_BUILD_TYPE=Release \
  -DOPENMETA_WITH_DNG_SDK_ADAPTER=ON \
  -DOPENMETA_USE_LIBCXX=ON \
  -DCMAKE_PREFIX_PATH='<dng-sdk-prefix>;<deps-prefix>'
cmake --build build-dng

3. Read One File Into <tt>MetaStore</tt>

This is the basic C++ read path.

#include "openmeta/simple_meta.h"

#include <array>
#include <cstddef>
#include <span>
#include <vector>

std::vector<std::byte> file_bytes = load_file_somehow("file.jpg");

openmeta::MetaStore store;
std::array<openmeta::ContainerBlockRef, 256> blocks {};
std::array<openmeta::ExifIfdRef, 512> ifds {};
std::vector<std::byte> payload(1 << 20);
std::array<uint32_t, 1024> payload_indices {};

openmeta::SimpleMetaDecodeOptions options;
const openmeta::SimpleMetaResult read = openmeta::simple_meta_read(
    std::span<const std::byte>(file_bytes.data(), file_bytes.size()),
    store,
    blocks,
    ifds,
    payload,
    payload_indices,
    options);

store.finalize();

Notes:

  • simple_meta_read(...) appends decoded entries to MetaStore.

  • Call store.finalize() before exact-key lookups.

  • The caller owns the scratch buffers. That is intentional.

4. Query Metadata

Use exact-key lookup through MetaStore::find_all(...) when you already know the metadata family and key:

#include "openmeta/meta_key.h"
#include "openmeta/meta_store.h"

openmeta::MetaKeyView make_key;
make_key.kind = openmeta::MetaKeyKind::ExifTag;
make_key.data.exif_tag.ifd = "ifd0";
make_key.data.exif_tag.tag = 0x010F;  // Make

for (openmeta::EntryId id : store.find_all(make_key)) {
    const openmeta::Entry& entry = store.entry(id);
    // Inspect entry.value and entry.origin here.
}

Use exact keys for:

  • EXIF tags

  • XMP properties

  • EXR attributes

  • ICC tags

  • IPTC datasets

For semantic inspection UI, use openmeta/metadata_query.h. It reports raw matches plus normalized candidates for areas such as crop/active-area, exposure/gain, white balance, color/profile, lens correction, orientation, and RAW-processing metadata. Color-profile matches include EXIF color-space evidence, ICC header/tag entries, XMP ICC/profile/color-space fields, and PNG profile text carriers. Source-bound camera RAW profile, look, tone-curve, and style metadata is reported separately as source_color_transform, while RAW value curves, linearity limits, calibration curves, and curve control points use dedicated RAW-processing semantic roles. Hosts can inspect these values without treating them as portable rendered-image color or profile metadata. query_descriptive_metadata(...) also exposes a bounded EXIF/IPTC/XMP reconciliation view for common descriptive fields: title/headline, description/caption, creator/author, keywords/subject, and IPTC created/digital-creation date-time evidence. These helpers use deterministic built-in name, namespace, and tag matching. Every raw query match retains exact_match, fuzzy_match, and fuzzy_score compatibility fields, but Semantic Query does not use partial matching because near names must not change metadata classification.

For vendor MakerNote/RAW fields, the query layer also builds conservative per-family grouped candidates for related white-balance, source-color-transform, raw-storage, sensor, computational, thermal, stitch/panorama, source-processing, raw value curve, linearity-limit, calibration-curve, and curve-control-point records. These records are for inspection and safe-transfer policy, not for writing source RAW transforms into rendered outputs. Grouped color, white-balance, and lens-correction records require numeric payloads with conservative minimum shapes before they become matrix/vector/table candidates. Malformed or text-only source records still remain visible as per-entry metadata, but they are not promoted into normalized grouped records. Known geometry patterns can also become normalized rectangles; current public coverage includes DNG crop/active-area tags, Phase One/Leaf RAW geometry, and Fujifilm RAF raw crop/zoom fields, plus Canon, Nikon Capture, and Sony panorama crop/border patterns.

For free-text metadata-name search, use the separate bounded API:

#include "openmeta/metadata_fuzzy_search.h"

openmeta::MetadataFuzzySearchOptions options;
options.minimum_score = 80;
options.max_results = 12;

const openmeta::MetadataFuzzySearchResult search =
    openmeta::fuzzy_search_metadata(store, "shuter speed", options);
if (search.status == openmeta::MetadataFuzzySearchStatus::Ok) {
    for (const openmeta::MetadataFuzzySearchMatch& match : search.matches) {
        // match.entry_id, match.name, match.score, and match.match_kind
    }
}

Ranking is deterministic: score, then exact/alias/fuzzy provenance, then stable entry id. The current contract accepts ASCII query text only and returns an explicit status for non-ASCII input; it does not perform Unicode normalization or transliteration. Python exposes the same result through Document.fuzzy_search(...) and TransferSourceSnapshot.fuzzy_search(...). See fuzzy_search.md for alias behavior, resource/threading bounds, quality gates, benchmark usage, and the large-store indexing decision.

For structured interpretation output, use openmeta/metadata_interpretation.h. It projects semantic query candidates into records that carry the query class, semantic kind, normalized shape, confidence, source entry ids, and normalized rect/margin/value arrays where available.

For duplicated concepts that may appear in multiple metadata families, use openmeta/metadata_concepts.h. The first experimental resolver covers orientation, date/time, exposure/gain, color/profile, GPS, geometry, lens correction, and RAW-processing. It returns candidate source entries, source families, preferred entries, normalized date/time fields where available, date/time precision, timezone kind, GPS altitude-reference state, canonical geometry origin/size/rect/margins, normalized exposure values, full normalized value vectors for grouped matrix/vector/table concepts, transfer hints, compatible/rendered safety booleans, and same-role conflict flags so host UI can show ambiguity instead of guessing silently. Transfer hints use safe, source_bound, rendered_unsafe, or requires_target_image_spec to separate portable facts from source RAW/correction data and target-owned image facts. transfer_concept_diagnostics_from_store(...) applies those hints to a selected transfer safety mode and returns keep/drop/requires-target-image-spec actions, severity tokens, stable summary/message tokens, localizable argument tokens, and default message text for transfer-preview UI. When a host knows the RAW storage context, pass MetadataRawDataDescriptor to the descriptor-aware overload so RAW curve/linearity and black/white-level diagnostics can distinguish stored RAW data from rendered pixels. If a decoder knows that a curve/LUT-like metadata entry is meaningful only for compressed RAW samples, set raw_descriptor.requires_compressed_raw_encoding = true before requesting concept diagnostics. If that curve/LUT only applies to the primary raw plane, also set raw_descriptor.requires_primary_raw_plane = true and provide has_plane_index / plane_index for the raw buffer being checked. Rendered-transfer drop messages distinguish source color transforms, white balance, lens correction, source RAW curves/linearity metadata, source-bound RAW processing, and target-owned image properties. Source color transforms cover camera RAW profiles, looks, tone curves, and vendor style/rendering tables that should not be treated as portable rendered-image color profiles. Source-bound RAW processing diagnostics also keep RAW value curves, linearity limits, calibration curves, curve control points, computational, thermal, and stitch/panorama roles separate for UI policy messages. GPS altitude reference codes can be displayed with metadata_concept_gps_altitude_reference_name(...).

For user-facing orientation display, use openmeta/orientation.h instead of showing only the numeric EXIF/TIFF index. interpret_exif_orientation(...) returns the index, human-readable label, clockwise rotation degrees, mirrored state, width/height-swap flag, and nearest rotation-only orientation.

For common enum-like TIFF/EXIF/DNG numeric values, and selected bounded Canon/Nikon/Sony/Fujifilm/Pentax/Olympus/Panasonic/Phase One/Kodak/Minolta/ Sigma/Samsung/Ricoh MakerNote contexts, use openmeta/exif_value_names.h. Unknown values return an empty string and remain available as numeric MetaStore values.

5. Create Fresh Metadata

Use the bounded high-level Creation API when the host has logical values rather than wire tag IDs:

#include "openmeta/metadata_creation.h"

#include <array>

const std::array fields = {
    openmeta::make_metadata_creation_text(
        openmeta::MetadataCreationFieldKind::Title, "Evening frame"),
    openmeta::make_metadata_creation_text(
        openmeta::MetadataCreationFieldKind::Creator, "Alice"),
    openmeta::make_metadata_creation_u32(
        openmeta::MetadataCreationFieldKind::Orientation, 6),
};

openmeta::MetadataCreationRequest request;
request.fields = fields;

openmeta::MetaStore store;
const openmeta::MetadataCreationResult created =
    openmeta::create_metadata(request, &store);

The result is a finalized store of canonical portable-XMP entries. The call is transactional: validation failures leave store unchanged. See creation.md for field mappings, value constraints, Python use, and destination-image safety requirements.

Edit Logical Metadata

Use the matching transactional Editing API when a finalized store already exists:

#include "openmeta/metadata_editing.h"

const std::array operations = {
    openmeta::make_metadata_edit_set(
        openmeta::make_metadata_creation_text(
            openmeta::MetadataCreationFieldKind::Title, "Edited title")),
    openmeta::make_metadata_edit_add(
        openmeta::make_metadata_creation_text(
            openmeta::MetadataCreationFieldKind::Keyword, "approved")),
};

openmeta::MetadataEditingRequest edit_request;
edit_request.operations = operations;

openmeta::MetaStore edited;
const openmeta::MetadataEditingResult edit_result =
    openmeta::edit_metadata(store, edit_request, &edited);

store is not mutated. The output is replaced only if every operation succeeds. Set operations preserve entry provenance, while removal creates a dirty tombstone. See editing.md for occurrence and conflict semantics.

Use the lower-level key/value API only when you need a wire-specific or custom entry.

This is useful when your application creates or edits metadata directly.

#include "openmeta/meta_key.h"
#include "openmeta/meta_store.h"
#include "openmeta/meta_value.h"

openmeta::MetaStore store;

const openmeta::BlockId block = store.add_block(openmeta::BlockInfo {});

openmeta::Entry make_entry;
make_entry.key = openmeta::make_exif_tag_key(store.arena(), "ifd0", 0x010F);
make_entry.value = openmeta::make_text(
    store.arena(), "Vendor", openmeta::TextEncoding::Ascii);
make_entry.origin.block = block;
make_entry.origin.order_in_block = 0;

store.add_entry(make_entry);
store.finalize();

The key/value helpers live in:

6. Export XMP From <tt>MetaStore</tt>

For portable sidecar output:

#include "openmeta/xmp_dump.h"

std::vector<std::byte> xmp_bytes;
openmeta::XmpSidecarRequest request;
request.format = openmeta::XmpSidecarFormat::Portable;
request.include_exif = true;
request.include_iptc = true;

const openmeta::XmpDumpResult dump =
    openmeta::dump_xmp_sidecar(store, &xmp_bytes, request);

For lossless OpenMeta-native sidecars, switch request.format to XmpSidecarFormat::Lossless.

7. Copy Metadata Into An Existing Target File

This is the common export workflow:

  • one source file provides metadata

  • one target file or template already owns the pixel container

  • OpenMeta edits the target metadata

#include "openmeta/metadata_transfer.h"

openmeta::ExecutePreparedTransferFileOptions options;
options.prepare.prepare.target_format = openmeta::TransferTargetFormat::Jpeg;
options.prepare.prepare.profile.safety =
    openmeta::TransferSafetyMode::RenderedImage;
options.edit_target_path = "rendered.jpg";

const openmeta::ExecutePreparedTransferFileResult exec =
    openmeta::execute_prepared_transfer_file("source.jpg", options);

openmeta::PersistPreparedTransferFileOptions persist;
persist.output_path = "rendered_with_meta.jpg";
persist.overwrite_output = true;

const openmeta::PersistPreparedTransferFileResult saved =
    openmeta::persist_prepared_transfer_file_result(exec, persist);

Use the same pattern for other file-backed targets:

  • TransferTargetFormat::Tiff

  • TransferTargetFormat::Dng

  • TransferTargetFormat::Png

  • TransferTargetFormat::Webp

  • TransferTargetFormat::Jp2

  • TransferTargetFormat::Jxl

  • bounded BMFF targets such as Heif, Avif, and Cr3

Read Once And Reuse Later

If your application already decoded source metadata earlier, keep a decoded source snapshot and execute the later save without reopening the source file:

#include "openmeta/metadata_transfer.h"

const openmeta::ReadTransferSourceSnapshotFileResult snapshot =
    openmeta::read_transfer_source_snapshot_file("source.jpg");

openmeta::ExecutePreparedTransferSnapshotOptions options;
options.prepare.target_format = openmeta::TransferTargetFormat::Tiff;
options.edit_target_path      = "target.tif";
options.execute.edit_apply    = true;

const openmeta::ExecutePreparedTransferFileResult result =
    openmeta::execute_prepared_transfer_snapshot(
        snapshot.snapshot, options);

Python exposes the same reusable snapshot flow for host code:

from pathlib import Path

import openmeta

snapshot_info = openmeta.read_transfer_source_snapshot_file("source.jpg")
snapshot = snapshot_info["snapshot"]

result = openmeta.transfer_snapshot_probe(
    snapshot,
    target_format=openmeta.TransferTargetFormat.Tiff,
    edit_target_path="target.tif",
    target_bytes=Path("target.tif").read_bytes(),
)

By default, source snapshots are decoded-store-backed. They are meant for the common EXIF/XMP/ICC/IPTC transfer workflow, where OpenMeta re-emits decoded metadata after applying the selected safety policy. If a host needs provenance for a later passthrough policy decision, enable ReadTransferSourceSnapshotFileOptions::preserve_raw_carriers or pass preserve_raw_carriers=True in Python. The snapshot then keeps bounded raw carrier records with original ContainerBlockRef ranges, route hints, and payload bytes up to max_raw_carrier_bytes. Each carrier also reports the snapshot-local decoded entry ids attributed to it. Transfer still uses decoded re-emission by default. Use raw_carrier_passthrough_audit_from_snapshot(...) to preflight which preserved carriers are candidates for a target format and which are blocked by missing payloads, target incompatibility, active safety filtering, content-bound C2PA, explicit profile policy, missing decoded entry links, or an unsupported carrier kind. Python exposes the same check as snapshot.raw_carrier_passthrough_audit(...). To allow the bounded passthrough path during snapshot preparation, set PrepareTransferRequest::raw_carrier_passthrough_mode to TransferRawCarrierPassthroughMode::WhenSafe, or pass raw_carrier_passthrough_mode=openmeta.TransferRawCarrierPassthroughMode.WhenSafe to Python snapshot transfer helpers. The current passthrough emitter is deliberately narrow: it can reuse eligible non-C2PA JUMBF and OpenMeta draft unsigned C2PA invalidation carriers for JPEG, JXL, and BMFF targets, plus draft unsigned C2PA invalidation carriers for WebP. EXIF/XMP/ICC/IPTC still use decoded re-emission. If the host owns the final file write path, the lower-level prepare_metadata_for_target_snapshot(...) entry point remains available. If the host already has a decoded MetaStore, build a reusable snapshot with build_transfer_source_snapshot(store). If it already owns the source bytes in memory, use read_transfer_source_snapshot_bytes(bytes) instead of the file-path reader. For large assets exposed through a host positional-read callback, use read_transfer_source_snapshot_random_access(...). It fetches structural and metadata ranges into caller-owned scratch without buffering the whole file and returns an owned finalized snapshot. Check both complete() and residual_metadata_paths. Native RAF/X3F/CRW metadata is positional; RAF/X3F embedded decoding follows declared preview, FujiIFD, and section-JPEG ranges without reading image data. Undeclared source-wide searches and selected recursive enrichment paths remain explicit residuals. Use collect_read_transfer_source_diagnostics(...) for machine-readable failure, scratch, MakerNote, and residual details. In Python, if the host already has doc = openmeta.read(...), call doc.build_transfer_source_snapshot() or openmeta.build_transfer_source_snapshot(doc) instead of reopening the file. If it also owns the destination bytes in memory, call the overload execute_prepared_transfer_snapshot(snapshot, target_bytes, options). If it already holds a prepared bundle, use execute_prepared_transfer_bundle(bundle, target_bytes, options) instead. Snapshot execution supports the same existing-sidecar merge and destination carrier-precedence controls as the file helper; when loading an existing sidecar it defaults to edit_target_path unless xmp_existing_sidecar_base_path is set explicitly. For embedded-only writeback with sidecar cleanup and no filesystem path, set xmp_existing_destination_sidecar_state explicitly so OpenMeta can return a cleanup decision without guessing a sidecar location. The Python snapshot helpers intentionally cover the core transfer/edit/persist path. The older transfer_probe(...) / unsafe_transfer_probe(...) entry points remain the broader artifact-dump/debug surface.

8. Check Runtime Capabilities

Use the capability API before enabling format/family operations in a host UI or integration layer.

#include "openmeta/metadata_capabilities.h"

const openmeta::MetadataCapability cap = openmeta::metadata_capability(
    openmeta::TransferTargetFormat::Avif,
    openmeta::MetadataCapabilityFamily::Xmp);

if (openmeta::metadata_capability_available(cap.target_edit)) {
    // The current build can edit AVIF XMP within the reported support level.
}

Each operation reports unsupported, supported, bounded, or disabled. bounded means the capability exists within OpenMeta’s documented contract. disabled is used for compile-time-disabled support such as XMP decode when XML support is not available.

Python exposes the same query:

cap = openmeta.metadata_capability(
    openmeta.TransferTargetFormat.Avif,
    openmeta.MetadataCapabilityFamily.Xmp,
)
print(cap["target_edit_name"])

9. Prepare Metadata For Host-Owned Encoders

Some applications do not want a file helper. They already own the encoder or the output container and just want OpenMeta to prepare metadata bytes.

EXR Host API

EXR is the cleanest host-adapter example.

#include "openmeta/exr_adapter.h"

openmeta::ExrAdapterBatch batch;
openmeta::BuildExrAttributeBatchFileOptions options;

const openmeta::BuildExrAttributeBatchFileResult result =
    openmeta::build_exr_attribute_batch_from_file(
        "source.jpg", &batch, options);

for (const openmeta::ExrAdapterAttribute& attr : batch.attributes) {
    // Forward attr.name, attr.type_name, and attr.value to your EXR writer.
}

Use this when the host already writes EXR files through OpenEXR or its own EXR code.

Generic Host Metadata Export

If your application owns the metadata object model, use the generic traversal API and build the mapping in the host layer.

#include "openmeta/interop_export.h"

class MyMetadataSink final : public openmeta::MetadataSink {
public:
    void on_item(const openmeta::ExportItem& item) noexcept override
    {
        // Map item.name + item.entry into your host metadata object.
    }
};

openmeta::ExportOptions options;
options.style              = openmeta::ExportNameStyle::FlatHost;
options.name_policy        = openmeta::ExportNamePolicy::ExifToolAlias;
options.include_makernotes = true;

MyMetadataSink sink;
openmeta::visit_metadata(store, options, sink);

JPEG / JXL / Other Encoder-Owned Outputs

For host-owned encoders, the transfer core exposes two patterns:

  1. implement a backend emitter such as JpegTransferEmitter or JxlTransferEmitter

  2. or build a target-neutral adapter view and consume explicit operations

Minimal JPEG/JXL-style pattern:

#include "openmeta/metadata_transfer.h"

openmeta::PrepareTransferFileOptions prepare;
prepare.prepare.target_format = openmeta::TransferTargetFormat::Jxl;

openmeta::PrepareTransferFileResult prepared =
    openmeta::prepare_metadata_for_target_file("source.jpg", prepare);

openmeta::PreparedTransferExecutionPlan plan;
openmeta::compile_prepared_transfer_execution(
    prepared.bundle, openmeta::EmitTransferOptions {}, &plan);

// Then either:
// - implement openmeta::JxlTransferEmitter and call
//   emit_prepared_transfer_compiled(...)
// - or build_prepared_transfer_adapter_view(...) and feed the ops into your
//   own backend abstraction

OpenMeta does not currently ship a TurboJPEG-specific wrapper, but the JPEG transfer path is designed for that kind of integration through JpegTransferEmitter and the adapter-view APIs.

For fuller C++ host-side examples, see host_integration.md.

10. Optional Adobe DNG SDK Bridge

If OpenMeta was built with OPENMETA_WITH_DNG_SDK_ADAPTER=ON, you can update an existing DNG file through the Adobe SDK bridge:

#include "openmeta/dng_sdk_adapter.h"

openmeta::ApplyDngSdkMetadataFileResult result =
    openmeta::update_dng_sdk_file_from_file("source.jpg", "target.dng");

This is for applications that already use the Adobe DNG SDK. It is not a raw image encoder.

11. CLI And Python Are Convenience Layers

The CLI and Python bindings are useful, but they are thin layers over the same public C++ APIs.

Transfer writeback follows the C++ file-helper contract. With --output, generated sidecar paths are derived from the output path, not from the input or target path. --xmp-writeback sidecar suppresses generated embedded XMP and writes the generated packet as output-stem.xmp. --xmp-writeback embedded_and_sidecar writes both carriers. Embedded-only writeback preserves an existing sidecar unless --xmp-destination-sidecar strip_existing is set; sidecar-only writeback preserves existing embedded XMP unless --xmp-destination-embedded strip_existing is set. --force controls overwriting output files and generated sidecars.

CLI:

./build/metaread file.jpg
./build/metatransfer --source-meta source.jpg --target-jpeg rendered.jpg --output rendered_with_meta.jpg --force
./build/metatransfer --source-meta source.jpg --target-jpeg rendered.jpg --xmp-writeback embedded_and_sidecar --output rendered_with_meta.jpg --force
./build/metatransfer --source-meta source.jpg --target-jpeg rendered.jpg --xmp-destination-sidecar strip_existing --output rendered_with_meta.jpg --force

Python:

PYTHONPATH=build-py/python python3 - <<'PY'
import openmeta

doc = openmeta.read("file.jpg")
print(doc.entry_count)
PY

PYTHONPATH=build-py/python python3 -m openmeta.python.metatransfer \
  --source-meta source.jpg \
  --target-jpeg rendered.jpg \
  --xmp-writeback embedded_and_sidecar \
  --output rendered_with_meta.jpg \
  --force

12. Pick The Next Doc

page Random-Access Input

OpenMeta’s random-access input contract is designed for image-processing and transcoding hosts that already own storage, scheduling, and I/O policy. It is not tied to a particular image library or file abstraction.

The positional source primitive, top-level snapshot assembly, and structured read diagnostics are stable in Host Adoption Profile v1. Low-level format-specific scanner, payload, and decoder APIs remain experimental.

Current Scope

Version 0.4.100 added the allocation-free source primitive in openmeta/random_access_source.h. Version 0.4.101 added source-relative ranges, caller-owned read windows, and the first decoder conversion. Version 0.4.102 added source-backed nested TIFF offset resolution. Version 0.4.103 extends that conversion to Olympus, Panasonic, and Samsung MakerNotes. Version 0.4.104 adds bounded Fujifilm and General Imaging MakerNote source layouts. Version 0.4.105 adds Kodak fixed-layout and outer-TIFF-relative MakerNotes. Version 0.4.106 adds Ricoh mixed-base and vendor subdirectory decoding plus Nintendo, Casio, Minolta, and FLIR callback parity. Version 0.4.107 adds bounded JPEG segment scanning. Version 0.4.108 adds positional PNG/WebP chunk scanning and bounded JP2/JXL/ISO-BMFF box and metadata-item traversal. Version 0.4.109 adds positional GIF extension scanning, EXR header traversal, logical metadata payload extraction, and decoded source-snapshot assembly. Version 0.4.111 adds native RAF, X3F, and CRW/CIFF positional metadata traversal plus structured snapshot-read diagnostics. Version 0.4.112 adds bounded RAF preview-JPEG and FujiIFD traversal plus X3F section-JPEG traversal. Version 0.4.113 stabilizes the source primitive, top-level snapshot assembly, and diagnostics through Host Adoption Profile v1. The contract now defines:

  • a fixed source size and synchronous read_at(offset, destination) callback

  • a non-owning descriptor for caller-owned contiguous memory

  • exact-read semantics with distinct short-read, I/O, cancellation, and source-change results

  • per-operation limits for request count, total requested bytes, and one read

  • independent sticky accounting state with first-failure diagnostics

  • borrowed source subranges without copying or changing callback offsets

  • caller-owned read-ahead windows with direct zero-copy views for memory sources

decode_exif_tiff_random_access(...) now traverses classic TIFF, BigTIFF, DNG, Panasonic RW2, and Olympus ORF headers, IFDs, pointer directories, and validated metadata values without materializing the complete source. It also decodes PrintIM, GeoTIFF, Pentax DNG private data, and selected self-contained MakerNotes from caller scratch. Nikon embedded TIFF and type 1 MakerNotes and Sony outer-TIFF-relative IFDs now read through the same bounded source. Canon uses checked absolute, MakerNote-relative, and signed adjusted-base candidates. Legacy Olympus values and nested sub-IFDs use outer-TIFF offsets, modern Olympus/OM System notes retain MakerNote-relative recursion, Panasonic retains its binary-table expansion, and self-contained Samsung STMN and Type2 notes retain their derived tables. Fujifilm FUJIFILM/GENERALE notes use bounded MakerNote-relative subranges, while General Imaging Type 2 notes use checked source windows without copying or patching bytes. Kodak fixed-layout records and Type 8, Type 10, and Type 11 IFDs use checked outer-TIFF offsets, including pointer and embedded vendor subtables. Ricoh classic notes use per-entry checked offset candidates and retain ImageInfo, CameraInfo, FaceInfo, SerialInfo, and Theta expansion. Nintendo CameraInfo, Casio QVC/DCI directories, Minolta binary tables, and FLIR outer-TIFF-relative values also retain their contiguous decode behavior.

Callback decoding does not yet claim complete MakerNote parity. Canon retains its complete existing derived-table decoder when required values are inside the declared MakerNote payload. If Canon values extend outside that payload, the main IFD is decoded from the source but the unconverted derived-table work is counted by ExifRandomAccessDecodeResult::nested_payloads_skipped. Unknown or unsupported vendor layouts use the same residual instead of decoding against an incorrect subspan. A contiguous source keeps the full existing decoder behavior and reports no random-access residual.

scan_jpeg_random_access(...) locates leading EXIF, XMP, ICC, MPF, vendor APP, JUMBF, Photoshop IRB, FLIR, and comment segments through the same positional source. It reads at most 512 bytes from a metadata segment for classification, preserves multipart APP11 normalization, and stops at Start of Scan without reading entropy-coded image data. Returned offsets are relative to the supplied source range.

scan_png_random_access(...), scan_webp_random_access(...), scan_gif_random_access(...), scan_jp2_random_access(...), scan_jxl_random_access(...), and scan_bmff_random_access(...) provide the same descriptor contract. PNG text prefixes are scanned incrementally. GIF traversal reads extension framing and sub-block lengths but skips raster sub-block contents. JP2/JXL/BMFF traversal reads box headers, brands, item-location tables, item references, ICC properties, and CR3 metadata wrappers as needed, but skips image codestream, mdat, and unrelated payload bytes. A 32-byte window is the minimum for these six scanners; larger windows reduce callback traffic.

decode_exr_header_random_access(...) traverses EXR attributes and stops at the header terminator without reading chunk tables or pixel data. Structural reads use ExrRandomAccessScratch::read_window; the largest attribute value selected for decode must fit value, or value_scratch_needed reports its exact size. measure_exr_header_random_access(...) validates names, types, counts, and ranges without fetching attribute bodies.

extract_payload_random_access(...) fetches one discovered logical metadata stream. It supports direct ranges, GIF sub-blocks, multipart JPEG ICC and extended XMP, general multipart blocks, and bounded Deflate/Brotli decompression. Compressed input uses caller-owned compressed scratch before decompression into the caller payload buffer.

Explicitly typed RAF, X3F, and CRW sources now use native positional readers. RAF reads its fixed header and declared native directories, X3F reads its header, section directory, and PROP sections, and CRW follows CIFF directory offsets and individual values. These paths do not read intervening image payload ranges. When embedded-container decoding is requested, scan_raf_random_access(...) follows the header-declared preview JPEG and FujiIFD/TIFF range, while scan_x3f_random_access(...) follows declared IMA2/IMAG SECi JPEG sections. Both reuse bounded JPEG metadata scanning and stop at Start of Scan without fetching entropy-coded image data.

Callback Example

#include "openmeta/random_access_source.h"

struct HostReader {
    // File descriptor, range client, asset reader, or another host-owned object.
};

openmeta::RandomAccessIoResult
host_read_at(void* context, uint64_t offset,
             std::span<std::byte> destination) noexcept
{
    HostReader* reader = static_cast<HostReader*>(context);
    // Perform one synchronous positional read without changing shared position.
    // Return the actual count. Report SourceChanged if the captured size is no
    // longer valid.
    return {/* code */, /* bytes_read */};
}

HostReader reader;
openmeta::RandomAccessSource source =
    openmeta::make_callback_random_access_source(
        source_size, &reader, host_read_at, /* concurrent_reads */ true);

openmeta::RandomAccessReadLimits limits;
limits.max_requests          = 4096;
limits.max_total_bytes       = 32ULL * 1024ULL * 1024ULL;
limits.max_single_read_bytes = 4ULL * 1024ULL * 1024ULL;

openmeta::RandomAccessReadState state;
std::array<std::byte, 16> header;
openmeta::RandomAccessReadCode code = openmeta::random_access_read_exact(
    source, 0, header, &state, limits);

random_access_read_exact(...) does not retry a short read. A host that uses a transport with partial-read semantics must complete its retry loop inside the callback or return the actual shorter count. OpenMeta performs range and budget checks before invoking the callback.

TIFF/DNG Decode Example

#include "openmeta/exif_tiff_decode.h"

std::array<std::byte, 16 * 1024> structural_window;
std::array<std::byte, 1 * 1024 * 1024> value_scratch;

openmeta::ExifRandomAccessScratch scratch;
scratch.read_window = structural_window;
scratch.value = value_scratch;
scratch.window_options.minimum_read_bytes = structural_window.size();

openmeta::RandomAccessSourceRange tiff =
    openmeta::make_random_access_source_range(source, tiff_offset, tiff_size);
openmeta::MetaStore store;
std::array<openmeta::ExifIfdRef, 128> ifds;

openmeta::ExifRandomAccessDecodeResult result =
    openmeta::decode_exif_tiff_random_access(
        tiff, store, ifds, scratch, openmeta::ExifDecodeOptions{}, limits);

read_window must hold 20 bytes for BigTIFF entries. Larger windows batch adjacent structural reads. value must hold the largest metadata value that the caller wants decoded and, when GeoTIFF is enabled, the combined GeoTIFF key, double, and ASCII parameter payloads. If it is too small, value_scratch_needed reports the required byte count; OpenMeta does not allocate a replacement.

Container Scan Example

#include "openmeta/container_scan.h"

std::array<std::byte, 512> scan_window;
openmeta::ContainerRandomAccessScratch scan_scratch;
scan_scratch.read_window = scan_window;
scan_scratch.window_options.minimum_read_bytes = scan_window.size();

openmeta::RandomAccessSourceRange jpeg =
    openmeta::make_random_access_source_range(
        source, jpeg_offset, jpeg_size);
std::array<openmeta::ContainerBlockRef, 32> blocks;

openmeta::ContainerRandomAccessScanResult scan =
    openmeta::scan_jpeg_random_access(
        jpeg, blocks, scan_scratch, limits);
if (!scan.complete()) {
    // Inspect scan.input for short read, I/O, source change, scratch, or limit.
}
if (scan.scan.status != openmeta::ScanStatus::Ok) {
    // The source was read successfully but is unsupported or malformed.
}

The 512-byte window is the maximum JPEG classification probe and preserves bare APP1 XMP detection parity. Smaller windows remain valid for inputs whose metadata probes fit, but return ScratchTooSmall when a larger probe is needed. Use measure_scan_jpeg_random_access(...) with the same scratch and limits to obtain scan.needed without block output storage.

For PNG, WebP, GIF, JP2, JXL, and ISO-BMFF sources, call the corresponding scan_*_random_access(...) or measure_scan_*_random_access(...) function with the same source-range and result pattern. These scanners require at least 32 bytes of read-window storage. A 4 KiB or larger read-ahead window is generally a better host default for table-heavy BMFF files.

Bounded Payload And Snapshot Assembly

#include "openmeta/metadata_transfer.h"

std::array<openmeta::ContainerBlockRef, 64> blocks;
std::array<openmeta::ExifIfdRef, 128> ifds;
std::array<uint32_t, 64> payload_indices;
std::array<std::byte, 4 * 1024> read_window;
std::array<std::byte, 2 * 1024 * 1024> payload;
std::array<std::byte, 2 * 1024 * 1024> compressed_payload;
std::array<std::byte, 1 * 1024 * 1024> value;

openmeta::ReadTransferSourceSnapshotRandomAccessScratch scratch;
scratch.blocks             = blocks;
scratch.ifds               = ifds;
scratch.payload_indices    = payload_indices;
scratch.read_window        = read_window;
scratch.payload            = payload;
scratch.compressed_payload = compressed_payload;
scratch.value              = value;

openmeta::ReadTransferSourceSnapshotRandomAccessResult result =
    openmeta::read_transfer_source_snapshot_random_access(
        source_range, openmeta::ContainerFormat::Jpeg, scratch, {}, limits);

The scanner, payload, decompression, and value workspaces are caller-owned and valid only for the call. The returned TransferSourceSnapshot owns its finalized MetaStore, so the host may release or reuse those workspaces after the call. Request-count and byte ceilings are cumulative across scan, payload, decode, PNG text-prefix, and optional raw-carrier reads; they do not reset at phase boundaries.

The current high-level positional path supports JPEG, PNG, WebP, GIF, JP2, JXL, HEIF/AVIF/CR3 BMFF containers, native TIFF/DNG-family input, EXR headers, and native RAF, X3F, and CRW metadata. Requested RAF/X3F embedded-container decoding follows declared preview, FujiIFD, and section-JPEG ranges. It does not search arbitrary image bytes for undeclared fallback signatures. A missing declared lane that would require such a fallback, selected source-wide BMFF enrichment, unsupported MakerNote subpaths, and whole-file raw-carrier preservation increment residual_metadata_paths. The decoded snapshot remains usable, but complete() returns false. Hosts must inspect the result rather than treating a usable partial snapshot as full positional parity.

Project machine-readable diagnostics without allocation:

std::array<openmeta::ReadTransferSourceDiagnostic, 8> diagnostics;
openmeta::ReadTransferSourceDiagnosticOptions diagnostic_options;
diagnostic_options.decode_makernote_requested = options.decode_makernote;
diagnostic_options.decode_embedded_containers_requested =
    options.decode_embedded_containers;

openmeta::ReadTransferSourceDiagnosticsResult diagnostic_result =
    openmeta::collect_read_transfer_source_diagnostics(
        result, diagnostics, diagnostic_options);

Each record has severity, stable code, domain, format, source offset, required byte count, item count, EXIF/native tag, and the original input failure code where available. Name and short-message helpers are static strings. If written != needed, resize the caller buffer and project again; the snapshot read itself is not repeated.

Raw-carrier preservation is opt-in and copies only discovered carrier bytes within max_raw_carrier_bytes; ordinary decoded snapshot assembly does not retain the whole source. Transfer preparation continues to apply normal safety policy and decoded re-emission rules.

Real-Time And Concurrent Use

The positional source, scanner, decoder, and payload layers add no global state, virtual dispatch, std::function, hidden allocation, file-position mutation, locking, or background work. The high-level snapshot result intentionally owns its MetaStore and optional raw-carrier bytes. The callback is a plain function pointer, and all counters belong to operation-local state.

OpenMeta will not issue concurrent callback calls within one synchronous scan or decode. Separate operations may share an immutable source when concurrent_reads is true and the host context actually supports concurrent positional reads. Each operation must use separate decoder scratch and RandomAccessReadState objects.

The TIFF/DNG decoder batches adjacent structural reads through the caller-owned window instead of issuing one host callback for every scalar. Out-of-line metadata values use caller value scratch so they do not evict the structural cache. Pixel and media payloads are outside this metadata input contract and are not fetched as part of ordinary metadata decoding or positional container scanning.

Source Lifetime

RandomAccessSource is borrowed. The backing memory, callback, and context must remain valid and immutable for the whole operation. The declared size is a snapshot of the source extent. If a callback detects replacement, truncation, or another size-changing mutation, it must return RandomAccessIoCode::SourceChanged.

The memory descriptor is suitable when a realtime pipeline already has the complete encoded asset in a stable buffer. The callback descriptor is suitable for file handles, range-backed storage, host asset APIs, and I/O proxy objects.

page RAW Read Parity Plan

This page tracks the public read-path work needed to move OpenMeta closer to ExifTool-level camera RAW coverage. It is about decoding and interpretation, not writer policy.

Here, camera RAW support means metadata carrier discovery and metadata interpretation. OpenMeta does not decode compressed sensor samples, demosaic or render RAW pixels, or provide a general native camera RAW writer. A strong shared TIFF/EXIF lane can still have partial vendor-private or model-specific interpretation, and preserving a raw MakerNote block is not the same as naming every entry inside it.

OpenMeta should keep a conservative rule here: preserve raw payloads whenever a family is only partially understood, and only promote fields to structured entries when their location, type, byte order, and meaning are stable enough to test.

Validation Method

RAW parity work is compared against ExifTool output with normalized values, group names, and intentional-difference notes. Each new lane should add:

  • a block-discovery test for the native container or embedded metadata carrier

  • a structured decode test for stable tags

  • a display-name or semantic-group test when the tag is user-visible

  • a transfer-safety test when the decoded value is source-specific

  • a compare note for unsupported or intentionally raw-only payloads

Family Gap Matrix

Family

Current lane

Main gap versus ExifTool

Next work

DNG and TIFF-based RAW

Strong baseline through TIFF/EXIF/IFD, DNG tags, XMP, ICC, and MakerNote payloads

Long-tail vendor private tables and model-specific MakerNote fields

Keep adding named tables only when they are stable and safety-classified

Nikon NEF/NRW

Strong TIFF/EXIF path plus expanded Nikon MakerNote tables and normalized Nikon Capture crop bounds

Model-specific encrypted/custom-setting tables and less common correction records

Add focused Nikon tables with byte-order/version gates and safety buckets

Sony ARW/SR2/SRF

Strong TIFF/EXIF path plus Sony RAW/source-processing classification and panorama crop-margin interpretation

Older SRF/SR2 private structures and model-specific private tables

Extend native SR2/SRF table naming and keep raw payload preservation as the fallback

Canon CR2

Strong TIFF/EXIF path plus Canon MakerNote, normalized aspect/crop geometry, and crop/aspect/color-data classification

Long-tail Canon custom functions and per-model color/correction tables

Continue table-by-table decode with rendered-transfer safety coverage

Canon CR3

Bounded BMFF plus EXIF/XMP/ICC/CR3 maker metadata, including item/property associations, direction-aware item relations, semantic item groups, component membership, semantic composition, typed relation counts, bounded grid/iovl/iden constructions, recursive item-offset descriptor resolution, graph-cycle/source validation, and complete bounded tili configuration/reference/offset-table interpretation

Independently authored tiled-image conformance samples and CR3-specific private records

Validate finalized tiled-image layouts against independent files, then continue bounded CR3 private-table work

Canon CRW/CIFF

Partial native lane with bounded positional recursive CIFF directories, stable scalar/subtable decoding, common native names, and derived EXIF bridge

Older Canon private tables and long-tail legacy records

Continue table-by-table decode only where stable validation data exists

Fujifilm RAF

Partial native lane with bounded positional header/directory reads, header-declared preview-JPEG EXIF/XMP and FujiIFD/TIFF traversal, RAF header fields, RAF directory geometry tags, RAFData geometry projection, normalized raw crop/zoom rectangles, and contiguous standalone XMP fallback

Model-specific RAF tables, less common native sections outside the stable carrier/header/directory subset, and callback-safe discovery for undeclared standalone carriers

Extend native RAF section inventory table-by-table, with broader color/correction safety buckets before transfer use

Sigma X3F

Partial native lane with bounded positional header/section-directory/PROP reads and declared section-JPEG metadata traversal, known PROP properties, and contiguous legacy embedded-EXIF fallback

Deeper image-processing/compression sections, model-specific private records, and callback-safe discovery for undeclared carriers

Add X3F native sections only when they expose stable user-visible fields or transfer-safety inputs

Panasonic, Olympus, Pentax, Kodak, Minolta, Samsung, Ricoh

Mixed TIFF/EXIF and MakerNote table coverage

Older model tables, preview/correction subtables, and private RAW payloads

Prioritize tables that affect crop, color, lens correction, orientation, or transfer safety

Apple, DJI, Google, FLIR

Live-vendor source-processing classification exists for rendered-transfer safety

Computational, thermal, radiometric, and shot-log interpretation depth

Add decode only for stable fields that hosts can use safely

Rare and legacy RAW families

Raw-preservation-first

Native container and MakerNote depth

Preserve raw blocks, then add support only when validation inputs and stable structure are available

Priority

  1. Keep writer safety explicit: decoded MakerNote sub-IFDs are not used to reconstruct vendor MakerNote blobs; the original raw MakerNote payload is preserved when available.

  2. Continue high-visibility native read gaps: more model-specific RAF native sections, long-tail CRW/CIFF private tables, and deeper X3F section interpretation.

  3. Deepen remaining BMFF interpretation for CR3, HEIF, and AVIF metadata graphs beyond current construction descriptors, component membership, direction-aware typed relations, semantic item groups, and primary-item summaries.

  4. Add X3F image-processing section decode only when the fields can be named, typed, and safety-classified.

  5. Continue vendor MakerNote table work for fields that affect crop, color, orientation, lens correction, or safe transfer decisions.

RAW Curve Applicability

RAW curve and LUT metadata should not be treated as automatically active just because the tag is present. Some formats may store curve-like metadata in both compressed and uncompressed variants, while only one raw storage path actually uses it.

OpenMeta now exposes a conservative applicability scaffold for RAW-processing concept candidates:

  • MetadataRawDataEncoding describes the host or decoder view of stored raw pixels, such as uncompressed, packed, lossless-compressed, lossy-compressed, rendered, or unknown.

  • MetadataRawDataDescriptor is the public carrier for dimensions, channel-count, bit-depth, compression code, storage encoding, optional raw plane index, and optional requires_compressed_raw_encoding / requires_primary_raw_plane flags when a host or decoder can provide them.

  • MetadataRawApplicabilityState marks current concept candidates as unknown, applicable to stored raw samples, conditional on raw encoding, or not applicable to stored raw samples.

The default resolver still marks curve/LUT-like RAW roles as conditional on raw encoding when no storage context is supplied. Descriptor-aware concept resolution overloads accept MetadataRawDataDescriptor; those overloads can mark recognized RAW-processing roles as applicable to stored RAW samples for known RAW encodings, not applicable for rendered data, or not applicable when a curve/LUT-like role is explicitly marked compressed-storage-only but the source descriptor says the raw samples are uncompressed or packed. This is a conservative storage-context classification, not proof that a vendor curve is active for a specific file.

If a decoder knows that a curve/LUT-like metadata entry only affects the primary raw plane, set requires_primary_raw_plane = true and provide has_plane_index / plane_index for the raw buffer being described. OpenMeta then marks that curve as not applicable for non-primary planes and conditional when the active plane is unknown.

Transfer preparation can also consume PrepareTransferRequest::source_raw_data_descriptor. When that descriptor says the source pixels are rendered, RAW-processing metadata is filtered even under compatible-file safety. The remaining gap is finer binding to the exact raw blob, packing/compression mode, and active decoder path before declaring that a specific vendor LUT or curve is active.

Future interpretation work should bind curve/LUT entries to the raw data descriptor that records the relevant blob, compression or packing mode, sample layout, offsets/byte counts when available, and the decoder stage where the curve applies.

Verification should require more than tag-name comparison: decoder-source tracing, runtime branch confirmation, metadata mutation/removal tests, and raw pixel-buffer diffs across compressed and uncompressed samples should be used before OpenMeta promotes a curve/LUT from present metadata to an active raw-processing operation.

page OpenEXR Metadata Fit for OpenMeta Core

Status: baseline contract (v1)

Goal

Assess whether the current OpenMeta metadata core can represent OpenEXR metadata well enough for read/edit workflows, and identify required API/model changes for good interoperability with OpenEXR and related host metadata layers.

What OpenEXR Metadata Looks Like

OpenEXR metadata is a per-part attribute map (name + typed value), not EXIF-like numeric tag tables. Attribute types are strongly typed in the SDK and include:

  • Scalars and enums (int, float, double, compression, lineOrder, envmap)

  • Geometric/math types (v2*, v3*, m33*, m44*, box2*)

  • Structured payloads (chlist, preview, tiledesc, timecode, keycode)

  • Strings and string vectors

  • Rational and opaque/custom attribute types

OpenEXR C APIs expose:

  • Count/list/get attribute by name or index (file order or sorted order)

  • Explicit typed getters/setters for built-in attribute types

  • Header write lifecycle (declare/set then write_header)

  • In-place header update mode with size constraints

Host Metadata Integration Signals

  • Common EXR host libraries often treat EXR metadata as arbitrary key/value attributes and map many EXR names to generic names (DateTime, Copyright, etc.) while preserving EXR-specific names under openexr:*.

  • EXR host stacks may expose EXIF/IPTC-like interoperability through arbitrary metadata transport, not because EXR natively stores EXIF/IPTC blocks.

  • OpenColorIO metadata model is mostly string-based transform/config metadata; it is useful for selected color-related fields, not as a full EXR container model.

Fit Against Current OpenMeta Core

Current OpenMeta strengths:

  • MetaStore already supports duplicate keys, per-block origin, deterministic indexing, and binary-search lookups.

  • MetaValue already supports scalar, array, bytes, text, and rational values.

  • Existing block model can represent per-part metadata boundaries.

Current implementation snapshot:

  • MetaKeyKind::ExrAttribute is available (part_index + name).

  • decode_exr_header(...) is implemented and wired into simple_meta_read fallback path (metadata-only header decode).

  • Common EXR scalar/vector/matrix types decode to typed MetaValue; unknown and complex payloads are preserved as raw bytes.

  • Unknown/custom EXR attrs can preserve original type name in Origin::wire_type_name (optional decode behavior).

  • Origin::wire_type carries EXR type code (WireFamily::Other), and wire_count currently stores attribute byte size.

Remaining gaps for production-level EXR workflows:

  • Persisting original EXR type_name for unknown/custom attrs (beyond numeric code).

  • Full canonical policy for complex structured attrs (chlist, preview, stringvector) and helper views.

  • EXR-aware write/edit lifecycle, including in-place header size constraints.

  • Optional EXR scanner integration in container_scan (today handled by fallback decode in simple_meta_read).

Design Direction (v1)

  1. Add EXR key space and provenance:

    • MetaKeyKind::ExrAttribute with fields: part_index, name.

    • Reserve block format/container code for EXR header metadata blocks.

  2. Add EXR wire typing:

    • Extend wire metadata to carry EXR type id + type_name string when needed.

    • Keep unknown/custom attributes as raw bytes + declared type name.

  3. Define canonical value encodings:

    • vectors/matrices/boxes as typed arrays with fixed element counts.

    • chlist, preview, and other complex structs as bytes + structured decode helpers (opt-in) to keep core storage compact and lossless.

  4. Add EXR decode entry point:

    • decode_exr_header(...) that fills MetaStore from EXR parts/attributes.

    • Keep image pixel I/O out of scope; metadata only.

  5. Add integration adapters:

    • flat host-attribute export: map EXR attrs to generic host names plus openexr:*.

    • OpenColorIO adapter: expose selected color metadata subset only.

Canonical encoding details for compound EXR values are tracked in: OpenMeta/docs/design/exr_canonical_value_encoding.md.

Practical Conclusion

OpenMeta core is close enough to support EXR metadata without redesigning the store. Main work is key-space/type modeling and a container-specific EXR decode frontend with clear canonical encoding rules for EXR compound attribute types.

page Shared Library Contract

OpenMeta supports static and shared C++20 libraries. The shared library is a C++ ABI artifact, not a stable C ABI. A consumer must use a compatible compiler, C++ standard library, compiler runtime, and build mode.

Build

Build only the shared library when packaging a runtime distribution:

cmake -S . -B build-shared -G Ninja -DCMAKE_BUILD_TYPE=Release \
  -DOPENMETA_BUILD_STATIC=OFF -DOPENMETA_BUILD_SHARED=ON
cmake --build build-shared
cmake --install build-shared --prefix /opt/openmeta

The installed CMake package is below ${CMAKE_INSTALL_LIBDIR}/cmake/OpenMeta. Consumers should select the shared target explicitly when they need dynamic linkage:

find_package(OpenMeta CONFIG REQUIRED)
target_link_libraries(my_program PRIVATE OpenMeta::openmeta_shared)

OpenMeta::openmeta remains an alias chosen by the installed package. Use the explicit shared target for packaging and runtime-linkage tests.

ABI And Toolchain

The installed package publishes OpenMeta_ABI_VERSION, currently 2. The ABI major changes only for an incompatible public C++ ABI change. On ELF platforms, the installed shared object has the corresponding SONAME major. Package version and ABI major are different: a patch or minor release may retain ABI 2.

When OpenMeta is built with OPENMETA_USE_LIBCXX=ON, the package requires a Clang consumer and propagates -stdlib=libc++ for compile and link steps. This prevents silently mixing the libc++ and libstdc++ std::string ABIs. For all other builds, use the same compiler family, C++ runtime, and compatible runtime settings as the package producer.

On MSVC, select the runtime library through CMAKE_MSVC_RUNTIME_LIBRARY when configuring OpenMeta. The installed targets propagate that selection to CMake consumers, and the package publishes it as OpenMeta_MSVC_RUNTIME_LIBRARY. For example, use MultiThreaded with an /MT dependency prefix and MultiThreadedDLL with an /MD dependency prefix. The default is /MD in Release and /MDd in Debug.

Dependencies And Runtime

Implementation dependencies of the shared target are private. A shared-only package therefore does not require CMake packages for zlib, Brotli, Expat, OpenSSL, or the optional DNG SDK merely to configure a consumer. Static targets continue to export their dependency closure because an archive does not retain that link information.

On ELF, static implementation archives are excluded from the dynamic symbol table. On macOS, OpenMeta rejects a static implementation dependency for a shared build because it could otherwise become a public dylib symbol; provide a dynamic dependency package or disable that optional feature.

On Windows, the static archive is openmeta_static.lib, the DLL import archive is openmeta_shared.lib, and the runtime DLL is openmeta.dll. Deploy the DLL next to the application or make its directory discoverable through the normal Windows DLL search policy. The installed-consumer test places the package bin directory on PATH before it runs its executable.

Unix shared builds use hidden implementation visibility and expose the public header declarations. Windows uses CMake’s generated DLL export table for the current C++ surface. A future frozen per-symbol Windows export list can reduce that generated export set without changing this consumer contract.

Verification

The openmeta_gate_shared_install target installs the current build into a temporary prefix, then configures, builds, and runs a separate consumer that uses only that installed package:

cmake --build build-shared --target openmeta_gate_shared_install

CTest exposes the same check as openmeta_shared_library_install_consumer when OPENMETA_BUILD_TESTS=ON. Test the package on every target platform. The Linux and Windows shared-only gates run in public CI; macOS package validation is a release check.

page Writer Target Contract

This page defines the bounded preserve/replace contract for OpenMeta transfer writers.

It is scoped to metadata transfer and metadata-only target edits. OpenMeta does not claim full arbitrary metadata-editor parity, pixel transcoding, or byte-for-byte preservation of rewritten metadata structures.

For generated XMP merge, precedence, sidecar output, and sidecar cleanup rules, see xmp_sync_policy.md.

Common Rules

Managed metadata families are replaced only when OpenMeta has a prepared block for that family or an explicit strip policy targets that family.

Unmanaged data is preserved as source ranges where the target edit path can parse the container safely. If parsing finds a structure outside the bounded contract, the edit fails with an unsupported or malformed result instead of guessing.

Managed XMP writeback has three modes:

  • EmbeddedOnly: generated XMP remains in the managed embedded carrier.

  • SidecarOnly: generated embedded XMP blocks are suppressed and returned as sidecar output.

  • EmbeddedAndSidecar: generated XMP is written to both the embedded carrier and sidecar output.

Destination embedded-XMP stripping is supported only for sidecar-only writeback on JPEG, TIFF/DNG, PNG, WebP, JP2, JXL, and bounded BMFF targets. Destination sidecar cleanup is supported only for embedded writeback.

Image-dependent metadata is target-owned. When source and target images may differ in dimensions, channel count, sample type, compression, orientation, colorspace, or strip/tile storage layout, host code must preserve or provide target-correct image buffer specs from the actual output image. Use PrepareTransferRequest::target_image_spec when the host knows target dimensions, orientation, samples-per-pixel, bit depth, sample format, photometric interpretation, planar configuration, compression, or EXIF color space. OpenMeta filters source EXIF/XMP image-layout fields during prepared transfer rather than copying stale source width/height, channel/layout, color-space aliases, or source-local storage offsets into another file. ICC transfer should be enabled only when the host knows that the source profile is valid for the target pixel buffer; otherwise the host writer should keep or inject the target profile. The Python binding exposes the same structure as openmeta.TransferTargetImageSpec; the C++ and Python metatransfer command wrappers expose matching --target-* flags for smoke tests and file-helper integration checks.

For coarse transfer safety, use TransferProfile::safety. The default CompatibleFile mode is for metadata repackage or recompression into a compatible target and preserves source camera/color metadata after the target-owned image-layout filter above. RenderedImage is for exports whose pixels may have changed, including RAW-to-rendered outputs. It keeps general descriptive metadata, time fields, GPS, IPTC, and portable XMP, but filters source raw color calibration, profile/gain tables, raw digests/storage identifiers, raw value curves, linearity limits, calibration curves, curve-control points, linearization/crop/correction tags, vendor RAW geometry/color/correction/private tags for Phase One/Leaf, Sony, Canon, Nikon, Fujifilm, Pentax, Panasonic, Olympus, Kodak, Minolta, Sigma, Samsung, Ricoh, Apple/Google computational capture fields, DJI/FLIR thermal processing fields, Casio/Sanyo preview or face-geometry fields, KyoceraRaw WB fields, Reconyx trail-camera processing/environment fields, HP/JVC/GE private placeholders, Motorola source-rendering/sensor fields, Nintendo parallax/camera-info fields, Microsoft stitch/panorama geometry fields, camera raw settings XMP, source ICC profiles, MakerNotes, and non-C2PA JUMBF data. Host code should provide target-correct ICC/profile data and image specs separately.

Transfer Safety Matrix

The table below is the public coarse policy for automatic transfer. It is not a privacy policy and it is not a replacement for application-specific metadata controls. Hosts may still strip more metadata. For per-candidate preflight UI, metadata_concepts.h exposes transfer hints such as safe, source_bound, rendered_unsafe, and requires_target_image_spec; transfer_concept_diagnostics_from_store(...) maps those hints to keep/drop/requires-target-image-spec actions, severity tokens, and default message text for a selected transfer mode. Descriptor-aware overloads accept MetadataRawDataDescriptor so RAW-processing diagnostics can account for a known stored-RAW or rendered source context. Candidates and diagnostics also report independent sensitivity; safe means technically portable, not safe to publish. Apply host consent/privacy policy to personal-contact, person-identity, location, and legal-rights metadata.

When the host or decoder already knows that the source pixel buffer is rendered rather than stored RAW samples, set PrepareTransferRequest::has_source_raw_data_descriptor and pass source_raw_data_descriptor.encoding = MetadataRawDataEncoding::Rendered. Preparation then filters RAW-processing metadata even under CompatibleFile; this prevents RAW calibration, curve, and camera-raw recipe data from being carried into metadata that no longer applies to the stored pixels.

When a decoder knows that a curve/LUT-like metadata entry only applies to compressed RAW storage, set source_raw_data_descriptor.requires_compressed_raw_encoding = true. Concept diagnostics can then drop that curve for uncompressed or packed raw buffers while still keeping non-curve RAW facts such as black level and raw-storage layout applicable.

When a decoder knows that a curve/LUT-like metadata entry only applies to the primary raw plane, set source_raw_data_descriptor.requires_primary_raw_plane = true and provide has_plane_index / plane_index for the raw buffer being checked. Concept diagnostics then drop that curve for non-primary planes and keep it conditional when the active plane is unknown.

Metadata group

Examples

CompatibleFile

RenderedImage

Notes

General descriptive metadata

title, description, creator, artist, copyright, rating, label, keywords

Keep

Keep

Safe because it describes the asset or authorship rather than the source pixel encoding.

Capture time

DateTimeOriginal, CreateDate, subsecond fields, timezone offset fields, GPS time

Keep

Keep

If the output represents a new capture or synthetic composition, host policy should replace or strip these values.

Camera and lens acquisition facts

Make, Model, LensModel, exposure time, f-number, ISO, focal length, flash, metering mode

Keep

Keep

These are safe as capture facts. They are not treated as processing instructions.

Location and IPTC editorial fields

EXIF GPS, XMP GPS aliases, IPTC location, caption, byline, credit, rights, job/reference fields

Keep

Keep

Privacy-sensitive data is intentionally left to host policy.

Portable XMP

Dublin Core, XMP Rights, IPTC Extension, generated EXIF/IPTC projections

Keep after image-layout filtering

Keep after image-layout and rendered-safety filtering

XMP properties from raw-processing namespaces are handled separately below.

Target image layout and storage

width, height, orientation, samples per pixel, bits per sample, sample format, photometric interpretation, compression, rows/strips/tiles, offsets, byte counts, thumbnail/interchange offsets

Target-owned; source values filtered

Target-owned; source values filtered

Host code must preserve target values or provide target_image_spec.

Output color/profile metadata

ICC profile blocks, EXIF/XMP ColorSpace, color-space aliases, Photoshop ICC profile name

Keep only when the source profile is valid for the target pixel buffer

Drop source ICC/profile facts; host writes target profile

Rendered exports often need a new output profile such as sRGB, Display P3, or a host-managed working/output profile.

RAW/DNG sensor and color pipeline

CFA pattern, black/white levels, linearization tables, linear response limits, RAW value curves, RAW curve control points, RAW calibration curves, ColorMatrix*, ForwardMatrix*, CameraCalibration*, AsShotNeutral, DNG private/profile tags, DNG XMP profile properties (dng:*), profile/gain tables, raw digests/storage identifiers, opcode/correction lists, Phase One/Leaf ColorMatrix1, ColorMatrix2, WB_RGBLevels, sensor-calibration flat fields and linearization coefficients, Sony/Canon/Nikon/Fujifilm/Pentax/Panasonic/Olympus/Kodak/Minolta/Sigma/Samsung/Ricoh/Apple/Casio/Sanyo/KyoceraRaw/Reconyx/Motorola MakerNote color, HDR, source-rendering, and white-balance coefficient tables

Keep only for compatible RAW/DNG-style transfer; drop when the supplied source RAW data descriptor says pixels are rendered or the checked raw plane cannot use the metadata

Drop

These values describe how to turn original sensor data into rendered color. Reusing them on already-rendered pixels can make CMS or editors apply the raw transform twice. Curve/LUT metadata is also conditional: prepare can consume coarse rendered-vs-stored, compressed-only, and primary-plane-only descriptor hints now, while exact activity for a raw blob/compression mode still needs deeper descriptor binding.

RAW crop, geometry, storage, correction, and private data

ActiveArea, DefaultCrop*, masked areas, opcode lists, distortion/vignetting/camera-profile correction data, Phase One/Leaf SensorWidth, SensorHeight, SensorLeftMargin, SensorTopMargin, ImageWidth, ImageHeight, CameraOrientation, RawFormat, RawData, StripOffsets, BlackLevel, BlackLevelData, SplitColumn, sensor-temperature correction fields, Sony/Canon/Nikon/Fujifilm/Pentax/Panasonic/Olympus/Kodak/Minolta/Sigma/Samsung/Ricoh decoded RAW geometry/storage/lens-correction fields such as SR2/SRF, RAF header/directory/RAFData fields, MinoltaRaw PRD/RIF/WBG tables, Pentax lens-correction tables, Panasonic sensor subtables, Olympus image-processing/raw-development tables, Kodak sensor/black-level/raw-histogram fields, Samsung Type2 raw/color/correction fields, Ricoh sensor/crop/vignetting fields, Apple computational capture/HDR fields, Google HDR+ and shot-log fields, pixel-shift, multi-shot, composite, and auto-lighting optimizer fields, DJI thermal parameter tables, FLIR thermal raw-data/radiometric calibration/palette/PiP fields, Casio/Sanyo preview image, face geometry, and private data-dump fields, Reconyx trail-camera environment/trigger fields, HP/JVC/GE private placeholders, Motorola sensor fields, Nintendo parallax/camera-info fields, Microsoft stitch/panorama geometry fields, Canon crop/aspect/color-data tables, and Nikon NEF/distortion/vignette tables or named correction fields

Keep only for compatible RAW/DNG-style transfer; drop when the supplied source RAW data descriptor says pixels are rendered

Drop

These values are tied to the original sensor geometry, computational rendering, radiometric calibration, source preview data, or raw-processing pipeline. Vendor-private RAW/source tables are dropped in rendered mode even when individual fields are unknown, while named entries also receive narrower color/WB/geometry/correction buckets. Use phaseone_raw_geometry_from_store(), phaseone_raw_processing_from_store(), and vendor_raw_processing_from_store() only to interpret source RAW metadata; rendered exports need target-owned geometry and color/profile data.

Camera raw settings XMP

crs:* development settings and raw-edit recipe metadata

Keep; drop when the supplied source RAW data descriptor says pixels are rendered

Drop

A rendered file should not normally carry a source raw-edit recipe unless the host intentionally writes a sidecar/workflow record.

Opaque MakerNote payloads

vendor MakerNote blobs and private nested IFDs

Keep carries the original raw ExifIFD:MakerNote payload as unverified opaque bytes; Drop omits it; unavailable Invalidate and Rewrite fail closed to Drop

Drop

Decoded safe facts can still be carried through standard EXIF/XMP fields; decoded-only vendor sub-IFDs are not reconstructed. Opaque preservation does not relocate nested vendor offsets, repair checksums, or prove semantic readability after EXIF repacking. Use makernote_transfer_audit_from_store(...) for generic trust and makernote_layout_transfer_audit_from_store(...) for bounded layout evidence. The layout audit identifies Nikon type 1 notes as outer-TIFF-dependent and can validate standard embedded-TIFF offsets in canonical Nikon type 3 notes, but it does not validate vendor-private binary offsets or checksums. Preserving an existing destination MakerNote during an unrelated target edit is safer than transferring a source note into a new EXIF layout because the destination’s established offset relationships can remain intact.

C2PA and JUMBF

APP11/JUMBF boxes, C2PA manifests, assertions, signatures

Follow explicit JUMBF/C2PA policy

Drop non-C2PA JUMBF; invalidate C2PA by default if it would otherwise be kept

Pixel-changing exports need a new content binding and signature from the host or signer.

Embedded previews and thumbnails

TIFF preview pages, SubIFD previews, JPEG interchange thumbnail data

Preserve only within bounded target-owned rewrite rules

Target-owned; host should regenerate or preserve target previews

Source previews commonly describe the source pixels, not the rendered target.

Target Summary

Target

Managed embedded carriers

Preserve/replace rule

Main limits

JPEG

APP1 EXIF, APP1 XMP, APP2 ICC, APP13 IPTC/IRB, bounded APP11 JUMBF/C2PA

Replace matching recognized leading metadata segments; preserve unknown leading segments and image scan data

Not a general JPEG marker editor

TIFF

root TIFF tags, EXIF/GPS/Interop IFDs, bounded page/SubIFD chains, XMP tag 700, IPTC 33723, ICC 34675

Rewrite bounded IFD structures and append new metadata tail data; preserve unrelated root tags and bounded downstream tails

Not arbitrary nested-IFD graph rewrite

DNG

same as TIFF plus DNG target-mode policy and minimal DNGVersion synthesis

Uses the TIFF-family rewrite contract; preserves DNG core target tags when merging non-DNG source metadata into an existing DNG target

Not a full DNG-specific rewrite engine

PNG

eXIf, XMP iTXt, iCCP

Insert prepared chunks after IHDR; replace matching managed chunks; preserve unrelated chunks

Requires valid PNG with terminal IEND

WebP

EXIF, XMP RIFF chunk, ICCP, bounded C2PA

Replace matching managed RIFF chunks; preserve unrelated chunks; patch VP8X feature bits

EXIF/XMP/ICC edits require an existing VP8X chunk

JP2

top-level Exif, top-level XMP xml box, jp2h/colr ICC

Replace matching top-level metadata boxes; rewrite jp2h only to replace/insert colr; preserve unrelated boxes and unrelated jp2h children

Does not synthesize jp2h; requires one existing jp2h for ICC

JXL

top-level Exif, XMP xml box, jumb, c2pa

Replace matching top-level boxes; preserve signature and non-managed boxes; classify jumb as generic JUMBF or C2PA

ICC is encoder handoff only; file edit emits uncompressed prepared metadata boxes

HEIF / AVIF / CR3

BMFF metadata items (Exif, XMP mime, JUMBF/C2PA), bounded colr/prof ICC properties, plus OpenMeta-authored metadata-only meta boxes

Preserve non-meta top-level boxes; replace prior OpenMeta-authored metadata meta; merge/replace/strip item metadata in parseable foreign top-level meta graphs by extending iinf/iloc/idat/iref; remap unambiguous managed item replacements across iref/version-0 grpl/ipma; replace prior ICC colr properties and remap iprp/ipco/ipma for bounded ICC

Does not rewrite arbitrary BMFF scene/property graphs

EXR

safe string header attributes through the EXR transfer emitter or adapter batch

No file rewrite contract today; host applies prepared attributes through its own EXR writer

Attribute-emitter target, not a file edit path

JPEG

The JPEG edit path scans leading metadata marker segments before image scan data.

OpenMeta replaces a leading segment when:

  • the segment route matches a prepared block route

  • sidecar-only writeback requests embedded XMP stripping and the segment is APP1 XMP

  • JUMBF or C2PA policy resolves to removal for matching APP11 carriers

Unknown APP/COM segments and all scan data after the leading metadata region are preserved. If same-size replacements are available, OpenMeta can use the in-place edit plan; otherwise it performs a metadata rewrite while preserving the image data range.

TIFF And DNG

TIFF-family editing supports classic TIFF and BigTIFF.

Managed updates include:

  • root IFD metadata tags such as XMP tag 700, IPTC tag 33723, and ICC tag 34675

  • EXIF payload materialized as bounded TIFF-family IFD structures

  • EXIF/GPS/Interop pointer regeneration

  • bounded preview-page chain replacement with downstream tail preservation

  • bounded SubIFD replacement with downstream auxiliary-tail preservation

  • preserving an existing target InteropIFD when a replaced ExifIFD omits its own interop child

The active root image IFD remains target-owned for pixel layout and local byte storage. Source EXIF values for root image width/height, sample layout, compression, orientation, strip/tile offsets, strip/tile byte counts, and thumbnail/JPEG interchange offsets are not allowed to replace the target’s active image structure during metadata transfer. For replaced preview-page and SubIFD structures, OpenMeta also strips source-local strip/tile/JPEG storage offsets and preserves the corresponding target-local storage fields when a matching target child exists.

Source IFD offsets are never copied as ordinary metadata values when OpenMeta does not also materialize their child directory. This currently applies to GlobalParametersIFD (0x0190) and DNG ExtraCameraProfiles (0xC6F5): prepare omits the source pointer and reports it as an unsupported EXIF entry. An existing target pointer and its target-owned child bytes remain unchanged during TIFF/DNG rewrite. Fresh output therefore contains neither a dangling source offset nor a partially reconstructed auxiliary directory.

The same target-owned rule is applied before packaging EXIF/XMP metadata for JPEG, PNG, WebP, JP2, JXL, BMFF-family targets, and EXR string attributes. Source descriptive tags such as make/model/date/GPS/copyright continue to transfer; source image-buffer facts do not become target image facts unless a host supplies target-correct values through target_image_spec or another writer-specific path.

Unrelated root IFD tags are preserved. Rewritten structures may be repacked into new offsets appended to the file; offset identity is not part of the contract.

DNG uses the same TIFF-family rewrite contract. ExistingTarget and TemplateTarget require a backing target container. MinimalFreshScaffold can emit a minimal metadata scaffold without an existing DNG target. When a non-DNG source is merged into an existing DNG target, OpenMeta preserves existing target DNG core tags within the bounded DNG policy layer.

PNG

The PNG edit path requires a valid PNG signature, an IHDR chunk, and a terminal IEND chunk.

Prepared eXIf, XMP iTXt, and iCCP chunks are inserted immediately after IHDR. Existing chunks from those managed families are removed when a replacement or strip policy targets that family. XMP matching is limited to iTXt chunks using the XML:com.adobe.xmp keyword.

All unrelated chunks are preserved. Bytes following the terminal IEND are preserved as part of the kept terminal range.

WebP

The WebP edit path requires a valid RIFF/WebP stream whose RIFF size consumes the input bytes.

Prepared EXIF, XMP, ICCP, and bounded C2PA chunks replace existing chunks from the same managed family. Unrelated chunks are preserved. When EXIF, XMP, or ICC is present after rewrite, OpenMeta patches the existing VP8X feature flags to match the final metadata state.

Prepared WebP EXIF chunks carry the TIFF byte stream directly. They do not include the JPEG APP1 Exif\0\0 preamble.

The current WebP edit contract requires an existing VP8X chunk for EXIF, XMP, or ICC metadata edits. It does not synthesize VP8X.

JP2

The JP2 edit path requires a valid JP2 signature box and file-type box.

Prepared top-level Exif and XMP xml boxes replace existing top-level boxes from the same managed family. Unrelated top-level boxes are preserved.

ICC update uses the bounded jp2h/colr route. OpenMeta rewrites the existing jp2h box to replace existing colr children with the prepared ICC colr payload, while preserving unrelated jp2h children. If no colr child exists, the prepared colr child is inserted. The contract requires one existing jp2h box and does not synthesize a new jp2h box.

JXL

The JXL edit path requires a valid JXL container.

Prepared top-level Exif, XMP xml, jumb, and c2pa boxes replace existing boxes from the same managed family. Unrelated top-level boxes are preserved, including the JXL signature box. Generic JUMBF and C2PA are distinguished so a generic jumb replacement does not accidentally remove a C2PA carrier, and the C2PA path does not remove unrelated generic JUMBF.

When Brotli support is available, the same family classification can inspect compressed brob metadata boxes by real type. The file edit path emits prepared metadata boxes directly; the jxl:icc-profile route remains an encoder-side handoff and is not serialized by the file edit path.

HEIF / AVIF / CR3

The bounded BMFF edit path preserves non-meta top-level boxes as source ranges.

When the target has no foreign top-level meta box, OpenMeta writes one metadata-only top-level meta box using the public bounded contract. That box can contain prepared Exif, XMP, JUMBF, C2PA, and ICC colr property payloads. A prior OpenMeta-authored metadata meta box is removed and replaced by the newly prepared box.

When the target already has a foreign top-level meta box, OpenMeta does not append a second competing meta graph. For parseable HEIF/AVIF-style item graphs it merges, replaces, or strips bounded Exif/XMP/JUMBF/C2PA metadata items in the existing meta by extending iinf, iloc, idat, and iref with cdsc references to the primary item. This constrained merge requires a single parseable iinf, iloc version 0/1/2, pitm, and at most one idat. When inserted metadata needs an item ID wider than 16 bits, OpenMeta upgrades the rebuilt iloc to version 2, emits infe version 3 for those inserted items, and uses iref version 1 for the corresponding cdsc references. If the existing graph has exhausted the usable 32-bit item-id space or mixes item-table shapes outside this bounded contract, the edit fails instead of truncating IDs.

Newly inserted metadata item payloads are appended to the rebuilt idat payload. To preserve broad reader compatibility, their iloc records keep construction method 0 and use absolute file-offset extents within the existing field widths. When all retained self-contained item locations can be represented as absolute extents, OpenMeta compacts the rebuilt iloc base-offset field width to zero for simpler reader compatibility.

Retained foreign item locations are supported when they use construction method 0 with file offsets, or construction method 1 with offsets into an existing idat, with data reference index 0 or an explicitly parsed self-contained version-0 dinf/dref url or urn entry. Construction method 2 is supported only when the retained item has parseable iref iloc references, using explicit extent indexes or reference order, and every referenced item is also retained with a supported local location and data reference index 0. Non-self-contained data references, missing method-2 references, removed referenced items, and other construction methods fail as unsupported instead of being rewritten by guesswork.

When exactly one removed managed item and one inserted item belong to the same Exif, XMP, JUMBF, or C2PA family, OpenMeta remaps that item ID in retained iref relation endpoints, version-0 grpl item-group members, and ipma associations. A strip operation has no replacement, and multiple old or new items make the mapping ambiguous; in both cases references to removed item IDs are deleted rather than redirected by guesswork. Unrelated relations, groups, properties, and associations remain unchanged.

For bounded ICC transfer, OpenMeta removes prior ICC colr/prof and colr/rICC properties from iprp/ipco, compacts/remaps existing ipma associations, appends the transferred colr/prof property, and associates it with the primary item and any retained item that previously referenced one of the replaced ICC properties. If the replaced association was marked essential, the transferred ICC association keeps that bit. Arbitrary non-ICC property replacement and broader BMFF scene/property graph rewriting remain out of scope.

If sidecar-only writeback asks to strip embedded XMP, OpenMeta can remove XMP from its own OpenMeta-authored metadata meta box and from parseable foreign top-level meta item graphs that satisfy the same bounded primary-item contract. Foreign graphs without pitm, with unsupported iloc, with multiple competing item tables, or otherwise outside that bounded shape are reported as unsupported instead of being guessed.

EXR

EXR is a transfer target and host-emitter path, not a file rewrite path.

OpenMeta prepares safe flattened string attributes for transfer and exposes the EXR attribute batch helpers for host-owned EXR writers. Existing EXR file metadata preservation is therefore owned by the host writer, not by an OpenMeta file edit helper.

One important pending use case is late-bound EXR metadata. Streaming tile or scanline writers sometimes only know a value after pixel data is finished, for example total_compute_time. The safe fast design is a fixed-size reservation/patch contract: reserve a typed attribute, such as a double, before writer construction, then patch exactly those value bytes after close. OpenMeta does not provide this patch API yet; it should remain separate from general EXR file rewrite because variable-length header changes would require moving later file structures.

Non-Goals

The writer contract does not promise:

  • arbitrary metadata editing for every carrier a format can contain

  • preserving byte offsets of rewritten TIFF-family structures

  • rewriting arbitrary existing BMFF item/property graphs

  • synthesizing missing JP2 jp2h or WebP VP8X structures

  • file-level EXR metadata rewrite

  • signed C2PA rewrite or trust-policy parity beyond the bounded staged handoff paths

page 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.

dir docs/design
dir docs
dir src/include
dir src/include/openmeta
dir docs/research
dir src
page OpenMeta

../../build/docs/doxygen/xml/docs/images/OpenMeta_Logo.png

OpenMeta is a metadata processing library for image files. It does not decode, decompress, demosaic, or render image pixels.

The current focus is format-agnostic metadata reads: find metadata blocks in common containers, decode them into a normalized in-memory model, and expose bounded transfer/edit building blocks for export workflows.