API Reference¶
This page is generated from the public C++ headers via Doxygen (XML) + Breathe.
-
struct AppendPreparedJpegJumbfOptions¶
- #include <metadata_transfer.h>
Options for explicit raw JUMBF append into a prepared JPEG bundle.
Public Members
-
bool replace_existing = false¶
If true, remove existing prepared
jpeg:app11-jumbfblocks first.
-
bool replace_existing = false¶
-
struct ApplyDngSdkMetadataFileOptions¶
- #include <dng_sdk_adapter.h>
File-helper options for DNG SDK adapter entry points.
-
struct ApplyDngSdkMetadataFileResult¶
- #include <dng_sdk_adapter.h>
File-helper result for DNG SDK adapter entry points.
-
struct ApplyTimePatchOptions¶
- #include <metadata_transfer.h>
Options for apply_time_patches.
-
struct ApplyTimePatchResult¶
- #include <metadata_transfer.h>
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¶
-
TransferStatus status = TransferStatus::Ok¶
-
struct BlockInfo¶
- #include <meta_store.h>
Container-block identity used to associate Entry::origin with a source block.
-
struct BlockSpan¶
- #include <meta_store.h>
-
struct BmffField¶
- #include <meta_key.h>
-
struct BmffField¶
- #include <meta_key.h>
Public Members
-
std::string_view field¶
-
std::string_view field¶
-
class BmffTransferEmitter¶
- #include <metadata_transfer.h>
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¶
-
virtual ~BmffTransferEmitter() = default¶
-
struct BuildExrAttributeBatchFileOptions¶
- #include <exr_adapter.h>
File-helper options for build_exr_attribute_batch_from_file.
-
struct BuildExrAttributeBatchFileResult¶
- #include <exr_adapter.h>
File-helper result for build_exr_attribute_batch_from_file.
-
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.
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.
-
std::string_view version¶
-
struct BuildPreparedC2paBindingResult¶
- #include <metadata_transfer.h>
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¶
-
TransferStatus status = TransferStatus::Unsupported¶
-
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_bytescapacity (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_byteswithalignmentand 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.
-
ByteArena() = default¶
-
struct ByteSpan¶
- #include <byte_arena.h>
A span (offset,size) into a ByteArena buffer.
-
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).
-
std::string name¶
-
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¶
-
CcmIssueSeverity severity = CcmIssueSeverity::Warning¶
-
struct CcmQueryLimits¶
- #include <ccm_query.h>
Limits for CCM query extraction.
-
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¶
-
bool require_dng_context = true¶
-
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¶
-
CcmQueryStatus status = CcmQueryStatus::Ok¶
-
struct Comment¶
- #include <meta_key.h>
Public Members
-
uint8_t reserved = 0¶
-
uint8_t reserved = 0¶
-
struct Comment¶
- #include <meta_key.h>
Public Members
-
uint8_t reserved = 0¶
-
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¶
-
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¶
-
ContainerFormat format = ContainerFormat::Unknown¶
-
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.
-
inline bool complete() const noexcept¶
-
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¶
-
std::span<std::byte> read_window¶
-
union Data¶
- #include <meta_key.h>
Public Functions
-
inline Data() noexcept¶
Public Members
-
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::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::JumbfField jumbf_field¶
-
struct openmeta::MetaKey::Data::JumbfCborKey jumbf_cbor_key¶
-
inline Data() noexcept¶
-
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¶
-
inline Data() noexcept¶
-
union Data¶
- #include <meta_value.h>
Public Functions
-
inline Data() noexcept¶
-
inline Data() noexcept¶
-
struct DngSdkAdapterOptions¶
- #include <dng_sdk_adapter.h>
Options for applying prepared OpenMeta metadata onto DNG SDK objects.
-
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¶
-
DngSdkAdapterStatus status = DngSdkAdapterStatus::Ok¶
-
struct EditOp¶
- #include <meta_edit.h>
A single edit operation recorded by MetaEdit.
-
struct EmittedBmffItemSummary¶
- #include <metadata_transfer.h>
One emitted ISO-BMFF metadata item summary entry.
-
struct EmittedBmffPropertySummary¶
- #include <metadata_transfer.h>
One emitted ISO-BMFF metadata property summary entry.
-
struct EmittedExrAttributeSummary¶
- #include <metadata_transfer.h>
One emitted EXR attribute summary entry.
-
struct EmittedJp2BoxSummary¶
- #include <metadata_transfer.h>
One emitted JP2 box summary entry.
-
struct EmittedJpegMarkerSummary¶
- #include <metadata_transfer.h>
One emitted JPEG marker summary entry.
-
struct EmittedJxlBoxSummary¶
- #include <metadata_transfer.h>
One emitted JPEG XL box summary entry.
-
struct EmittedPngChunkSummary¶
- #include <metadata_transfer.h>
One emitted PNG chunk summary entry.
-
struct EmittedTiffTagSummary¶
- #include <metadata_transfer.h>
One emitted TIFF tag summary entry.
-
struct EmittedWebpChunkSummary¶
- #include <metadata_transfer.h>
One emitted WebP chunk summary entry.
-
struct EmitTransferOptions¶
- #include <metadata_transfer.h>
Emission options shared by backend emit entry points.
-
struct EmitTransferResult¶
- #include <metadata_transfer.h>
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¶
-
TransferStatus status = TransferStatus::Ok¶
-
struct Entry¶
- #include <meta_store.h>
A single metadata entry (key/value) with provenance.
Note
Duplicate keys are allowed and preserved.
-
struct ExecutePreparedTransferBundleOptions¶
- #include <metadata_transfer.h>
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¶
-
ExecutePreparedTransferOptions execute¶
-
struct ExecutePreparedTransferFileOptions¶
- #include <metadata_transfer.h>
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
.xmpoutput 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¶
-
PrepareTransferFileOptions prepare¶
-
struct ExecutePreparedTransferFileResult¶
- #include <metadata_transfer.h>
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¶
-
PrepareTransferFileResult prepared¶
-
struct ExecutePreparedTransferOptions¶
- #include <metadata_transfer.h>
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¶
-
std::vector<TransferTimePatchInput> time_patches¶
-
struct ExecutePreparedTransferResult¶
- #include <metadata_transfer.h>
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¶
-
bool c2pa_stage_requested = false¶
-
struct ExecutePreparedTransferSnapshotOptions¶
- #include <metadata_transfer.h>
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
.xmpsidecar 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
.xmpoutput 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¶
-
PrepareTransferRequest prepare¶
-
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).
-
uint32_t max_ifds = 128¶
-
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¶
-
bool include_pointer_tags = true¶
-
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¶
-
ExifDecodeStatus status = ExifDecodeStatus::Ok¶
-
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¶
-
ExifIfdKind kind = ExifIfdKind::Ifd¶
-
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.
-
std::string_view ifd_prefix = "ifd"¶
-
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)"¶
-
ExifOrientationStatus status = ExifOrientationStatus::Ok¶
-
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.statusseparately.
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.
-
inline bool complete() const noexcept¶
-
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¶
-
std::span<std::byte> read_window¶
-
struct ExifTag¶
- #include <meta_key.h>
-
struct ExifTag¶
- #include <meta_key.h>
-
struct ExifTiffSerializeOptions¶
- #include <exif_tiff_serialize.h>
Policy and resource limits for canonical TIFF/EXIF serialization.
Public Members
-
bool include_subifds = false¶
-
bool inject_minimal_dng_version = false¶
-
bool validate = true¶
-
bool honor_wire_type_hints = true¶
-
ExifTiffMakerNotePolicy makernote_policy = ExifTiffMakerNotePolicy::Drop¶
-
uint64_t max_output_bytes = 64ULL * 1024ULL * 1024ULL¶
-
bool include_subifds = false¶
-
struct ExifTiffSerializeResult¶
- #include <exif_tiff_serialize.h>
Size and coverage details from canonical TIFF/EXIF serialization.
Public Functions
-
inline bool ok() const noexcept¶
-
inline bool ok() const noexcept¶
-
struct ExportItem¶
- #include <interop_export.h>
A single exported metadata item.
The name view is valid only for the duration of MetadataSink::on_item.
-
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¶
-
ExportNameStyle style = ExportNameStyle::Canonical¶
-
struct ExrAdapterAttribute¶
- #include <exr_adapter.h>
One owned EXR-native attribute payload.
-
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¶
-
uint32_t encoding_version = kExrCanonicalEncodingVersion¶
-
struct ExrAdapterOptions¶
- #include <exr_adapter.h>
Options for EXR attribute batch export.
-
struct ExrAdapterPartSpan¶
- #include <exr_adapter.h>
One contiguous per-part span inside ExrAdapterBatch::attributes.
-
struct ExrAdapterPartView¶
- #include <exr_adapter.h>
One zero-copy per-part attribute view over ExrAdapterBatch.
-
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¶
-
ExrAdapterStatus (*begin_part)(void *user, uint32_t part_index, uint32_t attribute_count) noexcept = 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¶
-
ExrAdapterStatus status = ExrAdapterStatus::Ok¶
-
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¶
-
ExrAdapterStatus status = ExrAdapterStatus::Ok¶
-
struct ExrAttribute¶
- #include <meta_key.h>
-
struct ExrAttribute¶
- #include <meta_key.h>
-
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¶
-
uint32_t max_parts = 64¶
-
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¶
-
bool decode_known_types = true¶
-
struct ExrDecodeResult¶
- #include <exr_decode.h>
Public Members
-
ExrDecodeStatus status = ExrDecodeStatus::Ok¶
-
uint32_t parts_decoded = 0¶
-
uint32_t entries_decoded = 0¶
-
ExrDecodeStatus status = ExrDecodeStatus::Ok¶
-
struct ExrPreparedAttribute¶
- #include <metadata_transfer.h>
EXR attribute payload for transfer emission.
-
struct ExrPreparedAttributeView¶
- #include <metadata_transfer.h>
Zero-copy EXR attribute view for prepared transfer emission.
-
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.
-
inline bool complete() const noexcept¶
-
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¶
-
std::span<std::byte> read_window¶
-
class ExrTransferEmitter¶
- #include <metadata_transfer.h>
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¶
-
virtual ~ExrTransferEmitter() = default¶
-
struct FlatHostImportItem¶
- #include <interop_import.h>
One ordered typed record imported from a flat host attribute model.
Public Members
-
std::string_view name¶
-
EntryId source_entry = kInvalidEntryId¶
-
MetaKeyView explicit_key¶
-
FlatHostImportValue value¶
-
std::string_view name¶
-
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¶
-
ExportNamePolicy name_policy = ExportNamePolicy::Spec¶
-
struct FlatHostImportResult¶
- #include <interop_import.h>
Transactional result for bounded flat host import.
Public Functions
-
inline bool ok() const noexcept¶
-
inline bool ok() const noexcept¶
-
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¶
-
std::span<const std::byte> payload¶
-
MetaValueKind kind = MetaValueKind::Empty¶
-
struct GeotiffKey¶
- #include <meta_key.h>
Public Members
-
uint16_t key_id = 0¶
-
uint16_t key_id = 0¶
-
struct GeotiffKey¶
- #include <meta_key.h>
Public Members
-
uint16_t key_id = 0¶
-
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¶
-
constexpr bool operator==(const HostAdoptionProfile&) const noexcept = default¶
-
struct IccDecodeLimits¶
- #include <icc_decode.h>
Resource limits applied during ICC decode to bound hostile inputs.
-
struct IccDecodeOptions¶
- #include <icc_decode.h>
Decoder options for decode_icc_profile.
Public Members
-
IccDecodeLimits limits¶
-
IccDecodeLimits limits¶
-
struct IccDecodeResult¶
- #include <icc_decode.h>
-
struct IccHeaderField¶
- #include <meta_key.h>
Public Members
-
uint32_t offset = 0¶
-
uint32_t offset = 0¶
-
struct IccHeaderField¶
- #include <meta_key.h>
Public Members
-
uint32_t offset = 0¶
-
uint32_t offset = 0¶
-
struct IccTag¶
- #include <meta_key.h>
Public Members
-
uint32_t signature = 0¶
-
uint32_t signature = 0¶
-
struct IccTag¶
- #include <meta_key.h>
Public Members
-
uint32_t signature = 0¶
-
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.
-
uint32_t signature = 0¶
-
struct IccTagInterpretLimits¶
- #include <icc_interpret.h>
Limits for ICC tag interpretation helpers.
-
struct IccTagInterpretOptions¶
- #include <icc_interpret.h>
Options for interpret_icc_tag.
Public Members
-
IccTagInterpretLimits limits¶
-
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¶
-
InteropSafetyReason reason = InteropSafetyReason::None¶
-
struct IptcDataset¶
- #include <meta_key.h>
-
struct IptcDataset¶
- #include <meta_key.h>
-
struct IptcIimDecodeLimits¶
- #include <iptc_iim_decode.h>
Resource limits applied during IPTC-IIM decode to bound hostile inputs.
-
struct IptcIimDecodeOptions¶
- #include <iptc_iim_decode.h>
Decoder options for decode_iptc_iim.
Public Members
-
IptcIimDecodeLimits limits¶
-
IptcIimDecodeLimits limits¶
-
struct IptcIimDecodeResult¶
- #include <iptc_iim_decode.h>
-
class Jp2TransferEmitter¶
- #include <metadata_transfer.h>
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¶
-
virtual ~Jp2TransferEmitter() = default¶
-
struct JpegEditPlan¶
- #include <metadata_transfer.h>
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¶
-
TransferStatus status = TransferStatus::Ok¶
-
class JpegTransferEmitter¶
- #include <metadata_transfer.h>
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¶
-
virtual ~JpegTransferEmitter() = default¶
-
struct JumbfCborKey¶
- #include <meta_key.h>
-
struct JumbfCborKey¶
- #include <meta_key.h>
Public Members
-
std::string_view key¶
-
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).
-
uint64_t max_semantic_work = kDefaultMaxSemanticWork¶
Maximum semantic work units. 0 is normalized to the finite default.
-
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.
Public Static Attributes
-
static constexpr uint64_t kDefaultMaxSemanticWork = 1ULL << 20¶
Default ceiling for semantic projection and verification work. One unit is one iteration over an attacker-controlled semantic entry, projection, reference, link, or box. Variable-length comparisons charge one additional unit per 256 bytes; substring searches charge per 256 worst-case compared bytes. Each semantic-key visit reserves 256 marker bytes for its bounded classifiers. Sorting charges a conservative comparison bound, including key lengths, plus its output pass. CBOR item parsing charges one unit per item; byte and text copies charge copied bytes in 256-byte units. COSE candidate parse, copy, and verification work charges its input bytes to bound token-level scans. 0 is normalized to this default.
-
uint64_t max_input_bytes = 64ULL * 1024ULL * 1024ULL¶
-
struct JumbfDecodeOptions¶
- #include <jumbf_decode.h>
Decoder options for decode_jumbf_payload.
Public Members
-
bool decode_cbor = true¶
If true, traverse
cborboxes and emit decoded CBOR key/value entries.
-
bool detect_c2pa = true¶
If true, emit a
c2pa.detectedmarker 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¶
-
bool decode_cbor = true¶
-
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¶
-
JumbfDecodeStatus status = JumbfDecodeStatus::Unsupported¶
-
struct JumbfField¶
- #include <meta_key.h>
-
struct JumbfField¶
- #include <meta_key.h>
Public Members
-
std::string_view field¶
-
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¶
-
JumbfDecodeStatus status = JumbfDecodeStatus::Unsupported¶
-
class JxlTransferEmitter¶
- #include <metadata_transfer.h>
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¶
-
virtual ~JxlTransferEmitter() = default¶
-
struct KeySpan¶
- #include <meta_store.h>
-
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.
-
LibRawOrientationTarget target = LibRawOrientationTarget::RawImage¶
-
struct LibRawFlipToExifResult¶
- #include <libraw_adapter.h>
Result for map_libraw_flip_to_exif_orientation.
-
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¶
-
uint64_t max_file_bytes = 0¶
-
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¶
-
LibRawOrientationFileStatus file_status = LibRawOrientationFileStatus::Ok¶
-
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.
-
LibRawOrientationTarget target = LibRawOrientationTarget::RawImage¶
-
struct LibRawOrientationResult¶
- #include <libraw_adapter.h>
Result for map_exif_orientation_to_libraw_flip.
Public Members
-
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¶
-
uint16_t exif_orientation = 1¶
-
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_bytesis 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¶
-
MappedFile() noexcept¶
-
struct MetadataApexTranslationOptions¶
- #include <metadata_translation.h>
Public Members
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
bool shutter_speed_value_to_exif = true¶
-
bool aperture_value_to_exif = true¶
-
bool brightness_value_to_exif = true¶
-
bool exposure_bias_value_to_exif = true¶
-
bool max_aperture_value_to_exif = true¶
-
uint32_t max_added_entries = kMetadataApexTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataCaptureTranslationMaxOperations¶
-
uint32_t max_text_bytes_per_property = kMetadataCaptureTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataApexTranslationMaxTotalTextBytes¶
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
struct MetadataAuthoringEntry¶
- #include <metadata_authoring.h>
One borrowed, ordered entry supplied to
create_metadata_store().
-
struct MetadataAuthoringOptions¶
- #include <metadata_authoring.h>
Resource and validation policy for generic metadata construction.
Public Members
-
uint32_t max_entries = 200000U¶
-
uint64_t max_arena_bytes = 64ULL * 1024ULL * 1024ULL¶
-
uint64_t max_value_bytes = 64ULL * 1024ULL * 1024ULL¶
-
uint32_t max_key_bytes = 4096U¶
-
MetadataAuthoringDuplicatePolicy duplicate_policy = MetadataAuthoringDuplicatePolicy::Allow¶
-
bool validate = true¶
-
MetadataValidationOptions validation¶
-
uint32_t max_entries = 200000U¶
-
struct MetadataAuthoringResult¶
- #include <metadata_authoring.h>
Transactional generic metadata construction result.
Public Functions
-
inline bool ok() const noexcept¶
Public Members
-
uint32_t entries_created = 0U¶
-
uint32_t failed_entry = kInvalidMetadataAuthoringEntry¶
-
MetadataValidationIssueCode validation_issue = MetadataValidationIssueCode::None¶
-
inline bool ok() const noexcept¶
-
struct MetadataCameraTextTranslationOptions¶
- #include <metadata_translation.h>
Public Members
-
MetadataTechnicalTranslationSourceMode source_mode = MetadataTechnicalTranslationSourceMode::DirtyOnly¶
-
MetadataTechnicalTranslationConflictPolicy conflict_policy = MetadataTechnicalTranslationConflictPolicy::FailOnConflict¶
-
bool spectral_sensitivity_to_exif = true¶
-
bool camera_owner_name_to_exif = true¶
-
bool body_serial_number_to_exif = true¶
-
bool lens_make_to_exif = true¶
-
bool lens_model_to_exif = true¶
-
bool lens_serial_number_to_exif = true¶
-
uint32_t max_added_entries = kMetadataCameraTextTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataTechnicalTranslationMaxOperations¶
-
uint32_t max_text_bytes_per_property = kMetadataTechnicalTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataCameraTextTranslationMaxTotalTextBytes¶
-
MetadataTechnicalTranslationSourceMode source_mode = MetadataTechnicalTranslationSourceMode::DirtyOnly¶
-
struct MetadataCapability¶
- #include <metadata_capabilities.h>
Capability record for one format/family pair.
Public Members
-
TransferTargetFormat format = TransferTargetFormat::Jpeg¶
-
MetadataCapabilitySupport structured_decode = MetadataCapabilitySupport::Unsupported¶
-
MetadataCapabilitySupport transfer_prepare = MetadataCapabilitySupport::Unsupported¶
-
MetadataCapabilitySupport target_edit = MetadataCapabilitySupport::Unsupported¶
-
MetadataCapabilitySupport raw_preservation = MetadataCapabilitySupport::Unsupported¶
Existing raw-carrier preservation in current transfer flows. This does not imply raw-preserving source snapshots.
-
TransferTargetFormat format = TransferTargetFormat::Jpeg¶
-
struct MetadataCaptureAdditionalTranslationOptions¶
- #include <metadata_translation.h>
Public Members
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
bool focal_length_in_35mm_film_to_exif = true¶
-
bool file_source_to_exif = true¶
-
bool scene_type_to_exif = true¶
-
uint32_t max_added_entries = kMetadataCaptureAdditionalTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataCaptureTranslationMaxOperations¶
-
uint32_t max_text_bytes_per_property = kMetadataCaptureTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataCaptureAdditionalTranslationMaxTotalTextBytes¶
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
struct MetadataCaptureRationalTranslationOptions¶
- #include <metadata_translation.h>
Public Members
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
bool subject_distance_to_exif = true¶
exif:SubjectDistance -> ExifIFD 0x9206 RATIONAL, meters.
-
bool digital_zoom_ratio_to_exif = true¶
exif:DigitalZoomRatio -> ExifIFD 0xa404 RATIONAL.
-
bool exposure_index_to_exif = true¶
exif:ExposureIndex -> ExifIFD 0xa215 RATIONAL.
-
bool flash_energy_to_exif = true¶
exif:FlashEnergy -> ExifIFD 0xa20b RATIONAL, BCPS.
-
uint32_t max_added_entries = kMetadataCaptureRationalTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataCaptureTranslationMaxOperations¶
-
uint32_t max_text_bytes_per_property = kMetadataCaptureTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataCaptureRationalTranslationMaxTotalTextBytes¶
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
struct MetadataCaptureSettingsTranslationOptions¶
- #include <metadata_translation.h>
Public Members
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
bool exposure_program_to_exif = true¶
exif:ExposureProgram -> ExifIFD 0x8822 SHORT.
-
bool metering_mode_to_exif = true¶
exif:MeteringMode -> ExifIFD 0x9207 SHORT.
-
bool sensing_method_to_exif = true¶
exif:SensingMethod -> ExifIFD 0xa217 SHORT.
-
bool custom_rendered_to_exif = true¶
exif:CustomRendered -> ExifIFD 0xa401 SHORT.
-
bool exposure_mode_to_exif = true¶
exif:ExposureMode -> ExifIFD 0xa402 SHORT.
-
bool white_balance_to_exif = true¶
exif:WhiteBalance -> ExifIFD 0xa403 SHORT.
-
bool scene_capture_type_to_exif = true¶
exif:SceneCaptureType -> ExifIFD 0xa406 SHORT.
-
bool gain_control_to_exif = true¶
exif:GainControl -> ExifIFD 0xa407 SHORT.
-
bool contrast_to_exif = true¶
exif:Contrast -> ExifIFD 0xa408 SHORT.
-
bool saturation_to_exif = true¶
exif:Saturation -> ExifIFD 0xa409 SHORT.
-
bool sharpness_to_exif = true¶
exif:Sharpness -> ExifIFD 0xa40a SHORT.
-
bool subject_distance_range_to_exif = true¶
exif:SubjectDistanceRange -> ExifIFD 0xa40c SHORT.
-
uint32_t max_added_entries = kMetadataCaptureSettingsTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataCaptureTranslationMaxOperations¶
-
uint32_t max_text_bytes_per_property = kMetadataCaptureTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataCaptureSettingsTranslationMaxTotalTextBytes¶
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
struct MetadataCaptureSpatialTranslationOptions¶
- #include <metadata_translation.h>
Public Members
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
bool focal_plane_to_exif = true¶
-
bool subject_area_to_exif = true¶
-
bool subject_location_to_exif = true¶
-
uint32_t max_added_entries = kMetadataCaptureSpatialTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataCaptureTranslationMaxOperations¶
-
uint32_t max_text_bytes_per_property = kMetadataCaptureTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataCaptureSpatialTranslationMaxTotalTextBytes¶
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
struct MetadataCaptureTranslationOptions¶
- #include <metadata_translation.h>
Caller-selected bounded reverse capture mappings.
Public Members
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
bool exposure_time_to_exif = true¶
exif:ExposureTime -> ExifIFD ExposureTime RATIONAL.
-
bool f_number_to_exif = true¶
exif:FNumber -> ExifIFD FNumber RATIONAL.
-
bool iso_to_exif = true¶
exif:ISO or standard ISOSpeedRatings -> ExifIFD SHORT.
-
bool focal_length_to_exif = true¶
exif:FocalLength -> ExifIFD FocalLength RATIONAL.
-
bool exposure_compensation_to_exif = true¶
exif:ExposureCompensation or ExposureBiasValue -> SRATIONAL.
-
uint32_t max_added_entries = kMetadataCaptureTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataCaptureTranslationMaxOperations¶
-
uint32_t max_text_bytes_per_property = kMetadataCaptureTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataCaptureTranslationMaxTotalTextBytes¶
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
struct MetadataCaptureTranslationResult¶
- #include <metadata_translation.h>
Transactional result details for one reverse capture translation.
Public Members
-
MetadataCaptureTranslationMapping failed_mapping = MetadataCaptureTranslationMapping::None¶
-
EntryId failed_source_entry = kInvalidEntryId¶
-
uint32_t source_properties = 0U¶
-
uint32_t groups_translated = 0U¶
-
uint32_t groups_preserved = 0U¶
-
uint32_t groups_unchanged = 0U¶
-
uint32_t entries_added = 0U¶
-
uint32_t entries_updated = 0U¶
-
uint32_t entries_removed = 0U¶
-
MetadataCaptureTranslationMapping failed_mapping = MetadataCaptureTranslationMapping::None¶
-
struct MetadataCompatibilityDumpOptions¶
- #include <compatibility_dump.h>
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¶
-
ExportNameStyle style = ExportNameStyle::FlatHost¶
-
struct MetadataCompositeTranslationOptions¶
- #include <metadata_translation.h>
Public Members
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
uint32_t max_added_entries = kMetadataCompositeTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataCaptureTranslationMaxOperations¶
-
uint32_t max_text_bytes_per_property = kMetadataCaptureTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataCompositeTranslationMaxTotalTextBytes¶
-
uint32_t max_exposure_values = kMetadataCompositeTranslationMaxExposureValues¶
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
struct MetadataConceptCandidate¶
- #include <metadata_concepts.h>
Public Members
-
MetadataConceptRecordKind record_kind = MetadataConceptRecordKind::None¶
Normalized structured-record type;
Nonefor 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¶
-
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.
-
MetadataConceptRecordKind record_kind = MetadataConceptRecordKind::None¶
-
struct MetadataConceptResolution¶
- #include <metadata_concepts.h>
Public Members
-
bool found = false¶
-
bool conflict = false¶
-
EntryId preferred_entry = kInvalidEntryId¶
-
std::vector<MetadataConceptCandidate> candidates¶
-
bool found = false¶
-
struct MetadataConceptResult¶
- #include <metadata_concepts.h>
Public Members
-
std::vector<MetadataConceptResolution> concepts¶
-
std::vector<MetadataConceptResolution> concepts¶
-
struct MetadataCreationField¶
- #include <metadata_creation.h>
One logical field supplied by a host application.
Public Members
-
MetadataCreationValueKind value_kind = MetadataCreationValueKind::Text¶
-
std::string_view text¶
-
uint32_t unsigned_value = 0U¶
-
int32_t signed_value = 0¶
-
MetadataCreationValueKind value_kind = MetadataCreationValueKind::Text¶
-
struct MetadataCreationLimits¶
- #include <metadata_creation.h>
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¶
-
uint32_t max_fields = kMetadataCreationMaxFields¶
-
struct MetadataCreationRequest¶
- #include <metadata_creation.h>
Stable creation request.
-
struct MetadataCreationResult¶
- #include <metadata_creation.h>
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¶
-
MetadataCreationStatus status = MetadataCreationStatus::Ok¶
-
struct MetadataDateTranslationOptions¶
- #include <metadata_translation.h>
Caller-selected bounded reverse-date mappings.
Public Members
-
MetadataDateTranslationConflictPolicy conflict_policy = MetadataDateTranslationConflictPolicy::FailOnConflict¶
-
bool create_date_to_exif_digitized = true¶
xmp:CreateDate -> EXIF DateTimeDigitized plus exact companions.
-
bool create_date_to_iptc_digital_creation = true¶
xmp:CreateDate -> IPTC DigitalCreationDate/Time.
-
bool date_created_to_iptc_created = true¶
photoshop:DateCreated -> IPTC DateCreated/TimeCreated.
-
bool date_time_original_to_exif_original = true¶
exif:DateTimeOriginal XMP -> native EXIF DateTimeOriginal companions.
-
uint32_t max_added_entries = kMetadataDateTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataDateTranslationMaxOperations¶
-
MetadataDateTranslationConflictPolicy conflict_policy = MetadataDateTranslationConflictPolicy::FailOnConflict¶
-
struct MetadataDateTranslationResult¶
- #include <metadata_translation.h>
Transactional result details for one reverse-date translation.
Public Members
-
MetadataDateTranslationMapping failed_mapping = MetadataDateTranslationMapping::None¶
-
EntryId failed_source_entry = kInvalidEntryId¶
-
uint32_t source_properties = 0U¶
-
uint32_t groups_translated = 0U¶
-
uint32_t groups_preserved = 0U¶
-
uint32_t groups_unchanged = 0U¶
-
uint32_t entries_added = 0U¶
-
uint32_t entries_updated = 0U¶
-
uint32_t entries_removed = 0U¶
-
MetadataDateTranslationMapping failed_mapping = MetadataDateTranslationMapping::None¶
-
struct MetadataDescriptiveTranslationOptions¶
- #include <metadata_translation.h>
Caller-selected bounded reverse descriptive mappings.
Public Members
-
MetadataDescriptiveTranslationSourceMode source_mode = MetadataDescriptiveTranslationSourceMode::DirtyOnly¶
-
MetadataDescriptiveTranslationConflictPolicy conflict_policy = MetadataDescriptiveTranslationConflictPolicy::FailOnConflict¶
-
bool title_to_iptc_object_name = true¶
-
bool description_to_iptc_caption = true¶
-
bool creators_to_iptc_bylines = true¶
-
bool keywords_to_iptc_keywords = true¶
-
bool copyright_to_iptc_copyright = true¶
-
bool credit_to_iptc_credit = true¶
-
bool source_to_iptc_source = true¶
-
uint32_t max_source_properties = kMetadataDescriptiveTranslationMaxSourceProperties¶
-
uint32_t max_added_entries = kMetadataDescriptiveTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataDescriptiveTranslationMaxOperations¶
-
uint64_t max_total_text_bytes = kMetadataDescriptiveTranslationMaxTotalTextBytes¶
-
MetadataDescriptiveTranslationSourceMode source_mode = MetadataDescriptiveTranslationSourceMode::DirtyOnly¶
-
struct MetadataDescriptiveTranslationResult¶
- #include <metadata_translation.h>
Transactional result details for one reverse descriptive translation.
Public Members
-
MetadataDescriptiveTranslationMapping failed_mapping = MetadataDescriptiveTranslationMapping::None¶
-
EntryId failed_source_entry = kInvalidEntryId¶
-
uint32_t source_properties = 0U¶
-
uint32_t groups_translated = 0U¶
-
uint32_t groups_preserved = 0U¶
-
uint32_t groups_unchanged = 0U¶
-
uint32_t entries_added = 0U¶
-
uint32_t entries_updated = 0U¶
-
uint32_t entries_removed = 0U¶
-
bool utf8_charset_added = false¶
-
MetadataDescriptiveTranslationMapping failed_mapping = MetadataDescriptiveTranslationMapping::None¶
-
struct MetadataDevelopmentCorrectionTranslationOptions¶
- #include <metadata_translation.h>
Translate EXIF 3.1 development and correction XMP properties.
The CIPA EXIF extension namespace is
http://cipa.jp/exif/1.0/(normallyexifEX). DevelopmentType is a resource with the published childrenDevelopmentCharactersticandFactoryDefault; the spelling ofCharactersticis part of the wire contract. DevelopmentTypeDescription is written as TIFF type 129 even for ASCII text. Correction values are bounded to their EXIF choices.A non-zero
exif_versionis required whenever a selected source is translated and must be exactly 300 or 310. The value is a host policy for the source discrepancy in the published CIPA material; this call never creates, changes or infers ExifVersion. A zero value therefore rejects a selected source with IncompleteSource. Preparation allocates; the commit is one transaction and hosts synchronize conflicting object access.Under FailOnConflict and ReplaceExisting, an exact valid singleton native value is promoted to Dirty by a same-value update that retains its value, wire hints, wire count, origin and endian flag. Dirty exact matches remain unchanged; PreserveExisting does not promote native values. A complete eligible source deletion preserves active values under PreserveExisting, conflicts under FailOnConflict, and tombstones all active values under ReplaceExisting. With no active native value, ReplaceExisting promotes a clean tombstone, reuses a dirty tombstone, or adds a typed Dirty|Deleted intent. Scalar fields use SHORT; DevelopmentTypeDescription uses UTF-8 Text with TIFF type 129. Promotions, tombstones and new intents consume max_operations; new intents also consume max_added_entries. Source masks, duplicate handling, limits and rollback follow the capture translation contract.
Public Members
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
bool development_type_to_exif = true¶
-
bool development_type_description_to_exif = true¶
-
bool distortion_correction_to_exif = true¶
-
bool chromatic_aberration_correction_to_exif = true¶
-
bool shading_correction_to_exif = true¶
-
bool noise_reduction_to_exif = true¶
-
uint32_t exif_version = 0U¶
Explicit host policy: 0 requires no selected source; use 300 or 310.
-
uint32_t max_added_entries = kMetadataDevelopmentCorrectionTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataCaptureTranslationMaxOperations¶
-
uint32_t max_text_bytes_per_property = kMetadataDevelopmentCorrectionTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataDevelopmentCorrectionTranslationMaxTotalTextBytes¶
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
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¶
-
uint32_t max_operations = kMetadataEditingMaxOperations¶
-
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.
-
struct MetadataEditingRequest¶
- #include <metadata_editing.h>
-
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¶
-
MetadataEditingStatus status = MetadataEditingStatus::Ok¶
-
struct MetadataEditorialTranslationOptions¶
- #include <metadata_translation.h>
Independent editorial mappings using the descriptive IPTC policies.
Public Members
-
MetadataDescriptiveTranslationSourceMode source_mode = MetadataDescriptiveTranslationSourceMode::DirtyOnly¶
-
MetadataDescriptiveTranslationConflictPolicy conflict_policy = MetadataDescriptiveTranslationConflictPolicy::FailOnConflict¶
-
bool headline_to_iptc = true¶
-
bool instructions_to_iptc = true¶
-
bool transmission_reference_to_iptc = true¶
-
uint32_t max_source_properties = kMetadataDescriptiveTranslationMaxSourceProperties¶
-
uint32_t max_added_entries = kMetadataEditorialTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataDescriptiveTranslationMaxOperations¶
-
uint64_t max_total_text_bytes = kMetadataDescriptiveTranslationMaxTotalTextBytes¶
-
MetadataDescriptiveTranslationSourceMode source_mode = MetadataDescriptiveTranslationSourceMode::DirtyOnly¶
-
struct MetadataEnvironmentTranslationOptions¶
- #include <metadata_translation.h>
Public Members
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
bool temperature_to_exif = true¶
-
bool humidity_to_exif = true¶
-
bool pressure_to_exif = true¶
-
bool water_depth_to_exif = true¶
-
bool acceleration_to_exif = true¶
-
bool camera_elevation_angle_to_exif = true¶
-
uint32_t max_added_entries = kMetadataEnvironmentTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataCaptureTranslationMaxOperations¶
-
uint32_t max_text_bytes_per_property = kMetadataCaptureTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataEnvironmentTranslationMaxTotalTextBytes¶
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
struct MetadataExifTextTranslationOptions¶
- #include <metadata_translation.h>
Public Members
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
bool exif_version_to_exif = true¶
-
bool flashpix_version_to_exif = true¶
-
bool user_comment_to_exif = true¶
-
bool image_title_to_exif = true¶
-
bool photographer_to_exif = true¶
-
bool image_editor_to_exif = true¶
-
bool camera_firmware_to_exif = true¶
-
bool raw_developing_software_to_exif = true¶
-
bool image_editing_software_to_exif = true¶
-
bool metadata_editing_software_to_exif = true¶
-
bool camera_owner_name_to_exif = true¶
-
bool lens_make_to_exif = true¶
-
bool lens_model_to_exif = true¶
-
uint32_t max_added_entries = kMetadataExifTextTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataCaptureTranslationMaxOperations¶
-
uint32_t max_text_bytes_per_property = kMetadataExifTextTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataExifTextTranslationMaxTotalTextBytes¶
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
struct MetadataFlashTranslationOptions¶
- #include <metadata_translation.h>
Public Members
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
uint32_t max_added_entries = kMetadataFlashTranslationMaxAddedEntries¶
-
uint32_t max_source_properties = kMetadataFlashTranslationMaxSourceProperties¶
-
uint32_t max_operations = kMetadataCaptureTranslationMaxOperations¶
-
uint32_t max_text_bytes_per_property = kMetadataCaptureTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataFlashTranslationMaxTotalTextBytes¶
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
struct MetadataFuzzySearchMatch¶
- #include <metadata_fuzzy_search.h>
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¶
-
EntryId entry_id = kInvalidEntryId¶
-
struct MetadataFuzzySearchOptions¶
- #include <metadata_fuzzy_search.h>
-
struct MetadataFuzzySearchResult¶
- #include <metadata_fuzzy_search.h>
Public Members
-
uint32_t examined_entry_count = 0U¶
-
uint32_t qualified_match_count = 0U¶
-
bool truncated = false¶
-
std::vector<MetadataFuzzySearchMatch> matches¶
-
uint32_t examined_entry_count = 0U¶
-
struct MetadataGeometryTranslationOptions¶
- #include <metadata_translation.h>
Caller-selected bounded reverse image-geometry mappings.
Public Members
-
MetadataGeometryTranslationSourceMode source_mode = MetadataGeometryTranslationSourceMode::DirtyOnly¶
-
MetadataGeometryTranslationConflictPolicy conflict_policy = MetadataGeometryTranslationConflictPolicy::FailOnConflict¶
-
bool orientation_to_exif = true¶
tiff:Orientation -> IFD0 Orientation SHORT.
-
bool dimensions_to_exif = true¶
XMP stored-raster dimensions -> canonical TIFF/EXIF LONG dimensions.
-
uint32_t max_added_entries = kMetadataGeometryTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataGeometryTranslationMaxOperations¶
-
uint32_t max_text_bytes_per_property = kMetadataGeometryTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataGeometryTranslationMaxTotalTextBytes¶
-
MetadataGeometryTranslationSourceMode source_mode = MetadataGeometryTranslationSourceMode::DirtyOnly¶
-
struct MetadataGeometryTranslationResult¶
- #include <metadata_translation.h>
Transactional result details for one reverse image-geometry translation.
Public Members
-
MetadataGeometryTranslationMapping failed_mapping = MetadataGeometryTranslationMapping::None¶
-
EntryId failed_source_entry = kInvalidEntryId¶
-
uint32_t source_properties = 0U¶
-
uint32_t groups_translated = 0U¶
-
uint32_t groups_preserved = 0U¶
-
uint32_t groups_unchanged = 0U¶
-
uint32_t entries_added = 0U¶
-
uint32_t entries_updated = 0U¶
-
uint32_t entries_removed = 0U¶
-
MetadataGeometryTranslationMapping failed_mapping = MetadataGeometryTranslationMapping::None¶
-
struct MetadataGpsDestinationTranslationOptions¶
- #include <metadata_translation.h>
Public Members
-
MetadataGpsTranslationConflictPolicy conflict_policy = MetadataGpsTranslationConflictPolicy::FailOnConflict¶
-
bool latitude_to_exif = true¶
-
bool longitude_to_exif = true¶
-
bool bearing_to_exif = true¶
-
bool distance_to_exif = true¶
-
uint32_t max_added_entries = kMetadataGpsDestinationTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataGpsTranslationMaxOperations¶
-
uint32_t max_text_bytes_per_property = kMetadataGpsTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataGpsDestinationTranslationMaxTotalTextBytes¶
-
MetadataGpsTranslationConflictPolicy conflict_policy = MetadataGpsTranslationConflictPolicy::FailOnConflict¶
- #include <metadata_translation.h>
Public Members
-
struct MetadataGpsQualityTranslationOptions¶
- #include <metadata_translation.h>
Public Members
-
MetadataGpsTranslationConflictPolicy conflict_policy = MetadataGpsTranslationConflictPolicy::FailOnConflict¶
-
bool status_to_exif = true¶
-
bool measure_mode_to_exif = true¶
-
bool dop_to_exif = true¶
-
bool differential_to_exif = true¶
-
bool horizontal_error_to_exif = true¶
-
uint32_t max_added_entries = kMetadataGpsQualityTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataGpsTranslationMaxOperations¶
-
uint32_t max_text_bytes_per_property = kMetadataGpsTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataGpsQualityTranslationMaxTotalTextBytes¶
-
MetadataGpsTranslationConflictPolicy conflict_policy = MetadataGpsTranslationConflictPolicy::FailOnConflict¶
-
struct MetadataGpsTextTranslationOptions¶
- #include <metadata_translation.h>
Public Members
-
MetadataGpsTranslationConflictPolicy conflict_policy = MetadataGpsTranslationConflictPolicy::FailOnConflict¶
-
bool satellites_to_exif = true¶
-
bool map_datum_to_exif = true¶
-
bool processing_method_to_exif = true¶
-
bool area_information_to_exif = true¶
-
uint32_t max_added_entries = kMetadataGpsTextTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataGpsTranslationMaxOperations¶
-
uint32_t max_text_bytes_per_property = kMetadataGpsTextTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataGpsTextTranslationMaxTotalTextBytes¶
-
MetadataGpsTranslationConflictPolicy conflict_policy = MetadataGpsTranslationConflictPolicy::FailOnConflict¶
-
struct MetadataGpsTranslationOptions¶
- #include <metadata_translation.h>
Public Members
-
MetadataGpsTranslationConflictPolicy conflict_policy = MetadataGpsTranslationConflictPolicy::FailOnConflict¶
-
bool latitude_to_exif = true¶
-
bool longitude_to_exif = true¶
-
bool altitude_to_exif = true¶
-
uint32_t max_added_entries = kMetadataGpsTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataGpsTranslationMaxOperations¶
-
uint32_t max_text_bytes_per_property = kMetadataGpsTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataGpsTranslationMaxTotalTextBytes¶
-
MetadataGpsTranslationConflictPolicy conflict_policy = MetadataGpsTranslationConflictPolicy::FailOnConflict¶
-
struct MetadataGpsTranslationResult¶
- #include <metadata_translation.h>
Public Members
-
MetadataGpsTranslationMapping failed_mapping = MetadataGpsTranslationMapping::None¶
-
EntryId failed_source_entry = kInvalidEntryId¶
-
uint32_t source_properties = 0U¶
-
uint32_t groups_translated = 0U¶
-
uint32_t groups_preserved = 0U¶
-
uint32_t groups_unchanged = 0U¶
-
uint32_t entries_added = 0U¶
-
uint32_t entries_updated = 0U¶
-
uint32_t entries_removed = 0U¶
-
MetadataGpsTranslationMapping failed_mapping = MetadataGpsTranslationMapping::None¶
-
struct MetadataIdentityTranslationOptions¶
- #include <metadata_translation.h>
Public Members
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
bool lens_specification_to_exif = true¶
-
bool image_unique_id_to_exif = true¶
-
uint32_t max_added_entries = kMetadataIdentityTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataCaptureTranslationMaxOperations¶
-
uint32_t max_text_bytes_per_property = kMetadataCaptureTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataIdentityTranslationMaxTotalTextBytes¶
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
struct MetadataImageEncodingTranslationOptions¶
- #include <metadata_translation.h>
Public Members
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
bool gamma_to_exif = true¶
-
bool compressed_bits_per_pixel_to_exif = true¶
-
bool components_configuration_to_exif = true¶
-
uint32_t max_added_entries = kMetadataImageEncodingTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataCaptureTranslationMaxOperations¶
-
uint32_t max_text_bytes_per_property = kMetadataCaptureTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataImageEncodingTranslationMaxTotalTextBytes¶
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
struct MetadataInterpretationRecord¶
- #include <metadata_interpretation.h>
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¶
-
uint8_t confidence = 0U¶
-
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¶
-
MetadataQueryKind query_kind = MetadataQueryKind::Crop¶
-
struct MetadataInterpretationResult¶
- #include <metadata_interpretation.h>
Public Members
-
std::vector<MetadataInterpretationRecord> records¶
-
std::vector<MetadataInterpretationRecord> records¶
-
struct MetadataIptcTranslationOptions¶
- #include <metadata_translation.h>
All supported IPTC text/priority mappings in one transaction.
Public Members
-
MetadataDescriptiveTranslationSourceMode source_mode = MetadataDescriptiveTranslationSourceMode::DirtyOnly¶
-
MetadataDescriptiveTranslationConflictPolicy conflict_policy = MetadataDescriptiveTranslationConflictPolicy::FailOnConflict¶
-
bool title_to_iptc_object_name = true¶
-
bool description_to_iptc_caption = true¶
-
bool creators_to_iptc_bylines = true¶
-
bool keywords_to_iptc_keywords = true¶
-
bool copyright_to_iptc_copyright = true¶
-
bool credit_to_iptc_credit = true¶
-
bool source_to_iptc_source = true¶
-
bool city_to_iptc = true¶
-
bool sublocation_to_iptc = true¶
-
bool state_to_iptc = true¶
-
bool country_to_iptc = true¶
-
bool country_code_to_iptc = true¶
-
bool headline_to_iptc = true¶
-
bool instructions_to_iptc = true¶
-
bool transmission_reference_to_iptc = true¶
-
bool authors_position_to_iptc = true¶
-
bool caption_writer_to_iptc = true¶
-
bool category_to_iptc = true¶
-
bool supplemental_categories_to_iptc = true¶
-
bool urgency_to_iptc = true¶
-
uint32_t max_source_properties = kMetadataDescriptiveTranslationMaxSourceProperties¶
-
uint32_t max_added_entries = kMetadataIptcTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataDescriptiveTranslationMaxOperations¶
-
uint64_t max_total_text_bytes = kMetadataDescriptiveTranslationMaxTotalTextBytes¶
-
MetadataDescriptiveTranslationSourceMode source_mode = MetadataDescriptiveTranslationSourceMode::DirtyOnly¶
-
struct MetadataLearningOptOutInTranslationOptions¶
- #include <metadata_translation.h>
Translate the EXIF 3.1 LearningOptOutIn XMP structure to tag 0x9287.
The source namespace is
http://cipa.jp/exif/1.0/and the exact source shape isLearningOptOutIn/NumberOfSetsplus the ordered scalar leavesLearningOptOutIn/Values[1]through[2*n]. Values are usage/intention pairs. The first usage value is zero, usage values are unique, and all values use the published bounded choices. Under FailOnConflict and ReplaceExisting, an exact valid singleton native value is promoted to Dirty by a same-value update that retains its bytes, wire hints, wire count, origin and endian flag. Dirty exact matches remain unchanged; PreserveExisting does not promote native values. A complete eligible deletion preserves active values under PreserveExisting, conflicts under FailOnConflict, and tombstones active values under ReplaceExisting. If no active native value exists, ReplaceExisting promotes a clean tombstone, reuses a dirty tombstone, or adds an empty Bytes value with TIFF type 7 as Dirty|Deleted intent. Promotions, tombstones and new intents consume max_operations; new intents also consume max_added_entries. Source masks, duplicates, limits and rollback follow the capture translation contract. Preparation may allocate; the commit is one transaction and hosts synchronize conflicting object access.Public Members
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
bool learning_opt_out_in_to_exif = true¶
-
uint32_t exif_version = 0U¶
Explicit host policy: 0 requires no selected source; use 300 or 310.
-
uint32_t max_sets = kMetadataLearningOptOutInTranslationMaxSets¶
-
uint32_t max_added_entries = kMetadataLearningOptOutInTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataCaptureTranslationMaxOperations¶
-
uint32_t max_text_bytes_per_property = kMetadataCaptureTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataCaptureTranslationMaxTotalTextBytes¶
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
struct MetadataLightSourceTranslationOptions¶
- #include <metadata_translation.h>
Public Members
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
uint32_t max_added_entries = kMetadataLightSourceTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataCaptureTranslationMaxOperations¶
-
uint32_t max_text_bytes_per_property = kMetadataCaptureTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataLightSourceTranslationMaxTotalTextBytes¶
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
struct MetadataLocationCreationTranslationOptions¶
- #include <metadata_translation.h>
Public Members
-
MetadataStructuredLocationKind location_kind = MetadataStructuredLocationKind::Unspecified¶
Both kind and index require explicit caller selection.
-
uint32_t location_index = 0U¶
-
MetadataDescriptiveTranslationSourceMode source_mode = MetadataDescriptiveTranslationSourceMode::DirtyOnly¶
-
MetadataDescriptiveTranslationConflictPolicy conflict_policy = MetadataDescriptiveTranslationConflictPolicy::FailOnConflict¶
-
bool city = true¶
-
bool sublocation = true¶
-
bool state = true¶
-
bool country = true¶
-
bool country_code = true¶
-
uint32_t max_source_properties = kMetadataDescriptiveTranslationMaxSourceProperties¶
-
uint32_t max_added_entries = kMetadataLocationCreationTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataDescriptiveTranslationMaxOperations¶
-
uint64_t max_total_text_bytes = kMetadataDescriptiveTranslationMaxTotalTextBytes¶
-
MetadataStructuredLocationKind location_kind = MetadataStructuredLocationKind::Unspecified¶
-
struct MetadataLocationTranslationOptions¶
- #include <metadata_translation.h>
Independent flat location mappings using the descriptive IPTC policies.
Public Members
-
MetadataDescriptiveTranslationSourceMode source_mode = MetadataDescriptiveTranslationSourceMode::DirtyOnly¶
-
MetadataDescriptiveTranslationConflictPolicy conflict_policy = MetadataDescriptiveTranslationConflictPolicy::FailOnConflict¶
-
bool city_to_iptc = true¶
-
bool sublocation_to_iptc = true¶
-
bool state_to_iptc = true¶
-
bool country_to_iptc = true¶
-
bool country_code_to_iptc = true¶
-
uint32_t max_source_properties = kMetadataDescriptiveTranslationMaxSourceProperties¶
-
uint32_t max_added_entries = kMetadataLocationTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataDescriptiveTranslationMaxOperations¶
-
uint64_t max_total_text_bytes = kMetadataDescriptiveTranslationMaxTotalTextBytes¶
-
MetadataDescriptiveTranslationSourceMode source_mode = MetadataDescriptiveTranslationSourceMode::DirtyOnly¶
-
struct MetadataPatchExifOptions¶
- #include <metadata_patch.h>
TIFF serialization policy; store validation is shared by both families.
Public Members
-
bool include_subifds = false¶
-
bool inject_minimal_dng_version = false¶
-
bool honor_wire_type_hints = true¶
-
ExifTiffMakerNotePolicy makernote_policy = ExifTiffMakerNotePolicy::Drop¶
-
uint64_t max_output_bytes = 64ULL * 1024ULL * 1024ULL¶
-
bool include_subifds = false¶
-
class MetadataPatchHandle¶
- #include <metadata_patch.h>
Opaque identity for one slot in one preparation generation.
Public Functions
-
constexpr MetadataPatchHandle() noexcept = default¶
-
inline bool valid() const noexcept¶
Private Members
-
uint64_t token_ = 0U¶
Friends
- friend struct MetadataPatchHandleAccess
-
constexpr MetadataPatchHandle() noexcept = default¶
-
struct MetadataPatchPlanOptions¶
- #include <metadata_patch.h>
Preparation may allocate. Only requested payload families are serialized.
Public Members
-
uint64_t plan_id = 0U¶
Host-issued identity in [1, kMaxMetadataPatchPlanId]. Never reuse an ID while a prior plan, worker or handle with that ID may still be used. The host coordinates ID assignment across its preparation callers.
-
XmpPortableOptions xmp¶
Portable XMP policy.
-
uint32_t max_patch_requests = 4096U¶
-
bool validate = true¶
-
uint64_t plan_id = 0U¶
-
struct MetadataPatchRequest¶
- #include <metadata_patch.h>
An EXIF key/occurrence with an exact native shape, or an XMP namespace URI and simple property path in the final portable serializer output. XMP occurrence must be zero; duplicates and structural paths are rejected. escaped_width is required for XMP and includes XML escaping, not a NUL. It must be zero for EXIF. Requests never add properties or pad values.
Public Members
-
MetaKeyView key¶
-
uint32_t occurrence = 0U¶
-
MetadataPatchValueSpec expected¶
-
uint32_t escaped_width = 0U¶
-
MetaKeyView key¶
-
struct MetadataPatchResult¶
- #include <metadata_patch.h>
Public Functions
-
inline bool ok() const noexcept¶
Public Members
-
MetadataPatchCode code = MetadataPatchCode::None¶
-
ExifTiffSerializeStatus serialize_status = ExifTiffSerializeStatus::Ok¶
-
XmpDumpStatus xmp_status = XmpDumpStatus::Ok¶
-
uint64_t payload_size = 0U¶
-
uint32_t handle_count = 0U¶
-
uint32_t patched_handles = 0U¶
-
uint32_t failed_index = 0xFFFFFFFFU¶
-
inline bool ok() const noexcept¶
-
struct MetadataPatchUpdate¶
- #include <metadata_patch.h>
Borrowed update. XMP accepts logical Text/Utf8 or Text/Ascii only.
-
struct MetadataPatchValueSpec¶
- #include <metadata_patch.h>
Exact native TIFF value shape. XMP requests use escaped_width instead.
Public Members
-
MetaValueKind kind = MetaValueKind::Scalar¶
-
MetaElementType elem_type = MetaElementType::U8¶
-
TextEncoding text_encoding = TextEncoding::Unknown¶
-
uint32_t count = 1U¶
-
MetaValueKind kind = MetaValueKind::Scalar¶
-
struct MetadataProfileTranslationOptions¶
- #include <metadata_translation.h>
Translate five exact profile authoring properties into native EXIF.
tiff:ImageDescription,tiff:Artist, andtiff:Copyrighttarget IFD0 tags 0x010e, 0x013b, and 0x8298.exif:ColorSpaceaccepts only 1 or 65535 and targets ExifIFD 0xa001.exif:RelatedSoundFileaccepts a printable ASCII 8.3 filename and targets ExifIFD 0xa004. No ICC, image dimensions, or audio-file association is inferred. A scalar Copyright source writes a single native part; an existing legacy two-part NUL value is preserved by PreserveExisting and conflicts under FailOnConflict. Preparation may allocate; the commit is one transaction and hosts synchronize shared-object access.Public Members
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
bool image_description_to_exif = true¶
-
bool artist_to_exif = true¶
-
bool copyright_to_exif = true¶
-
bool color_space_to_exif = true¶
-
uint32_t max_added_entries = kMetadataProfileTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataCaptureTranslationMaxOperations¶
-
uint32_t max_text_bytes_per_property = kMetadataProfileTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataProfileTranslationMaxTotalTextBytes¶
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
struct MetadataQueryCandidate¶
- #include <metadata_query.h>
Public Members
-
MetadataQueryValueShape normalized_shape = MetadataQueryValueShape::Unknown¶
-
uint8_t confidence = 0U¶
-
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¶
-
MetadataQueryValueShape normalized_shape = MetadataQueryValueShape::Unknown¶
-
struct MetadataQueryMatch¶
- #include <metadata_query.h>
Public Members
-
EntryId entry_id = kInvalidEntryId¶
-
MetaKeyKind key_kind = MetaKeyKind::ExifTag¶
-
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¶
-
EntryId entry_id = kInvalidEntryId¶
-
struct MetadataQueryResult¶
- #include <metadata_query.h>
Public Members
-
MetadataQueryKind kind = MetadataQueryKind::Crop¶
-
std::vector<MetadataQueryMatch> matches¶
-
std::vector<MetadataQueryCandidate> candidates¶
-
MetadataQueryKind kind = MetadataQueryKind::Crop¶
-
struct MetadataRawDataDescriptor¶
- #include <metadata_concepts.h>
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¶
-
MetadataRawDataEncoding encoding = MetadataRawDataEncoding::Unknown¶
-
struct MetadataSensitivityTranslationOptions¶
- #include <metadata_translation.h>
Public Members
-
MetadataCaptureTranslationSourceMode source_mode = MetadataCaptureTranslationSourceMode::DirtyOnly¶
DirtyOnly selects the group when any recognized member is Dirty; active clean companions participate once the group is selected.
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
uint32_t max_added_entries = kMetadataSensitivityTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataCaptureTranslationMaxOperations¶
-
uint32_t max_text_bytes_per_property = kMetadataCaptureTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataSensitivityTranslationMaxTotalTextBytes¶
-
MetadataCaptureTranslationSourceMode source_mode = MetadataCaptureTranslationSourceMode::DirtyOnly¶
-
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¶
-
struct MetadataStructuredCaptureTranslationOptions¶
- #include <metadata_translation.h>
Public Members
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
bool oecf_to_exif = true¶
-
bool spatial_frequency_response_to_exif = true¶
-
bool cfa_pattern_to_exif = true¶
-
bool device_setting_description_to_exif = true¶
-
uint32_t max_added_entries = kMetadataStructuredCaptureTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataCaptureTranslationMaxOperations¶
-
uint32_t max_columns = kMetadataStructuredCaptureTranslationMaxColumns¶
-
uint32_t max_values = kMetadataStructuredCaptureTranslationMaxValues¶
-
uint32_t max_text_bytes_per_property = kMetadataStructuredCaptureTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataStructuredCaptureTranslationMaxTotalTextBytes¶
-
uint32_t max_payload_bytes = kMetadataStructuredCaptureTranslationMaxPayloadBytes¶
-
MetadataCaptureTranslationConflictPolicy conflict_policy = MetadataCaptureTranslationConflictPolicy::FailOnConflict¶
-
struct MetadataStructuredLocationTranslationOptions¶
- #include <metadata_translation.h>
Public Members
-
MetadataStructuredLocationKind location_kind = MetadataStructuredLocationKind::Shown¶
-
uint32_t location_index = 0U¶
Zero requires a single record; positive values select an exact XMP index.
-
MetadataDescriptiveTranslationSourceMode source_mode = MetadataDescriptiveTranslationSourceMode::DirtyOnly¶
-
MetadataDescriptiveTranslationConflictPolicy conflict_policy = MetadataDescriptiveTranslationConflictPolicy::FailOnConflict¶
-
bool city = true¶
-
bool sublocation = true¶
-
bool state = true¶
-
bool country = true¶
-
bool country_code = true¶
-
uint32_t max_source_properties = kMetadataDescriptiveTranslationMaxSourceProperties¶
-
uint32_t max_added_entries = kMetadataStructuredLocationTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataDescriptiveTranslationMaxOperations¶
-
uint64_t max_total_text_bytes = kMetadataDescriptiveTranslationMaxTotalTextBytes¶
-
MetadataStructuredLocationKind location_kind = MetadataStructuredLocationKind::Shown¶
-
struct MetadataTechnicalTranslationOptions¶
- #include <metadata_translation.h>
Caller-selected bounded reverse technical mappings.
Public Members
-
MetadataTechnicalTranslationSourceMode source_mode = MetadataTechnicalTranslationSourceMode::DirtyOnly¶
-
MetadataTechnicalTranslationConflictPolicy conflict_policy = MetadataTechnicalTranslationConflictPolicy::FailOnConflict¶
-
bool modify_date_to_exif_datetime = true¶
xmp:ModifyDate -> IFD0 DateTime plus exact EXIF companions.
-
bool make_to_exif_make = true¶
tiff:Make -> IFD0 Make.
-
bool model_to_exif_model = true¶
tiff:Model -> IFD0 Model.
-
bool creator_tool_to_exif_software = true¶
xmp:CreatorTool -> IFD0 Software.
-
uint32_t max_added_entries = kMetadataTechnicalTranslationMaxAddedEntries¶
-
uint32_t max_operations = kMetadataTechnicalTranslationMaxOperations¶
-
uint32_t max_text_bytes_per_property = kMetadataTechnicalTranslationMaxTextBytesPerProperty¶
-
uint64_t max_total_text_bytes = kMetadataTechnicalTranslationMaxTotalTextBytes¶
-
MetadataTechnicalTranslationSourceMode source_mode = MetadataTechnicalTranslationSourceMode::DirtyOnly¶
-
struct MetadataTechnicalTranslationResult¶
- #include <metadata_translation.h>
Transactional result details for one reverse technical translation.
Public Members
-
MetadataTechnicalTranslationMapping failed_mapping = MetadataTechnicalTranslationMapping::None¶
-
EntryId failed_source_entry = kInvalidEntryId¶
-
uint32_t source_properties = 0U¶
-
uint32_t groups_translated = 0U¶
-
uint32_t groups_preserved = 0U¶
-
uint32_t groups_unchanged = 0U¶
-
uint32_t entries_added = 0U¶
-
uint32_t entries_updated = 0U¶
-
uint32_t entries_removed = 0U¶
-
MetadataTechnicalTranslationMapping failed_mapping = MetadataTechnicalTranslationMapping::None¶
-
struct MetadataTypedEditingOperation¶
- #include <metadata_editing.h>
Exact keys are matched without namespace aliasing or native translation. Set/Remove default to one unambiguous active entry. Remove also accepts kMetadataEditingAllOccurrences. Numeric occurrences follow request order.
Public Members
-
MetadataAuthoringEntry entry¶
-
uint32_t occurrence = kMetadataTypedEditingUniqueOccurrence¶
-
MetadataAuthoringEntry entry¶
-
struct MetadataTypedEditingOptions¶
- #include <metadata_editing.h>
Public Members
-
uint32_t max_operations = kMetadataTypedEditingMaxOperations¶
-
uint32_t max_entries = 200000U¶
-
uint32_t max_key_bytes = 4096U¶
-
uint64_t max_arena_bytes = 64ULL * 1024ULL * 1024ULL¶
-
uint64_t max_value_bytes = 64ULL * 1024ULL * 1024ULL¶
-
uint64_t max_request_bytes = 8ULL * 1024ULL * 1024ULL¶
-
MetadataValidationOptions validation¶
-
uint32_t max_operations = kMetadataTypedEditingMaxOperations¶
-
struct MetadataTypedEditingResult¶
- #include <metadata_editing.h>
Public Functions
-
inline bool ok() const noexcept¶
Public Members
-
uint32_t failed_operation_index = kInvalidMetadataEditingOperationIndex¶
-
EntryId failed_entry = kInvalidEntryId¶
-
MetadataValidationIssueCode validation_issue = MetadataValidationIssueCode::None¶
-
uint32_t operations_applied = 0U¶
-
uint32_t entries_added = 0U¶
-
uint32_t entries_updated = 0U¶
-
uint32_t entries_removed = 0U¶
-
inline bool ok() const noexcept¶
-
struct MetadataValidationContext¶
- #include <validate.h>
Optional destination/raw-image facts used for cross-entry validation.
-
struct MetadataValidationIssue¶
- #include <validate.h>
One fixed-field structured issue from detached validation.
Public Members
-
ValidateIssueSeverity severity = ValidateIssueSeverity::Warning¶
-
EntryId entry = kInvalidEntryId¶
-
MetaKeyKind key_kind = MetaKeyKind::ExifTag¶
-
uint16_t tag = 0U¶
-
ValidateIssueSeverity severity = ValidateIssueSeverity::Warning¶
-
struct MetadataValidationOptions¶
- #include <validate.h>
Policy and resource bounds for detached entry/store validation.
Public Members
-
bool validate_schema = true¶
-
bool validate_wire_hints = true¶
-
bool require_finalized = false¶
-
bool warnings_as_errors = false¶
-
uint32_t max_issues = 4096U¶
-
uint32_t max_key_bytes = 4096U¶
-
uint32_t max_entries = 200000U¶
-
uint64_t max_arena_bytes = 64ULL * 1024ULL * 1024ULL¶
-
uint64_t max_value_bytes = 64ULL * 1024ULL * 1024ULL¶
-
MetadataUnknownTagPolicy unknown_exif_tags = MetadataUnknownTagPolicy::Allow¶
-
MetadataValidationContext context¶
-
bool validate_schema = true¶
-
struct MetadataValidationResult¶
- #include <validate.h>
Detached entry/store validation result.
Public Functions
-
inline bool ok() const noexcept¶
Public Members
-
uint32_t entries_checked = 0U¶
-
uint32_t warning_count = 0U¶
-
uint32_t error_count = 0U¶
-
std::vector<MetadataValidationIssue> issues¶
-
inline bool ok() const noexcept¶
-
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.
-
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).
-
struct MetaKeyView¶
- #include <meta_key.h>
A borrowed metadata key view.
Intended for lookups and comparisons without allocating/copying strings.
-
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:
entries_in_block returns entries sorted by Origin::order_in_block.
find_all returns all matching entries (duplicates preserved).
Public Functions
-
MetaStore() = default¶
-
void reserve(uint32_t block_capacity, uint32_t entry_capacity, size_t arena_bytes)¶
Reserves build, lookup-index, and arena capacity during initialization. The call is ignored after finalization and does not change logical size.
-
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.
-
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¶
-
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¶
-
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(aByteSpaninto aByteArena). 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¶
-
struct MetaValueView¶
- #include <meta_value.h>
Borrowed typed metadata value used by authoring and host import APIs.
Scalars use scalar. Arrays, bytes, and text use payload; the caller retains ownership for the duration of the consuming call.
Public Members
-
MetaValueKind kind = MetaValueKind::Empty¶
-
MetaElementType elem_type = MetaElementType::U8¶
-
TextEncoding text_encoding = TextEncoding::Unknown¶
-
uint32_t count = 0U¶
-
std::span<const std::byte> payload¶
-
MetaValueKind kind = MetaValueKind::Empty¶
-
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:*.
-
inline OcioAdapterOptions() noexcept¶
-
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¶
-
ExportNameStyle style = ExportNameStyle::XmpPortable¶
-
struct OcioMetadataNode¶
- #include <ocio_adapter.h>
Minimal tree node similar to OCIO FormatMetadata composition.
-
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¶
-
uint64_t max_file_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¶
-
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¶
-
BlockId block = kInvalidBlockId¶
-
struct PayloadLimits¶
- #include <container_payload.h>
Resource limits applied during payload extraction to bound hostile inputs.
-
struct PayloadOptions¶
- #include <container_payload.h>
Options for payload extraction.
Public Members
-
bool decompress = true¶
If true, attempt to decompress payloads marked with BlockCompression.
-
PayloadLimits limits¶
-
bool decompress = true¶
-
struct PayloadRandomAccessResult¶
- #include <container_payload.h>
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.compressedwas too small. Zero means no stream was skipped for this reason.
-
inline bool complete() const noexcept¶
-
struct PayloadRandomAccessScratch¶
- #include <container_payload.h>
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¶
-
std::span<std::byte> read_window¶
-
struct PayloadResult¶
- #include <container_payload.h>
-
struct PersistPreparedTransferFileOptions¶
- #include <metadata_transfer.h>
Options for persist_prepared_transfer_file_result.
-
struct PersistPreparedTransferFileResult¶
- #include <metadata_transfer.h>
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¶
-
TransferStatus status = TransferStatus::Unsupported¶
-
struct PhaseOneRawGeometry¶
- #include <phaseone_geometry.h>
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¶
-
uint32_t sensor_width = 0¶
-
struct PhaseOneRawGeometryResult¶
- #include <phaseone_geometry.h>
Public Members
-
PhaseOneRawGeometry geometry¶
-
PhaseOneRawGeometry geometry¶
-
struct PhaseOneRawProcessingInfo¶
- #include <phaseone_geometry.h>
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¶
-
bool has_color_matrix1 = false¶
-
struct PhaseOneRawProcessingResult¶
- #include <phaseone_geometry.h>
-
struct PhotoshopIrb¶
- #include <meta_key.h>
Public Members
-
uint16_t resource_id = 0¶
-
uint16_t resource_id = 0¶
-
struct PhotoshopIrb¶
- #include <meta_key.h>
Public Members
-
uint16_t resource_id = 0¶
-
uint16_t resource_id = 0¶
-
struct PhotoshopIrbDecodeLimits¶
- #include <photoshop_irb_decode.h>
Resource limits applied during IRB decode to bound hostile inputs.
-
struct PhotoshopIrbDecodeOptions¶
- #include <photoshop_irb_decode.h>
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¶
-
bool decode_iptc_iim = true¶
-
struct PhotoshopIrbDecodeResult¶
- #include <photoshop_irb_decode.h>
-
struct PhotoshopIrbField¶
- #include <meta_key.h>
-
struct PhotoshopIrbField¶
- #include <meta_key.h>
-
struct PlanJpegEditOptions¶
- #include <metadata_transfer.h>
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¶
-
JpegEditMode mode = JpegEditMode::Auto¶
-
struct PlanTiffEditOptions¶
- #include <metadata_transfer.h>
Options for TIFF edit planning.
-
struct PngText¶
- #include <meta_key.h>
-
struct PngText¶
- #include <meta_key.h>
-
class PngTransferEmitter¶
- #include <metadata_transfer.h>
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¶
-
virtual ~PngTransferEmitter() = default¶
-
struct PreparedBmffEmitOp¶
- #include <metadata_transfer.h>
One precompiled ISO-BMFF metadata emit operation.
-
struct PreparedBmffEmitPlan¶
- #include <metadata_transfer.h>
Reusable precompiled ISO-BMFF metadata emit plan.
Public Members
-
uint32_t contract_version = kMetadataTransferContractVersion¶
-
std::vector<PreparedBmffEmitOp> ops¶
-
uint32_t contract_version = kMetadataTransferContractVersion¶
-
struct PreparedExrEmitOp¶
- #include <metadata_transfer.h>
One precompiled EXR emit operation (prepared block -> EXR attribute).
Public Members
-
uint32_t block_index = 0¶
-
uint32_t block_index = 0¶
-
struct PreparedExrEmitPlan¶
- #include <metadata_transfer.h>
Reusable precompiled EXR emit plan for a prepared transfer bundle.
Public Members
-
uint32_t contract_version = kMetadataTransferContractVersion¶
-
std::vector<PreparedExrEmitOp> ops¶
-
uint32_t contract_version = kMetadataTransferContractVersion¶
-
struct PreparedJp2EmitOp¶
- #include <metadata_transfer.h>
One precompiled JP2 emit operation (route -> JP2 box mapping).
-
struct PreparedJp2EmitPlan¶
- #include <metadata_transfer.h>
Reusable precompiled JP2 emit plan for a prepared transfer bundle.
Public Members
-
uint32_t contract_version = kMetadataTransferContractVersion¶
-
std::vector<PreparedJp2EmitOp> ops¶
-
uint32_t contract_version = kMetadataTransferContractVersion¶
-
struct PreparedJpegEmitOp¶
- #include <metadata_transfer.h>
One precompiled JPEG emit operation (route -> marker mapping).
-
struct PreparedJpegEmitPlan¶
- #include <metadata_transfer.h>
Reusable precompiled JPEG emit plan for a prepared transfer bundle.
Public Members
-
uint32_t contract_version = kMetadataTransferContractVersion¶
-
std::vector<PreparedJpegEmitOp> ops¶
-
uint32_t contract_version = kMetadataTransferContractVersion¶
-
struct PreparedJxlEmitOp¶
- #include <metadata_transfer.h>
One precompiled JPEG XL emit operation (route -> backend mapping).
-
struct PreparedJxlEmitPlan¶
- #include <metadata_transfer.h>
Reusable precompiled JPEG XL emit plan for a prepared transfer bundle.
Public Members
-
uint32_t contract_version = kMetadataTransferContractVersion¶
-
std::vector<PreparedJxlEmitOp> ops¶
-
uint32_t contract_version = kMetadataTransferContractVersion¶
-
struct PreparedJxlEncoderHandoff¶
- #include <metadata_transfer.h>
Owned JXL encoder-side handoff independent from bundle payload storage.
-
struct PreparedJxlEncoderHandoffIoResult¶
- #include <metadata_transfer.h>
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¶
-
TransferStatus status = TransferStatus::Unsupported¶
-
struct PreparedJxlEncoderHandoffView¶
- #include <metadata_transfer.h>
Encoder-side handoff view for prepared JPEG XL metadata.
-
class PreparedMetadataPatchInstance¶
- #include <metadata_patch.h>
Independently owned worker payloads. Creation may allocate and the worker survives destruction of its plan. Patch success/failure, payload access and library replay allocate nothing. Payload addresses and lengths remain stable until reset, replacement or destruction. The host must synchronize all conflicting access, including reads through payload views and destruction. The patch API uses no atomics, mutexes or global mutable state. It does not detect concurrent misuse. Independent instances own independent writable data.
Public Functions
-
PreparedMetadataPatchInstance() noexcept¶
-
~PreparedMetadataPatchInstance() noexcept¶
-
PreparedMetadataPatchInstance(PreparedMetadataPatchInstance &&other) noexcept¶
-
PreparedMetadataPatchInstance &operator=(PreparedMetadataPatchInstance &&other) noexcept¶
-
PreparedMetadataPatchInstance(const PreparedMetadataPatchInstance&) = delete¶
-
PreparedMetadataPatchInstance &operator=(const PreparedMetadataPatchInstance&) = delete¶
-
bool valid() const noexcept¶
-
uint32_t handle_count() const noexcept¶
-
std::span<const std::byte> payload(MetadataPatchPayload family) const noexcept¶
-
void reset() noexcept¶
Private Members
-
void *state_ = nullptr¶
Friends
-
friend MetadataPatchResult create_prepared_metadata_patch_instance(const PreparedMetadataPatchPlan&, PreparedMetadataPatchInstance*) noexcept¶
Creates a worker without modifying the plan or existing output on failure.
-
friend MetadataPatchResult patch_prepared_metadata_instance(PreparedMetadataPatchInstance*, std::span<const MetadataPatchUpdate>) noexcept¶
Validate the complete batch before writing either payload. All errors leave every payload byte unchanged. XMP validation includes UTF-8, XML characters, and the exact escaped width. Input payloads may not alias either destination. Input views and values must remain immutable for the duration of this call.
-
PreparedMetadataPatchInstance() noexcept¶
-
class PreparedMetadataPatchPlan¶
- #include <metadata_patch.h>
Move-only owner of immutable payloads and compiled patch slots.
Public Functions
-
PreparedMetadataPatchPlan() noexcept¶
-
~PreparedMetadataPatchPlan() noexcept¶
-
PreparedMetadataPatchPlan(PreparedMetadataPatchPlan &&other) noexcept¶
-
PreparedMetadataPatchPlan &operator=(PreparedMetadataPatchPlan &&other) noexcept¶
-
PreparedMetadataPatchPlan(const PreparedMetadataPatchPlan&) = delete¶
-
PreparedMetadataPatchPlan &operator=(const PreparedMetadataPatchPlan&) = delete¶
-
bool valid() const noexcept¶
-
uint32_t handle_count() const noexcept¶
-
std::span<const std::byte> payload(MetadataPatchPayload family) const noexcept¶
-
void reset() noexcept¶
Private Members
-
void *state_ = nullptr¶
Friends
-
friend MetadataPatchResult prepare_metadata_patch_plan(const MetaStore&, std::span<const MetadataPatchRequest>, const MetadataPatchPlanOptions&, std::span<MetadataPatchHandle>, PreparedMetadataPatchPlan*) noexcept¶
The host supplies a fresh options.plan_id for each successful preparation. On failure both the output plan and every output handle remain unchanged.
-
friend MetadataPatchResult create_prepared_metadata_patch_instance(const PreparedMetadataPatchPlan&, PreparedMetadataPatchInstance*) noexcept¶
Creates a worker without modifying the plan or existing output on failure.
-
PreparedMetadataPatchPlan() noexcept¶
-
struct PreparedPngEmitOp¶
- #include <metadata_transfer.h>
One precompiled PNG emit operation (route -> PNG chunk mapping).
-
struct PreparedPngEmitPlan¶
- #include <metadata_transfer.h>
Reusable precompiled PNG emit plan for a prepared transfer bundle.
Public Members
-
uint32_t contract_version = kMetadataTransferContractVersion¶
-
std::vector<PreparedPngEmitOp> ops¶
-
uint32_t contract_version = kMetadataTransferContractVersion¶
-
struct PreparedTiffEmitOp¶
- #include <metadata_transfer.h>
One precompiled TIFF emit operation (route -> TIFF tag mapping).
-
struct PreparedTiffEmitPlan¶
- #include <metadata_transfer.h>
Reusable precompiled TIFF emit plan for a prepared transfer bundle.
Public Members
-
uint32_t contract_version = kMetadataTransferContractVersion¶
-
std::vector<PreparedTiffEmitOp> ops¶
-
uint32_t contract_version = kMetadataTransferContractVersion¶
-
struct PreparedTransferAdapterOp¶
- #include <metadata_transfer.h>
One compiled adapter-facing operation derived from a prepared bundle.
Public Members
-
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¶
-
uint32_t block_index = 0U¶
-
struct PreparedTransferAdapterView¶
- #include <metadata_transfer.h>
One target-neutral adapter view over prepared transfer operations.
Public Members
-
uint32_t contract_version = kPreparedTransferAdapterContractVersion¶
-
TransferTargetFormat target_format = TransferTargetFormat::Jpeg¶
-
EmitTransferOptions emit¶
-
std::vector<PreparedTransferAdapterOp> ops¶
-
uint32_t contract_version = kPreparedTransferAdapterContractVersion¶
-
struct PreparedTransferArtifactInfo¶
- #include <metadata_transfer.h>
Common summary for one persisted transfer artifact.
Public Members
-
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¶
-
bool has_contract_version = false¶
-
struct PreparedTransferArtifactIoResult¶
- #include <metadata_transfer.h>
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¶
-
TransferStatus status = TransferStatus::Unsupported¶
-
struct PreparedTransferBlock¶
- #include <metadata_transfer.h>
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.
-
TransferBlockKind kind = TransferBlockKind::Other¶
-
struct PreparedTransferBundle¶
- #include <metadata_transfer.h>
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<uint16_t> tiff_ifd0_removals¶
Sorted native TIFF IFD0 tags to remove during TIFF/DNG editing. Preparation emits only ImageDescription (0x010E), Make (0x010F), Model (0x0110), Software (0x0131), DateTime (0x0132), Artist (0x013B), and Copyright (0x8298), from dirty native tombstones with EXIF output enabled. TIFF edit APIs consume this list. Fresh TIFF emit, adapter, payload, and codec handoff APIs reject non-empty lists because their operation schemas cannot represent deletion. Keep this list empty for other consumers. Source snapshots retain the tombstone flags used to derive this list during preparation.
-
std::vector<uint16_t> tiff_exif_removals¶
Sorted allowlisted native EXIF IFD tags to remove during TIFF/DNG editing: ExposureTime (0x829A), FNumber (0x829D), PhotographicSensitivity (0x8827), ISO speed companions (0x8830-0x8835), DateTimeOriginal (0x9003), DateTimeDigitized (0x9004), OffsetTime tags (0x9010-0x9012), APEX fields (0x9201-0x9205), Flash (0x9209), FocalLength (0x920A), SubSecTime tags (0x9290-0x9292), LensMake/LensModel/LensSerialNumber (0xA433-0xA435), and closed capture settings: ExposureProgram (0x8822), MeteringMode (0x9207), SensingMethod (0xA217), CustomRendered (0xA401), ExposureMode (0xA402), WhiteBalance (0xA403), SceneCaptureType (0xA406), GainControl (0xA407), Contrast (0xA408), Saturation (0xA409), Sharpness (0xA40A), and SubjectDistanceRange (0xA40C); spatial fields SubjectArea (0x9214), FocalPlaneXResolution/FocalPlaneYResolution (0xA20E/0xA20F), FocalPlaneResolutionUnit (0xA210), and SubjectLocation (0xA214); rational fields SubjectDistance (0x9206), DigitalZoomRatio (0xA404), ExposureIndex (0xA215), FlashEnergy (0xA20B), LensSpecification (0xA432), and ImageUniqueID (0xA420); additional capture fields FocalLengthIn35mmFilm (0xA405), FileSource (0xA300), SceneType (0xA301); and environment fields Temperature, Humidity, Pressure, WaterDepth, Acceleration and CameraElevationAngle (0x9400-0x9405); composite/structured fields (0xA460-0xA462, 0x8828, 0xA20C, 0xA302, 0xA40B); and EXIF text/version fields ExifVersion (0x9000), FlashpixVersion (0xA000), UserComment (0x9286), CameraOwnerName (0xA430), and EXIF 3 text (0xA436-0xA43C). Explicit per-tag removals preserve unspecified destination ExifIFD entries. Fresh emit, adapter, payload, and codec handoff APIs reject non-empty removal lists because their operation schemas cannot express deletion. Source snapshots retain the tombstone flags used to derive this list during preparation.
-
bool tiff_merge_existing_exif = false¶
Preserve unspecified destination ExifIFD entries when applying dirty allowlisted native timestamp, capture, APEX, setting, lens, spatial or environment, composite, structured or EXIF text/version edits to TIFF/DNG. This mode is opt-in and defaults to whole-ExifIFD replacement behavior.
-
std::vector<uint16_t> tiff_gps_removals¶
Sorted native GPS IFD tags 1..31 to remove during TIFF/DNG editing. GPSVersionID (tag 0) is structural and is never removed directly. A nonempty list implies destination merge, even when tiff_merge_existing_gps is false. The edit preserves other destination GPS values. Fresh emit and non-edit consumers reject GPS removals.
-
bool tiff_merge_existing_gps = false¶
Preserve unspecified destination GPS IFD entries when applying dirty supported GPS edits to TIFF/DNG. GPS removals imply this behavior even when this flag is false. Fresh emit may use a merge-only bundle, but adapter views reject it because they cannot express destination state. With no merge intent, GPS payloads retain whole-IFD replacement behavior.
-
std::vector<TimePatchSlot> time_patch_map¶
-
std::vector<std::byte> generated_xmp_sidecar¶
-
uint32_t contract_version = kMetadataTransferContractVersion¶
-
struct PreparedTransferC2paHandoffPackage¶
- #include <metadata_transfer.h>
Structured external-signer handoff package for one prepared rewrite.
Public Members
-
PreparedTransferC2paSignRequest request¶
-
BuildPreparedC2paBindingResult binding¶
-
std::vector<std::byte> binding_bytes¶
-
PreparedTransferC2paSignRequest request¶
-
struct PreparedTransferC2paPackageIoResult¶
- #include <metadata_transfer.h>
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¶
-
TransferStatus status = TransferStatus::Unsupported¶
-
struct PreparedTransferC2paRewriteChunk¶
- #include <metadata_transfer.h>
One deterministic chunk in the rewrite-without-C2PA byte stream.
-
struct PreparedTransferC2paRewriteRequirements¶
- #include <metadata_transfer.h>
Future-facing signer prerequisites for C2PA rewrite.
Public Members
-
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¶
-
TransferTargetFormat target_format = TransferTargetFormat::Jpeg¶
-
struct PreparedTransferC2paSignedPackage¶
- #include <metadata_transfer.h>
Persistable external-signer result package for one prepared rewrite.
Public Members
-
PreparedTransferC2paSignRequest request¶
-
PreparedTransferC2paSignerInput signer_input¶
-
PreparedTransferC2paSignRequest request¶
-
struct PreparedTransferC2paSignerInput¶
- #include <metadata_transfer.h>
External signer material returned for one prepared C2PA rewrite request.
-
struct PreparedTransferC2paSignRequest¶
- #include <metadata_transfer.h>
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¶
-
TransferStatus status = TransferStatus::Unsupported¶
-
struct PreparedTransferExecutionPlan¶
- #include <metadata_transfer.h>
Reusable compiled execution plan for high-throughput transfer workflows.
Public Members
-
uint32_t contract_version = kMetadataTransferContractVersion¶
-
TransferTargetFormat target_format = TransferTargetFormat::Jpeg¶
-
EmitTransferOptions emit¶
-
PreparedJpegEmitPlan jpeg_emit¶
-
PreparedTiffEmitPlan tiff_emit¶
-
PreparedJxlEmitPlan jxl_emit¶
-
PreparedWebpEmitPlan webp_emit¶
-
PreparedPngEmitPlan png_emit¶
-
PreparedJp2EmitPlan jp2_emit¶
-
PreparedExrEmitPlan exr_emit¶
-
PreparedBmffEmitPlan bmff_emit¶
-
uint32_t contract_version = kMetadataTransferContractVersion¶
-
class PreparedTransferHandoff¶
- #include <prepared_transfer_handoff.h>
Move-only owner of immutable target-specific metadata and operations.
The public object has a fixed opaque-pointer layout. Preparation performs all allocation and route compilation. Indexed access and replay borrow immutable storage and perform no allocation. Concurrent const access is supported when each replay uses independent caller state; reset, move, destruction, or preparation require exclusive ownership.
Public Functions
-
PreparedTransferHandoff() noexcept¶
-
~PreparedTransferHandoff() noexcept¶
-
PreparedTransferHandoff(PreparedTransferHandoff &&other) noexcept¶
-
PreparedTransferHandoff &operator=(PreparedTransferHandoff &&other) noexcept¶
-
PreparedTransferHandoff(const PreparedTransferHandoff&) = delete¶
-
PreparedTransferHandoff &operator=(const PreparedTransferHandoff&) = delete¶
-
bool valid() const noexcept¶
-
TransferTargetFormat target_format() const noexcept¶
-
uint32_t operation_count() const noexcept¶
-
void reset() noexcept¶
Private Members
-
void *state_ = nullptr¶
Friends
-
friend PreparedTransferHandoffResult prepare_transfer_handoff(const TransferSourceSnapshot&, const PrepareTransferRequest&, const EmitTransferOptions&, PreparedTransferHandoff*) noexcept¶
Prepare immutable target payloads and typed operations once.
On failure,
out_handoffis unchanged. Stable v1 deliberately rejects opt-in raw-carrier passthrough because that policy remains experimental.
-
friend PreparedTransferHandoffResult prepared_transfer_handoff_operation(const PreparedTransferHandoff&, uint32_t, PreparedTransferHandoffOperationView*) noexcept¶
Resolve one operation without allocation or route parsing by the host.
-
friend PreparedTransferHandoffResult create_prepared_transfer_handoff_instance(const PreparedTransferHandoff&, PreparedTransferHandoffInstance*) noexcept¶
Clone one independently owned mutable worker instance.
Creation may allocate. On failure,
out_instanceis unchanged. The new instance does not borrow the source handoff and remains valid after the source is reset, moved, prepared again, or destroyed.
-
PreparedTransferHandoff() noexcept¶
-
class PreparedTransferHandoffInstance¶
- #include <prepared_transfer_handoff.h>
Move-only mutable worker instance cloned from an immutable handoff.
Creation allocates and copies compact payload/operation state. Fixed-width patching, indexed access, and replay perform no allocation. One instance requires exclusive ownership while patching; independent instances may be patched and replayed concurrently and do not borrow their source template.
Public Functions
-
PreparedTransferHandoffInstance() noexcept¶
-
~PreparedTransferHandoffInstance() noexcept¶
-
PreparedTransferHandoffInstance(PreparedTransferHandoffInstance &&other) noexcept¶
-
PreparedTransferHandoffInstance &operator=(PreparedTransferHandoffInstance &&other) noexcept¶
-
PreparedTransferHandoffInstance(const PreparedTransferHandoffInstance&) = delete¶
-
PreparedTransferHandoffInstance &operator=(const PreparedTransferHandoffInstance&) = delete¶
-
bool valid() const noexcept¶
-
TransferTargetFormat target_format() const noexcept¶
-
uint32_t operation_count() const noexcept¶
-
uint32_t time_patch_slot_count(TimePatchField field) const noexcept¶
-
void reset() noexcept¶
Private Members
-
void *state_ = nullptr¶
Friends
-
friend PreparedTransferHandoffResult create_prepared_transfer_handoff_instance(const PreparedTransferHandoff&, PreparedTransferHandoffInstance*) noexcept¶
Clone one independently owned mutable worker instance.
Creation may allocate. On failure,
out_instanceis unchanged. The new instance does not borrow the source handoff and remains valid after the source is reset, moved, prepared again, or destroyed.
-
friend PreparedTransferHandoffPatchResult patch_prepared_transfer_handoff_instance(PreparedTransferHandoffInstance*, std::span<const TimePatchView>) noexcept¶
Apply one strict fixed-width patch batch transactionally.
Every field must be valid, unique, and have at least one prepared slot. Every value must exactly match every corresponding slot width and must not alias instance payload storage. Validation completes before any payload byte changes. Successful and failed calls perform no allocation.
-
friend PreparedTransferHandoffPatchResult prepared_transfer_handoff_instance_time_patch_field(const PreparedTransferHandoffInstance&, TimePatchField, PreparedTransferHandoffTimePatchFieldView*) noexcept¶
Query the exact serialized width and slot count for one field.
The query performs no allocation and exposes no payload offsets. It fails if the field is absent or its prepared slots do not have one uniform nonzero width, because one strict patch value could not update such a layout.
-
friend PreparedTransferHandoffResult prepared_transfer_handoff_instance_operation(const PreparedTransferHandoffInstance&, uint32_t, PreparedTransferHandoffOperationView*) noexcept¶
Resolve one mutable-instance operation without allocation.
-
PreparedTransferHandoffInstance() noexcept¶
-
struct PreparedTransferHandoffOperationView¶
- #include <prepared_transfer_handoff.h>
One borrowed typed operation from a prepared handoff.
payloadis the prepared carrier payload for all non-EXR operations. ForExrAttribute, useexr_name,exr_type_name, andexr_value;payloadremains available only for diagnostics. Views borrow either handoff or instance storage. They remain valid until that owner is reset, moved from, destroyed, or prepared again; mutable-instance payload contents may change after a successful patch.Public Members
-
TransferSemanticKind semantic_kind = TransferSemanticKind::Unknown¶
-
PreparedTransferAdapterOp operation¶
-
std::span<const std::byte> payload¶
-
std::string_view exr_name¶
-
std::string_view exr_type_name¶
-
std::span<const std::byte> exr_value¶
-
bool exr_is_opaque = false¶
-
TransferSemanticKind semantic_kind = TransferSemanticKind::Unknown¶
-
struct PreparedTransferHandoffPatchResult¶
- #include <prepared_transfer_handoff.h>
Allocation-free result for one transactional instance patch batch.
Public Functions
-
inline bool ok() const noexcept¶
Public Members
-
TransferStatus status = TransferStatus::Ok¶
-
uint32_t patched_slots = 0U¶
-
uint32_t failed_update_index = 0xFFFFFFFFU¶
-
uint32_t failed_slot_index = 0xFFFFFFFFU¶
-
uint32_t errors = 0U¶
-
inline bool ok() const noexcept¶
-
struct PreparedTransferHandoffResult¶
- #include <prepared_transfer_handoff.h>
Stable result for preparation, operation access, and replay.
Public Functions
-
inline bool ok() const noexcept¶
Public Members
-
TransferStatus status = TransferStatus::Ok¶
-
PrepareTransferCode prepare_code = PrepareTransferCode::None¶
-
EmitTransferCode adapter_code = EmitTransferCode::None¶
-
uint32_t operation_count = 0U¶
-
uint32_t warnings = 0U¶
-
uint32_t errors = 0U¶
-
uint32_t failed_operation_index = 0xFFFFFFFFU¶
-
inline bool ok() const noexcept¶
-
struct PreparedTransferHandoffTimePatchFieldView¶
- #include <prepared_transfer_handoff.h>
Stable description of one patchable field in a worker instance.
Public Members
-
TimePatchField field = TimePatchField::DateTime¶
-
uint16_t width = 0U¶
-
uint32_t slot_count = 0U¶
-
TimePatchField field = TimePatchField::DateTime¶
-
struct PreparedTransferPackageBatch¶
- #include <metadata_transfer.h>
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¶
-
uint32_t contract_version = kMetadataTransferContractVersion¶
-
struct PreparedTransferPackageBlob¶
- #include <metadata_transfer.h>
One owned output chunk materialized from a package plan.
-
struct PreparedTransferPackageChunk¶
- #include <metadata_transfer.h>
One deterministic output chunk for a packaged transfer write.
-
struct PreparedTransferPackageIoResult¶
- #include <metadata_transfer.h>
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¶
-
TransferStatus status = TransferStatus::Unsupported¶
-
struct PreparedTransferPackagePlan¶
- #include <metadata_transfer.h>
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¶
-
uint32_t contract_version = kMetadataTransferContractVersion¶
-
struct PreparedTransferPackageReplayCallbacks¶
- #include <metadata_transfer.h>
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¶
-
TransferStatus (*begin_batch)(void *user, TransferTargetFormat target_format, uint32_t chunk_count) noexcept = nullptr¶
-
struct PreparedTransferPackageReplayResult¶
- #include <metadata_transfer.h>
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¶
-
TransferStatus status = TransferStatus::Ok¶
-
struct PreparedTransferPackageView¶
- #include <metadata_transfer.h>
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¶
-
TransferSemanticKind semantic_kind = TransferSemanticKind::Unknown¶
-
struct PreparedTransferPayload¶
- #include <metadata_transfer.h>
One owned semantic payload copied from a prepared transfer bundle.
Public Members
-
TransferSemanticKind semantic_kind = TransferSemanticKind::Unknown¶
-
std::string semantic_name¶
-
std::string route¶
-
std::vector<std::byte> payload¶
-
TransferSemanticKind semantic_kind = TransferSemanticKind::Unknown¶
-
struct PreparedTransferPayloadBatch¶
- #include <metadata_transfer.h>
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¶
-
uint32_t contract_version = kMetadataTransferContractVersion¶
-
struct PreparedTransferPayloadIoResult¶
- #include <metadata_transfer.h>
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¶
-
TransferStatus status = TransferStatus::Unsupported¶
-
struct PreparedTransferPayloadReplayCallbacks¶
- #include <metadata_transfer.h>
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¶
-
TransferStatus (*begin_batch)(void *user, TransferTargetFormat target_format, uint32_t payload_count) noexcept = nullptr¶
-
struct PreparedTransferPayloadReplayResult¶
- #include <metadata_transfer.h>
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¶
-
TransferStatus status = TransferStatus::Ok¶
-
struct PreparedTransferPayloadView¶
- #include <metadata_transfer.h>
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¶
-
std::span<const std::byte> payload¶
-
TransferSemanticKind semantic_kind = TransferSemanticKind::Unknown¶
-
struct PreparedTransferPolicyDecision¶
- #include <metadata_transfer.h>
Effective policy decision captured during bundle preparation.
Public Members
-
TransferPolicySubject subject = TransferPolicySubject::MakerNote¶
-
TransferPolicyAction requested = TransferPolicyAction::Keep¶
-
TransferPolicyAction effective = TransferPolicyAction::Keep¶
-
TransferPolicyReason reason = TransferPolicyReason::Default¶
-
TransferC2paMode c2pa_mode = TransferC2paMode::NotApplicable¶
-
TransferC2paSourceKind c2pa_source_kind = TransferC2paSourceKind::NotApplicable¶
-
TransferC2paPreparedOutput c2pa_prepared_output = TransferC2paPreparedOutput::NotApplicable¶
-
uint32_t matched_entries = 0¶
-
std::string message¶
-
TransferPolicySubject subject = TransferPolicySubject::MakerNote¶
-
struct PreparedWebpEmitOp¶
- #include <metadata_transfer.h>
One precompiled WebP emit operation (route -> RIFF chunk mapping).
-
struct PreparedWebpEmitPlan¶
- #include <metadata_transfer.h>
Reusable precompiled WebP emit plan for a prepared transfer bundle.
Public Members
-
uint32_t contract_version = kMetadataTransferContractVersion¶
-
std::vector<PreparedWebpEmitOp> ops¶
-
uint32_t contract_version = kMetadataTransferContractVersion¶
-
struct PrepareTransferFileOptions¶
- #include <metadata_transfer.h>
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¶
-
bool include_pointer_tags = true¶
-
struct PrepareTransferFileResult¶
- #include <metadata_transfer.h>
High-level file read/prepare result.
Public Members
-
TransferFileStatus file_status = TransferFileStatus::Ok¶
-
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¶
-
TransferFileStatus file_status = TransferFileStatus::Ok¶
-
struct PrepareTransferRequest¶
- #include <metadata_transfer.h>
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. Recognized RAW curves and linearity entries are also dropped when the descriptor’s compression or primary-plane requirements rule them out. Unknown or incomplete context retains conditional candidates.
-
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¶
-
TransferTargetFormat target_format = TransferTargetFormat::Jpeg¶
-
struct PrepareTransferResult¶
- #include <metadata_transfer.h>
Result details for preparation.
Public Members
-
TransferStatus status = TransferStatus::Ok¶
-
uint32_t warnings = 0¶
-
uint32_t errors = 0¶
-
std::string message¶
-
TransferStatus status = TransferStatus::Ok¶
-
struct PreviewCandidate¶
- #include <preview_extract.h>
Preview candidate discovered in a container.
Public Members
-
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¶
-
ContainerFormat format = ContainerFormat::Unknown¶
-
struct PreviewExtractOptions¶
- #include <preview_extract.h>
Options for preview extraction.
-
struct PreviewExtractResult¶
- #include <preview_extract.h>
Result for preview extraction.
Public Members
-
PreviewExtractStatus status = PreviewExtractStatus::Ok¶
-
uint64_t written = 0¶
-
uint64_t needed = 0¶
-
PreviewExtractStatus status = PreviewExtractStatus::Ok¶
-
struct PreviewScanLimits¶
- #include <preview_extract.h>
Limits for preview candidate discovery.
-
struct PreviewScanOptions¶
- #include <preview_extract.h>
Options for preview candidate discovery.
-
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¶
-
PreviewScanStatus status = PreviewScanStatus::Ok¶
-
struct PrintImDecodeLimits¶
- #include <printim_decode.h>
Resource limits for decoding a PrintIM block.
-
struct PrintImDecodeResult¶
- #include <printim_decode.h>
PrintIM decode result summary.
Public Members
-
uint32_t entries_decoded = 0¶
-
uint32_t entries_decoded = 0¶
-
struct PrintImField¶
- #include <meta_key.h>
-
struct PrintImField¶
- #include <meta_key.h>
Public Members
-
std::string_view field¶
-
std::string_view field¶
-
struct RandomAccessIoResult¶
- #include <random_access_source.h>
Result returned by a host-provided positional read callback.
-
struct RandomAccessReadLimits¶
- #include <random_access_source.h>
Per-operation source-I/O ceilings. A zero ceiling means unlimited.
-
struct RandomAccessReadState¶
- #include <random_access_source.h>
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
-
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¶
-
inline bool ok() const noexcept¶
-
struct RandomAccessReadWindow¶
- #include <random_access_source.h>
Caller-owned cache storage for bounded source views.
storageis 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¶
-
inline void reset() noexcept¶
-
struct RandomAccessReadWindowOptions¶
- #include <random_access_source.h>
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.
-
uint64_t minimum_read_bytes = 4096U¶
-
struct RandomAccessSource¶
- #include <random_access_source.h>
Borrowed immutable random-access byte source.
Exactly one backing is used for a non-empty source:
contiguous_dataorread_at. OpenMeta does not own either backing or the callback context.concurrent_readsis descriptive; callers may share a source between independent OpenMeta operations only when it is true and the backing remains immutable for the complete operation.
-
struct RandomAccessSourceRange¶
- #include <random_access_source.h>
Borrowed subrange of one random-access source.
-
struct RandomAccessViewResult¶
- #include <random_access_source.h>
Borrowed view returned by random_access_read_view.
Public Functions
-
inline bool ok() const noexcept¶
-
inline bool ok() const noexcept¶
-
struct ReadTransferSourceDiagnostic¶
- #include <metadata_transfer.h>
One stable v1 allocation-free positional read diagnostic.
Public Members
-
ContainerFormat format = ContainerFormat::Unknown¶
-
uint64_t offset = 0U¶
-
uint64_t required_bytes = 0U¶
-
uint32_t count = 0U¶
-
uint16_t tag = 0U¶
-
RandomAccessReadCode input_code = RandomAccessReadCode::Ok¶
-
ContainerFormat format = ContainerFormat::Unknown¶
-
struct ReadTransferSourceDiagnosticOptions¶
- #include <metadata_transfer.h>
Stable v1 optional lanes used to classify positional read residuals.
-
struct ReadTransferSourceDiagnosticsResult¶
- #include <metadata_transfer.h>
Stable v1 caller-buffer result for positional read diagnostics.
Public Functions
-
inline bool complete() const noexcept¶
-
inline bool complete() const noexcept¶
-
struct ReadTransferSourceSnapshotBytesResult¶
- #include <metadata_transfer.h>
High-level in-memory read result for read_transfer_source_snapshot_bytes.
- API Stability
Experimental host-facing API.
Public Members
-
TransferStatus status = TransferStatus::Ok¶
-
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¶
- #include <metadata_transfer.h>
File-read + decode options for read_transfer_source_snapshot_file.
- API Stability
Experimental host-facing API.
-
struct ReadTransferSourceSnapshotFileResult¶
- #include <metadata_transfer.h>
High-level file read result for read_transfer_source_snapshot_file.
- API Stability
Experimental host-facing API.
Public Members
-
TransferFileStatus file_status = TransferFileStatus::Ok¶
-
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¶
- #include <metadata_transfer.h>
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¶
-
bool include_pointer_tags = true¶
-
struct ReadTransferSourceSnapshotRandomAccessResult¶
- #include <metadata_transfer.h>
Stable v1 result of bounded positional source snapshot assembly.
Public Functions
-
inline bool complete() const noexcept¶
Public Members
-
TransferStatus status = TransferStatus::Ok¶
-
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¶
-
inline bool complete() const noexcept¶
-
struct ReadTransferSourceSnapshotRandomAccessScratch¶
- #include <metadata_transfer.h>
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¶
-
std::span<ContainerBlockRef> blocks¶
-
struct ScanResult¶
- #include <container_scan.h>
-
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¶
-
JumbfDecodeOptions jumbf¶
-
PhotoshopIrbDecodeOptions photoshop_irb¶
-
uint32_t max_total_entries = 200000U¶
-
struct SimpleMetaResult¶
- #include <simple_meta.h>
Public Members
-
ScanResult scan¶
-
PayloadResult payload¶
-
ExrDecodeResult exr¶
-
ExifDecodeResult exif¶
-
JumbfDecodeResult jumbf¶
-
XmpDecodeResult xmp¶
-
ScanResult scan¶
-
class SpanTransferByteWriter : public openmeta::TransferByteWriter¶
- #include <metadata_transfer.h>
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¶
-
inline explicit SpanTransferByteWriter(std::span<std::byte> buffer) noexcept¶
-
struct SRational¶
- #include <meta_value.h>
Signed rational (numerator/denominator), typically used by EXIF/TIFF.
-
struct TiffEditPlan¶
- #include <metadata_transfer.h>
Planned TIFF edit summary (draft API). Keep the input and bundle unchanged until application; replan after edits. This summary does not bind or verify the exact identity of every update.
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¶
-
TransferStatus status = TransferStatus::Ok¶
-
class TiffTransferEmitter¶
- #include <metadata_transfer.h>
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¶
-
virtual ~TiffTransferEmitter() = default¶
-
struct TimePatchSlot¶
- #include <metadata_transfer.h>
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¶
-
TimePatchField field = TimePatchField::DateTime¶
-
struct TimePatchUpdate¶
- #include <metadata_transfer.h>
One time patch update payload for apply_time_patches.
-
struct TimePatchView¶
- #include <metadata_transfer.h>
Non-owning time patch view for hot-path transfer execution.
-
class TransferAdapterSink¶
- #include <metadata_transfer.h>
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¶
-
virtual ~TransferAdapterSink() = default¶
-
class TransferByteWriter¶
- #include <metadata_transfer.h>
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¶
-
virtual ~TransferByteWriter() = default¶
-
struct TransferCompatibilityDumpOptions¶
- #include <compatibility_dump.h>
Options for dump_transfer_compatibility.
-
struct TransferConceptDiagnostic¶
- #include <metadata_transfer.h>
Public Members
-
MetadataConceptRecordKind record_kind = MetadataConceptRecordKind::None¶
Structured-record type copied from the concept candidate.
-
MetadataConceptSensitivity sensitivity = MetadataConceptSensitivity::None¶
Host policy signal; independent from
hintandaction.
-
EntryId entry_id = kInvalidEntryId¶
-
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¶
-
MetadataConceptRecordKind record_kind = MetadataConceptRecordKind::None¶
-
struct TransferConceptDiagnostics¶
- #include <metadata_transfer.h>
Public Members
-
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¶
-
uint32_t candidate_count = 0U¶
-
struct TransferMakerNoteAudit¶
- #include <metadata_transfer.h>
Source evidence and current writer capabilities for MakerNote transfer.
Public Members
-
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¶
-
uint32_t raw_payload_count = 0U¶
-
struct TransferMakerNoteLayoutAudit¶
- #include <metadata_transfer.h>
Vendor-layout evidence that can be established without rewriting a note.
Public Members
-
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 source_offset_context_required = false¶
-
bool vendor_private_offsets_verified = false¶
-
bool vendor_checksum_validation_available = false¶
-
bool semantic_roundtrip_validation_available = false¶
-
uint32_t raw_payload_count = 0U¶
-
struct TransferProfile¶
- #include <metadata_transfer.h>
Transfer policy profile for initial no-edits workflows.
Public Members
-
TransferPolicyAction makernote = TransferPolicyAction::Keep¶
-
bool allow_time_patch = true¶
-
TransferPolicyAction makernote = TransferPolicyAction::Keep¶
-
struct TransferRawCarrierPassthroughAudit¶
- #include <metadata_transfer.h>
Diagnostic summary for raw-carrier passthrough eligibility.
Public Members
-
TransferTargetFormat target_format = TransferTargetFormat::Jpeg¶
-
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¶
-
TransferTargetFormat target_format = TransferTargetFormat::Jpeg¶
-
struct TransferRawCarrierPassthroughAuditOptions¶
- #include <metadata_transfer.h>
Options for auditing raw-carrier passthrough eligibility.
Public Members
-
TransferTargetFormat target_format = TransferTargetFormat::Jpeg¶
-
TransferProfile profile¶
-
bool require_decoded_entry_links = true¶
-
TransferTargetFormat target_format = TransferTargetFormat::Jpeg¶
-
struct TransferRawCarrierPassthroughDecision¶
- #include <metadata_transfer.h>
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¶
-
std::string source_route¶
-
std::string target_route¶
-
uint32_t carrier_index = 0U¶
-
struct TransferSafetyAudit¶
- #include <metadata_transfer.h>
Source metadata and filtered-entry counts for one transfer safety mode.
Public Members
-
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¶
-
uint32_t source_image_properties = 0U¶
-
struct TransferSourceRawCarrier¶
- #include <metadata_transfer.h>
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.
-
std::vector<std::byte> payload¶
Original metadata payload bytes, bounded by read options.
-
ContainerBlockRef block¶
-
struct TransferSourceSnapshot¶
- #include <metadata_transfer.h>
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.
-
struct TransferSourceSnapshotIoOptions¶
- #include <metadata_transfer.h>
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¶
-
uint64_t max_serialized_bytes = 256ULL * 1024ULL * 1024ULL¶
-
struct TransferSourceSnapshotIoResult¶
- #include <metadata_transfer.h>
Result for persisted target-neutral source snapshot I/O.
Public Members
-
TransferStatus status = TransferStatus::Unsupported¶
-
uint64_t bytes = 0U¶
-
uint32_t errors = 0U¶
-
std::string message¶
-
TransferStatus status = TransferStatus::Unsupported¶
-
struct TransferTargetImageSpec¶
- #include <metadata_transfer.h>
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¶
-
bool has_dimensions = false¶
-
struct TransferTimePatchInput¶
- #include <metadata_transfer.h>
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¶
-
TimePatchField field = TimePatchField::DateTime¶
-
struct URational¶
- #include <meta_value.h>
Unsigned rational (numerator/denominator), typically used by EXIF/TIFF.
-
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.
-
ValidateIssueSeverity severity = ValidateIssueSeverity::Warning¶
-
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.
-
bool include_pointer_tags = true¶
-
struct ValidatePreparedC2paSignResult¶
- #include <metadata_transfer.h>
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¶
-
TransferStatus status = TransferStatus::Unsupported¶
-
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¶
-
ValidateStatus status = ValidateStatus::Ok¶
-
struct VendorRawProcessingSummary¶
- #include <vendor_raw_processing.h>
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¶
-
uint32_t fields_seen = 0U¶
-
class WebpTransferEmitter¶
- #include <metadata_transfer.h>
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¶
-
virtual ~WebpTransferEmitter() = default¶
-
struct WireType¶
- #include <meta_store.h>
Wire-format element type + family (e.g. TIFF type code).
-
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).
-
uint32_t max_depth = 128¶
-
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:Descriptionas XMP properties.
-
XmpDecodeMalformedMode malformed_mode = XmpDecodeMalformedMode::Malformed¶
Controls whether malformed XML should be reported as Malformed or as best-effort OutputTruncated.
-
XmpDecodeLimits limits¶
-
bool decode_description_attributes = true¶
-
struct XmpDecodeResult¶
- #include <xmp_decode.h>
-
struct XmpDumpLimits¶
- #include <xmp_dump.h>
Resource limits applied during dump to bound output generation.
-
struct XmpDumpOptions¶
- #include <xmp_dump.h>
Dump options for dump_xmp_lossless.
-
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¶
-
XmpDumpStatus status = XmpDumpStatus::Ok¶
-
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_pathvalues, indexed[n]paths, bounded lang-alt paths liketitle[@xml:lang=x-default], bounded one-level structured paths likeCreatorContactInfo/CiEmailWork, bounded qualified one-level structured child paths likeLocationShown[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, andVersions[1]/stVer:event/stEvt:action, bounded indexed-structured paths likeLicensee[1]/LicenseeName, bounded second-level structured scalar paths likeCreatorContactInfo/CiAdrRegion/ProvinceName, bounded structured child indexed paths likeCreatorContactInfo/CiAdrExtadr[1], and bounded structured child lang-alt paths likeCreatorContactInfo/CiAdrCity[@xml:lang=x-default]are emitted. Known standard malformed flat structured child values likeCreator[1]/NameandCreator[1]/Roleare also promoted into the canonicallang-altor indexed shapes when no explicit canonical child entries already exist. Known malformed Adobe structured child paths likeDerivedFrom/documentID,JobRef[1]/id,Manifest[1]/reference/filePath, andVersions[1]/event/actionare likewise promoted into their canonical qualified child prefixes. The same bounded promotion applies to known second-level standard shapes likeCreatorContactInfo/CiAdrRegion/ProvinceNameandCreatorContactInfo/CiAdrRegion/ProvinceCode. Bounded second-level structured child lang-alt paths likeCreatorContactInfo/CiAdrRegion/ProvinceName[@xml:lang=x-default]and bounded second-level structured child indexed paths likeCreatorContactInfo/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:GPSDateTimeinstead ofexif:GPSTimeStampfor GPS time.Default keeps standard portable naming. This compatibility mode is useful for tools that normalize XMP GPS time under
GPSDateTime.
-
XmpDumpLimits limits¶
-
struct XmpProperty¶
- #include <meta_key.h>
-
struct XmpProperty¶
- #include <meta_key.h>
-
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).
-
XmpSidecarFormat format = XmpSidecarFormat::Lossless¶
-
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).
-
XmpSidecarFormat format = XmpSidecarFormat::Lossless¶
-
namespace openmeta¶
Scalar constructors
Arena-backed constructors
-
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
Typedefs
-
using BlockId = uint32_t¶
-
using EntryId = uint32_t¶
-
using MetadataPatchReplayCallback = bool (*)(void *user, MetadataPatchPayload family, std::span<const std::byte> payload) noexcept¶
-
using ReadTransferSourceSnapshotOptions = ReadTransferSourceSnapshotFileOptions¶
Generic decode options for transfer source snapshot reads.
-
using PreparedTransferHandoffReplayCallback = TransferStatus (*)(void *user, const PreparedTransferHandoffOperationView *operation) noexcept¶
Allocation-free replay callback invoked once per prepared operation.
-
using RandomAccessReadAt = RandomAccessIoResult (*)(void *context, uint64_t offset, std::span<std::byte> destination) noexcept¶
Host callback for one synchronous positional read.
Okrequires exactlydestination.size()bytes. A callback that reaches a premature end returnsOkwith the actual shorter count; OpenMeta reports a short read. If the source no longer has the size captured in RandomAccessSource, returnSourceChanged.The callback must not throw. It may partially overwrite
destinationon 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.
-
enumerator Ok¶
-
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.
-
enumerator None¶
-
enum class CcmIssueSeverity : uint8_t¶
Validation issue severity.
Values:
-
enumerator Warning¶
-
enumerator Error¶
Field-level hard-invalid issue (the field is skipped).
-
enumerator Warning¶
-
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¶
-
enumerator DecodeFailed¶
-
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).
-
enumerator Ok¶
-
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.
-
enumerator Ok¶
-
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¶
-
enumerator Mrw¶
-
enumerator Unknown¶
-
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¶
-
enumerator Unknown¶
-
enum class BlockCompression : uint8_t¶
Compression type for the block payload bytes (if any).
Values:
-
enumerator None¶
-
enumerator Deflate¶
-
enumerator Brotli¶
-
enumerator None¶
-
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¶
-
enumerator None¶
-
enum class DngSdkAdapterStatus : uint8_t¶
Result status for the optional DNG SDK adapter.
Values:
-
enumerator Ok¶
-
enumerator InvalidArgument¶
-
enumerator Unsupported¶
-
enumerator Malformed¶
-
enumerator InternalError¶
-
enumerator Ok¶
-
enum class ExifDecodeStatus : uint8_t¶
EXIF/TIFF decode result status.
Values:
-
enumerator Ok¶
-
enumerator OutputTruncated¶
-
enumerator Unsupported¶
-
enumerator Malformed¶
-
enumerator LimitExceeded¶
-
enumerator Ok¶
-
enum class ExifLimitReason : uint8_t¶
Best-effort reason for ExifDecodeStatus::LimitExceeded.
Values:
-
enumerator None¶
-
enumerator MaxIfds¶
-
enumerator MaxEntriesPerIfd¶
-
enumerator MaxTotalEntries¶
-
enumerator ValueCountTooLarge¶
-
enumerator MaxArenaBytes¶
-
enumerator None¶
-
enum class ExifIfdKind : uint8_t¶
Logical IFD kinds exposed by decode_exif_tiff().
Values:
-
enumerator Ifd¶
-
enumerator ExifIfd¶
-
enumerator GpsIfd¶
-
enumerator InteropIfd¶
-
enumerator SubIfd¶
-
enumerator Ifd¶
-
enum class ExifTiffMakerNotePolicy : uint8_t¶
Opaque MakerNote handling for canonical TIFF serialization.
Values:
-
enumerator Drop¶
-
enumerator PreserveOpaque¶
-
enumerator Drop¶
-
enum class ExifTiffSerializeStatus : uint8_t¶
Stable result status for
serialize_exif_tiff().Values:
-
enumerator Ok¶
-
enumerator OutputTruncated¶
-
enumerator InvalidOptions¶
-
enumerator StoreNotFinalized¶
-
enumerator InvalidMetadata¶
-
enumerator NoExifData¶
-
enumerator LimitExceeded¶
-
enumerator SerializationFailed¶
-
enumerator Ok¶
-
enum class ExrAdapterStatus : uint8_t¶
Result status for EXR adapter export.
Values:
-
enumerator Ok¶
-
enumerator InvalidArgument¶
-
enumerator Unsupported¶
-
enumerator Ok¶
-
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.
-
enumerator Ok¶
-
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.
-
enumerator Ok¶
-
enum class IccTagInterpretStatus : uint8_t¶
Best-effort status for interpret_icc_tag.
Values:
-
enumerator Ok¶
-
enumerator Unsupported¶
-
enumerator Malformed¶
-
enumerator LimitExceeded¶
-
enumerator Ok¶
-
enum class InteropSafetyStatus : uint8_t¶
Status for strict safe interop export APIs.
Values:
-
enumerator Ok¶
-
enumerator InvalidArgument¶
-
enumerator UnsafeData¶
-
enumerator InternalError¶
-
enumerator Ok¶
-
enum class InteropSafetyReason : uint8_t¶
Reason code for InteropSafetyError.
Values:
-
enumerator None¶
-
enumerator UnsafeBytes¶
-
enumerator InvalidTextEncoding¶
-
enumerator UnsafeTextControlCharacter¶
-
enumerator InternalMismatch¶
-
enumerator None¶
-
enum class ExportNameStyle : uint8_t¶
Key naming policy used by visit_metadata.
- API Stability
Stable enum shape.
Canonical,XmpPortable, andFlatHostnaming 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.
-
enumerator Spec¶
-
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.
-
enumerator SourceEntry¶
-
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¶
-
enumerator None¶
-
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.
-
enumerator Ok¶
-
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.
-
enumerator Ok¶
-
enum class C2paVerifyBackend : uint8_t¶
Draft C2PA verification backend selection.
Values:
-
enumerator None¶
-
enumerator Auto¶
-
enumerator Native¶
-
enumerator OpenSsl¶
-
enumerator None¶
-
enum class C2paVerifyStatus : uint8_t¶
Draft C2PA verification status.
Values:
-
enumerator NotRequested¶
-
enumerator DisabledByBuild¶
-
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.
-
enumerator NotRequested¶
-
enum class LibRawOrientationStatus : uint8_t¶
Result status for EXIF/XMP orientation to LibRaw flip mapping.
Values:
-
enumerator Ok¶
-
enumerator InvalidArgument¶
-
enumerator Unsupported¶
-
enumerator Ok¶
-
enum class LibRawOrientationCode : uint8_t¶
Detailed mapping code for LibRawOrientationResult.
Values:
-
enumerator None¶
-
enumerator PreviewPassThrough¶
-
enumerator MissingExifOrientationAssumedDefault¶
-
enumerator InvalidExifOrientation¶
-
enumerator UnsupportedMirroredOrientation¶
-
enumerator MirroredOrientationDropped¶
-
enumerator None¶
-
enum class LibRawOrientationSource : uint8_t¶
Canonical metadata source used for LibRawOrientationResult.
Values:
-
enumerator ExplicitInput¶
-
enumerator AssumedDefault¶
-
enumerator ExifIfd0¶
-
enumerator XmpTiffOrientation¶
-
enumerator ExplicitInput¶
-
enum class LibRawOrientationTarget : uint8_t¶
Output target for LibRaw orientation mapping.
Values:
-
enumerator RawImage¶
-
enumerator EmbeddedPreview¶
-
enumerator RawImage¶
-
enum class LibRawMirrorPolicy : uint8_t¶
Policy for mirrored EXIF orientations (2/4/5/7).
Values:
-
enumerator Reject¶
-
enumerator DropMirror¶
-
enumerator Reject¶
-
enum class LibRawFlipToExifCode : uint8_t¶
Detailed mapping code for LibRawFlipToExifResult.
Values:
-
enumerator None¶
-
enumerator PreviewPassThrough¶
-
enumerator InvalidLibRawFlip¶
-
enumerator None¶
-
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¶
-
enumerator Ok¶
-
enum class MappedFileStatus : uint8_t¶
Status code for MappedFile operations.
Values:
-
enumerator Ok¶
-
enumerator OpenFailed¶
-
enumerator StatFailed¶
-
enumerator TooLarge¶
-
enumerator MapFailed¶
-
enumerator Ok¶
-
enum class EditOpKind : uint8_t¶
The operation kind for a MetaEdit command stream.
Values:
-
enumerator AddEntry¶
-
enumerator SetValue¶
-
enumerator Tombstone¶
-
enumerator SetValueWithWire¶
-
enumerator AddEntry¶
-
enum class EntryFlags : uint8_t¶
Per-entry flags used during edits and provenance tracking.
Values:
-
enumerator None¶
-
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 ValueBigEndian¶
Structured EXIF bytes use big-endian integers; unset means little-endian. Applies to 8828, 9286, A20C, A302, A40B and A462. UTF-16 BOMs override it. The raw value remains byte-for-byte unchanged after decoding.
-
enumerator None¶
-
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¶
-
enumerator ExifTag¶
-
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¶
-
enumerator None¶
-
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¶
-
enumerator CanonColorBalance001D¶
-
enumerator CanonAfInfo0011¶
-
enumerator SonyPrivateField¶
-
enumerator NikonCaptureField¶
-
enumerator None¶
-
enum class MetaValueKind : uint8_t¶
Top-level value storage kind.
Values:
-
enumerator Empty¶
-
enumerator Scalar¶
An inline scalar stored in MetaValue::data.
-
enumerator Empty¶
-
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¶
-
enumerator U8¶
-
enum class TextEncoding : uint8_t¶
Encoding hint for text values.
Values:
-
enumerator Unknown¶
-
enumerator Ascii¶
-
enumerator Utf8¶
-
enumerator Utf16LE¶
-
enumerator Utf16BE¶
-
enumerator Unknown¶
-
enum class MetadataAuthoringDuplicatePolicy : uint8_t¶
Handling of repeated explicit keys during generic store construction.
Values:
-
enumerator Allow¶
-
enumerator RejectExactKeys¶
-
enumerator Allow¶
-
enum class MetadataAuthoringStatus : uint8_t¶
Stable result status for
create_metadata_store().Values:
-
enumerator Ok¶
-
enumerator NullOutput¶
-
enumerator InvalidOptions¶
-
enumerator TooManyEntries¶
-
enumerator UnsupportedKeyKind¶
-
enumerator InvalidKey¶
-
enumerator InvalidValue¶
-
enumerator LimitExceeded¶
-
enumerator DuplicateKey¶
-
enumerator ValidationFailed¶
-
enumerator Ok¶
-
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¶
-
enumerator Exif¶
-
enum class MetadataCapabilitySupport : uint8_t¶
Support level for one operation in MetadataCapability.
Values:
-
enumerator Unsupported¶
-
enumerator Supported¶
-
enumerator Bounded¶
-
enumerator Disabled¶
-
enumerator Unsupported¶
-
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¶
-
enumerator Orientation¶
-
enum class MetadataConceptSourceFamily : uint8_t¶
Values:
-
enumerator Unknown¶
-
enumerator Exif¶
-
enumerator Xmp¶
-
enumerator Iptc¶
-
enumerator Icc¶
-
enumerator PngText¶
-
enumerator InterpretationRecord¶
-
enumerator Unknown¶
-
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¶
-
enumerator Primary¶
-
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¶
-
enumerator None¶
-
enum class MetadataImageRegionShape : uint8_t¶
Values:
-
enumerator Unknown¶
-
enumerator Rectangle¶
-
enumerator Circle¶
-
enumerator Polygon¶
-
enumerator Unknown¶
-
enum class MetadataImageRegionCoordinateUnit : uint8_t¶
Values:
-
enumerator Unknown¶
-
enumerator Pixel¶
-
enumerator Relative¶
-
enumerator Unknown¶
-
enum class MetadataConceptSensitivity : uint8_t¶
Policy sensitivity is independent from technical transfer safety.
Values:
-
enumerator None¶
-
enumerator PersonalContact¶
-
enumerator PersonIdentity¶
-
enumerator Location¶
-
enumerator LegalRights¶
-
enumerator None¶
-
enum class MetadataConceptDateTimePrecision : uint8_t¶
Values:
-
enumerator Unknown¶
-
enumerator Date¶
-
enumerator DateTime¶
-
enumerator DateTimeSubsecond¶
-
enumerator Unknown¶
-
enum class MetadataConceptTimeZoneKind : uint8_t¶
Values:
-
enumerator Unknown¶
-
enumerator Local¶
-
enumerator Utc¶
-
enumerator Offset¶
-
enumerator Unknown¶
-
enum class MetadataConceptTransferHint : uint8_t¶
Values:
-
enumerator Unknown¶
-
enumerator Safe¶
-
enumerator SourceBound¶
-
enumerator RenderedUnsafe¶
-
enumerator RequiresTargetImageSpec¶
-
enumerator Unknown¶
-
enum class MetadataRawDataEncoding : uint8_t¶
Values:
-
enumerator Unknown¶
-
enumerator Uncompressed¶
-
enumerator Packed¶
-
enumerator LosslessCompressed¶
-
enumerator LossyCompressed¶
-
enumerator Rendered¶
-
enumerator Unknown¶
-
enum class MetadataRawApplicabilityState : uint8_t¶
Values:
-
enumerator Unknown¶
-
enumerator AppliesToStoredRaw¶
-
enumerator ConditionalOnRawEncoding¶
-
enumerator NotApplicableToStoredRaw¶
-
enumerator Unknown¶
-
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¶
-
enumerator Title¶
-
enum class MetadataCreationValueKind : uint8_t¶
Input value representation for one creation field.
Values:
-
enumerator Text¶
-
enumerator UnsignedInteger¶
-
enumerator SignedInteger¶
-
enumerator UnsignedRational¶
-
enumerator Text¶
-
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¶
-
enumerator Ok¶
-
enum class MetadataEditingOperationKind : uint8_t¶
Values:
-
enumerator Add¶
-
enumerator Set¶
-
enumerator Remove¶
-
enumerator Add¶
-
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¶
-
enumerator Ok¶
-
enum class MetadataTypedEditingAddPolicy : uint8_t¶
Values:
-
enumerator FailIfPresent¶
-
enumerator Append¶
-
enumerator FailIfPresent¶
-
enum class MetadataTypedEditingStatus : uint8_t¶
Values:
-
enumerator Ok¶
-
enumerator NullOutput¶
-
enumerator BaseNotFinalized¶
-
enumerator InvalidOptions¶
-
enumerator TooManyOperations¶
-
enumerator UnsupportedKeyKind¶
-
enumerator InvalidKey¶
-
enumerator InvalidValue¶
-
enumerator InvalidOperation¶
-
enumerator InvalidOccurrence¶
-
enumerator TargetNotFound¶
-
enumerator AmbiguousTarget¶
-
enumerator TargetAlreadyExists¶
-
enumerator LimitExceeded¶
-
enumerator ValidationFailed¶
-
enumerator Ok¶
-
enum class MetadataFuzzySearchStatus : uint8_t¶
Values:
-
enumerator Ok¶
-
enumerator EmptyQuery¶
-
enumerator QueryTooShort¶
-
enumerator QueryTooLong¶
-
enumerator UnsupportedQueryText¶
-
enumerator InvalidOptions¶
-
enumerator Ok¶
-
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.
-
enumerator Exact¶
-
enum class MetadataPatchPayload : uint8_t¶
Unwrapped payload selected independently of any image container.
Values:
-
enumerator ExifTiff¶
-
enumerator Xmp¶
-
enumerator ExifTiff¶
-
enum class MetadataPatchCode : uint16_t¶
Values:
-
enumerator None¶
-
enumerator NullOutput¶
-
enumerator InvalidOptions¶
-
enumerator StoreNotFinalized¶
-
enumerator InvalidMetadata¶
-
enumerator NoExifData¶
-
enumerator LimitExceeded¶
-
enumerator SerializationFailed¶
-
enumerator EmptyRequests¶
-
enumerator HandleBufferSizeMismatch¶
-
enumerator InvalidRequest¶
-
enumerator KeyNotFound¶
-
enumerator OccurrenceOutOfRange¶
-
enumerator ValueTypeMismatch¶
-
enumerator EntryNotSerializable¶
-
enumerator DuplicateRequest¶
-
enumerator AllocationFailed¶
-
enumerator InvalidPlan¶
-
enumerator InvalidInstance¶
-
enumerator EmptyUpdates¶
-
enumerator InvalidHandle¶
-
enumerator ForeignHandle¶
-
enumerator DuplicateHandle¶
-
enumerator WidthMismatch¶
-
enumerator InvalidValue¶
-
enumerator ValueAliasesInstance¶
-
enumerator UnsupportedShape¶
-
enumerator AmbiguousProperty¶
-
enumerator NullReplayCallback¶
-
enumerator ReplayFailed¶
-
enumerator None¶
-
enum class MetadataQueryKind : uint8_t¶
Values:
-
enumerator Crop¶
-
enumerator ExposureGain¶
-
enumerator WhiteBalance¶
-
enumerator Color¶
-
enumerator LensCorrection¶
-
enumerator Orientation¶
-
enumerator RawProcessing¶
-
enumerator Descriptive¶
-
enumerator Crop¶
-
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¶
-
enumerator Unknown¶
-
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¶
-
enumerator Unknown¶
-
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¶
-
enumerator None¶
-
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¶
-
enumerator Jpeg¶
-
enum class DngTargetMode : uint8_t¶
Public DNG target contract for metadata-only transfer workflows. Existing/template preparation treats clean source DNGVersion as context and preserves the target version. Eligible dirty versions can replace it under CompatibleFile; RenderedImage filtering still excludes RAW version edits. Only MinimalFreshScaffold preparation synthesizes a missing DNGVersion.
Values:
-
enumerator ExistingTarget¶
-
enumerator TemplateTarget¶
-
enumerator MinimalFreshScaffold¶
-
enumerator ExistingTarget¶
-
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¶
-
enumerator Exif¶
-
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¶
-
enumerator Ok¶
-
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¶
-
enumerator None¶
-
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¶
-
enumerator None¶
-
enum class PrepareTransferFileCode : uint16_t¶
Stable file/read/prepare error code for PrepareTransferFileResult.
Values:
-
enumerator None¶
-
enumerator EmptyPath¶
-
enumerator MapFailed¶
-
enumerator PayloadBufferPlatformLimit¶
-
enumerator DecodeFailed¶
-
enumerator None¶
-
enum class ReadTransferSourceSnapshotFileCode : uint16_t¶
Stable file/read error code for ReadTransferSourceSnapshotFileResult.
Values:
-
enumerator None¶
-
enumerator EmptyPath¶
-
enumerator MapFailed¶
-
enumerator PayloadBufferPlatformLimit¶
-
enumerator DecodeFailed¶
-
enumerator None¶
-
enum class ReadTransferSourceSnapshotBytesCode : uint16_t¶
Stable bytes/read error code for ReadTransferSourceSnapshotBytesResult.
Values:
-
enumerator None¶
-
enumerator PayloadBufferPlatformLimit¶
-
enumerator DecodeFailed¶
-
enumerator None¶
-
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.
-
enumerator None¶
-
enum class ReadTransferSourceDiagnosticSeverity : uint8_t¶
Severity of one structured positional snapshot read diagnostic.
Values:
-
enumerator Info¶
-
enumerator Warning¶
-
enumerator Error¶
-
enumerator Info¶
-
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¶
-
enumerator Input¶
-
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¶
-
enumerator InputFailure¶
-
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¶
-
enumerator Ok¶
-
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¶
-
enumerator MakerNote¶
-
enum class TransferPolicyAction : uint8_t¶
Requested/effective action for a metadata family during transfer.
Values:
-
enumerator Keep¶
-
enumerator Drop¶
-
enumerator Invalidate¶
-
enumerator Rewrite¶
-
enumerator Keep¶
-
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 TargetImageProperties¶
-
enumerator SafetyModeFiltered¶
-
enumerator RawDataDescriptorFiltered¶
-
enumerator OpaquePayloadPreservedUnverified¶
Opaque bytes are retained, but nested offsets, vendor checksums, and semantic readability after relocation are not verified.
Rewrite was requested, but no safe serializer is available; payloads are dropped rather than silently treated as preserved rewrites.
-
enumerator Default¶
-
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¶
-
enumerator NotApplicable¶
-
enum class TransferC2paSourceKind : uint8_t¶
Classified C2PA source state observed during prepare.
Values:
-
enumerator NotApplicable¶
-
enumerator NotPresent¶
-
enumerator DecodedOnly¶
-
enumerator ContentBound¶
-
enumerator DraftUnsignedInvalidation¶
-
enumerator NotApplicable¶
-
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¶
-
enumerator NotApplicable¶
-
enum class TransferC2paRewriteState : uint8_t¶
Current rewrite-signing readiness for C2PA transfer.
Values:
-
enumerator NotApplicable¶
-
enumerator NotRequested¶
-
enumerator SigningMaterialRequired¶
-
enumerator Ready¶
-
enumerator NotApplicable¶
-
enum class TransferC2paRewriteChunkKind : uint8_t¶
One deterministic chunk in the future C2PA rewrite binding sequence.
Values:
-
enumerator SourceRange¶
-
enumerator PreparedJpegSegment¶
-
enumerator PreparedJxlBox¶
-
enumerator PreparedBmffMetaBox¶
-
enumerator SourceRange¶
-
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.
-
enumerator CompatibleFile¶
-
enum class TransferC2paSignedPayloadKind : uint8_t¶
Classified logical C2PA payload kind supplied by an external signer.
Values:
-
enumerator NotApplicable¶
-
enumerator GenericJumbf¶
-
enumerator DraftUnsignedInvalidation¶
-
enumerator ContentBound¶
-
enumerator NotApplicable¶
-
enum class TransferC2paSemanticStatus : uint8_t¶
Semantic validation status for a staged logical C2PA payload.
Values:
-
enumerator NotChecked¶
-
enumerator Ok¶
-
enumerator Invalid¶
-
enumerator NotChecked¶
-
enum class TransferMakerNoteTrust : uint8_t¶
Trust state for vendor MakerNote data observed in a decoded store.
Values:
-
enumerator NotPresent¶
-
enumerator DecodedOnlyNotSerializable¶
-
enumerator OpaquePreservationUnverified¶
-
enumerator NotPresent¶
-
enum class TransferMakerNoteVendor : uint8_t¶
Vendor identified from raw MakerNote layout and source-make evidence.
Values:
-
enumerator Unknown¶
-
enumerator Nikon¶
-
enumerator Canon¶
-
enumerator Unknown¶
-
enum class TransferMakerNoteLayout : uint8_t¶
Raw MakerNote layout relevant to offset-safe transfer.
Values:
-
enumerator UnknownOrMixed¶
-
enumerator NikonType1OuterTiff¶
-
enumerator NikonType3EmbeddedTiff¶
-
enumerator CanonSourceDependentIfd¶
-
enumerator UnknownOrMixed¶
-
enum class TransferMakerNoteLayoutTrust : uint8_t¶
Structural trust established for a raw MakerNote layout.
Values:
-
enumerator NotPresent¶
-
enumerator UnrecognizedOrMixed¶
-
enumerator OuterTiffOffsetsUnsafe¶
-
enumerator SourceOffsetBasisAmbiguous¶
-
enumerator EmbeddedTiffStructureUnverified¶
-
enumerator EmbeddedTiffStructureVerified¶
-
enumerator NotPresent¶
-
enum class TransferConceptDiagnosticAction : uint8_t¶
Values:
-
enumerator Keep¶
-
enumerator Drop¶
-
enumerator RequiresTargetImageSpec¶
-
enumerator Keep¶
-
enum class TransferConceptDiagnosticReason : uint8_t¶
Values:
-
enumerator Unknown¶
-
enumerator Safe¶
-
enumerator SourceBound¶
-
enumerator RenderedUnsafe¶
-
enumerator TargetImageSpecRequired¶
-
enumerator RawApplicabilityConditional¶
-
enumerator RawApplicabilityNotApplicable¶
-
enumerator Unknown¶
-
enum class TransferConceptDiagnosticSeverity : uint8_t¶
Values:
-
enumerator Info¶
-
enumerator Warning¶
-
enumerator Info¶
-
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¶
-
enumerator DateTime¶
-
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 UnsupportedKind¶
-
enumerator Candidate¶
-
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.
-
enumerator Disabled¶
-
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¶
-
enumerator None¶
-
enum class JpegEditMode : uint8_t¶
Draft JPEG edit strategy selection.
Values:
-
enumerator Auto¶
-
enumerator InPlace¶
-
enumerator MetadataRewrite¶
-
enumerator Auto¶
-
enum class TransferPackageChunkKind : uint8_t¶
One chunk in a packaged transfer output plan.
Values:
-
enumerator SourceRange¶
-
enumerator PreparedTransferBlock¶
-
enumerator PreparedJpegSegment¶
-
enumerator InlineBytes¶
-
enumerator SourceRange¶
-
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¶
-
enumerator Unknown¶
-
enum class PreparedJxlEmitKind : uint8_t¶
Kind of precompiled JPEG XL emit operation.
Values:
-
enumerator Box¶
-
enumerator IccProfile¶
-
enumerator Box¶
-
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¶
-
enumerator Unknown¶
-
enum class PreparedBmffEmitKind : uint8_t¶
Kind of precompiled ISO-BMFF metadata emit operation.
Values:
-
enumerator Item¶
-
enumerator MimeXmp¶
-
enumerator Property¶
-
enumerator Item¶
-
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¶
-
enumerator JpegMarker¶
-
enum class XmpExistingSidecarMode : uint8_t¶
Existing sibling XMP sidecar handling for transfer preparation.
Values:
-
enumerator Ignore¶
-
enumerator MergeIfPresent¶
-
enumerator Ignore¶
-
enum class XmpExistingSidecarPrecedence : uint8_t¶
Conflict precedence between a merged destination-side
.xmpand source-embedded existing XMP.Values:
-
enumerator SidecarWins¶
-
enumerator SourceWins¶
-
enumerator SidecarWins¶
-
enum class XmpExistingDestinationEmbeddedMode : uint8_t¶
Existing destination embedded-XMP handling for file-helper transfer execution.
Values:
-
enumerator Ignore¶
-
enumerator MergeIfPresent¶
-
enumerator Ignore¶
-
enum class XmpExistingDestinationEmbeddedPrecedence : uint8_t¶
Conflict precedence between merged destination embedded XMP and source-embedded existing XMP.
Values:
-
enumerator DestinationWins¶
-
enumerator SourceWins¶
-
enumerator DestinationWins¶
-
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¶
-
enumerator SidecarWins¶
-
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
.xmpoutput.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
.xmpwriteback.
-
enumerator EmbeddedOnly¶
-
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.
-
enumerator PreserveExisting¶
-
enum class XmpDestinationSidecarMode : uint8_t¶
Destination sibling XMP sidecar handling for file-helper transfer execution.
Values:
-
enumerator PreserveExisting¶
Leave an existing sibling
.xmpuntouched when embedded-only writeback is selected.
-
enumerator StripExisting¶
Request removal of an existing sibling
.xmpwhen embedded-only writeback is selected.
-
enumerator PreserveExisting¶
-
enum class XmpExistingDestinationSidecarState : uint8_t¶
Host-reported presence of an existing destination sibling
.xmpsidecar.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.
-
enumerator Unknown¶
-
enum class MetadataDateTranslationSourceMode : uint8_t¶
Which XMP entries are eligible as reverse-translation sources.
Values:
-
enumerator DirtyOnly¶
Translate only entries marked Dirty, including dirty tombstones.
-
enumerator All¶
Translate active clean or dirty entries; tombstones still require Dirty.
-
enumerator DirtyOnly¶
-
enum class MetadataDateTranslationConflictPolicy : uint8_t¶
How an existing native EXIF/IPTC date group is reconciled.
Values:
-
enumerator PreserveExisting¶
Keep the complete existing native group when any member is present.
-
enumerator FailOnConflict¶
Require the native group to be absent or already exactly equivalent.
-
enumerator ReplaceExisting¶
Replace the native group and tombstone stale or duplicate members.
-
enumerator PreserveExisting¶
-
enum class MetadataDateTranslationMapping : uint8_t¶
Exact source mapping associated with a result or failure.
Values:
-
enumerator None¶
-
enumerator XmpCreateDate¶
-
enumerator PhotoshopDateCreated¶
-
enumerator XmpDateTimeOriginal¶
-
enumerator None¶
-
enum class MetadataDateTranslationStatus : uint8_t¶
Stable result status for translate_xmp_creation_dates.
Values:
-
enumerator Ok¶
-
enumerator NullOutput¶
-
enumerator SourceNotFinalized¶
-
enumerator InvalidOptions¶
-
enumerator AmbiguousSource¶
-
enumerator InvalidSourceValue¶
-
enumerator InvalidDateTime¶
-
enumerator UnsupportedPrecision¶
-
enumerator NativeConflict¶
-
enumerator EntryLimitExceeded¶
-
enumerator OperationLimitExceeded¶
-
enumerator InternalError¶
-
enumerator Ok¶
-
enum class MetadataTechnicalTranslationSourceMode : uint8_t¶
Which exact XMP properties are eligible as reverse technical sources.
Values:
-
enumerator DirtyOnly¶
Translate only entries marked Dirty, including dirty tombstones.
-
enumerator All¶
Translate active clean or dirty entries; tombstones still require Dirty.
-
enumerator DirtyOnly¶
-
enum class MetadataTechnicalTranslationConflictPolicy : uint8_t¶
How an existing native EXIF group is reconciled.
Values:
-
enumerator PreserveExisting¶
-
enumerator FailOnConflict¶
-
enumerator ReplaceExisting¶
-
enumerator PreserveExisting¶
-
enum class MetadataTechnicalTranslationMapping : uint8_t¶
Exact technical source mapping associated with a result or failure.
Values:
-
enumerator None¶
-
enumerator XmpModifyDate¶
-
enumerator TiffMake¶
-
enumerator TiffModel¶
-
enumerator XmpCreatorTool¶
-
enumerator XmpSpectralSensitivity¶
-
enumerator XmpCameraOwnerName¶
-
enumerator XmpBodySerialNumber¶
-
enumerator XmpLensMake¶
-
enumerator XmpLensModel¶
-
enumerator XmpLensSerialNumber¶
-
enumerator None¶
-
enum class MetadataTechnicalTranslationStatus : uint8_t¶
Values:
-
enumerator Ok¶
-
enumerator NullOutput¶
-
enumerator SourceNotFinalized¶
-
enumerator InvalidOptions¶
-
enumerator AmbiguousSource¶
-
enumerator InvalidSourceValue¶
-
enumerator InvalidDateTime¶
-
enumerator UnsupportedPrecision¶
-
enumerator NonAsciiSource¶
-
enumerator ValueTooLong¶
-
enumerator SourceLimitExceeded¶
-
enumerator NativeConflict¶
-
enumerator EntryLimitExceeded¶
-
enumerator OperationLimitExceeded¶
-
enumerator InternalError¶
-
enumerator UnsupportedSourceShape¶
-
enumerator Ok¶
-
enum class MetadataCaptureTranslationSourceMode : uint8_t¶
Which exact XMP properties are eligible as reverse capture sources.
Values:
-
enumerator DirtyOnly¶
Translate only entries marked Dirty, including dirty tombstones.
-
enumerator All¶
Translate active clean or dirty entries; tombstones still require Dirty.
-
enumerator DirtyOnly¶
-
enum class MetadataCaptureTranslationConflictPolicy : uint8_t¶
How an existing native EXIF capture field is reconciled.
Values:
-
enumerator PreserveExisting¶
-
enumerator FailOnConflict¶
-
enumerator ReplaceExisting¶
-
enumerator PreserveExisting¶
-
enum class MetadataCaptureTranslationMapping : uint8_t¶
Exact capture source mapping associated with a result or failure.
Values:
-
enumerator None¶
-
enumerator XmpExposureTime¶
-
enumerator XmpFNumber¶
-
enumerator XmpIso¶
-
enumerator XmpFocalLength¶
-
enumerator XmpExposureCompensation¶
-
enumerator XmpExposureProgram¶
-
enumerator XmpMeteringMode¶
-
enumerator XmpSensingMethod¶
-
enumerator XmpCustomRendered¶
-
enumerator XmpExposureMode¶
-
enumerator XmpWhiteBalance¶
-
enumerator XmpSceneCaptureType¶
-
enumerator XmpGainControl¶
-
enumerator XmpContrast¶
-
enumerator XmpSaturation¶
-
enumerator XmpSharpness¶
-
enumerator XmpSubjectDistanceRange¶
-
enumerator XmpSubjectDistance¶
-
enumerator XmpDigitalZoomRatio¶
-
enumerator XmpExposureIndex¶
-
enumerator XmpFlashEnergy¶
-
enumerator XmpFlash¶
-
enumerator XmpLightSource¶
-
enumerator XmpSensitivity¶
-
enumerator XmpLensSpecification¶
-
enumerator XmpImageUniqueID¶
-
enumerator XmpShutterSpeedValue¶
-
enumerator XmpApertureValue¶
-
enumerator XmpBrightnessValue¶
-
enumerator XmpMaxApertureValue¶
-
enumerator XmpFocalPlaneResolution¶
-
enumerator XmpSubjectArea¶
-
enumerator XmpSubjectLocation¶
-
enumerator XmpFocalLengthIn35mmFilm¶
-
enumerator XmpFileSource¶
-
enumerator XmpSceneType¶
-
enumerator XmpTemperature¶
-
enumerator XmpHumidity¶
-
enumerator XmpPressure¶
-
enumerator XmpWaterDepth¶
-
enumerator XmpAcceleration¶
-
enumerator XmpCameraElevationAngle¶
-
enumerator XmpGamma¶
-
enumerator XmpCompressedBitsPerPixel¶
-
enumerator XmpComponentsConfiguration¶
-
enumerator XmpCompositeImage¶
-
enumerator XmpOecf¶
-
enumerator XmpSpatialFrequencyResponse¶
-
enumerator XmpCfaPattern¶
-
enumerator XmpDeviceSettingDescription¶
-
enumerator XmpExifVersion¶
-
enumerator XmpFlashpixVersion¶
-
enumerator XmpUserComment¶
-
enumerator XmpImageTitle¶
-
enumerator XmpPhotographer¶
-
enumerator XmpImageEditor¶
-
enumerator XmpCameraFirmware¶
-
enumerator XmpRAWDevelopingSoftware¶
-
enumerator XmpImageEditingSoftware¶
-
enumerator XmpMetadataEditingSoftware¶
-
enumerator XmpCameraOwnerName¶
-
enumerator XmpLensMake¶
-
enumerator XmpLensModel¶
-
enumerator XmpDevelopmentType¶
-
enumerator XmpDevelopmentTypeDescription¶
-
enumerator XmpDistortionCorrection¶
-
enumerator XmpChromaticAberrationCorrection¶
-
enumerator XmpShadingCorrection¶
-
enumerator XmpNoiseReduction¶
-
enumerator XmpLearningOptOutIn¶
-
enumerator XmpTiffImageDescription¶
-
enumerator XmpTiffArtist¶
-
enumerator XmpTiffCopyright¶
-
enumerator XmpColorSpace¶
-
enumerator XmpRelatedSoundFile¶
-
enumerator None¶
-
enum class MetadataCaptureTranslationStatus : uint8_t¶
Values:
-
enumerator Ok¶
-
enumerator NullOutput¶
-
enumerator SourceNotFinalized¶
-
enumerator InvalidOptions¶
-
enumerator AmbiguousSource¶
-
enumerator InvalidSourceValue¶
-
enumerator InvalidNumericValue¶
-
enumerator ValueOutOfRange¶
-
enumerator ValueTooLong¶
-
enumerator SourceLimitExceeded¶
-
enumerator NativeConflict¶
-
enumerator EntryLimitExceeded¶
-
enumerator OperationLimitExceeded¶
-
enumerator InternalError¶
-
enumerator IncompleteSource¶
-
enumerator UnsupportedSourceShape¶
-
enumerator Ok¶
-
enum class MetadataGeometryTranslationSourceMode : uint8_t¶
Which exact XMP properties are eligible as reverse geometry sources.
Values:
-
enumerator DirtyOnly¶
Translate only a group with at least one Dirty member.
-
enumerator All¶
Translate active clean or dirty entries; tombstones still require Dirty.
-
enumerator DirtyOnly¶
-
enum class MetadataGeometryTranslationConflictPolicy : uint8_t¶
How an existing native EXIF geometry group is reconciled.
Values:
-
enumerator PreserveExisting¶
-
enumerator FailOnConflict¶
-
enumerator ReplaceExisting¶
-
enumerator PreserveExisting¶
-
enum class MetadataGeometryTranslationMapping : uint8_t¶
Exact image-geometry source mapping associated with a result or failure.
Values:
-
enumerator None¶
-
enumerator XmpOrientation¶
-
enumerator XmpDimensions¶
-
enumerator None¶
-
enum class MetadataGeometryTranslationStatus : uint8_t¶
Values:
-
enumerator Ok¶
-
enumerator NullOutput¶
-
enumerator SourceNotFinalized¶
-
enumerator InvalidOptions¶
-
enumerator InvalidTargetImageSpec¶
-
enumerator TargetImageSpecRequired¶
-
enumerator TargetImageSpecMismatch¶
-
enumerator AmbiguousSource¶
-
enumerator IncompleteSourceGroup¶
-
enumerator InvalidSourceValue¶
-
enumerator InvalidNumericValue¶
-
enumerator ValueOutOfRange¶
-
enumerator ValueTooLong¶
-
enumerator SourceLimitExceeded¶
-
enumerator NativeConflict¶
-
enumerator EntryLimitExceeded¶
-
enumerator OperationLimitExceeded¶
-
enumerator InternalError¶
-
enumerator Ok¶
-
enum class MetadataDescriptiveTranslationSourceMode : uint8_t¶
Which XMP entries are eligible as reverse descriptive sources.
Values:
-
enumerator DirtyOnly¶
Translate a property group only when at least one member is Dirty.
-
enumerator All¶
Translate active clean or dirty entries; tombstones still require Dirty.
-
enumerator DirtyOnly¶
-
enum class MetadataDescriptiveTranslationConflictPolicy : uint8_t¶
How an existing native IPTC-IIM dataset group is reconciled.
Values:
-
enumerator PreserveExisting¶
-
enumerator FailOnConflict¶
-
enumerator ReplaceExisting¶
-
enumerator PreserveExisting¶
-
enum class MetadataDescriptiveTranslationMapping : uint8_t¶
Exact descriptive, location, or editorial source mapping for a result.
Values:
-
enumerator None¶
-
enumerator DcTitle¶
-
enumerator DcDescription¶
-
enumerator DcCreator¶
-
enumerator DcSubject¶
-
enumerator DcRights¶
-
enumerator PhotoshopCredit¶
-
enumerator PhotoshopSource¶
-
enumerator PhotoshopCity¶
-
enumerator IptcLocation¶
-
enumerator PhotoshopState¶
-
enumerator PhotoshopCountry¶
-
enumerator IptcCountryCode¶
-
enumerator PhotoshopHeadline¶
-
enumerator PhotoshopInstructions¶
-
enumerator PhotoshopTransmissionReference¶
-
enumerator PhotoshopAuthorsPosition¶
-
enumerator PhotoshopCaptionWriter¶
-
enumerator PhotoshopCategory¶
-
enumerator PhotoshopSupplementalCategories¶
-
enumerator PhotoshopUrgency¶
-
enumerator None¶
-
enum class MetadataDescriptiveTranslationStatus : uint8_t¶
Values:
-
enumerator Ok¶
-
enumerator NullOutput¶
-
enumerator SourceNotFinalized¶
-
enumerator InvalidOptions¶
-
enumerator SourceLimitExceeded¶
-
enumerator AmbiguousSource¶
-
enumerator InvalidSourceValue¶
-
enumerator ValueTooLong¶
-
enumerator NativeConflict¶
-
enumerator NativeEncodingConflict¶
-
enumerator EntryLimitExceeded¶
-
enumerator OperationLimitExceeded¶
-
enumerator InternalError¶
-
enumerator AmbiguousLocation¶
-
enumerator LocationNotFound¶
-
enumerator UnsupportedSourceShape¶
-
enumerator Ok¶
-
enum class MetadataStructuredLocationKind : uint8_t¶
Values:
-
enumerator Shown¶
-
enumerator Created¶
-
enumerator Unspecified¶
-
enumerator Shown¶
-
enum class MetadataGpsTranslationSourceMode : uint8_t¶
Values:
-
enumerator DirtyOnly¶
-
enumerator All¶
-
enumerator DirtyOnly¶
-
enum class MetadataGpsTranslationConflictPolicy : uint8_t¶
Values:
-
enumerator PreserveExisting¶
-
enumerator FailOnConflict¶
-
enumerator ReplaceExisting¶
-
enumerator PreserveExisting¶
-
enum class MetadataGpsTranslationMapping : uint8_t¶
Values:
-
enumerator None¶
-
enumerator ExifGpsLatitude¶
-
enumerator ExifGpsLongitude¶
-
enumerator ExifGpsAltitude¶
-
enumerator GpsVersion¶
-
enumerator ExifGpsTimeStamp¶
-
enumerator ExifGpsSpeed¶
-
enumerator ExifGpsTrack¶
-
enumerator ExifGpsImgDirection¶
-
enumerator ExifGpsDestLatitude¶
-
enumerator ExifGpsDestLongitude¶
-
enumerator ExifGpsDestBearing¶
-
enumerator ExifGpsDestDistance¶
-
enumerator ExifGpsStatus¶
-
enumerator ExifGpsMeasureMode¶
-
enumerator ExifGpsDop¶
-
enumerator ExifGpsDifferential¶
-
enumerator ExifGpsHPositioningError¶
-
enumerator ExifGpsSatellites¶
-
enumerator ExifGpsMapDatum¶
-
enumerator ExifGpsProcessingMethod¶
-
enumerator ExifGpsAreaInformation¶
-
enumerator None¶
-
enum class MetadataGpsTranslationStatus : uint8_t¶
Values:
-
enumerator Ok¶
-
enumerator NullOutput¶
-
enumerator SourceNotFinalized¶
-
enumerator InvalidOptions¶
-
enumerator AmbiguousSource¶
-
enumerator IncompleteSource¶
-
enumerator InvalidSourceValue¶
-
enumerator ValueOutOfRange¶
-
enumerator UnsupportedPrecision¶
-
enumerator UnsupportedGpsVersion¶
-
enumerator ValueTooLong¶
-
enumerator SourceLimitExceeded¶
-
enumerator NativeConflict¶
-
enumerator EntryLimitExceeded¶
-
enumerator OperationLimitExceeded¶
-
enumerator InternalError¶
-
enumerator Ok¶
-
enum class ExifOrientationStatus : uint8_t¶
Result status for EXIF/TIFF orientation interpretation.
Values:
-
enumerator Ok¶
-
enumerator InvalidArgument¶
-
enumerator Ok¶
-
enum class PhaseOneRawGeometryStatus : uint8_t¶
Values:
-
enumerator Ok¶
-
enumerator MissingField¶
-
enumerator InvalidValue¶
-
enumerator OutOfBounds¶
-
enumerator Ok¶
-
enum class PhaseOneRawProcessingStatus : uint8_t¶
Values:
-
enumerator Ok¶
-
enumerator MissingField¶
-
enumerator InvalidValue¶
-
enumerator Partial¶
-
enumerator Ok¶
-
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.
-
enumerator Ok¶
-
enum class PhotoshopIrbStringCharset : uint8_t¶
Charset policy for legacy 8-bit Photoshop IRB text payloads.
Values:
-
enumerator Latin¶
-
enumerator Ascii¶
-
enumerator Latin¶
-
enum class PreparedTransferHandoffCode : uint16_t¶
Stable result code for prepared-transfer handoff operations.
Values:
-
enumerator None¶
-
enumerator NullOutput¶
-
enumerator RawCarrierPassthroughUnsupported¶
-
enumerator AllocationFailed¶
-
enumerator PrepareFailed¶
-
enumerator OperationCompilationFailed¶
-
enumerator InvalidState¶
-
enumerator NullOperationView¶
-
enumerator OperationIndexOutOfRange¶
-
enumerator NullReplayCallback¶
-
enumerator ReplayCallbackFailed¶
-
enumerator None¶
-
enum class PreparedTransferHandoffPatchCode : uint16_t¶
Stable result code for fixed-width instance patches.
Values:
-
enumerator None¶
-
enumerator NullInstance¶
-
enumerator NullFieldView¶
-
enumerator InvalidState¶
-
enumerator EmptyUpdates¶
-
enumerator InvalidField¶
-
enumerator DuplicateField¶
-
enumerator SlotNotFound¶
-
enumerator InvalidSlot¶
-
enumerator WidthMismatch¶
-
enumerator ValueAliasesInstance¶
-
enumerator LimitExceeded¶
-
enumerator None¶
-
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.
-
enumerator ExifJpegInterchange¶
-
enum class PreviewScanStatus : uint8_t¶
Status for preview candidate discovery.
Values:
-
enumerator Ok¶
-
enumerator OutputTruncated¶
-
enumerator Unsupported¶
-
enumerator Malformed¶
-
enumerator LimitExceeded¶
-
enumerator Ok¶
-
enum class PreviewExtractStatus : uint8_t¶
Status for preview extraction.
Values:
-
enumerator Ok¶
-
enumerator OutputTruncated¶
-
enumerator Malformed¶
-
enumerator LimitExceeded¶
-
enumerator Ok¶
-
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.
-
enumerator Ok¶
-
enum class RandomAccessIoCode : uint8_t¶
Status returned directly by a host-provided positional read callback.
Values:
-
enumerator Ok¶
-
enumerator IoError¶
-
enumerator SourceChanged¶
-
enumerator Cancelled¶
-
enumerator Ok¶
-
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¶
-
enumerator Ok¶
-
enum class ValidateStatus : uint8_t¶
Top-level validation status for validate_file.
Values:
-
enumerator Ok¶
-
enumerator OpenFailed¶
-
enumerator TooLarge¶
-
enumerator ReadFailed¶
-
enumerator Ok¶
-
enum class ValidateIssueSeverity : uint8_t¶
Validation issue severity.
Values:
-
enumerator Warning¶
-
enumerator Error¶
-
enumerator Warning¶
-
enum class MetadataValidationStatus : uint8_t¶
Stable result status for detached metadata entry/store validation.
Values:
-
enumerator Ok¶
-
enumerator InvalidArgument¶
-
enumerator InvalidMetadata¶
-
enumerator LimitExceeded¶
-
enumerator Ok¶
-
enum class MetadataUnknownTagPolicy : uint8_t¶
Policy for EXIF/TIFF tags not present in the built-in standard schema table.
Values:
-
enumerator Allow¶
-
enumerator Warning¶
-
enumerator Error¶
-
enumerator Allow¶
-
enum class MetadataValidationIssueCode : uint16_t¶
Stable detached metadata validation issue code.
Values:
-
enumerator None¶
-
enumerator StoreNotFinalized¶
-
enumerator InvalidEntryId¶
-
enumerator StoreLimitExceeded¶
-
enumerator ValueLimitExceeded¶
-
enumerator InvalidKey¶
-
enumerator InvalidOrigin¶
-
enumerator InvalidValueShape¶
-
enumerator ScalarOutOfRange¶
-
enumerator RationalDenominatorZero¶
-
enumerator InvalidText¶
-
enumerator InvalidWireType¶
-
enumerator InvalidWireCount¶
-
enumerator WrongIfd¶
-
enumerator WrongType¶
-
enumerator WrongCount¶
-
enumerator DuplicateSingleton¶
-
enumerator InvalidXmpNamespace¶
-
enumerator InvalidXmpPropertyPath¶
-
enumerator UnknownExifTag¶
-
enumerator ImageContextMismatch¶
-
enumerator InconsistentRelatedEntries¶
-
enumerator IssueLimitExceeded¶
-
enumerator None¶
-
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¶
-
enumerator Sony¶
-
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¶
-
enumerator None¶
-
enum class XmpDecodeStatus : uint8_t¶
XMP decode result status.
Values:
-
enumerator Ok¶
-
enumerator OutputTruncated¶
-
enumerator Unsupported¶
-
enumerator Malformed¶
-
enumerator LimitExceeded¶
-
enumerator Ok¶
-
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.
-
enumerator Malformed¶
-
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.
-
enumerator CurrentBehavior¶
-
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.
-
enumerator KnownPortableOnly¶
-
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.
-
enumerator PreserveAll¶
-
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.
-
enumerator Ok¶
-
enum class XmpSidecarFormat : uint8_t¶
Sidecar format selection for dump_xmp_sidecar.
Values:
-
enumerator Lossless¶
-
enumerator Portable¶
-
enumerator Lossless¶
Functions
-
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,AnalogBalanceCalibrationIlluminant*
-
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
persistedwhen 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_indexto identify the logical stream to extract and, when applicable, gathers additional parts fromblocksto reassemble it.Supported reassembly:
Multi-part logical streams with ContainerBlockRef::part_count > 1
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
blocksare relative tosource. 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 intoout_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_mrw(std::span<const std::byte> bytes, std::span<ContainerBlockRef> out) noexcept¶
Scans at most 65,536 Minolta MRW metadata segments and their embedded TTW TIFF payloads. A larger segment count is malformed.
-
ScanResult measure_scan_mrw(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 withinmetaboxes.
-
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 readingmdatpayloads.- 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 or a validated private-table field context. Compatibility policy may also 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:
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.
-
ExifTiffSerializeResult serialize_exif_tiff(const MetaStore &store, std::span<std::byte> output, const ExifTiffSerializeOptions &options = ExifTiffSerializeOptions{}) noexcept¶
Serialize an unwrapped little-endian TIFF/EXIF byte stream.
Output begins with the TIFF
IIheader. It never includes anExif\0\0preamble, JPEG APP1 framing, or a boxed-container EXIF offset prefix. Call once with an empty span to measure, then provide a span ofneededbytes. Repeated calls for an immutable finalized store are deterministic and safe to run concurrently.
-
const char *exif_tiff_serialize_status_name(ExifTiffSerializeStatus status) noexcept¶
-
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
stringattribute per block and target part0.
-
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:
MetaKeyKind::ExrAttribute (
part_index+ attribute name)typed MetaValue for common scalar/vector/matrix EXR types
raw MetaValueKind::Bytes for unknown/complex EXR types
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:
MetaKeyKind::IccHeaderField entries for common header fields (typed when interpretation is stable: signature/u32/u64/s15Fixed16 arrays)
MetaKeyKind::IccTag entries (tag signature -> raw tag bytes)
-
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
falsefor 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 aDirty | Deletedtombstone 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::updatedincludes 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:
MetaKeyKind::IptcDataset (record + dataset id)
MetaValueKind::Bytes (raw dataset payload)
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:
MetaKeyKind::JumbfField for structural fields
MetaKeyKind::JumbfCborKey for decoded CBOR keys/values
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.flipconvention.Supported exact mappings are:
EXIF
1-> LibRaw0EXIF
3-> LibRaw3EXIF
6-> LibRaw6EXIF
8-> LibRaw5
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->14->35->87->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.flipvalue back into EXIF/TIFF orientation space.Supported exact mappings are:
LibRaw
0-> EXIF1LibRaw
3-> EXIF3LibRaw
5-> EXIF8LibRaw
6-> EXIF6
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:0x0112XMP
tiff:Orientationassumed default EXIF orientation
1if 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
editstobaseand 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
testare present inflags.
-
MetaKeyView make_exif_tag_key_view(std::string_view ifd, uint16_t tag) noexcept¶
Creates a borrowed key for an EXIF/TIFF tag within a named IFD token.
-
MetaKeyView make_iptc_dataset_key_view(uint16_t record, uint16_t dataset) noexcept¶
Creates a borrowed key for one IPTC-IIM record/dataset pair.
-
MetaKeyView make_xmp_property_key_view(std::string_view schema_ns, std::string_view property_path) noexcept¶
Creates a borrowed key for one URI-qualified XMP property path.
-
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_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_xmp_property_key(ByteArena &arena, std::string_view schema_ns, std::string_view property_path)¶
-
MetaKey make_photoshop_irb_field_key(ByteArena &arena, uint16_t resource_id, 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.
-
MetaValueView make_value_view_u8(uint8_t value) noexcept¶
-
MetaValueView make_value_view_i8(int8_t value) noexcept¶
-
MetaValueView make_value_view_u16(uint16_t value) noexcept¶
-
MetaValueView make_value_view_i16(int16_t value) noexcept¶
-
MetaValueView make_value_view_u32(uint32_t value) noexcept¶
-
MetaValueView make_value_view_i32(int32_t value) noexcept¶
-
MetaValueView make_value_view_u64(uint64_t value) noexcept¶
-
MetaValueView make_value_view_i64(int64_t value) noexcept¶
-
MetaValueView make_value_view_f32_bits(uint32_t bits) noexcept¶
-
MetaValueView make_value_view_f64_bits(uint64_t bits) noexcept¶
-
MetaValueView make_value_view_urational(uint32_t numer, uint32_t denom) noexcept¶
-
MetaValueView make_value_view_srational(int32_t numer, int32_t denom) noexcept¶
-
MetaValueView make_value_view_bytes(std::span<const std::byte> bytes) noexcept¶
-
MetaValueView make_value_view_text(std::string_view text, TextEncoding encoding) noexcept¶
-
MetaValueView make_value_view_array(MetaElementType elem_type, std::span<const std::byte> raw_elements, uint32_t element_count) noexcept¶
-
MetadataAuthoringResult create_metadata_store(std::span<const MetadataAuthoringEntry> entries, MetaStore *output, const MetadataAuthoringOptions &options = MetadataAuthoringOptions{}) noexcept¶
Build a finalized detached store from borrowed typed entries.
Authorable key families are EXIF/TIFF tags, XMP properties, and IPTC-IIM datasets. Unknown/private EXIF tags and custom XMP namespace URIs are accepted without registry changes. All borrowed keys and values are copied. The output store is replaced only after the complete request passes resource, structural, and enabled schema validation.
-
const char *metadata_authoring_status_name(MetadataAuthoringStatus status) noexcept¶
-
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_storeis 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¶
-
MetadataTypedEditingResult edit_metadata_typed(const MetaStore &base, std::span<const MetadataTypedEditingOperation> operations, MetaStore *output, const MetadataTypedEditingOptions &options = MetadataTypedEditingOptions{}) noexcept¶
Applies ordered EXIF/TIFF, IPTC and XMP edits to a detached candidate. Every supplied value and the complete result are validated. Set retains entry identity, source block/order and flags, but replaces wire hints with those supplied for the new value; default hints request inferred encoding. Add creates an entry without source-block provenance. Remove ignores value and wire hints, retains a dirty tombstone, and fails for a missing target. Output, including an aliased base/output, is replaced only on success. This is a bounded preparation operation that allocates, not patch replay.
-
const char *metadata_typed_editing_status_name(MetadataTypedEditingStatus 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
kMetadataFuzzySearchMaxQueryBytesandkMetadataFuzzySearchMaxCandidateBytes.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)¶
-
uint32_t metadata_patch_contract_version() noexcept¶
-
const char *metadata_patch_code_name(MetadataPatchCode code) noexcept¶
-
MetadataPatchResult prepare_metadata_patch_plan(const MetaStore &store, std::span<const MetadataPatchRequest> requests, const MetadataPatchPlanOptions &options, std::span<MetadataPatchHandle> handles, PreparedMetadataPatchPlan *out_plan) noexcept¶
The host supplies a fresh options.plan_id for each successful preparation. On failure both the output plan and every output handle remain unchanged.
-
MetadataPatchResult create_prepared_metadata_patch_instance(const PreparedMetadataPatchPlan &plan, PreparedMetadataPatchInstance *out_instance) noexcept¶
Creates a worker without modifying the plan or existing output on failure.
-
MetadataPatchResult patch_prepared_metadata_instance(PreparedMetadataPatchInstance *instance, std::span<const MetadataPatchUpdate> updates) noexcept¶
Validate the complete batch before writing either payload. All errors leave every payload byte unchanged. XMP validation includes UTF-8, XML characters, and the exact escaped width. Input payloads may not alias either destination. Input views and values must remain immutable for the duration of this call.
-
MetadataPatchResult replay_prepared_metadata_instance(const PreparedMetadataPatchInstance &instance, MetadataPatchReplayCallback callback, void *user) noexcept¶
Replay existing payloads in EXIF, XMP order without allocation or mutation. A false callback stops replay; prior callback effects belong to the caller. Callbacks must not reset, move, destroy or patch the instance during replay.
-
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:MakerNotevalue 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 bounded implementation recognizes canonical Nikon type 1 notes, whose offsets depend on the outer TIFF, Nikon type 3 notes containing an embedded TIFF at byte 10, and Canon raw-IFD notes when Canon source-make evidence is present. Canon offset selection depends on original source-container context and therefore remains ambiguous after extraction. 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 morejpeg:app11-jumbfprepared 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-*whereNin [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 materializationtiff: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 profilejxl:box-exif->Exifjxl:box-xml->xmljxl:box-jumb->jumbjxl: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->EXIFwebp:chunk-xmp->XMPwebp:chunk-iccp->ICCPwebp: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->eXIfpng:chunk-xmp->iTXtpng: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->Exifjp2:box-xml->xmljp2:box-jp2h-colr->jp2hcarrying onecolrICC 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-> EXRstringheader 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->Exifitem payloadbmff:item-xmp->mimeitem carrying XMPbmff:item-jumb->jumbitem payloadbmff:item-c2pa->c2paitem payloadbmff:property-colr-icc->colrproperty payload withprofICC 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.
formatmust 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_pathsreports requested or format-specific enrichment paths that are not represented by discovered payload blocks. A nonzero value keeps the usable result but makescomplete()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
neededand writes the prefix that fits inout. 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
optionsand replacesout_snapshotonly 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 -> preparewith 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
requestby combining preserved source ranges fromtarget_inputwith prepared target carrier chunks frombundle.
-
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
bundleand 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 manyintegrations.
-
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 -> writeworkflows. 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 -> emitintegrations 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.
AutoselectsInPlacewhen all emitted payloads can replace existing leading JPEG metadata segments with exact size match; otherwise it selectsMetadataRewrite.
-
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. ForMetadataRewrite, 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¶
-
MetadataDateTranslationResult translate_xmp_creation_dates(const MetaStore &source, const MetadataDateTranslationOptions &options, MetaStore *out_store)¶
Translate exact standard XMP creation-date properties into native EXIF/IPTC entries.
The source store is immutable and the output is replaced only after every selected mapping parses and reconciles successfully. Parsing accepts only a full Gregorian
YYYY-MM-DDdate with optionalTfollowed byhh:mm:ss, up to nine fractional digits, andZor+/-HH:MMtimezone.EXIF projection requires a time and preserves fractions and timezone through SubSecTime* and OffsetTime* companion tags. It emits Dirty|Deleted intents for absent timestamp companions, including when the native key is missing; the lexical fraction and timezone control companion presence. An accepted exact EXIF timestamp group also marks clean active members Dirty to carry the projection authority. Those SetValue operations count as entries_updated and against max_operations. PreserveExisting leaves an active group untouched. IPTC projection supports date only or whole seconds with an optional timezone; fractional seconds return UnsupportedPrecision rather than being truncated. Exact source-property namespaces are required, and duplicate eligible sources are ambiguous.
Calls keep no global state and are safe when each call owns its output store.
-
const char *metadata_date_translation_status_name(MetadataDateTranslationStatus status) noexcept¶
-
const char *metadata_date_translation_mapping_name(MetadataDateTranslationMapping mapping) noexcept¶
-
MetadataTechnicalTranslationResult translate_xmp_technical_metadata(const MetaStore &source, const MetadataTechnicalTranslationOptions &options, MetaStore *out_store)¶
Translate exact standard XMP/TIFF technical properties into EXIF.
Supported mappings are xmp:ModifyDate, tiff:Make, tiff:Model, and xmp:CreatorTool. ModifyDate requires a full time and preserves up to nine fractional digits and a timezone through SubSecTime and OffsetTime. It emits Dirty|Deleted intents for absent timestamp companions, including when the native key is missing; lexical fraction and timezone control companion presence. An accepted exact ModifyDate EXIF group also marks clean active timestamp members Dirty to carry the projection authority. Those SetValue operations count as entries_updated and against max_operations. Text mappings require non-empty 7-bit ASCII without embedded NUL bytes.
Each mapping reconciles independently. The source store is immutable and the output is replaced only after every selected mapping and resource limit succeeds. Exact namespaces and property paths are required, and duplicate eligible sources are ambiguous.
-
const char *metadata_technical_translation_status_name(MetadataTechnicalTranslationStatus status) noexcept¶
-
const char *metadata_technical_translation_mapping_name(MetadataTechnicalTranslationMapping mapping) noexcept¶
-
MetadataTechnicalTranslationResult translate_xmp_camera_text_metadata(const MetaStore &source, const MetadataCameraTextTranslationOptions &options, MetaStore *out_store)¶
Translate six independent camera/lens/spectral text fields atomically.
Exact exif:SpectralSensitivity and exifEX:CameraOwnerName, BodySerialNumber, LensMake, LensModel and LensSerialNumber map to their ExifIFD ASCII tags. The five exifEX fields also accept historical OpenMeta exif namespace aliases. Inputs must be nonempty printable ASCII (0x20..0x7e), stored as ASCII or UTF-8 text. No trimming, Unicode conversion, identity inference or spectral grammar interpretation is performed. Eligible duplicates and structured/indexed forms fail. Missing or disabled sources retain native fields; dirty tombstones remove selected fields under ReplaceExisting. Native equivalence requires ASCII/UTF-8 Text with matching bytes, ignoring native terminal NUL bytes. For LensMake, LensModel, and LensSerialNumber, an accepted owner deletion records Dirty|Deleted intent when the native key is absent. Accepted exact clean native values are marked Dirty with their original text and wire provenance. These updates and added intents count against the call budgets.
Each field has its own conflict decision and result group; the entire call commits once, including aliased source/output. Preparation may allocate.
-
MetadataCaptureTranslationResult translate_xmp_exif_text_metadata(const MetaStore &source, const MetadataExifTextTranslationOptions &options, MetaStore *out_store)¶
Translate exif:ExifVersion, FlashpixVersion and UserComment, plus ten exifEX text properties, in one transaction. UserComment accepts a scalar or x-default language alternative; other languages remain in XMP. Versions are exactly four digits; FlashpixVersion supports 0100. Text is XML-valid ASCII/UTF-8 without a BOM or embedded NUL, with whitespace preserved. ASCII text uses TIFF type 2; non-ASCII uses EXIF type 129. The seven EXIF 3 text tags and type 129 require an explicit effective ExifVersion >= 0300. Photographer/ImageEditor require native IFD0 Artist; software-detail tags require native IFD0 Software. No values are inferred. UserComment uses ASCII, EXIF 3 UNICODE/UTF-8, or legacy UNICODE/UTF-16LE with a BOM according to the effective version. Version edits must preserve the interpretation of an existing comment or explicitly replace/remove it. Under FailOnConflict and ReplaceExisting, exact clean native matches are promoted with a same-value update that keeps their raw bytes, value encoding, wire hints, endian flag and provenance; this includes ASCII text stored as TIFF type 129. PreserveExisting retains active native values without promotion, and dirty exact matches remain unchanged. Under a ReplaceExisting version-family downgrade, a matching UserComment is re-encoded and a selected ASCII owner/lens type-129 value is rewritten as type 2; unselected type-129 and EXIF 3 text values still block a legacy downgrade.
A complete selected deletion preserves active native values under PreserveExisting, conflicts under FailOnConflict, and removes them under ReplaceExisting. If no active native value exists, the translator carries a Dirty|Deleted intent even when the native key is absent. It promotes a clean deletion marker when one exists, leaves an existing dirty marker unchanged, or adds a typed marker (Text for text tags, Bytes/U8 for versions and UserComment). Source masks, duplicate handling and bounded preparation keep the capture contract rules. Clean promotions count as updates and operations; new markers count as additions and operations. Omitted or disabled sources leave native metadata untouched, and output is unchanged on failure. Hosts synchronize conflicting access to shared stores.
-
MetadataCaptureTranslationResult translate_xmp_capture_additional_metadata(const MetaStore &source, const MetadataCaptureAdditionalTranslationOptions &options, MetaStore *out_store)¶
Translate exif:FocalLengthIn35mmFilm (or FocalLengthIn35mmFormat), FileSource and SceneType transactionally. Focal length is a SHORT in millimetres, with zero meaning unknown. FileSource codes 0..3 and SceneType code 1 are stored as UNDEFINED count 1, not TIFF BYTE. XMP accepts scalar integers or decimal integer text. No labels, units, rounding or camera-model inference is used. Duplicate aliases and non-scalar paths fail. Dirty tombstones, conflicts, budgets and aliased output follow the capture translation contract. Accepted exact clean native values gain Dirty while retaining native code bytes, flags and wire provenance. Complete eligible deletion retains Dirty+Deleted intent for absent keys. PreserveExisting retains an active owner without promotion; omission and ineligible sources preserve the destination. Intent, promotion and duplicate removals consume existing preflight budgets. Repeated calls reuse intent; the host synchronizes shared objects.
-
MetadataCaptureTranslationResult translate_xmp_environment_metadata(const MetaStore &source, const MetadataEnvironmentTranslationOptions &options, MetaStore *out_store)¶
Translate six scalar exifEX environment properties transactionally. Legacy exif namespace aliases are accepted, but duplicate eligible aliases fail. Temperature (degrees C), WaterDepth (metres) and CameraElevationAngle (degrees) use SRATIONAL. Humidity (percent), Pressure (hPa) and Acceleration (mGal, 10^-5 m/s^2) use RATIONAL. Finite elevation is in [-180, 180). No additional physical range or unit conversion is imposed.
Typed rationals, integers, exact decimal/scientific or fraction text are supported. Raw denominator 0xffffffff means unknown; signed fields use -1. The sentinel is recognized before reduction and preserves its numerator. Text “Unknown” uses numerator zero; signed sentinel text accepts n/-1 or n/4294967295. Other finite denominators must be positive. Finite input that would reduce to the reserved denominator fails. No float approximation. Dirty tombstones, conflicts, budgets and aliased output follow the capture contract. Accepted exact clean native values gain Dirty while retaining raw rational components, unknown numerator/denominator bits, flags and provenance. Complete eligible deletion retains Dirty+Deleted intent even for absent native keys. PreserveExisting keeps active owners without promotion; omission and ineligible sources preserve the destination. Intent, promotions and duplicate removals consume existing preflight budgets; repeat calls reuse intent. Each call is one transaction; shared-object access is host-owned.
-
MetadataCaptureTranslationResult translate_xmp_image_encoding_metadata(const MetaStore &source, const MetadataImageEncodingTranslationOptions &options, MetaStore *out_store)¶
Translate Gamma and CompressedBitsPerPixel as exact nonnegative RATIONALs, and ComponentsConfiguration as four UNDEFINED bytes with codes 0..6. Gamma accepts exifEX and legacy exif; the other two use exif. Components accept a typed unsigned array or four dense one-based indexed properties. The host asserts correspondence to the encoded pixels. No channel reorder, gamma application, compression measurement or pixel inference occurs. Existing target-image transfer filtering remains applicable. Accepted exact clean native values gain Dirty while retaining their rational components, byte spans, flags and wire provenance. Eligible deletion records typed Dirty|Deleted intent for absent native fields. Promotion, deletion intent and duplicate removal use the existing preflight limits; repeated calls reuse intent. PreserveExisting retains active owners, while omission and ineligible sources leave destination fields unchanged. Host synchronization remains external.
-
MetadataCaptureTranslationResult translate_xmp_composite_metadata(const MetaStore &source, const MetadataCompositeTranslationOptions &options, MetaStore *out_store)¶
Reconcile CompositeImage and its two companions as one bounded transaction. Canonical sources use exifEX and the full EXIF property names; legacy exif and ExifTool CompositeImageCount/CompositeImageExposureTimes aliases are explicit alternatives. Mixing aliases for one field fails.
CompositeImage is 0..3; companions require 2 or 3, and 3 requires both. Counts are total >=2 and used ==0 (unavailable) or 2..total. Exposure times use the CIPA structure: seven summary rationals, NumberOfSequences, optional NumberOfImagesInSequences and dense Values. The list contains m*n values, bounded by max_exposure_values, and agrees with the total count when present. Summary 0/0 means unavailable; m=0 omits n and Values. Finite values are exact nonnegative seconds; no totals, extrema or exposure models are inferred.
Any selected member selects the complete source group, including clean companions. Missing native companions are removed only by ReplaceExisting. A deleted CompositeImage with absent/deleted companions removes the group. New A462 byte payloads are little-endian; decoded big-endian bytes retain their raw content and EntryFlags::ValueBigEndian provenance. Typed Set with wire hints resets that flag for the newly supplied little-endian payload. Contract 2 promotes accepted exact clean native group values to Dirty while retaining their raw values, byte order, flags and wire provenance. Complete eligible deletion creates or reuses typed Dirty|Deleted intent for absent group members. Under ReplaceExisting, valid code 0 or 1, and code 2 with an omitted optional companion, also creates or reuses intent for that absent companion. Existing companion values are removed in the same transaction. PreserveExisting retains an active group without promotion; omission and ineligible sources leave it unchanged. Promotion, intent and duplicate removal consume the existing preflight limits. Repeated calls reuse intent; host synchronization remains external.
-
MetadataCaptureTranslationResult translate_xmp_structured_capture_metadata(const MetaStore &source, const MetadataStructuredCaptureTranslationOptions &options, MetaStore *out_store)¶
Translate exif:OECF, SpatialFrequencyResponse, CFAPattern and DeviceSettingDescription together, with independent field conflict policies. Each selected structure requires positive SHORT Columns/Rows and dense Values. OECF/SFR also require one ASCII Names item per column and rows*columns exact signed/unsigned rationals. CFA requires rows*columns codes 0..6. Device settings are ordered UTF-8 text; display dimensions do not determine their count. Text must be representable in XML 1.0, without embedded NULs.
Columns is canonical; the published CIPA spelling Columus is an explicit alternative for OECF/SFR. Mixed aliases or root/child representations fail. Numeric Values may be typed arrays; text arrays use dense indexed children. A root Bytes value supplies a validated little-endian native payload instead. Any eligible member selects the complete structure, including clean siblings. An exact native byte payload promotes matching clean native entries to Dirty while retaining their bytes, ValueBigEndian flag and wire origin. An all-deleted structure removes active native values and creates or reuses a typed Dirty|Deleted native intent when no active value exists. Repeated calls reuse that intent. Partial shapes and late malformed sources fail atomically. PreserveExisting retains active native fields; omitted mappings and ineligible sources cause no edits.
New payload headers/rationals use little-endian. Device strings each have a UTF-16LE BOM and terminator. Decoded bytes retain their original content and ValueBigEndian provenance; string BOMs determine their own byte order. Promotion, absent deletion intents and duplicate removal use the existing max_added_entries and max_operations limits. Existing column, value, text and payload limits also apply. Preparation may allocate. Hosts synchronize conflicting object access.
-
MetadataCaptureTranslationResult translate_xmp_development_correction_metadata(const MetaStore &source, const MetadataDevelopmentCorrectionTranslationOptions &options, MetaStore *out_store)¶
-
MetadataCaptureTranslationResult translate_xmp_learning_opt_out_in_metadata(const MetaStore &source, const MetadataLearningOptOutInTranslationOptions &options, MetaStore *out_store)¶
-
MetadataCaptureTranslationResult translate_xmp_profile_metadata(const MetaStore &source, const MetadataProfileTranslationOptions &options, MetaStore *out_store)¶
-
MetadataCaptureTranslationResult translate_xmp_apex_metadata(const MetaStore &source, const MetadataApexTranslationOptions &options, MetaStore *out_store)¶
Translate five scalar exif-namespace APEX properties in one transaction.
ShutterSpeedValue, BrightnessValue and ExposureBiasValue use SRATIONAL; ApertureValue and MaxApertureValue use nonnegative RATIONAL, including zero. ExposureCompensation is an alias for ExposureBiasValue. All values are direct APEX units, never seconds or f-numbers. No ExposureTime/FNumber inference or cross-field exposure consistency check is performed.
Scalar integers, the target rational type, and exact decimal/scientific or fraction text are supported. Denominators must be positive. Brightness text “Unknown” or an explicit signed fraction with numerator -1 denotes unknown, as does a typed SRational with numerator -1. Other brightness inputs are finite; a reduced -1/n is encoded as -2/(2n), or rejected if it cannot fit. New/replaced unknown values use -1/1; equivalent native scalars retain their encoding. No floating-point approximation is used.
Each enabled field reconciles independently. Duplicate eligible aliases and indexed/structured source shapes fail. Accepted dirty tombstones carry native Dirty+Deleted intent even when the source native key is absent. Omission preserves the destination. Accepted clean exact native values gain Dirty without changing their scalar or wire provenance. Added intents and same-value updates count against budgets before publication; repeat calls reuse them. The capture ExposureCompensation mapping owns the same bias singleton; disable one bias mapping when composing these calls. Limits and conflicts precede all mutation, including aliased output. Preparation may allocate; shared-object access and aggregate publication are host-owned.
-
MetadataCaptureTranslationResult translate_xmp_capture_spatial_metadata(const MetaStore &source, const MetadataCaptureSpatialTranslationOptions &options, MetaStore *out_store)¶
Translate focal-plane resolution and subject arrays in one transaction.
FocalPlaneXResolution, FocalPlaneYResolution and FocalPlaneResolutionUnit in the exif namespace form one complete group. Resolutions are positive exact unsigned rationals; units are 2/inches or 3/cm. No default unit is inferred. SubjectArea is a U16 array of two (point), three (circle) or four (rectangle) values. SubjectLocation has two U16 coordinates. Each array is independent. Root U16 arrays or dense indexed integer/text members [1]..[N] are accepted. Coordinates and dimensions are preserved, including zero; no rotation, cropping, image-size validation or relationship between arrays is inferred.
One eligible dirty member selects its whole group, including clean active companions. Duplicate, sparse, qualified and mixed root/indexed shapes fail. A root tombstone or complete deleted group carries Dirty+Deleted native intent even when the native keys are absent; partial deletion fails. Omission retains the destination. Conflicts apply to each whole group. Accepted clean exact native values gain Dirty through same-value updates that retain value and wire provenance. PreserveExisting retains any active native group without promotion. New intents, promotions and duplicate removals consume the existing budgets; repeated calls reuse intent without growing history. Results count three logical groups and up to five native entries. Bounds and all validation precede mutation, including aliased output. Preparation may allocate; synchronization of shared objects is the host’s responsibility.
-
MetadataCaptureTranslationResult translate_xmp_identity_metadata(const MetaStore &source, const MetadataIdentityTranslationOptions &options, MetaStore *out_store)¶
Translate lens specification and image identity in one transaction.
exifEX:LensSpecification (or historical exif alias) accepts one four-element URational array or four dense [1]..[4] scalar properties. One dirty member selects the complete lens group, including clean companions. Numeric text accepts exact integer, decimal, scientific and fraction forms. Focal lengths must be positive and ordered; apertures must be positive or exactly 0/0 for unknown. Values are reduced to unsigned 32-bit rational components. exif:ImageUniqueID accepts exactly 32 ASCII hex characters as ASCII/UTF-8 Text. Case and leading zeros are retained; identity is never generated or inferred.
Duplicate aliases, mixed root/indexed forms and incomplete arrays fail. A dirty root tombstone or four deleted members removes the lens group; partial member deletion fails. The image ID uses a scalar tombstone. Complete eligible deletion retains Dirty+Deleted intent for absent native keys. Accepted exact clean natives gain Dirty while retaining native lens components, unknown markers, ID case/NUL and wire provenance. PreserveExisting keeps an active owner without promotion; omission preserves the destination. Intent, promotion and duplicate-removal costs precede publication and repeated calls reuse intent. Shared-object synchronization belongs to the host. Conflict and resource checks precede all mutations, including aliased output. Preparation may allocate. This is a structural translation contract, not validation of UUID generation, uniqueness or capture-time identity policy.
-
MetadataCaptureTranslationResult translate_xmp_capture_metadata(const MetaStore &source, const MetadataCaptureTranslationOptions &options, MetaStore *out_store)¶
Translate exact standard or OpenMeta-portable XMP capture properties into native EXIF scalar fields.
Unsigned rational sources accept typed scalar values or full decimal, scientific-decimal, integer, and
numerator/denominatortext. Focal length additionally accepts the portablemmsuffix. Exposure compensation uses a signed rational. ISO is restricted to one integer in the EXIF SHORT range. Text conversion is exact after rational reduction; values that cannot fit the native EXIF representation fail rather than being approximated.Portable
ISOandExposureCompensationaliases and standardISOSpeedRatingsandExposureBiasValuepaths target the same singleton; multiple eligible aliases are ambiguous. Each mapping reconciles independently and the output is replaced only after every selected mapping and resource limit succeeds. For ExposureTime, FNumber, base ISO, FocalLength and exposure compensation, accepted deletion records Dirty|Deleted intent even when the native key is absent. Accepted exact clean native scalars are marked Dirty without changing their value or wire provenance. These updates and intents count against the call budgets. ExposureCompensation and ExposureBiasValue share this singleton lifecycle with the APEX bias mapping; disable one bias mapping when composing the two translators.
-
const char *metadata_capture_translation_status_name(MetadataCaptureTranslationStatus status) noexcept¶
-
const char *metadata_capture_translation_mapping_name(MetadataCaptureTranslationMapping mapping) noexcept¶
-
MetadataCaptureTranslationResult translate_xmp_capture_settings_metadata(const MetaStore &source, const MetadataCaptureSettingsTranslationOptions &options, MetaStore *out_store)¶
Translate twelve exact exif-namespace camera-setting properties to native SHORT singletons using the capture transaction and conflict contract.
Accepts scalar integers, unsigned decimal integer text, and exact existing OpenMeta labels for the documented closed code sets. SceneCaptureType also accepts portable “Night scene”. Unknown codes, signs in text, floating point, rational/array values, qualifiers, and coercion are excluded. ExposureProgram is limited to 0..8; the read-only Bulb extension is not a writeback code. No exposure, white-balance, rendering, or sensor-state inference is performed. Each enabled setting owns one independent native field. Accepted dirty tombstones carry native Dirty+Deleted intent even when the source native key is absent; omission preserves the destination. Accepted clean exact native values gain Dirty while retaining scalar and wire provenance. Intent and same-value update costs precede publication; repeat calls reuse them. Preparation may allocate. Failure leaves source and output unchanged.
-
MetadataCaptureTranslationResult translate_xmp_capture_rational_metadata(const MetaStore &source, const MetadataCaptureRationalTranslationOptions &options, MetaStore *out_store)¶
Translate four exact unsigned capture rationals atomically.
Accepts scalar integers, unsigned rationals, and exact decimal/scientific or fraction text. SubjectDistance zero means unknown; a wire numerator of UINT32_MAX means infinity. Exact Unknown/Infinity labels are also accepted. Decimal/scientific finite distances that would encode the infinity sentinel fail. DigitalZoomRatio zero means unused; ExposureIndex must be positive; FlashEnergy may be zero. Zero denominators and floating-point values fail. No units, APEX values, flash state, or EXIF versions are inferred or converted. Older TIFF/EP aliases are not targets. Complete eligible deletion retains Dirty+Deleted native intent even for absent keys. Accepted exact clean natives gain Dirty through same-value updates that retain rational components and wire provenance. PreserveExisting retains active owners without promotion; omission preserves the destination. Intent, promotion and duplicate-removal costs count against existing limits; repeat calls reuse intent. Hosts synchronize shared objects. Preparation may allocate; failure leaves source and output unchanged, including aliased calls.
-
MetadataCaptureTranslationResult translate_xmp_flash_metadata(const MetaStore &source, const MetadataFlashTranslationOptions &options, MetaStore *out_store)¶
Write one complete ExifIFD Flash SHORT without inferring missing bits.
Accepts either scalar exif:Flash (integer or exact OpenMeta label), or all five structured Fired, Function, Mode, RedEyeMode, and Return children. Function true means no flash function. One dirty child selects the complete active group in DirtyOnly mode. A dirty scalar tombstone or five dirty child tombstones removes the native tag; partial groups/deletion and competing shapes fail. Reserved high bits and Return code 1 fail. No physical-state consistency or exposure/FlashEnergy inference is performed. An accepted owner deletion records Dirty|Deleted intent when the native key is absent. An accepted exact clean native value is marked Dirty without changing its scalar or wire provenance; these changes count against the resource limits. All conflicts and resource checks precede one atomic transaction. Preparation may allocate.
-
MetadataCaptureTranslationResult translate_xmp_light_source_metadata(const MetaStore &source, const MetadataLightSourceTranslationOptions &options, MetaStore *out_store)¶
Translate one exact exif:LightSource to ExifIFD 0x9208 SHORT.
Accepts scalar integers or unsigned decimal integer text for codes 0..4, 9..34, and 255. Exact unique OpenMeta labels and the explicit aliases Tungsten and Cloudy weather are accepted. Daylight is ambiguous between codes 1 and 25 and fails even if native metadata could supply a preferred interpretation. No white-balance, Flash, illuminant, color-temperature or version inference is performed. Missing sources retain native values; dirty tombstones remove them under ReplaceExisting. All changes are atomic and preparation may allocate.
-
MetadataCaptureTranslationResult translate_xmp_sensitivity_metadata(const MetaStore &source, const MetadataSensitivityTranslationOptions &options, MetaStore *out_store)¶
Translate one complete seven-tag EXIF sensitivity group.
Accepts exact exifEX properties PhotographicSensitivity, SensitivityType, StandardOutputSensitivity, RecommendedExposureIndex, ISOSpeed, ISOSpeedLatitudeyyy and ISOSpeedLatitudezzz. Legacy OpenMeta exif:ISO and companion names, and single-member exif:ISOSpeedRatings, are accepted aliases. Duplicate aliases are ambiguous. Values are unsigned integer scalars or decimal integer text. PhotographicSensitivity is 1..65535, SensitivityType is 0..7, and optional LONG companions are 1..UINT32_MAX.
Active groups require PhotographicSensitivity and SensitivityType. Supplied parameters selected by the type must agree, with values >=65535 represented by 65535 in the SHORT. Latitude values require both latitude tags and ISOSpeed. Missing optional sources mean absent target members. A validated sparse group records Dirty|Deleted intent for each absent native member; a base-property dirty tombstone selects all seven tags for deletion. PreserveExisting preserves any active group; FailOnConflict accepts an absent or exact group and rejects active mismatches. Accepted exact clean native scalars are marked Dirty without changing their values or wire provenance. Intents and updates count against the shared operation and entry limits. No type, high-range value, exposure setting or EXIF version is inferred. All seven tags share one result group and one transaction; cold preparation may allocate.
-
MetadataGeometryTranslationResult translate_xmp_image_geometry(const MetaStore &source, const TransferTargetImageSpec &target_image_spec, const MetadataGeometryTranslationOptions &options, MetaStore *out_store)¶
Translate exact XMP image geometry into target-bound native EXIF.
Active orientation and dimension sources must exactly match the corresponding host-supplied target facts. Width and height are stored-raster dimensions; they are never swapped according to display orientation. The dimension group emits canonical IFD0 ImageWidth/ImageLength and ExifIFD PixelXDimension/PixelYDimension LONG values. Orientation emits one IFD0 Orientation SHORT.
Standard and OpenMeta-portable dimension aliases may coexist only when they agree. Duplicate exact properties, incomplete active/deleted dimension pairs, missing target facts, and source/target mismatches fail transactionally.
-
const char *metadata_geometry_translation_status_name(MetadataGeometryTranslationStatus status) noexcept¶
-
const char *metadata_geometry_translation_mapping_name(MetadataGeometryTranslationMapping mapping) noexcept¶
-
MetadataDescriptiveTranslationResult translate_xmp_descriptive_metadata(const MetaStore &source, const MetadataDescriptiveTranslationOptions &options, MetaStore *out_store)¶
Translate exact standard XMP descriptive properties into IPTC-IIM.
Supported mappings are dc:title, dc:description, dc:creator, dc:subject, dc:rights, photoshop:Credit, and photoshop:Source. Default-language singleton paths and indexed creator/subject items are required exactly. Repeated values retain XMP index order.
IPTC-IIM dataset byte limits are enforced without truncation. Non-ASCII UTF-8 adds CodedCharacterSet ESC % G only when existing active IPTC bytes are ASCII or are replaced by this transaction; otherwise the call fails with NativeEncodingConflict. The output is replaced only after all selected mappings and resource limits succeed.
-
const char *metadata_descriptive_translation_status_name(MetadataDescriptiveTranslationStatus status) noexcept¶
-
const char *metadata_descriptive_translation_mapping_name(MetadataDescriptiveTranslationMapping mapping) noexcept¶
-
MetadataDescriptiveTranslationResult translate_xmp_location_metadata(const MetaStore &source, const MetadataLocationTranslationOptions &options, MetaStore *out_store)¶
Translate flat IPTC Core XMP location properties into native IPTC-IIM.
Exact mappings are photoshop:City, Iptc4xmpCore:Location, photoshop:State, photoshop:Country, and Iptc4xmpCore:CountryCode. Country codes require two or three uppercase ASCII letters; code membership and country-name agreement are caller responsibilities. Text byte limits and UTF-8 charset safety use the same transaction as descriptive translation. Duplicate active singleton sources are ambiguous. Structured locations and GPS are not aliases.
Policies, status, mapping diagnostics, and counters use the descriptive translation types. At most five datasets and one charset entry are added. The immutable source and output are unchanged on failure.
-
MetadataDescriptiveTranslationResult translate_xmp_structured_location_metadata(const MetaStore &source, const MetadataStructuredLocationTranslationOptions &options, MetaStore *out_store)¶
Reconcile five text fields from one explicit structured location into flat legacy XMP and native IPTC-IIM in a single atomic transaction.
Exact Iptc4xmpExt LocationShown[n] or LocationCreated[n] records are selected. The existing scalar LocationCreated resource form is accepted as index one. Created and Shown never fall back to each other. Multiple records require an explicit index. GPS, nested Address fields, names, IDs, and WorldRegion are retained but not projected. No record is merged with another record.
City, Sublocation, ProvinceState, CountryName, and CountryCode use the flat location text limits and charset policy. Each flat XMP/native IPTC pair is one conflict group. PreserveExisting retains both if either exists; missing structured fields are untouched. Dirty field tombstones remove both under ReplaceExisting. Structure/array tombstones are not field-removal requests. Counters include both destinations and any UTF-8 marker. Failure leaves source and output unchanged; preparation may allocate. Existing APIs are unchanged.
-
MetadataDescriptiveTranslationResult translate_xmp_location_to_structured_metadata(const MetaStore &source, const MetadataLocationCreationTranslationOptions &options, MetaStore *out_store)¶
Copy five exact flat legacy XMP location fields into one explicitly selected IPTC Extension LocationShown or LocationCreated record.
Uses the flat location text limits and exact country-code contract. Native IPTC is not an implicit source. Missing fields retain destinations; dirty leaf tombstones remove selected leaves under ReplaceExisting. Unrelated fields and records remain untouched. No geographic or Created/Shown inference.
Created permits index one only. Shown permits an existing record or append at the next dense index, bounded by 1024. Sparse/mixed or opaque container shapes fail. Removing an entire non-last record fails to prevent reindexing. Existing scalar Created resources retain their shape; new records use the indexed Bag form. All selected fields commit atomically; preparation may allocate.
-
MetadataDescriptiveTranslationResult translate_xmp_editorial_metadata(const MetaStore &source, const MetadataEditorialTranslationOptions &options, MetaStore *out_store)¶
Translate exact Photoshop XMP editorial properties into IPTC-IIM.
Headline maps to 2:105 (256 bytes), Instructions to 2:40 (256 bytes), and TransmissionReference to 2:103 (32 bytes). All are singleton text properties. Limits count UTF-8 bytes and never truncate. Title, description, rights, and other identifiers are not aliases for these properties.
Policies, status, diagnostics, and counters use the descriptive translation types. Duplicate active sources are ambiguous. Dirty deletions remove native groups only with ReplaceExisting. Charset safety and resource limits use the same transaction as descriptive translation. At most three datasets and one charset entry are added. The source and output are unchanged on failure.
-
MetadataDescriptiveTranslationResult translate_xmp_iptc_metadata(const MetaStore &source, const MetadataIptcTranslationOptions &options, MetaStore *out_store)¶
Translate 20 XMP text/priority groups into IPTC-IIM atomically.
Includes the descriptive, location, and editorial mappings, plus Photoshop AuthorsPosition (2:85, 32 bytes), CaptionWriter (2:122, 32 bytes), Category (2:15, one to three ASCII letters), indexed SupplementalCategories (2:20, 32 bytes each), and Urgency (2:10, one digit from 1 to 8). Urgency also accepts a signed or unsigned integer scalar in that range. Repeated values retain numeric XMP index order and duplicates at distinct indexes.
Source selection, conflicts, dirty removal, provenance, byte/resource limits, and charset safety share one transaction across all selected groups. Date fields use translate_xmp_creation_dates separately. The caller associates AuthorsPosition with the first creator; this operation does not infer that relationship or create a missing creator. Existing subgroup APIs are unchanged.
-
MetadataGpsTranslationResult translate_xmp_gps_metadata(const MetaStore &source, const MetadataGpsTranslationOptions &options, MetaStore *out_store)¶
Atomically translate primary exif:GPSLatitude, GPSLongitude, and GPSAltitude/GPSAltitudeRef XMP properties into native gpsifd entries.
Coordinates accept unsigned degrees plus decimal minutes or integer minutes plus decimal seconds, separated by commas and followed by uppercase N/S or E/W. Output is exact normalized DMS RATIONAL[3] plus ASCII reference. Altitude is nonnegative exact text/integer/rational with a required XMP sea-level reference 0 or 1. GPS 2.4 uses native sea-level codes 2 or 3; GPS 2.0 through 2.3 use 0 or 1. No ellipsoid/datum conversion is performed.
One dirty altitude member selects the complete active pair. Removing the altitude group requires both members to be dirty tombstones. Native groups reconcile as complete pairs. GPSVersionID is retained, or 2.3.0.0 is added when selected active output needs it. Removing the last GPS value also removes its version tag; unrelated GPS fields prevent that cleanup.
Contract 2 carries Dirty+Deleted intent for accepted absent native members. Accepted exact clean values gain Dirty without changing their native encoding. These additions and same-value updates consume the existing resource limits; repeated calls reuse intent. Omitted source groups preserve destination fields. All five GPS translators share these ownership rules. TIFF destination merges retain GPSVersionID while any destination GPS value remains.
Failure leaves source and output unchanged. Preparation may allocate.
Atomically translate GPS time, speed, track, and image direction.
GPSTimeStamp requires a complete ISO date/time with an explicit timezone. Numeric offsets are normalized to UTC; fractional seconds stay exact. Output is GPSDateStamp plus GPSTimeStamp RATIONAL[3]. Leap seconds and partial dates/times are unsupported. Date output requires GPS 2.2 through 2.4; a missing native version defaults to 2.3.0.0.
Speed/track/image direction require their complete XMP value/reference pair. Values use the primary GPS exact unsigned rational syntax. Angles are in [0, 359.99]. Canonical K/M/N and T/M references, plus the existing portable aliases km/h, mph, knots, True North, and Magnetic North, are accepted. Units and north references are retained without conversion or inference.
Source selection, paired conflicts/removal, version cleanup, provenance, and failure atomicity follow the primary GPS contract. That API’s options and mapping set are unchanged. Preparation may allocate.
-
MetadataGpsTranslationResult translate_xmp_gps_destination_metadata(const MetaStore &source, const MetadataGpsDestinationTranslationOptions &options, MetaStore *out_store)¶
Atomically translate destination GPS coordinates, bearing, and distance.
GPSDestLatitude/Longitude use the primary GPS exact coordinate syntax. GPSDestBearing and GPSDestDistance each require their complete XMP reference/value pair. Bearing is in [0, 359.99], with T/M or the portable True North/Magnetic North aliases. Distance is an exact unsigned rational, with K/M/N units (kilometers, miles, nautical miles). Kilometers, Miles, and Nautical miles are accepted aliases. Historical portable Knots also means N distance; it never requests a speed or unit conversion.
No position, bearing, distance, datum, or north reference is inferred or converted. Source selection, paired conflicts/removal, version cleanup, provenance, limits, and failure atomicity follow the primary GPS contract. Existing primary and navigation APIs are unchanged. Preparation may allocate.
-
MetadataGpsTranslationResult translate_xmp_gps_quality_metadata(const MetaStore &source, const MetadataGpsQualityTranslationOptions &options, MetaStore *out_store)¶
Atomically write receiver status, mode, DOP, correction, and accuracy.
GPSStatus accepts A/V or Measurement Active/Measurement Void. Measure mode accepts integer 2/3 or their exact text forms. Differential accepts integer 0/1, their text forms, or No Correction/Differential Corrected. DOP and horizontal error use exact nonnegative rational syntax; horizontal error is in meters. Differential requires GPS 2.2 through 2.4; horizontal error requires GPS 2.3 through 2.4. Versions are never inferred from source XMP or upgraded; missing native versions default to 2.3.0.0.
Each source is independent. One dirty tombstone removes its native field. Selection, conflict policy, version cleanup, provenance, limits, and failure atomicity follow the primary GPS contract. Preparation may allocate.
-
MetadataGpsTranslationResult translate_xmp_gps_text_metadata(const MetaStore &source, const MetadataGpsTextTranslationOptions &options, MetaStore *out_store)¶
Atomically write satellite, datum, processing-method, and area text.
Satellites/datum require ASCII. Method/area accept valid UTF-8 and write UNDEFINED with ASCII or UNICODE prefixes; Unicode output uses UTF-16LE BOM. Empty text is a value. NUL/control characters and malformed UTF-8 fail. Native equivalence recognizes ASCII and BOM-marked UTF-16, optionally with one terminator. JIS, unknown prefixes, and BOM-less Unicode are not guessed. Method/area require GPS 2.2 through 2.4; missing versions default to 2.3.0.0. No datum conversion or processing/receiver-state inference is performed. Singleton selection, removal, conflict, version, and atomicity follow the quality GPS contract. Preparation may allocate.
-
const char *metadata_gps_translation_status_name(MetadataGpsTranslationStatus status) noexcept¶
-
const char *metadata_gps_translation_mapping_name(MetadataGpsTranslationMapping mapping) 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:nameform 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
5reports mirror + 270 degrees clockwise. Invalid values return0and setout_validto 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 return0.
-
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:
MetaKeyKind::PhotoshopIrb (resource id)
MetaValueKind::Bytes (raw resource payload)
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¶
-
std::string_view prepared_transfer_handoff_code_name(PreparedTransferHandoffCode code) noexcept¶
Stable token for one prepared-transfer handoff result code.
-
std::string_view prepared_transfer_handoff_code_message(PreparedTransferHandoffCode code) noexcept¶
Stable default message for one prepared-transfer handoff result code.
-
std::string_view prepared_transfer_handoff_patch_code_name(PreparedTransferHandoffPatchCode code) noexcept¶
Stable token for one prepared-transfer instance patch result code.
-
std::string_view prepared_transfer_handoff_patch_code_message(PreparedTransferHandoffPatchCode code) noexcept¶
Stable default message for one instance patch result code.
-
uint32_t prepared_transfer_handoff_contract_version() noexcept¶
Returns the prepared-transfer handoff version compiled into the library.
-
uint32_t prepared_transfer_handoff_instance_contract_version() noexcept¶
Returns the mutable instance contract version compiled into the library.
-
PreparedTransferHandoffResult prepare_transfer_handoff(const TransferSourceSnapshot &snapshot, const PrepareTransferRequest &request, const EmitTransferOptions &emit_options, PreparedTransferHandoff *out_handoff) noexcept¶
Prepare immutable target payloads and typed operations once.
On failure,
out_handoffis unchanged. Stable v1 deliberately rejects opt-in raw-carrier passthrough because that policy remains experimental.
-
PreparedTransferHandoffResult prepared_transfer_handoff_operation(const PreparedTransferHandoff &handoff, uint32_t operation_index, PreparedTransferHandoffOperationView *out_operation) noexcept¶
Resolve one operation without allocation or route parsing by the host.
-
PreparedTransferHandoffResult replay_prepared_transfer_handoff(const PreparedTransferHandoff &handoff, PreparedTransferHandoffReplayCallback callback, void *user) noexcept¶
Replay immutable typed operation views without recompilation or allocation.
-
PreparedTransferHandoffResult create_prepared_transfer_handoff_instance(const PreparedTransferHandoff &handoff, PreparedTransferHandoffInstance *out_instance) noexcept¶
Clone one independently owned mutable worker instance.
Creation may allocate. On failure,
out_instanceis unchanged. The new instance does not borrow the source handoff and remains valid after the source is reset, moved, prepared again, or destroyed.
-
PreparedTransferHandoffPatchResult prepared_transfer_handoff_instance_time_patch_field(const PreparedTransferHandoffInstance &instance, TimePatchField field, PreparedTransferHandoffTimePatchFieldView *out_field) noexcept¶
Query the exact serialized width and slot count for one field.
The query performs no allocation and exposes no payload offsets. It fails if the field is absent or its prepared slots do not have one uniform nonzero width, because one strict patch value could not update such a layout.
-
PreparedTransferHandoffPatchResult patch_prepared_transfer_handoff_instance(PreparedTransferHandoffInstance *instance, std::span<const TimePatchView> updates) noexcept¶
Apply one strict fixed-width patch batch transactionally.
Every field must be valid, unique, and have at least one prepared slot. Every value must exactly match every corresponding slot width and must not alias instance payload storage. Validation completes before any payload byte changes. Successful and failed calls perform no allocation.
-
PreparedTransferHandoffResult prepared_transfer_handoff_instance_operation(const PreparedTransferHandoffInstance &instance, uint32_t operation_index, PreparedTransferHandoffOperationView *out_operation) noexcept¶
Resolve one mutable-instance operation without allocation.
-
PreparedTransferHandoffResult replay_prepared_transfer_handoff_instance(const PreparedTransferHandoffInstance &instance, PreparedTransferHandoffReplayCallback callback, void *user) noexcept¶
Replay mutable-instance operations without recompilation or allocation.
-
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/JPEGInterchangeFormatLengthpairsJpgFromRawandJpgFromRaw2byte blobsCanon 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
storecontaining MetaKeyKind::PrintImField entries. The original EXIF tag should still be preserved separately by the EXIF/TIFF decoder.Field naming:
versionfor the header version (ASCII, 4 bytes)0xNNNNfor 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:
EXIF/TIFF-IFD tags (decode_exif_tiff) from:
JPEG/PNG/WebP/etc. EXIF blocks
TIFF/DNG containers (whole file treated as a TIFF-IFD stream)
ISO-BMFF containers (HEIF/AVIF/CR3) Exif items
ICC profiles (decode_icc_profile)
Photoshop IRB / 8BIM resources (decode_photoshop_irb)
IPTC-IIM dataset streams (decode_iptc_iim)
OpenEXR header attributes (decode_exr_header)
JUMBF / C2PA payloads (decode_jumbf_payload)
XMP packets (decode_xmp_packet)
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-sidecarequivalent)DNG/CCM query/validation issues (
collect_dng_ccm_fields)
-
MetadataValidationResult validate_entry(const MetaStore &store, EntryId entry, const MetadataValidationOptions &options = MetadataValidationOptions{}) noexcept¶
Validate one entry in a detached store without modifying it.
-
MetadataValidationResult validate_store(const MetaStore &store, const MetadataValidationOptions &options = MetadataValidationOptions{}) noexcept¶
Validate structural, schema, duplicate, and optional image relationships.
-
const char *metadata_validation_status_name(MetadataValidationStatus status) noexcept¶
-
const char *metadata_validation_issue_code_name(MetadataValidationIssueCode code) noexcept¶
-
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:
MetaKeyKind::XmpProperty (
schema_nsURI +property_path)MetaValueKind::Text (UTF-8)
Duplicate properties are preserved. The six camera/lens/spectral ASCII writeback properties retain leading/trailing XML-decoded whitespace in their exact standard or supported legacy namespaces. Other text retains the existing ASCII-whitespace trimming behavior.
-
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:
selects format via XmpSidecarOptions::format,
grows output buffer automatically on XmpDumpStatus::OutputTruncated,
returns final bytes in
out(trimmed to XmpDumpResult::written on success).
-
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 kExifTiffSerializeContractVersion = 1U¶
Stable canonical TIFF/EXIF serialization 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.
-
constexpr uint32_t kMetadataAuthoringContractVersion = 1U¶
Stable generic typed authoring contract version.
-
constexpr uint32_t kInvalidMetadataAuthoringEntry = 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¶
-
constexpr uint32_t kMetadataTypedEditingContractVersion = 1U¶
-
constexpr uint32_t kMetadataTypedEditingUniqueOccurrence = 0xfffffffeU¶
-
constexpr uint32_t kMetadataTypedEditingMaxOperations = 4096U¶
-
static constexpr uint32_t kMetadataFuzzySearchMaxResults = 256U¶
-
static constexpr uint32_t kMetadataFuzzySearchMaxQueryBytes = 256U¶
-
static constexpr uint32_t kMetadataFuzzySearchMaxCandidateBytes = 1024U¶
-
constexpr uint32_t kMetadataPatchContractVersion = 1U¶
-
constexpr uint32_t kMaxPreparedMetadataPatchHandles = 65534U¶
-
constexpr uint64_t kMaxMetadataPatchPlanId = 0x0000FFFFFFFFFFFFULL¶
-
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 kMetadataDateTranslationContractVersion = 2U¶
Experimental XMP creation-date translation contract version.
-
constexpr uint32_t kMetadataDateTranslationMaxAddedEntries = 16U¶
Hard limit for native entries added by one date-translation call.
-
constexpr uint32_t kMetadataDateTranslationMaxOperations = 1024U¶
-
constexpr uint32_t kMetadataTechnicalTranslationContractVersion = 2U¶
Experimental reverse technical-EXIF translation contract version.
-
constexpr uint32_t kMetadataTechnicalTranslationMaxAddedEntries = 6U¶
-
constexpr uint32_t kMetadataTechnicalTranslationMaxOperations = 1024U¶
-
constexpr uint32_t kMetadataTechnicalTranslationMaxTextBytesPerProperty = 4096U¶
-
constexpr uint64_t kMetadataTechnicalTranslationMaxTotalTextBytes = 16ULL * 1024ULL¶
-
constexpr uint32_t kMetadataCameraTextTranslationContractVersion = 2U¶
Experimental camera/lens/spectral ASCII writeback contract.
-
constexpr uint32_t kMetadataCameraTextTranslationMaxAddedEntries = 6U¶
-
constexpr uint64_t kMetadataCameraTextTranslationMaxTotalTextBytes = 24576U¶
-
constexpr uint32_t kMetadataCaptureTranslationContractVersion = 3U¶
Experimental reverse capture-EXIF translation contract version.
-
constexpr uint32_t kMetadataCaptureTranslationMaxAddedEntries = 5U¶
-
constexpr uint32_t kMetadataCaptureTranslationMaxOperations = 1024U¶
-
constexpr uint32_t kMetadataCaptureTranslationMaxTextBytesPerProperty = 128U¶
-
constexpr uint64_t kMetadataCaptureTranslationMaxTotalTextBytes = 640U¶
-
constexpr uint32_t kMetadataExifTextTranslationContractVersion = 2U¶
Bounded EXIF text/version translation contract.
-
constexpr uint32_t kMetadataExifTextTranslationMaxAddedEntries = 13U¶
-
constexpr uint32_t kMetadataExifTextTranslationMaxTextBytesPerProperty = 65536U¶
-
constexpr uint64_t kMetadataExifTextTranslationMaxTotalTextBytes = 1048576U¶
-
constexpr uint32_t kMetadataCaptureAdditionalTranslationContractVersion = 2U¶
-
constexpr uint32_t kMetadataCaptureAdditionalTranslationMaxAddedEntries = 3U¶
-
constexpr uint64_t kMetadataCaptureAdditionalTranslationMaxTotalTextBytes = 384U¶
-
constexpr uint32_t kMetadataEnvironmentTranslationContractVersion = 2U¶
-
constexpr uint32_t kMetadataEnvironmentTranslationMaxAddedEntries = 6U¶
-
constexpr uint64_t kMetadataEnvironmentTranslationMaxTotalTextBytes = 768U¶
-
constexpr uint32_t kMetadataImageEncodingTranslationContractVersion = 2U¶
Experimental image-encoding metadata contract; these calls do not alter pixels.
-
constexpr uint32_t kMetadataImageEncodingTranslationMaxAddedEntries = 3U¶
-
constexpr uint64_t kMetadataImageEncodingTranslationMaxTotalTextBytes = 768U¶
-
constexpr uint32_t kMetadataCompositeTranslationContractVersion = 2U¶
-
constexpr uint32_t kMetadataCompositeTranslationMaxAddedEntries = 3U¶
-
constexpr uint32_t kMetadataCompositeTranslationMaxExposureValues = 4096U¶
-
constexpr uint64_t kMetadataCompositeTranslationMaxTotalTextBytes = 1024ULL * 1024ULL¶
-
constexpr uint32_t kMetadataStructuredCaptureTranslationContractVersion = 2U¶
-
constexpr uint32_t kMetadataStructuredCaptureTranslationMaxAddedEntries = 4U¶
-
constexpr uint32_t kMetadataStructuredCaptureTranslationMaxColumns = 256U¶
-
constexpr uint32_t kMetadataStructuredCaptureTranslationMaxValues = 4096U¶
-
constexpr uint32_t kMetadataStructuredCaptureTranslationMaxTextBytesPerProperty = 4096U¶
-
constexpr uint64_t kMetadataStructuredCaptureTranslationMaxTotalTextBytes = 1024ULL * 1024ULL¶
-
constexpr uint32_t kMetadataStructuredCaptureTranslationMaxPayloadBytes = 1024U * 1024U¶
-
constexpr uint32_t kMetadataDevelopmentCorrectionTranslationContractVersion = 2U¶
EXIF 3.1 development and correction writeback contract version.
-
constexpr uint32_t kMetadataDevelopmentCorrectionTranslationMaxAddedEntries = 6U¶
-
constexpr uint32_t kMetadataDevelopmentCorrectionTranslationMaxTextBytesPerProperty = 65536U¶
-
constexpr uint64_t kMetadataDevelopmentCorrectionTranslationMaxTotalTextBytes = 1048576ULL¶
-
constexpr uint32_t kMetadataLearningOptOutInTranslationContractVersion = 2U¶
Experimental bounded EXIF 3.1 LearningOptOutIn translation contract.
-
constexpr uint32_t kMetadataLearningOptOutInTranslationMaxSets = 64U¶
-
constexpr uint32_t kMetadataLearningOptOutInTranslationMaxAddedEntries = 1U¶
-
constexpr uint32_t kMetadataProfileTranslationContractVersion = 1U¶
Experimental bounded profile/authoring translation contract.
-
constexpr uint32_t kMetadataProfileTranslationMaxAddedEntries = 5U¶
-
constexpr uint32_t kMetadataProfileTranslationMaxTextBytesPerProperty = 65536U¶
-
constexpr uint64_t kMetadataProfileTranslationMaxTotalTextBytes = 1048576U¶
-
constexpr uint32_t kMetadataApexTranslationContractVersion = 2U¶
-
constexpr uint32_t kMetadataApexTranslationMaxAddedEntries = 5U¶
-
constexpr uint64_t kMetadataApexTranslationMaxTotalTextBytes = 640U¶
-
constexpr uint32_t kMetadataCaptureSpatialTranslationContractVersion = 2U¶
-
constexpr uint32_t kMetadataCaptureSpatialTranslationMaxAddedEntries = 5U¶
-
constexpr uint64_t kMetadataCaptureSpatialTranslationMaxTotalTextBytes = 1152U¶
-
constexpr uint32_t kMetadataIdentityTranslationContractVersion = 2U¶
-
constexpr uint32_t kMetadataIdentityTranslationMaxAddedEntries = 2U¶
-
constexpr uint64_t kMetadataIdentityTranslationMaxTotalTextBytes = 544U¶
-
constexpr uint32_t kMetadataCaptureSettingsTranslationContractVersion = 2U¶
Experimental closed-enum capture-settings translation contract.
-
constexpr uint32_t kMetadataCaptureSettingsTranslationMaxAddedEntries = 12U¶
-
constexpr uint64_t kMetadataCaptureSettingsTranslationMaxTotalTextBytes = 1536U¶
-
constexpr uint32_t kMetadataCaptureRationalTranslationContractVersion = 2U¶
Experimental exact capture-rational writeback contract.
-
constexpr uint32_t kMetadataCaptureRationalTranslationMaxAddedEntries = 4U¶
-
constexpr uint64_t kMetadataCaptureRationalTranslationMaxTotalTextBytes = 512U¶
-
constexpr uint32_t kMetadataFlashTranslationContractVersion = 2U¶
Experimental complete Flash-bitfield writeback contract.
-
constexpr uint32_t kMetadataFlashTranslationMaxAddedEntries = 1U¶
-
constexpr uint32_t kMetadataFlashTranslationMaxSourceProperties = 16U¶
-
constexpr uint64_t kMetadataFlashTranslationMaxTotalTextBytes = 640U¶
-
constexpr uint32_t kMetadataLightSourceTranslationContractVersion = 1U¶
Experimental unambiguous LightSource writeback contract.
-
constexpr uint32_t kMetadataLightSourceTranslationMaxAddedEntries = 1U¶
-
constexpr uint64_t kMetadataLightSourceTranslationMaxTotalTextBytes = 128U¶
-
constexpr uint32_t kMetadataSensitivityTranslationContractVersion = 2U¶
Experimental complete sensitivity-group writeback contract.
-
constexpr uint32_t kMetadataSensitivityTranslationMaxAddedEntries = 7U¶
-
constexpr uint64_t kMetadataSensitivityTranslationMaxTotalTextBytes = 896U¶
-
constexpr uint32_t kMetadataGeometryTranslationContractVersion = 1U¶
Experimental target-bound image-geometry translation contract version.
-
constexpr uint32_t kMetadataGeometryTranslationMaxAddedEntries = 5U¶
-
constexpr uint32_t kMetadataGeometryTranslationMaxOperations = 1024U¶
-
constexpr uint32_t kMetadataGeometryTranslationMaxTextBytesPerProperty = 32U¶
-
constexpr uint64_t kMetadataGeometryTranslationMaxTotalTextBytes = 160U¶
-
constexpr uint32_t kMetadataDescriptiveTranslationContractVersion = 1U¶
Experimental reverse descriptive-metadata translation contract version.
-
constexpr uint32_t kMetadataDescriptiveTranslationMaxSourceProperties = 1024U¶
-
constexpr uint32_t kMetadataDescriptiveTranslationMaxAddedEntries = 1025U¶
-
constexpr uint32_t kMetadataDescriptiveTranslationMaxOperations = 4096U¶
-
constexpr uint64_t kMetadataDescriptiveTranslationMaxTotalTextBytes = 8ULL * 1024ULL * 1024ULL¶
-
constexpr uint32_t kMetadataLocationTranslationContractVersion = 1U¶
Experimental reverse IPTC Core location translation contract version.
-
constexpr uint32_t kMetadataLocationTranslationMaxAddedEntries = 6U¶
-
constexpr uint32_t kMetadataStructuredLocationTranslationContractVersion = 1U¶
Experimental structured location to flat XMP and IPTC reconciliation.
-
constexpr uint32_t kMetadataStructuredLocationTranslationMaxAddedEntries = 11U¶
-
constexpr uint32_t kMetadataLocationCreationTranslationContractVersion = 1U¶
Experimental flat-XMP-to-structured-location construction contract.
-
constexpr uint32_t kMetadataLocationCreationTranslationMaxAddedEntries = 5U¶
-
constexpr uint32_t kMetadataLocationCreationTranslationMaxIndex = 1024U¶
-
constexpr uint32_t kMetadataEditorialTranslationContractVersion = 1U¶
Experimental reverse IPTC editorial translation contract version.
-
constexpr uint32_t kMetadataEditorialTranslationMaxAddedEntries = 4U¶
-
constexpr uint32_t kMetadataIptcTranslationContractVersion = 1U¶
Experimental combined IPTC text/priority translation contract version.
-
constexpr uint32_t kMetadataIptcTranslationMaxAddedEntries = 1025U¶
-
constexpr uint32_t kMetadataGpsTranslationContractVersion = 2U¶
Experimental primary GPS position/altitude writeback contract.
-
constexpr uint32_t kMetadataGpsTranslationMaxAddedEntries = 7U¶
-
constexpr uint32_t kMetadataGpsTranslationMaxOperations = 1024U¶
-
constexpr uint32_t kMetadataGpsTranslationMaxTextBytesPerProperty = 128U¶
-
constexpr uint64_t kMetadataGpsTranslationMaxTotalTextBytes = 512U¶
-
constexpr uint32_t kMetadataGpsDestinationTranslationContractVersion = 2U¶
-
constexpr uint32_t kMetadataGpsDestinationTranslationMaxAddedEntries = 9U¶
-
constexpr uint64_t kMetadataGpsDestinationTranslationMaxTotalTextBytes = 768U¶
-
constexpr uint32_t kMetadataGpsQualityTranslationContractVersion = 2U¶
-
constexpr uint32_t kMetadataGpsQualityTranslationMaxAddedEntries = 6U¶
-
constexpr uint64_t kMetadataGpsQualityTranslationMaxTotalTextBytes = 640U¶
-
constexpr uint32_t kMetadataGpsTextTranslationContractVersion = 2U¶
-
constexpr uint32_t kMetadataGpsTextTranslationMaxAddedEntries = 5U¶
-
constexpr uint64_t kMetadataGpsTextTranslationMaxTotalTextBytes = 16384U¶
-
constexpr uint32_t kMetadataGpsTextTranslationMaxTextBytesPerProperty = 4096U¶
-
constexpr uint32_t kPreparedTransferHandoffContractVersion = 1U¶
Stable prepared-transfer handoff contract version.
-
constexpr uint32_t kPreparedTransferHandoffInstanceContractVersion = 1U¶
Stable mutable prepared-transfer instance contract version.
-
constexpr uint32_t kRandomAccessSourceContractVersion = 1U¶
Stable allocation-free positional source contract version.
-
constexpr uint32_t kMetadataValidationContractVersion = 1U¶
Stable detached entry/store validation contract version.
-
MetaValue make_text(ByteArena &arena, std::string_view text, TextEncoding encoding)¶
- file api_stability.md
- file canonical_patching.md
- file canonical_serialization.md
- file capture_sync_milestone.md
- file compatibility_dump.md
- file creation.md
- file exr_canonical_value_encoding.md
- file development.md
- file doxygen.md
- file editing.md
- file exif_authoring_inventory.md
- file flat_host_mapping.md
- file fuzzy_search.md
- file generic_authoring.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 migration_0_5.md
- file migration_0_6.md
- file migration_0_7.md
- file migration_0_8.md
- file prepared_transfer_handoff.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 translation.md
- file writer_target_contract.md
- file xmp_sync_policy.md
- file README.md
- file api.h
- 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 “openmeta/interop_export.h”#include “openmeta/metadata_transfer.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 “openmeta/container_scan.h”#include <cstddef>#include <cstdint>#include <span>
Reassembles and optionally decompresses logical metadata payloads.
- file container_scan.h
- #include “openmeta/api.h”#include “openmeta/random_access_source.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 “openmeta/metadata_transfer.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 “openmeta/random_access_source.h”#include <cstddef>#include <cstdint>#include <span>#include <string_view>
Decoder for TIFF-IFD tag streams (used by EXIF and TIFF/DNG).
- file exif_tiff_serialize.h
- #include “openmeta/api.h”#include “openmeta/meta_store.h”#include <cstddef>#include <cstdint>#include <span>
Deterministic target-neutral TIFF/EXIF serialization.
- 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 “openmeta/metadata_transfer.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 “openmeta/random_access_source.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 “openmeta/interop_import.h”#include “openmeta/metadata_transfer.h”#include “openmeta/random_access_source.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/interop_export.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 <cstddef>#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_authoring.h
- #include “openmeta/api.h”#include “openmeta/meta_store.h”#include “openmeta/validate.h”#include <cstdint>#include <span>
Transactional construction of generic typed metadata stores.
- file metadata_capabilities.h
- #include “openmeta/api.h”#include “openmeta/metadata_transfer.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 “openmeta/metadata_query.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 “openmeta/metadata_authoring.h”#include “openmeta/metadata_creation.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 “openmeta/metadata_query.h”#include <cstdint>#include <vector>
Structured metadata interpretation records built from semantic query candidates.
- file metadata_patch.h
- #include “openmeta/api.h”#include “openmeta/exif_tiff_serialize.h”#include “openmeta/meta_key.h”#include “openmeta/meta_value.h”#include “openmeta/xmp_dump.h”#include <cstddef>#include <cstdint>#include <span>
Prepared transactional TIFF/EXIF and scalar XMP payload patching.
- 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/metadata_concepts.h”#include “openmeta/resource_policy.h”#include “openmeta/simple_meta.h”#include “openmeta/vendor_raw_processing.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 metadata_translation.h
- #include “openmeta/api.h”#include “openmeta/meta_store.h”#include <cstdint>
Bounded explicit translation between metadata families.
- file ocio_adapter.h
- #include “openmeta/api.h”#include “openmeta/interop_export.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/iptc_iim_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 prepared_transfer_handoff.h
- #include “openmeta/api.h”#include “openmeta/metadata_transfer.h”#include <cstddef>#include <cstdint>#include <span>#include <string_view>
Stable target preparation and typed codec handoff contract.
- file preview_extract.h
- #include “openmeta/api.h”#include “openmeta/container_scan.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/container_payload.h”#include “openmeta/exif_tiff_decode.h”#include “openmeta/exr_decode.h”#include “openmeta/icc_decode.h”#include “openmeta/iptc_iim_decode.h”#include “openmeta/jumbf_decode.h”#include “openmeta/photoshop_irb_decode.h”#include “openmeta/preview_extract.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/container_payload.h”#include “openmeta/container_scan.h”#include “openmeta/exif_tiff_decode.h”#include “openmeta/exr_decode.h”#include “openmeta/icc_decode.h”#include “openmeta/iptc_iim_decode.h”#include “openmeta/jumbf_decode.h”#include “openmeta/meta_store.h”#include “openmeta/photoshop_irb_decode.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/meta_store.h”#include “openmeta/resource_policy.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.
OpenMeta 0.8.3 retains the unfrozen development ABI label 4. C++ layouts and APIs may change without advancing this label; consumers rebuild against matching release headers and libraries. CMake package discovery permits a newer release within the requested major version; this does not guarantee ABI compatibility. Existing patch/handoff and snapshot v1 contracts retain their versioned guarantees. See the migration guide.
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(...)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.
Prepared Transfer Handoff v1: immutable template preparation/replay plus
PreparedTransferHandoffInstancecreation, exact-width/slot-count field queries, strict fixed-width patches, indexed views, replay, and runtime contract queriesStable v1
Move-only opaque owners hide routes and bundle state. Template preparation and worker creation may allocate. Instance query/patch/index/replay allocate nothing; patch batches are exact-width, required-slot, alias-rejecting, and transactional. Independent instances own their payloads and can run concurrently. Raw-carrier passthrough, variable-width/structural mutation, persistence, and destination editing remain outside v1. See prepared_transfer_handoff.md.
Runtime capability query:
metadata_capability(...)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(...), andcollect_read_transfer_source_diagnostics(...)openmeta/random_access_source.h,openmeta/metadata_transfer.hStable 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 thescan_*_random_access(...)familyopenmeta/exif_tiff_decode.h,openmeta/exr_decode.h,openmeta/container_payload.h,openmeta/container_scan.hExperimental
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(...)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_fieldentries. See compatibility_dump.md.XMP sync and writeback policy enums:
XmpConflictPolicy, existing-carrier precedence enums,XmpWritebackMode, destination carrier modesStable
Stable bounded writer policy for generated portable XMP. See xmp_sync_policy.md.
Generic metadata traversal:
visit_metadata(...),MetadataSink,ExportOptions,ExportItemStable
v1 traversal contract. Borrowed names are valid only during
MetadataSink::on_item(...).ExportNameStyle::CanonicalandExportNameStyle::XmpPortableStable
Stable naming modes for key-space-aware and portable exports.
ExportNameStyle::FlatHostStable
Stable v1 flat host naming contract. See flat_host_mapping.md.
Typed FlatHost import:
import_flat_host_metadata(...)Stable v1
Transactional detached-store reconciliation. Existing values and tombstones use exact source identity or a unique
FlatHostname; duplicate names are rejected, removals retain stable ids/provenance asDirty \| Deleted, and new arbitrary entries require an explicit typedMetaKeyView.Fresh metadata creation:
create_metadata(...)and typed field helpersExperimental
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 Pythoncreate_metadata(...)wrapper. Direct EXIF/IPTC projection remains a Translation concern. See creation.md.Generic typed metadata authoring:
create_metadata_store(...), borrowed key/value helpers, andMetaStore::reserve(...)openmeta/metadata_authoring.h,openmeta/meta_key.h,openmeta/meta_value.h,openmeta/meta_store.hExperimental v1
Transactional bounded construction of finalized EXIF/TIFF/DNG-style, XMP, and IPTC-IIM entries. Unknown/private EXIF and custom XMP namespaces remain authorable; safe scalar/indexed custom XMP is supported. Output is replaced only after enabled validation succeeds. C++ only in this milestone. See generic_authoring.md.
Detached store/schema validation:
validate_entry(...),validate_store(...)Experimental v1
Structured structural and initial TIFF/EXIF/GPS/DNG/XMP schema diagnostics with resource limits, permissive unknown-tag policy, duplicate-singleton checks, rational/text checks, and optional image/CFA/color context. This does not prove that semantically valid metadata describes the destination pixels.
Canonical TIFF/EXIF serialization:
serialize_exif_tiff(...)Experimental v1
Deterministic measure/write API for unwrapped little-endian TIFF bytes. The same payload feeds target transfer wrapping; JPEG/TIFF, PNG/WebP, and boxed EXIF framing remain separate. Opaque MakerNotes drop by default. See canonical_serialization.md.
Prepared TIFF/EXIF and scalar XMP patching:
prepare_metadata_patch_plan(...),PreparedMetadataPatchPlan,PreparedMetadataPatchInstance, andpatch_prepared_metadata_instance(...)Experimental v1
Target-neutral opaque handles for typed EXIF and emitted scalar XMP values. Preparation and worker creation may allocate; mixed EXIF/XMP batches, payload access and library replay do not. Failed batches change neither payload. Handles expose no offsets and belong to one preparation generation. See canonical_patching.md.
Logical metadata editing:
edit_metadata(...)and add/set/remove helpersExperimental
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
Documentwithout mutating its source. See editing.md.Exact-key typed editing:
edit_metadata_typed(...)Experimental v1
Transactional C++ Add/Set/Remove for supported EXIF/IPTC/XMP and private/custom keys, explicit occurrence/conflict handling, updated wire hints, resource ceilings and complete candidate validation. See editing.md.
Reverse creation-date translation:
translate_xmp_creation_dates(...)Experimental
Transactional v2 projection of eligible edited XMP creation dates into exact native EXIF/IPTC date groups. The caller selects mappings, source mode, conflict behavior, and lowered resource limits; lossy precision, malformed dates, duplicate sources, and unresolved conflicts fail without replacing the output. Python exposes the same C++ transaction through a detached
Document. See translation.md.Reverse technical EXIF translation:
translate_xmp_technical_metadata(...)Experimental
Transactional v2 projection of exact
xmp:ModifyDate,tiff:Make,tiff:Model, andxmp:CreatorToolproperties into native EXIF groups. Full ModifyDate precision uses OffsetTime/SubSecTime companions; singleton conflicts, dirty tombstones, ASCII validity, duplicates, and resource limits are explicit. Python remains a thin detached-document wrapper. See translation.md.Reverse capture EXIF translation:
translate_xmp_capture_metadata(...)Experimental
Transactional v2 projection of exposure time, F-number, ISO, focal length, and exposure compensation XMP properties into tag-specific native
RATIONAL,SHORT, andSRATIONALscalars. Exact integer conversion, portable/standard alias ambiguity, dirty tombstones, conflicts, and resource limits are explicit; unrepresentable decimals fail instead of being approximated. Python remains a thin detached-document wrapper. See translation.md.EXIF 3.1 LearningOptOutIn translation:
translate_xmp_learning_opt_out_in_metadata(...)Experimental v1
Bounded transactional projection of the exact
exifEX:LearningOptOutInusage/intention structure into native tag0x9287. The first usage, duplicate usage, complete-shape, explicit 0300/0310 version policy, byte-order provenance, conflicts, tombstones and limits are explicit. Python mirrors the detached-store transaction. See translation.md.Profile authoring translation:
translate_xmp_profile_metadata(...)Experimental v1
Bounded transactional projection of
tiff:ImageDescription,Artist, scalarCopyright,exif:ColorSpaceand printable 8.3RelatedSoundFileinto native EXIF. Text encoding, legacy two-part Copyright conflict behavior, color labels, filename validation, limits and host-owned synchronization are explicit; no ICC/image/audio inference is performed. Python mirrors the detached-store transaction. See translation.md.Target-bound image-geometry translation:
translate_xmp_image_geometry(...)openmeta/metadata_translation.h,openmeta/metadata_transfer.hExperimental
Transactional v1 projection of exact XMP orientation and complete stored-raster dimensions into canonical native TIFF/EXIF
SHORT/LONGgroups. Active values must agree with caller-providedTransferTargetImageSpecfacts; standard/portable aliases, incomplete pairs, dirty tombstones, conflicts, and limits are explicit. Display-oriented dimensions are never inferred or swapped. Python remains a thin detached-document wrapper. See translation.md.Reverse descriptive translation:
translate_xmp_descriptive_metadata(...)Experimental
Transactional v1 projection of exact default-language title/description/rights, indexed creators/keywords, credit, and source into bounded IPTC-IIM datasets. Repeated cardinality, dirty tombstones, byte limits, conflicts, and UTF-8 charset declaration are explicit; unsafe legacy charset reinterpretation fails atomically. Python remains a thin detached-document wrapper. See translation.md.
Reverse location translation:
translate_xmp_location_metadata(...)Experimental
Transactional v1 projection of five flat IPTC Core location properties into native IPTC-IIM. Reuses descriptive policies, statuses, and result diagnostics with separate location options. Exact singleton paths, byte limits, country-code syntax, dirty tombstones, and charset safety are explicit; structured locations and GPS are outside the contract. Python provides the same operation. See translation.md.
Reverse editorial translation:
translate_xmp_editorial_metadata(...)Experimental
Transactional v1 Headline, Instructions, and TransmissionReference writeback with independent editorial options. Reuses descriptive policies/results, exact singleton validation, UTF-8 safety, and resource limits. Python provides the same operation. See translation.md.
Combined IPTC translation:
translate_xmp_iptc_metadata(...)Experimental
Transactional v1 writeback of 20 text/priority groups, adding creator job title, caption writer, category, supplemental categories, and urgency. Independent flags, shared charset/resource limits, and cross-group atomicity. Existing subgroup/date contracts are unchanged. Python provides the same operation. See translation.md.
Structured location reconciliation:
translate_xmp_structured_location_metadata(...)Experimental
Transactional v1 projection of one explicitly selected structured record into five flat XMP/native IPTC pairs. Record kind/index, paired conflicts, dirty leaf removal, text limits, and charset safety are explicit. Python provides the same operation. See translation.md.
Primary GPS translation:
translate_xmp_gps_metadata(...)Experimental
Transactional v1 latitude/longitude and altitude/reference writeback. Exact rational precision, paired source/native reconciliation, GPS version handling, and resource limits are explicit. Python provides the same operation. See translation.md.
GPS time/navigation translation:
translate_xmp_gps_navigation_metadata(...)Experimental
Transactional v1 UTC date/time, speed/unit, track/reference, and image direction/reference writeback. Exact precision, UTC rollover, version support, paired conflicts/removal, and portable reference aliases are explicit. Python provides the same operation. See translation.md.
Destination GPS translation:
translate_xmp_gps_destination_metadata(...)Experimental
Transactional v1 destination coordinates, bearing/reference, and distance/unit writeback. Exact precision, paired conflicts/removal, version retention, and historical distance-label compatibility are explicit. Python provides the same operation. See translation.md.
GPS quality translation:
translate_xmp_gps_quality_metadata(...)Experimental
Transactional v1 status, measurement mode, DOP, differential correction, and horizontal error with explicit enum, precision, version, and removal contracts. Python provides the same operation. See translation.md.
GPS text translation:
translate_xmp_gps_text_metadata(...)Experimental
Transactional v1 satellites, map datum, processing method, and area with explicit ASCII/Unicode encoding, version, conflict, and removal contracts. Python provides the same operation. See translation.md.
LightSource translation:
translate_xmp_light_source_metadata(...)Experimental
One bounded LightSource SHORT with exact code/unique-label selection, ambiguity rejection, typed conflicts and removal. Python provides the same operation. See translation.md.
Sensitivity translation:
translate_xmp_sensitivity_metadata(...)Experimental
Version 2 seven-tag sensitivity group with explicit companions, LONG limits, whole-group conflicts and atomic removal. Independent options preserve existing capture layouts. Python provides the same operation. See translation.md.
Camera/lens/spectral text translation:
translate_xmp_camera_text_metadata(...)Experimental
Version 2 six-field printable-ASCII transaction with bounded lens lifecycle, with exact namespaces, explicit aliases, typed conflicts, bounds and removal. Python provides the same operation. See translation.md.
Flash translation:
translate_xmp_flash_metadata(...)Experimental
Version 2 scalar or five-child Flash writeback with explicit bitfield, conflict, and removal rules. Python provides the same operation. See translation.md.
Capture rational translation:
translate_xmp_capture_rational_metadata(...)Experimental
Four exact unsigned capture rationals with explicit sentinel, precision, conflict, and removal rules. Python provides the same operation. See translation.md.
Capture settings translation:
translate_xmp_capture_settings_metadata(...)Experimental
Twelve closed SHORT camera-setting enums with explicit labels, limits, and atomic conflicts/removal. Python provides the same operation. See translation.md.
Structured location construction:
translate_xmp_location_to_structured_metadata(...)Experimental
Five flat XMP fields into one explicitly selected Created/Shown record, with dense indexes and atomic leaf conflicts/removal. Python provides the same operation. See translation.md.
EXIF/TIFF orientation helpers:
interpret_exif_orientation(...),exif_orientation_name(...),exif_orientation_rotation_degrees_cw(...),exif_orientation_rotation_only(...)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 helpersStable
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
CustomRenderedlabels, Nintendo category labels, Sanyo public-context scalar labels, current Canon RF lens-type labels, current Nikon ZLensData0800LensIDlabels, 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 orfalseand remain lossless metadata.Photoshop IRB decode:
decode_photoshop_irb(...),measure_photoshop_irb(...)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, andGlbC, opaquealisandtdtabyte counts, orderedobjproperty/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.Additional capture and environment translation:
translate_xmp_capture_additional_metadata(...),translate_xmp_environment_metadata(...)Experimental v1
Nine typed native fields, explicit aliases/codes/units, exact rationals and raw unknown-denominator preservation. Two bounded transactions with thin Python wrappers. See translation.md.
Image encoding and composite translation:
translate_xmp_image_encoding_metadata(...),translate_xmp_composite_metadata(...)Experimental v1
Six native fields with exact nonnegative rationals, four component codes, complete composite dependencies and bounded exposure lists. Python mirrors both transactions. Raw big-endian exposure bytes use
EntryFlags::ValueBigEndian; snapshots carrying this flag require 0.5.7 or later. See translation.md.Semantic metadata query:
query_metadata(...),query_crop_metadata(...), and focused query helpersExperimental
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, andfuzzy_scorecompatibility fields. Exact descriptive semantics added after the full legacy 32-bit match-term mask may have zeromatched_terms; their explicit semantic and confidence remain authoritative. Grouped candidates includematrix_set,vector_set, andtableshapes 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 explicitsource_color_transformsemantic, RAW curve/linearity metadata uses dedicated RAW-processing semantics, and computational, thermal, and stitch/panorama fields use explicit source-processing subroles. PythonDocumentandTransferSourceSnapshotmirror this as thin dictionary-returning wrappers.Bounded fuzzy entry search:
fuzzy_search_metadata(...),metadata_fuzzy_search_available()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
DocumentandTransferSourceSnapshotexpose thin dictionary wrappers.Structured metadata interpretation records:
interpret_metadata(...),interpret_metadata_query(...)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
DocumentandTransferSourceSnapshotexpose matching dictionary wrappers.Cross-family concept resolution:
resolve_metadata_concepts(...),resolve_metadata_concept(...)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, andrequires_target_image_specevidence, 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 markedconditional_on_raw_encodinguntil a raw data descriptor can confirm whether they affect the stored samples; descriptor-aware overloads acceptMetadataRawDataDescriptorand can collapse supported stored-RAW descriptors toapplies_to_stored_raw, rendered descriptors tonot_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 EXIFOffsetTime*andSubSecTime*entries are assembled withDateTime*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-scopeGPSDateStampplusGPSTimeStampentries, direct XMPGPSDateTime/GPSDateTimeStampvalues map to the GPS timestamp role, IPTC digital-creation date/time and XMPDateTimeDigitizedmap to theDigitizeddate/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 ExtensionLocationShown/LocationCreatedcoordinates use distinct roles. Structured candidates exposelocation_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. TheDescriptivekind 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 exposerecord_scopeso related names and identifiers remain associated. It is intended for inspection UI and host policy decisions; it does not rewrite metadata or hide ambiguity. PythonDocumentandTransferSourceSnapshotexpose matching dictionary wrappers, including subsecond, location-scope, record-scope, and language fields and the thinMetadataRawDataDescriptorobject 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(...)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 acceptMetadataRawDataDescriptorand make RAW-processing keep/drop decisions reflect the supplied stored-RAW, compressed-only, primary-plane-only, or rendered storage context.PrepareTransferRequest::source_raw_data_descriptorapplies rendered-source RAW filtering and, since 0.5.13, recognized curve/linearity compression and primary-plane restrictions duringprepare_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. PythonDocumentandTransferSourceSnapshotexposetransfer_concept_diagnostics(...)dictionaries withseverity_name,token,message_token,message_arguments,message,location_scope,record_scope,language, and RAW applicability fields, with overloads that accept the thinMetadataRawDataDescriptorobject; Python transfer helpers also acceptsource_raw_data_descriptorfor prepare-time filtering.Vendor RAW-processing summaries:
vendor_raw_processing_from_store(...),classify_vendor_raw_processing_field(...)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(...)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(...)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. It also recognizes plausible Canon source-dependent IFD notes when the EXIF camera make is Canon, but reports their source offset basis as ambiguous and does not mark them rewritable. The writer still cannot reconstruct decoded fields, relocate vendor-private offsets, repair checksums, prove semantic readability, or pass MakerNotes through as raw carriers. Python
DocumentandTransferSourceSnapshotexpose matching thin dictionary wrappers.Raw-carrier passthrough audit:
raw_carrier_passthrough_audit_from_snapshot(...)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:
TransferSourceSnapshotStable 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(...)Experimental
Convenience entry points outside the narrow positional Host Adoption Profile.
Versioned source snapshot persistence:
serialize_transfer_source_snapshot(...),deserialize_transfer_source_snapshot(...)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(...)Experimental
Intended for hosts that already decoded metadata and want to prepare transfer artifacts without reopening the source file.
TransferRawCarrierPassthroughMode::WhenSafeis 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(...)Experimental
Intended for deferred save/writeback from a reusable decoded source snapshot.
Bundle execution:
execute_prepared_transfer_bundle(...)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,kPreparedTransferAdapterContractVersionStable 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. Stable hosts obtain payload and EXR name/type/value views through
PreparedTransferHandoff; 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(...)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 helpersExperimental
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
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, andsensitivityfields. 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 interpretsafeas 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, andpreviewsemantics. 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
tilCversion 0 tile dimensions, up to eight extra dimensions,dref/detimapping, internaltile_item_type/tipaassociations, 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.TiledImageConfigurationremains 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 for read/state compatibility and Prepared Transfer Handoff v1 for stable target preparation, then query format capabilities separately.
The 0.5.8 structured capture batch adds OECF, SpatialFrequencyResponse, CFAPattern and DeviceSettingDescription through
translate_xmp_structured_capture_metadataand its Python counterpart. The 0.5.8 combined inventory was 65 distinct native tags across fifteen APIs (62 retained by compatible-file transfer). ABI 3 and host synchronization remain unchanged; big-endian snapshots for the four new fields need a 0.5.8 reader. See Structured capture data.EXIF text update (0.5.9)¶
The 0.5.9 text/version batch adds UserComment, both version fields and seven EXIF 3 text tags. The new EXIF text API also supports UTF-8 owner/lens fields. The combined capture inventory is 75 distinct ExifIFD tags across sixteen APIs; compatible-file transfer retains 72. Version and Artist/Software companion requirements are explicit. ABI 3, snapshot v1 layout and host synchronization responsibilities remain unchanged. BOM-less big-endian UserComment snapshots require a 0.5.9 reader. See the EXIF text/version translation contract for limits and the recorded OIIO/ExifTool reader limitations.
Standard validation update (0.5.10)¶
The 64 previously unrecognized capture/date/GPS reverse targets now have fixed schemas. Five Interop fields and three structural pointers are also recognized. Malformed known field types, counts and covered values can now fail default authoring, typed editing and canonical serialization. Valid InteroperabilityIndex is accepted despite its numeric ID overlap with GPS. Portable output preserves eligible existing XMP when the corresponding native value fails shared checks.
Public signatures, contract versions, ABI 3, snapshot v1 layout and host-owned synchronization remain unchanged. No mandatory complete-file profile is imposed. See generic validation for scope and limits.
EXIF 3.1 LearningOptOutIn and profile authoring update (0.5.12)¶
The experimental LearningOptOutIn and profile translation contracts are versioned by
kMetadataLearningOptOutInTranslationContractVersion == 1andkMetadataProfileTranslationContractVersion == 1. They preserve ABI 3, snapshot v1 and host-owned synchronization. The contracts are bounded and transactional, but they do not impose mandatory complete-file companions, rewrite arbitrary RDF, infer ICC/image/audio authority, or close downstream OIIO/iRAW acceptance. See translation.md.EXIF 3.1 development and correction update (0.5.11)¶
The experimental
translate_xmp_development_correction_metadatacontract and its Python counterpart add the six EXIF 3.1 development/correction fields A40D–A412. The packed DevelopmentType resource, publishedDevelopmentCharactersticspelling, UTF-8 type-129 description, explicit 0300/0310 host version policy, value bounds and transaction rules are versioned bykMetadataDevelopmentCorrectionTranslationContractVersion == 1. Native schema validation, typed editing, portable output and serialization use the same checks. ABI 3, snapshot v1 and host-owned synchronization remain unchanged. LearningOptOutIn and complete-file profile validation remain outside this contract. See development and correction data.
- page Prepared metadata patching
OpenMeta 0.5.0 provides
openmeta/metadata_patch.hfor unwrapped canonical TIFF/EXIF and portable XMP payloads. One plan can contain either family or both. One update batch validates every requested change before writing either payload.This replaces the pre-0.5
exif_tiff_patch.hAPI. See migration_0_5.md for the source and binary migration.Preparation and worker ownership¶
Prepare after authoring a finalized store. For EXIF, select an exact key, zero-based occurrence and native value shape. For XMP, select the namespace URI and simple property path in the serializer output, plus the exact escaped width.
#include "openmeta/metadata_patch.h" #include <array> std::array<openmeta::MetadataPatchRequest, 2> requests; requests[0].key = openmeta::make_exif_tag_key_view("exififd", 0x9211U); requests[0].expected.kind = openmeta::MetaValueKind::Scalar; requests[0].expected.elem_type = openmeta::MetaElementType::U32; requests[0].expected.count = 1U; requests[1].key = openmeta::make_xmp_property_key_view( "https://example.test/capture/1.0/", "FrameNumber"); requests[1].escaped_width = 10U; // The store already emits ten text bytes. std::array<openmeta::MetadataPatchHandle, 2> handles; openmeta::PreparedMetadataPatchPlan plan; openmeta::MetadataPatchPlanOptions options; options.plan_id = 1U; // Example host-issued ID; use a fresh ID for each preparation. const openmeta::MetadataPatchResult prepared = openmeta::prepare_metadata_patch_plan(store, requests, options, handles, &plan); if (!prepared.ok()) { // Report prepared.code and prepared.failed_index outside capture. return; } openmeta::PreparedMetadataPatchInstance worker; if (!openmeta::create_prepared_metadata_patch_instance(plan, &worker).ok()) { return; }
Preparation and worker creation may allocate. Each worker owns its payloads and compiled slots and survives destruction of the plan. The host controls synchronization, ownership and publication. Each mutable worker requires exclusive access, including against reads through borrowed payload views and destruction. Neither the source store nor a template is modified by patching.
The serializer records the XMP locations internally after applying its conflict policy. Namespace prefixes and text sentinels are not application identifiers. The default patch options include existing XMP, preserve custom namespaces and let existing XMP win over generated projections. Scalar EXIF/IPTC projections can also be selected by their emitted XMP identity. Only requested payload families are generated.
Host-owned preparation identity and synchronization¶
Set
options.plan_idto a host-issued value from 1 throughkMaxMetadataPatchPlanId(48 bits). Zero and larger values returnInvalidOptions. Each successful preparation needs a fresh ID, even when the serialized packet is identical. An ID may be reused only after all prior plans, workers and handles with that ID can no longer be used. A host sequence must coordinate all preparation callers; separate per-thread counters starting at the same value do not provide distinct IDs. Exhaustion requires the host to stop or establish that old IDs are no longer usable; do not silently wrap.The library stores and compares the supplied identity. It cannot detect duplicate IDs assigned to separate plans by the host. Preparation, worker creation, patching and replay use no atomics, mutexes or global mutable state. The host must synchronize conflicting access and object lifetime; concurrent misuse is not detected and may cause undefined behavior. Independent plans and workers with independent writable buffers do not share patch state.
Transactional EXIF and XMP updates¶
const std::array<openmeta::MetadataPatchUpdate, 2> updates = {{ { handles[0], openmeta::make_value_view_u32(42U) }, { handles[1], openmeta::make_value_view_text( "0000000042", openmeta::TextEncoding::Utf8) }, }}; const openmeta::MetadataPatchResult patched = openmeta::patch_prepared_metadata_instance(&worker, updates); if (!patched.ok()) { // Every EXIF and XMP payload byte still has its previous value. return; } const auto exif = worker.payload(openmeta::MetadataPatchPayload::ExifTiff); const auto xmp = worker.payload(openmeta::MetadataPatchPayload::Xmp); // Copy these compact payloads into the host's preallocated frame buffers.
Successful and rejected batches, payload access and library replay allocate no heap memory. Payload addresses and lengths remain stable. Input values must remain immutable throughout the call and cannot borrow bytes from either worker payload. Duplicate, invalid, foreign and stale-generation handles fail before any write when the host follows the ID lifetime contract. Transactional here means all-or-nothing payload changes within one call; it does not provide inter-thread synchronization. A valid early EXIF update followed by an invalid XMP update changes neither family. A caller that keeps both families in one plan needs no separate EXIF/XMP preflight or rollback layer.
replay_prepared_metadata_instancecalls a synchronous callback in EXIF then XMP order, skipping absent families. The callback owns any output effects and must meet the application’s allocation requirements. A false callback stops replay; already performed host writes are not rolled back. Do not publish a partially written frame, or mutate/reset the worker from a replay callback.Values and bounds¶
EXIF uses host-native
MetaValueViewvalues and canonical little-endian TIFF encoding. The logical kind, element type, encoding and count must match the compiled request. Fixed arrays and byte values are supported. Text counts omit the serialized terminal NUL. Rational denominators must be nonzero. Regenerated IFD pointers, synthetic entries and values the classic TIFF serializer omits cannot be selected.XMP accepts logical UTF-8 or ASCII text for existing simple scalar properties. It validates UTF-8 and XML 1.0 characters, then escapes
&,<,>, quotes and apostrophes. CR is emitted as
to preserve it through XML line-ending normalization. Escaped output must have exactly the prepared width:&consumes five bytes as&. There is no padding, truncation, raw-XML insertion or numeric/date reformatting. Leading zeros and subsecond digits remain intact. An empty scalar can only be replaced with another zero-width value.The character rules follow XML 1.0 and RFC 3629.
Array items, language alternatives, qualifiers, nested structures, new properties, new namespace declarations and variable-width changes are outside the initial XMP patch contract. Such properties elsewhere in the packet remain unchanged. Use store editing and serialization to prepare a new layout at a stopped or drained worker boundary.
The default request limit is 4096; the hard handle ceiling is 65534. XMP output has a configurable nonzero bound, defaulting to 16 MiB and 65536 emitted entries. These are library defaults, not measured camera packet sizes or latency claims. A complete oversized packet fails preparation rather than publishing a partial patch plan.
Container ownership¶
Payloads carry no JPEG markers, PNG chunks, JP2/JPH UUID boxes or image data. The host owns framing, lengths, offsets, checksums, encoders and final I/O. The existing prepared-transfer handoff remains useful for target-specific typed operations and replay. Its time-field operations are not aliases for this new standalone payload API. A new generic property request should use this API.
- page Canonical Metadata Serialization
openmeta/exif_tiff_serialize.hexposes the same deterministic EXIF/TIFF serializer used by target transfer preparation without requiring a fake target container.Measure And Write¶
#include "openmeta/exif_tiff_serialize.h" #include <cstddef> #include <vector> const openmeta::ExifTiffSerializeResult measured = openmeta::serialize_exif_tiff(store, {}); if (measured.status != openmeta::ExifTiffSerializeStatus::OutputTruncated) { // No EXIF data, invalid metadata, or a resource failure. } std::vector<std::byte> bytes(static_cast<size_t>(measured.needed)); const openmeta::ExifTiffSerializeResult written = openmeta::serialize_exif_tiff(store, bytes);
The output is an unwrapped little-endian TIFF byte stream beginning with
IIand TIFF magic42. It contains neither anExif\0\0preamble nor container framing.neededsupports exact capacity planning; a short span receives a deterministic prefix and returnsOutputTruncated.Repeated calls against an immutable finalized store are deterministic and safe to run concurrently. Serialization is a preparation operation and may allocate internally. For a realtime or repeated-image path, serialize once, retain the immutable bytes, and replay that caller-owned buffer without any OpenMeta allocation. Per-frame fields should stay in a host-owned fixed header unless they must also appear in EXIF/XMP.
Carrier Wrapping¶
The canonical payload maps to current transfer carriers as follows:
Destination
Prepared EXIF payload
JPEG and current TIFF/DNG backend handoff
Exif\0\0+ TIFFPNG
eXIfand WebPEXIFTIFF
JP2/JXL/BMFF EXIF carrier
big-endian offset
6+Exif\0\0+ TIFFprepare_metadata_for_target()now applies these wrappers to the canonical payload. Hosts writing a different container should own its framing and use the canonical bytes directly.For fixed-width values that must change during repeated execution,
metadata_patch.hcompiles exact key occurrences into opaque plan-scoped handles. Its immutable canonical plan, per-worker instances, transactional typed patches, and payload replay remain independent of container selection. See `canonical_patching.md`. Do not retain or infer private TIFF byte offsets.Policy And Limits¶
The serializer validates finalized stores by default, honors compatible TIFF wire-type hints, and applies a caller-specified output limit. Opaque MakerNotes are dropped by default.
PreserveOpaqueretains only an existing raw MakerNote value; it does not reconstruct decoded vendor tables, relocate vendor-private offsets, or repair checksums.include_subifdsandinject_minimal_dng_versionare explicit because they are RAW/DNG-oriented choices. A syntactically valid payload can still contain image-dependent metadata that is wrong for the destination. Build and validate against the actual encoded image specification before persistence.
- page Capture synchronization milestones: 0.5.4–0.5.12
Development/correction and learning lifecycle in 0.8.11¶
The six existing development/correction fields A40D-A412 and LearningOptOutIn 9287 now use translation contract 2. Exact valid clean native matches gain Dirty while retaining values, wire hints/counts, origin and endian provenance. Dirty matches remain unchanged. Complete ReplaceExisting deletion retains typed native intent even when a key is absent; clean tombstones are promoted and dirty ones reused. Promotions and deletion intents consume operation limits, and new intents also consume entry limits. Conflict, source-mask and rollback rules remain.
Selected sources still require explicit host exif_version 300 or 310; translation never infers or changes ExifVersion or processing history. These APIs do not validate a complete destination EXIF profile. All seven fields use selective TIFF/BigTIFF/DNG merge and removal in both safety modes, including restored snapshots. The shared native allowlist grows from 77 to 84. Existing/template DNG version retention, source-pixel filters, ABI 4, snapshot v1 and host-owned synchronization remain unchanged.
LearningOptOutIn uses checked 16-bit word conversion from native provenance to canonical little endian and then to the target TIFF byte order. Unrelated UNDEFINED payloads remain opaque. Canonical encoding validates learning values before copying them.
Audit date: 2026-09-14. The original observations below describe C++ 0.5.4. The 0.5.5 update closes the identified portable-output gaps without adding tags or changing API signatures, ABI 3, or host synchronization responsibilities.
Native EXIF text/version lifecycle in 0.8.10¶
The 13 existing text/version fields now have translation contract 2. Exact clean native matches gain Dirty while retaining bytes, encoding and wire provenance, including comment BOMs/padding and valid ASCII type 129. Complete eligible deletion retains typed intent even for absent keys. All 13 use the native TIFF/BigTIFF/DNG merge/removal path; the shared allowlist grows from 66 to 77. Explicit version changes still enforce charset and companion rules. Existing/template DNG preparation retains the target DNGVersion unless an eligible dirty version requests replacement. Fresh scaffolds retain their version-generation policy. ABI 4, snapshot v1 and host synchronization remain unchanged. See the contract.
Native structured capture lifecycle in 0.8.9¶
The four existing structured fields now have translation contract 2: exact clean native values gain Dirty, and complete eligible absent deletion retains typed intent. All four enter the native TIFF/BigTIFF/DNG merge/removal allowlist. Existing numeric endian conversion preserves string bytes and per-string BOMs. Rendered-image source filtering of CFA remains; filtering alone does not remove unselected destination metadata during selective merge. Explicit dirty native deletion supplies that intent. ABI 4, snapshot v1 and host synchronization remain unchanged. See the contract.
Native encoding and composite lifecycle in 0.8.8¶
The six existing fields now have translation contract 2: exact clean native values gain Dirty, and eligible absent deletion retains typed intent. Composite ReplaceExisting also clears omitted companions from the destination. The three composite fields enter the native TIFF/BigTIFF/DNG merge/removal allowlist; encoding fields retain their source-pixel transfer exclusions. Canonical EXIF serialization retains all six. ABI 4, snapshot v1 and host synchronization remain unchanged. See the contract.
EXIF 3.1 LearningOptOutIn and profile authoring in 0.5.12¶
The seventh EXIF 3.1 field,
LearningOptOutIn9287, now has a bounded C++ and Python transaction. It accepts the exactexifEXusage/intention structure, validates complete dense pairs, preserves native byte-order provenance and requires an explicit host EXIF version of 0300 or 0310. Dirty tombstones remove the native value only underReplaceExisting.The same release adds one profile transaction for IFD0
ImageDescription010E,Artist013B, scalarCopyright8298, ExifIFDColorSpaceA001andRelatedSoundFileA004. It defines text/filename validation and legacy two-part Copyright conflict behavior. It does not infer ICC, image or audio authority and does not impose a complete-file profile.Existing JP2 and boxed JPH rewrite support is covered by focused ordinary, extended, terminal-box and positional-scan tests. Downstream OIIO/iRAW acceptance and real-file ICC/read-back remain external gates.
EXIF 3.1 development and correction data in 0.5.11¶
The six EXIF 3.1 fields A40D–A412 are implemented as one bounded C++ and Python transaction. DevelopmentType packs two byte choices (1, 2 or 4) and uses the published
exifEX:DevelopmentCharactersticandexifEX:FactoryDefaultresource children. DevelopmentTypeDescription uses UTF-8 TIFF type 129 even for ASCII text. The three correction switches accept 0/1; NoiseReduction accepts 0..3.Selected sources require an explicit host
exif_versionof 0300 or 0310. The translator never changes ExifVersion, so it does not hide the DC-008/DC-010 edition discrepancy. Native schemas, typed editing, portable output and TIFF serialization share the same checks. Compatible-file and rendered-image transfer retain these fields when present; OpenMeta does not infer processing history from RAW or MakerNote data. LearningOptOutIn is added by the 0.5.12 contract below.EXIF text and version metadata in 0.5.9¶
The 0.5.9 text/version batch adds UserComment, both version fields and seven EXIF 3 text tags. The new EXIF text API also supports UTF-8 owner/lens fields. The combined capture inventory is now 81 distinct ExifIFD tags across seventeen APIs; compatible-file transfer retains the six development/correction fields and still filters the three source-encoding fields for rendered-image output. Version and Artist/Software companion requirements are explicit. ABI 3, snapshot v1 layout and host synchronization responsibilities remain unchanged. BOM-less big-endian UserComment snapshots require a 0.5.9 reader. See the EXIF text/version and development/correction translation contracts for limits and the recorded OIIO/ExifTool reader limitations.
Structured capture in 0.5.8¶
OECF, SpatialFrequencyResponse, CFAPattern and DeviceSettingDescription add four native targets in one API. The combined fixture now covers 65 targets across fifteen APIs; compatible-file transfer retains 62. Exact rational pairs, Unicode, empty settings and TIFF byte order survive the qualified round trips. See the contract.
Encoding and composite capture in 0.5.7¶
Two more APIs cover Gamma, compressed bits per pixel, component configuration, and the three-field composite group. The current fixture has 61 native tags across fourteen APIs. Direct serialization retains all 61; target transfer filters the three encoding fields under the existing destination-image policy. Composite exposure data retains exact fractions and unavailable summaries, including raw big-endian values through snapshot persistence. See the contracts.
Typed editing and new fields in 0.5.6¶
The exact-key editor validates ordered EXIF/IPTC/XMP Add/Set/Remove operations and the complete candidate before publication. It preserves source identity, updates obsolete wire hints, and supports aliased output. See editing.md. Three additional capture fields and six environment fields now share the translation, portable-output and persistence qualification. The environment contract preserves unknown-denominator sentinels before rational reduction.
The 0.5.6 combined fixture covers twelve APIs and 55 unique targets, typed XMP edits, exact finite and unknown rationals, and serialized transfer snapshots through JPEG, classic TIFF and BigTIFF add/replace paths. Python exposes the two new translators; installed shared-library checks exercise authoring, typed editing, translation, validation and portable output. The earlier audit evidence below remains historical and describes its original 46-target scope.
Fixes in 0.5.5¶
Primary ExifIFD FNumber, FocalLength and DigitalZoomRatio emit exact fractions. Their native types/counts and valid value ranges are checked before claiming generated properties. Sensitivity scalars receive the same pre-claim checks. Under
CanonicalizeManaged, valid generated scalar replacements remove legacy ISO/indexed ISO and sensitivity companion aliases, including across theexif/exifEXnamespaces. Missing or invalid replacements retain source values. Retained indexedISOSpeedRatingskeeps that recognized array name rather than becoming unsupportedISO[1]when no replacement is available. Replacement is per property; it does not infer or repair group relationships.PreserveAllstill retains legacy aliases, and reverse translation still rejects duplicate eligible sources. Default native conflict behavior and per-call transactions also remain unchanged. Combined tests cover all ten APIs, exact boundaries, malformed values, policies and JPEG/classic TIFF/BigTIFF snapshots. The earlier rounded packets cannot recover lost precision without the native originals. FocalLength portable fractions express millimeters withoutmm.Implemented capture targets¶
Seventeen explicit reverse APIs cover 81 distinct ExifIFD tags. The count includes camera text and excludes GPS, dates, geometry, IPTC and vendor MakerNotes. It is an inventory count, not a percentage of all EXIF or competitor coverage. All function names below have the prefix
translate_xmp_and suffix_metadata. Detailed source types, aliases, limits and removal rules are in Metadata translation.API stem
Targets
ExifIFD tags
capture
5
ExposureTime 829A, FNumber 829D, ISO 8827, FocalLength 920A, ExposureBiasValue 9204
capture_settings
12
ExposureProgram 8822, MeteringMode 9207, SensingMethod A217, CustomRendered A401, ExposureMode A402, WhiteBalance A403, SceneCaptureType A406, GainControl A407, Contrast A408, Saturation A409, Sharpness A40A, SubjectDistanceRange A40C
capture_rational
4
SubjectDistance 9206, DigitalZoomRatio A404, ExposureIndex A215, FlashEnergy A20B
flash
1
Flash 9209
light_source
1
LightSource 9208
sensitivity
7
ISO 8827, SensitivityType 8830, StandardOutputSensitivity 8831, RecommendedExposureIndex 8832, ISOSpeed 8833, ISOSpeedLatitudeyyy 8834, ISOSpeedLatitudezzz 8835
camera_text
6
SpectralSensitivity 8824, CameraOwnerName A430, BodySerialNumber A431, LensMake A433, LensModel A434, LensSerialNumber A435
identity
2
LensSpecification A432, ImageUniqueID A420
apex
5
ShutterSpeedValue 9201, ApertureValue 9202, BrightnessValue 9203, ExposureBiasValue 9204, MaxApertureValue 9205
capture_spatial
5
FocalPlaneXResolution A20E, FocalPlaneYResolution A20F, FocalPlaneResolutionUnit A210, SubjectArea 9214, SubjectLocation A214
capture_additional
3
FocalLengthIn35mmFilm A405, FileSource A300, SceneType A301
environment
6
Temperature 9400, Humidity 9401, Pressure 9402, WaterDepth 9403, Acceleration 9404, CameraElevationAngle 9405
image_encoding
3
Gamma A500, CompressedBitsPerPixel 9102, ComponentsConfiguration 9101
composite
3
CompositeImage A460, SourceImageNumberOfCompositeImage A461, SourceExposureTimesOfCompositeImage A462
structured_capture
4
OECF 8828, SpatialFrequencyResponse A20C, CFAPattern A302, DeviceSettingDescription A40B
exif_text
13 (10 new)
ExifVersion 9000, FlashpixVersion A000, UserComment 9286, ImageTitle A436, Photographer A437, ImageEditor A438, CameraFirmware A439, RAWDevelopingSoftware A43A, ImageEditingSoftware A43B, MetadataEditingSoftware A43C, CameraOwnerName A430, LensMake A433, LensModel A434
development_correction
6
DevelopmentType A40D, DevelopmentTypeDescription A40E, DistortionCorrection A40F, ChromaticAberrationCorrection A410, ShadingCorrection A411, NoiseReduction A412
Tag IDs are hexadecimal. The 86 API mappings include five shared targets and six new singleton development/correction targets: ISO belongs to basic capture and sensitivity; ExposureBiasValue belongs to basic capture and APEX. CameraOwnerName, LensMake and LensModel belong to camera text and EXIF text. Counting each shared tag once gives 81.
Historical 0.5.4 qualification and gaps¶
A combined fixture exercises all ten APIs with ordinary values and a second set containing nonterminating fractions. Explicit
ReplaceExistingproduces all 46 targets with exact native types, counts and values in JPEG and classic TIFF. Reversing the call order gives the same native result, and repeating the calls adds no entries. This qualifies those fixtures, not every combination of accepted values, conflicts or containers.The audit found the following portable-output gaps in 0.5.4:
Case
Observed result
Consequence
Native FNumber
17/6Portable XMP contains
2.8Reverse translation silently changes the value to
14/5.Native FocalLength
50/3Portable XMP contains
16.7 mmReverse translation silently changes the value to
167/10.Native DigitalZoomRatio
1/3Portable XMP contains
0.333333333333333The exact reverse parser rejects the decimal because its reduced numerator/denominator do not fit the native type. The four-field rational call remains transactional.
Existing
exif:ISOplus a generated sensitivity groupBoth
exif:ISOandexifEX:PhotographicSensitivitysurvive, including withCanonicalizeManagedThe sensitivity reverse API rejects the duplicate eligible aliases as
AmbiguousSource.Malformed native SHORT for FNumber, FocalLength or DigitalZoomRatio, with valid existing XMP
CurrentBehaviorclaims the property but emits no valueValid existing XMP can disappear.
ExistingWinsretains it in these fixtures.ExposureTime, SubjectDistance, ExposureIndex and FlashEnergy retain their exact fractions in the tested packets. Missing fields after the DigitalZoomRatio failure reflect rollback of that whole API call; they are not four independent formatting defects. The newer APEX, identity and spatial contracts also survive the combined control round trip.
ExistingWinswithPreserveAllretains the original rational values in the combined fractional fixture, but still has the ISO alias collision. Disabling EXIF projection and emitting only the retained source XMP gives an exact 46-target reverse round trip for both fixtures. That choice is suitable only when the source XMP is authoritative and complete: it cannot publish later native-only edits. No general synchronization workaround is claimed.Composition and host responsibilities¶
Translation and portable output are separate operations. Transfer does not invoke the reverse APIs. See XMP sync policy for source, destination, sidecar and generated-property precedence.
Each reverse call has its own transaction. With
Allsource selection and the defaultFailOnConflict, basic capture can create ISO before the sensitivity call sees it. The latter then rejects the incomplete native sensitivity group, even when ISO matches. In the audited fixture, calling sensitivity first passes; explicit replacement also passes in either order. Hosts should assign ownership of shared targets or choose a deliberate conflict policy. A partial group is not equivalent to the requested complete group.Stage a sequence of calls in a candidate store/document and publish it only after all calls succeed. A late invalid SubjectLocation leaves the original document and the earlier successful candidate intact in the Python probe. Reassigning the host’s current document after every call publishes partial work across the sequence. This is distinct from the per-call transaction guarantee.
Retained source XMP, native entries and destination carriers each need an explicit authority decision. Packet absence does not encode a deletion request; dirty tombstones and carrier cleanup follow their separate documented policies. The library does not infer photographic relationships such as FNumber/APEX, ExposureTime/APEX, focal length/sensor dimensions or ISO/gain. Synchronization of conflicting shared-object access remains the host’s responsibility.
Completed fix scope in 0.5.5¶
The combined fix retains the existing reverse API signatures and conflict policies. Its acceptance checks are:
Emit exact accepted values for FNumber, FocalLength and DigitalZoomRatio, including boundary fractions and zero where the existing contract permits it.
Validate native scalar types and counts before claiming a generated property. Invalid native values must leave valid existing XMP available.
Reconcile eligible sensitivity aliases under
CanonicalizeManagedonly when a valid generated replacement exists. Test legacy scalar/indexed ISO paths, canonical companions, absent/invalid replacements and conflicting values. KeepPreserveAlland per-call ambiguity rules explicit.Run one combined regression batch over all ten APIs, shared targets, policies, failure rollback and JPEG/classic TIFF/BigTIFF persistence. Qualify exact wire values and independent image reads together, then run the platform matrix once against the final patch.
The additional capture and environment batches are implemented in 0.5.6. Encoding/composite contracts are implemented in 0.5.7 and structured capture contracts in 0.5.8; text/comment/version contracts are implemented in 0.5.9. The standard EXIF inventory selected validation consistency for existing writeback fields, implemented in 0.5.10. The six EXIF 3.1 development/correction fields are implemented in 0.5.11 and LearningOptOutIn/profile authoring are implemented in 0.5.12. Fuzzy search remains lowest priority.
Remaining field families¶
These are candidate families outside the sixteen capture contracts, not a complete remaining-tags denominator. Read/display support does not imply reverse support.
Family
Examples
Work needed before implementation
Existing-field validation
Routed-field schemas and legal Interop tag IDs
Implemented in 0.5.10; full file-profile conformance remains separate.
EXIF 3.1 development/correction
Six fields A40D–A412
Implemented in 0.5.11; maintain the bounded version, value and transfer policy.
Other standard authoring/profile rules
IFD0 descriptive fields, color/Interop, LearningOptOutIn and RelatedSoundFile
Bounded 0.5.12 routes exist; complete-file authority and companion validation remain separate.
MakerNotes
Vendor/version-specific offsets and integrity fields
Continue the separate rewrite-trust work; generic opaque authoring does not establish safe relocation.
The audit does not reopen downstream application acceptance or claim arbitrary RDF synchronization, complete EXIF authoring, whole-corpus qualification or competitor parity.
- 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
DocumentandTransferSourceSnapshotexpose 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 selectedExportNameStyle. By default the dump uses the stableFlatHostcontract. BMFF component membership, role, policy, and derived-image construction fields such asbmff:scene.component.item_id,bmff:scene.component.role,bmff:scene.component.metadata_policy, andbmff:scene.component.multi_image_policy, plusbmff:derived_image.constructionandbmff:derived_image.construction_valid,bmff:derived_image.graph_valid, andbmff:derived_image.descriptor_reference_depth, are emitted as normalbmff_fieldentries, 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.hprovides 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 finalizedMetaStorecontaining 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.
storeis 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
TitleText
dc:title[x-default]Singleton language alternative
DescriptionText
dc:description[x-default]Singleton language alternative
CreatorText
dc:creator[n]Additive ordered sequence
KeywordText
dc:subject[n]Additive unordered bag
CopyrightText
dc:rights[x-default]Singleton language alternative
RightsUsageTermsText
xmpRights:UsageTerms[x-default]Singleton language alternative
CreditText
photoshop:CreditSingleton
SourceText
photoshop:SourceSingleton
CreateDateText
xmp:CreateDateCaller supplies the XMP date lexical value
ModifyDateText
xmp:ModifyDateCaller supplies the XMP date lexical value
RatingSigned integer
xmp:Rating-1..5LabelText
xmp:LabelSingleton
CameraMakeText
tiff:MakeSingleton
CameraModelText
tiff:ModelSingleton
SoftwareText
xmp:CreatorToolSingleton
DateTimeOriginalText
exif:DateTimeOriginalCaller supplies the XMP date lexical value
OrientationUnsigned integer
tiff:OrientationEXIF orientation index
1..8PixelWidthUnsigned integer
exif:ExifImageWidthMust be nonzero
PixelHeightUnsigned integer
exif:ExifImageHeightMust be nonzero
ColorSpaceUnsigned integer
exif:ColorSpace1..65535ExposureTimeUnsigned rational
exif:ExposureTimeNonzero numerator and denominator
FNumberUnsigned rational
exif:FNumberNonzero numerator and denominator
IsoSensitivityUnsigned integer
exif:ISOMust be nonzero
FocalLengthUnsigned rational
exif:FocalLengthNonzero 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:
1024fields1 MiBof UTF-8 text per field8 MiBof UTF-8 text per request
MetadataCreationRequest::limitsmay 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
ValueErrorwith the C++ status and rejected field index. The returned object is a normalDocument: 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 not implied by this API. Use the explicit Translation steps for supported creation dates, common technical and capture EXIF fields, and common descriptive IPTC fields; see translation.md.
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.
The logical-field API does not expose arbitrary custom properties, binary values, or direct EXIF/IPTC construction. C++ hosts that know exact keys and types can use the transactional generic builder in generic_authoring.md, including safe scalar/indexed custom XMP. Full arbitrary RDF structures and fresh ICC profile construction remain outside the current authoring scope.
- page Canonical EXR Value Encoding in OpenMeta
Status: baseline contract (v1)
Scope¶
This defines how OpenEXR attribute values should be represented in
MetaValueandOrigin/WireTypeso decode/edit/write logic stays deterministic and lossless.Keying is handled separately by
MetaKeyKind::ExrAttributewith:part_index(EXR part id)name(attribute name)
Wire Type Contract¶
Origin::wire_type.family = WireFamily::OtherOrigin::wire_type.code = exr_attribute_type_tnumeric valueOrigin::wire_countstores raw attribute byte size (current implementation)
For unknown/user-defined EXR attribute types, preserve:
raw payload bytes in
MetaValueKind::Bytestype string in
Origin::wire_type_name(optional decode behavior)
Canonical Mapping Table¶
EXR_ATTR_INT->Scalar + I32EXR_ATTR_FLOAT->Scalar + F32EXR_ATTR_DOUBLE->Scalar + F64EXR_ATTR_RATIONAL->Scalar + SRational(num,denom)EXR_ATTR_STRING->Text + Utf8(best effort, fallbackUnknown)EXR_ATTR_STRING_VECTOR->Bytes(current), planned structured helper API for element iterationEXR_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 + U8Struct/blob attrs (
chlist,preview,bytes,opaque) ->Bytesfor 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¶
Keep
MetaStorecompact and storage-agnostic.Guarantee lossless round-trip for all EXR attributes, including unknown ones.
Avoid hard-coding large per-type structs in core until a stable EXR read/write adapter lands.
Open Questions¶
Whether
string_vectorshould become first-classArray + Textrather than a packed-bytes representation.Where to attach EXR
type_namefor unknown/custom attrs without bloating all entries.Whether
chlistshould get a dedicated typed view API in v1 or remain bytes in core with helper parsing only.
- page Development
See also:
docs/metadata_support.mdfor current container/block/decode support anddocs/interpretation_status.mdfor the semantic interpretation matrix. If you are looking for the shortest practical entry path, start withdocs/quick_start.mdbefore this file.If you already have a host encoder, SDK, or container API, use
docs/host_integration.mdafter the quick start.OpenMeta Structure¶
Development/correction and learning lifecycle in 0.8.11¶
The six existing development/correction fields A40D-A412 and LearningOptOutIn 9287 now use translation contract 2. Exact valid clean native matches gain Dirty while retaining values, wire hints/counts, origin and endian provenance. Dirty matches remain unchanged. Complete ReplaceExisting deletion retains typed native intent even when a key is absent; clean tombstones are promoted and dirty ones reused. Promotions and deletion intents consume operation limits, and new intents also consume entry limits. Conflict, source-mask and rollback rules remain.
Selected sources still require explicit host exif_version 300 or 310; translation never infers or changes ExifVersion or processing history. These APIs do not validate a complete destination EXIF profile. All seven fields use selective TIFF/BigTIFF/DNG merge and removal in both safety modes, including restored snapshots. The shared native allowlist grows from 77 to 84. Existing/template DNG version retention, source-pixel filters, ABI 4, snapshot v1 and host-owned synchronization remain unchanged.
LearningOptOutIn uses checked 16-bit word conversion from native provenance to canonical little endian and then to the target TIFF byte order. Unrelated UNDEFINED payloads remain opaque. Canonical encoding validates learning values before copying them.
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
MetaStoreentries.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
avioAVIF 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, boundedgrid/iovl/idenconstruction semantics with recursive item-offset descriptors and graph-cycle/source validation, bounded completetiliconfiguration/reference/offset-table interpretation,container_graphconcepts, 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, EXIFOffsetTime*/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 either the logical-field API or exact typed keys.
High, about 82-87%; the logical-field API and thin Python wrapper remain simple, while the C++ generic v1 builder now transactionally covers EXIF/TIFF/DNG-style tags, IPTC datasets, custom scalar/indexed XMP, borrowed typed values, wire hints, capacity planning, and detached schema validation. Full RDF authoring and fresh ICC construction remain open.
Editing
Modify logical fields or exact typed EXIF/IPTC/XMP keys while preserving valid surrounding structure.
Medium-high, about 75-80%; the logical and exact-key v1 add/set/remove transactions, complete candidate validation, wire-hint replacement, 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.
High, about 85-90%; the primary writer contract, bounded EXIF/IPTC/XMP synchronization policy, compare-backed release gates, stable prepared handoff, and TIFF/DNG baseline are complete.
Translation
Project metadata between families through explicit bounded mappings, including strict paired IPTC creation-date projection to XMP plus transactional reverse projection of edited XMP dates, common technical and capture fields, target-bound image geometry, descriptive properties, flat IPTC Core locations, and editorial fields into native EXIF/IPTC groups.
Medium-high, about 82-87% for the declared scope; exact date parsing, four technical and five typed capture EXIF mappings, target-validated orientation and complete stored-dimension groups, 20 IPTC text/priority mappings with combined atomic writeback, primary GPS coordinate/altitude groups with exact rational precision and version handling, structured-location record selection and paired flat-XMP/IPTC reconciliation, GPS UTC date/time and navigation pairs, repeated-value reconciliation, exact rational conversion, safe ASCII/UTF-8 handling, tombstone propagation, resource limits, JPEG/TIFF round trips, and thin Python exposure are implemented.
Writing
Serialize metadata and write or rewrite it into target containers.
High, about 80-85%; target-neutral deterministic TIFF/EXIF measure/write plus immutable compiled fixed-width patch plans now feed host-owned replay and existing JPEG/TIFF, PNG/WebP, JP2/JXL, and BMFF wrappers; JPEG is strong, TIFF/DNG have a bounded rewrite contract, and compact BMFF
ilocfields can be normalized, while broader BMFF/JXL/EXR behavior remains intentionally bounded.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 a98-100%range because not every declared container lane has an independent conformance sample set, even though tracked inputs have explicit read outcomes.The logical and generic typed Creation, detached store validation, canonical TIFF/EXIF serialization and prepared fixed-width patching, Editing, reverse-date, reverse-capture, target-bound geometry, and reverse-descriptive Translation milestones are implemented in
metadata_creation.h,metadata_authoring.h,exif_tiff_serialize.h,metadata_patch.h,metadata_editing.h, plusmetadata_translation.h, with their contracts documented in `creation.md`, `generic_authoring.md`, `canonical_serialization.md`, `canonical_patching.md`, `editing.md`, and `translation.md`. The active implementation sequence continues through Transfer, Translation, and Writing. Creation and Editing resume for multilingual alternatives, full RDF structured values, fresh ICC construction, structural block operations, and broader cross-family synchronization. Adapters and Utilities remain deferred. Fuzzy Search has the lowest priority and resumes after those stages. Its remaining work includes independently sourced quality expansion, designed Unicode/transliteration behavior, multilingual gates, and an optional immutable index for repeated searches over large stores.The 0.8.10 lifecycle batch completes the 13 existing EXIF text/version fields. Exact clean matches retain raw bytes and wire provenance when promoted to Dirty; eligible absent deletion creates typed intent. All 13 use TIFF/BigTIFF/DNG selective merge/removal. Existing/template DNG preparation retains the target DNGVersion when no eligible explicit dirty version change is supplied. Fresh scaffolds retain their version-generation policy. ABI 4 and host synchronization remain unchanged.
The 0.8.9 lifecycle batch completes exact clean-value promotion and typed absent deletion for OECF, SpatialFrequencyResponse, CFAPattern and DeviceSettingDescription. Eligible native changes use the existing TIFF merge/removal paths and endian conversion. Rendered-image source filtering remains distinct from an explicit destination deletion. ABI 4 and host synchronization remain unchanged.
The 0.8.8 lifecycle batch completes exact clean-value promotion and typed absent deletion for the existing image-encoding/composite group. Composite native writeback uses the existing TIFF/BigTIFF/DNG merge and removal paths. Encoding properties remain excluded from target transfer because they depend on source pixels. ABI 4 and host synchronization remain unchanged.
The 0.5.6 batch adds exact-key typed editing plus three additional capture and six environment mappings. The 0.5.7 encoding/composite batch adds six more fields; the 0.5.8 structured batch adds four more. Capture-related translation now covers 75 unique ExifIFD targets across sixteen APIs after the 0.5.9 text/version batch. The combined author/edit/translate/persist workflow includes exact unknown-denominator handling; see capture synchronization milestones.
Query results should expose both inspection-level matches and interpreted candidates. A crop query, for example, may match separate
DefaultCropOriginandDefaultCropSizetags, anActiveArearectangle, 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 distinctcolor_profilesemantic 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 useexif_tag_numeric_value_format(...)andexif_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 usematrix_set,vector_set, andtablevalue 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 retainexact_match,fuzzy_match, andfuzzy_scorecompatibility fields, but tolerant free-text ranking belongs to the separate Fuzzy Search API. PythonDocumentandTransferSourceSnapshotmirror 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.hAPI 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.20A 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 viaCMAKE_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.xmpsidecars). 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 arapidfuzz::rapidfuzzpackage target orOPENMETA_RAPIDFUZZ_INCLUDE_DIRpointing at headers containingrapidfuzz/fuzz.hpp.zlib (
OPENMETA_WITH_ZLIB): inflates Deflate-compressed payloads, including PNGiCCP(ICC profiles) and compressed text/XMP chunks (iTXt,zTXt).Brotli (
OPENMETA_WITH_BROTLI): decompresses JPEG XLbrob”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 viafind_package(OpenSSL)when needed. Current results are diagnostic only: cryptographic signature success is reported assignature_verified_onlyand 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=ONWhen 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-libsVersioning¶
VERSIONis the single source of truth for the project version:CMake reads
VERSIONand setsPROJECT_VERSION.The Python wheel version is derived from
VERSION(via scikit-build-core metadata).
CLI Tools¶
metavalidatechecks 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
metavalidateCLI is a thin wrapper overopenmeta::validate_file(...). Machine-readable JSON output includes issue codes suitable for gating, for examplexmp/output_truncatedandxmp/invalid_or_malformed_xml_text.metadumpis 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:GPSTimeStampis emitted as XMP date-time text (YYYY-MM-DDThh:mm:ssZ) only whenGPSDateStampis available; otherwise it is skipped.Compatibility mode
--portable-exiftool-gpsdatetime-aliasemitsexif:GPSDateTimeinstead ofexif:GPSTimeStamp.Portable IPTC-IIM mapping covers
dc:*plus selectedphotoshop:*andIptc4xmpCore:*fields (for example city/state/country/headline/credit and location/country-code).
metatransferis 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
metatransferis a thin CLI wrapper over the public transfer APIs. It usesprepare_metadata_for_target_file(...)for source read/decode plusexecute_prepared_transfer(...)for time patching, route compile/emit, and optional JPEG/TIFF edit plan/apply. When--jpeg-jumbfis used, the CLI also callsappend_prepared_bundle_jpeg_jumbf(...)before execute. The core also exposescompile_prepared_transfer_execution(...)plusexecute_prepared_transfer_compiled(...)forprepare once -> compile once -> patch/emit manyworkflows. When-ois used, the CLI passes aTransferByteWritersink 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-spaceflags populatePrepareTransferRequest::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 buildsExif,xml, and boundedjumbbox payloads plus the encoder ICC profile fromMetaStorecompile_prepared_bundle_jxl(...)andemit_prepared_bundle_jxl_compiled(...)provide the sameprepare once -> compile once -> emit manyshape as JPEG/TIFFexecute_prepared_transfer(...)andemit_prepared_transfer_compiled(..., JxlTransferEmitter&)now accept JXL bundlesjxl:icc-profileis emitted throughJxlTransferEmitter::set_icc_profile(...)and stays separate from the JXL box pathfile-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
JumbfCborKeyroots into generic JXLjumbboxes when no raw source payload is availableIPTC requested for JXL is projected into the existing
xmlXMP box; OpenMeta does not create a raw IPTC-IIM JXL carrierbuild_prepared_jxl_encoder_handoff_view(...)is the explicit encoder-side ICC handoff contract for JXL, andbuild_prepared_jxl_encoder_handoff(...)/serialize_prepared_jxl_encoder_handoff(...)add an owned persisted handoff object for cross-process reuse: at most one preparedjxl:icc-profilepayload plus the remaining JXL box countsinspect_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 handoffsthe JXL compile/emit path now rejects multiple prepared ICC profiles so the encoder handoff and backend execution contracts match
build_prepared_transfer_emit_package(...)pluswrite_prepared_transfer_package(...)can serialize direct JXL box bytes from prepared bundles, andbuild_prepared_transfer_package_batch(...)can materialize those bytes into one owned replay batchbounded 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
jumbboxes are distinguished as generic JUMBF vs C2PA for that replacement decisionwhen Brotli support is available, the same distinction is applied to compressed
brob(realtype=jumb)source boxes before deciding whether to preserve or replace themthe package writer remains box-only, so it still rejects
jxl:icc-profile; ICC remains encoder-only on JXLCLI/Python
metatransferwrappers now expose this bounded edit path through--target-jxl ... --source-meta ... --output ...when the prepared bundle does not requirejxl:icc-profileJXL 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-jumbapply, and bounded file-helper edit execution
WebP prepare/emit now uses the same bounded transfer contract:
prepare_metadata_for_target(..., TransferTargetFormat::Webp, ...)currently buildsEXIF,XMP,ICCP, and boundedC2PARIFF metadata chunks fromMetaStoreWebP
EXIFchunk payloads contain direct TIFF bytes and intentionally omit the JPEG APP1Exif\0\0preamblecompile_prepared_bundle_webp(...)andemit_prepared_bundle_webp_compiled(...)provide the sameprepare once -> compile once -> emit manyshape as JPEG/TIFF/JXLexecute_prepared_transfer(...)andemit_prepared_transfer_compiled(..., WebpTransferEmitter&)now accept WebP bundlesIPTC requested for WebP is projected into the existing
XMPchunk; OpenMeta does not create a raw IPTC-IIM WebP carrierdraft OpenMeta invalidation payloads and generated invalidation output use the
C2PARIFF chunk pathbuild_prepared_transfer_emit_package(...)pluswrite_prepared_transfer_package(...)can serialize direct WebP chunk bytes from prepared bundles, andbuild_prepared_transfer_package_batch(...)can materialize those bytes into one owned replay batchfull WebP signed C2PA rewrite remains follow-up work
ISO-BMFF metadata-item transfer now uses the same bounded contract for
HEIF/AVIF/CR3targets:prepare_metadata_for_target(..., TransferTargetFormat::{Heif,Avif,Cr3}, ...)currently buildsbmff:item-exif,bmff:item-xmp, boundedbmff:item-jumb, boundedbmff:item-c2pa, andbmff:property-colr-iccpayloadsEXIF is prepared as a BMFF item payload with the 4-byte big-endian TIFF-offset prefix plus full
Exif\0\0bytesIPTC requested for BMFF is projected into
bmff:item-xmp; OpenMeta does not create a raw IPTC-IIM BMFF carrierICC requested for BMFF uses the bounded property path:
bmff:property-colr-icccarries ‘u32be(‘prof’) + <icc-profile>as the payload bytes for acolrproperty, not a BMFF metadata itemfile-based prepare can preserve source generic JUMBF payloads and raw OpenMeta draft C2PA invalidation payloads as BMFF metadata itemsstore-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(…), andemit_prepared_transfer_compiled(…, BmffTransferEmitter&)provide the reusable item/property-emitter paththe shared package-batch persistence/replay layer can own and hand off those stable BMFF item and property payload bytesOpenMeta 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 extendingiinf,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 widerinfe/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 whenirefilocreferences 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. Since 0.6.2, one further method-2 level is supported, ending at local method 0/1 extents. The new nested form validates nonzero lengths, logical slices, physical terminal ranges and a shared 2^20-visit validation work limit (LimitExceededbefore output on exhaustion); cycles and deeper chains reject before output. Method-0 offsets with validated self-contained data references rebase whenmetachanges size. Bounded ICC transfer removes prior ICCcolr/profandcolr/rICCproperties fromiprp/ipco, compacts/remaps existingipmaassociations, 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;–target-heif,–target-avif, and–target-cr3now accept–source-meta PATHplus–output PATHfor metadata transfer onto an existing BMFF target filethe 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(…), andapply_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-c2pabefore bounded BMFF editCLI/Python signer-input options now support JPEG, JXL, and bounded BMFF targets; the legacy option name–jpeg-c2pa-signedis kept for compatibility even when the target is JXL or BMFF -TransferProfilenow uses explicitTransferPolicyActionvalues formakernote,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-TransferC2paPreparedOutputso 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.It is separate frompolicy_decisions
.Current JPEG, JXL, and bounded BMFF prepare fillstate,source_kind, matched decoded-entry count, existing carrier segment count, and the required signer inputs.Current rewrite prep also emitscontent_binding_chunks, a deterministic sequence that describes the rewrite output before any new C2PA payload is inserted: preserved source ranges plus prepared JPEG segments for JPEG, preserved source ranges plus prepared JXL boxes for JXL, or preserved source ranges plus one prepared metadata-onlymetabox for the bounded BMFF edit path.Current state is usuallySigningMaterialRequired; it advances toReadyonce an external signed payload is staged back into the bundle. -build_prepared_c2pa_sign_request(...)derives an explicit external signer request fromPreparedTransferBundle::c2pa_rewrite.It reports carrier route, manifest label, source-range chunk count, prepared-segment chunk count, and the full content-binding chunk list.CLI/Python thin wrappers expose this asc2pa_sign_request. -build_prepared_c2pa_sign_request_binding(...)reconstructs the exact content-binding byte stream from the request plus the target container bytes.It fails closed on stale requests, bad source ranges, and block/size mismatches.Current bounded targets are JPEG, JXL, and BMFF. -metatransfer –dump-c2pa-bindingandunsafe_transfer_probe(include_c2pa_binding_bytes=True)are thin wrapper entry points for JPEG, JXL, and bounded BMFF targets. -build_prepared_c2pa_handoff_package(...)bundles the signer request and exact content-binding bytes into one public handoff object.Callers can persist or pass one object to an external signer.Wrappers still use the same core helper instead of rebuilding either part on their own. -serialize_prepared_c2pa_handoff_package(...)anddeserialize_prepared_c2pa_handoff_package(...)persist that handoff object as one stable binary package. -build_prepared_c2pa_signed_package(...)packages the sign request plus signer material and returned logical payload for a second persisted round-trip object. -serialize_prepared_c2pa_signed_package(...)anddeserialize_prepared_c2pa_signed_package(...)persist that signed package. -validate_prepared_c2pa_sign_result(...)validates a returned signed logical C2PA payload before bundle mutation.It reports payload kind, logical payload size, staged carrier size, staged segment count, semantic validation status/reason, and validation errors.Current semantic validation requires a manifest, at least one claim, at least one signature, linked-signature consistency, no unresolved or ambiguous explicit claim references, exactly one manifest for the current sign request,claim_generatorwhen the request requires manifest-builder output, at least one decoded assertion when the request requires content binding, 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, and 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, and an exact match between the signer-providedmanifest_builder_outputbytes and the primary CBOR manifest payload embedded in the returned signed JUMBF. -apply_prepared_c2pa_sign_result(...)uses the same validation path.Current JPEG validation now also checks that the staged APP11 sequence reconstructs the logical payload byte-for-byte, that APP11 sequence numbers are contiguous, that repeated APP11 C2PA headers stay consistent, and that the logical root type plus BMFF declared size stay internally consistent before final emit/write.Current bounded BMFF validation also checks that the stagedbmff:item-c2pacarrier reconstructs the logical payload byte-for-byte before bounded BMFF edit applies it.Final JPEG emit/write also validates the prepared APP11 C2PA carrier against the bundle's own C2PA contract. -GeneratedDraftUnsignedInvalidationmust carry a draft invalidation payload. -SignedRewritemust carry content-bound C2PA andPreparedTransferBundle::c2pa_rewritemust already beReady. -DroppedandNotPresentmay not leave a prepared APP11 C2PA carrier.Missing required carriers fail before backend bytes are written. -apply_prepared_c2pa_sign_result(...)
is the first bundle-level handoff point back from an external signer.
It validates the signer request against the current prepared bundle.It requires explicit signer material fields plus a content-bound logical C2PA payload.On success it replaces preparedjpeg:app11-c2pablocks orbmff:item-c2paitems and upgrades the resolved C2PA policy toSignedRewritewithTransferPolicyReason::ExternalSignedPayload.CLI/Python thin wrappers expose the validation result asc2pa_stage_validateand the stage result asc2pa_stagefor both JPEG and bounded BMFF signer-input paths.
Current policy resolution for JPEG/TIFF prepare is:MakerNote:Keepby default,Dropwhen requested, and unavailableInvalidate/Rewritefail closed toDrop.Keepremains opaque-byte preservation; use the generic and layout transfer audits before relying on a moved note.JUMBF: -prepare_metadata_for_target(...)can now project decoded non-C2PAJumbfCborKeyroots into generic JPEG APP11 JUMBF payloads.The projected path is intentionally bounded: ambiguous numeric map keys and decoded-CBOR bool/simple/sentinel and large-negative fallback forms are rejected, while tagged CBOR values are preserved. -prepare_metadata_for_target_file(...)
can preserve source JUMBF payloads for JPEG targets by repacking them into APP11 segments. -append_prepared_bundle_jpeg_jumbf(...)is the explicit public helper for adding one logical raw JUMBF payload to a prepared JPEG bundle, andmetatransfer –jpeg-jumbf file.jumbfis the thin CLI path over it.
C2PA: -c2pa=invalidateon JPEG targets now resolves to a draft unsigned APP11 C2PA invalidation payload instead of drop-only behavior.The generated draft payload now includes an explicit OpenMeta contract marker and contract version in its CBOR map.
File-based JPEG prepare can preserve an existing OpenMeta draft invalidation payload as raw APP11 C2PA (TransferC2paMode::PreserveRaw
). -Rewriteresolves toDropwithTransferPolicyReason::SignedRewriteUnavailableuntil re-sign support exists, whilePreparedTransferBundle::c2pa_rewritereports the signer prerequisites that would be needed to perform it.OpenMeta still does not sign internally, but it can now stage externally signed logical C2PA payloads back into prepared JPEG APP11 carrier blocks after request validation. -build_prepared_c2pa_handoff_package(...)andvalidate_prepared_c2pa_sign_result(...)are the public handoff and pre-stage validation helpers for that external-signer path. -metatransfercan now dump a persisted handoff package, dump a persisted signed package, and load a persisted signed package back into the same prepare/validate/apply flow.
JPEG edit/rewrite now recognizes existing APP11 JUMBF/C2PA carrier segments.Existing C2PA APP11 payloads are dropped automatically when the output metadata changes.
Existing JUMBF APP11 payloads are removed when the resolved transfer policy for JUMBF isDrop
.
C2PA raw preserve still resolves toDrop` because signed content-bound metadata has no safe preserve path without re-sign support.
thumdumpis preview-only and optimized for batch preview extraction:#Positional input / output ./build/thumdump input.jpg preview.jpg #Explicit input / output ./build/thumdump -i input.jpg -o preview.jpg #Batch mode ./build/thumdump --out-dir previews --first-only input1.jpg input2.cr2 #If multiple previews exist, --out gets auto - suffixed: #preview_1.jpg, preview_2.jpg, ... ./build/thumdump input.arq preview.jpg
Resource Budgets (Draft)¶
OpenMeta tools now default to no hard file-size cap (--max-file-bytes 0). Resource control is expected to come from parser/decode budgets:metaread/metavalidate/metadump/metatransfer:--max-payload-bytes,--max-payload-parts--max-exif-ifds,--max-exif-entries,--max-exif-total--max-exif-value-bytes,--max-xmp-input-bytes
metadump/thumdumppreview scan:--max-preview-ifds,--max-preview-total,--max-preview-bytes
This policy surface is intentionally marked draft and may be refined.Code Organization (EXIF + MakerNotes)¶
Core EXIF/TIFF decoding:
src/openmeta/exif_tiff_decode.ccNormalized DNG/RAW CCM query surface:
src/include/openmeta/ccm_query.h,src/openmeta/ccm_query.cc(collect_dng_ccm_fields(...)) with DNG-oriented validation diagnostics (CcmIssue) in warning mode and non-finite numeric field rejection. Current warning taxonomy also includes practical checks such asinvalid_illuminant_code,white_xy_out_of_range, and unusually large matrix-like field counts.ICC tag interpretation helpers:
src/include/openmeta/icc_interpret.h,src/openmeta/icc_interpret.cc(icc_tag_name(...),interpret_icc_tag(...)fordesc/text/sig/mluc/dtim/view/meas/chrm/sf32/uf32/ui08/ui16/ui32/mft1/mft2/mAB/mBA/XYZ/curv/para, plusformat_icc_tag_display_value(...)for shared CLI/Python rendering)ISO-BMFF (HEIF/AVIF/CR3) container-derived fields:
src/openmeta/bmff_fields_decode.ccEmitted during
simple_meta_read(...)asMetaKeyKind::BmffFieldentries.Current fields:
ftyp.*brand codes/names and compatible-brand counts, primary item properties (meta.primary_item_id,primary.width,primary.height,primary.rotation_degrees,primary.mirrorfrompitm+iprp/ipco ispe/irot/imir+ipma), primarycolrsummaries (primary.color_type,primary.color_type_name,primary.nclx_colour_primaries,primary.nclx_transfer_characteristics,primary.nclx_matrix_coefficients,primary.nclx_full_range_flag, andprimary.color_profile_bytesfor bounded ICC profile carriers),ipcoproperty-container summaries (ipco.property_count,ipco.known_property_count,ipco.unknown_property_count, and per-known-type counts),ipmaitem-property association rows (ipma.association_count,ipma.item_id,ipma.property_index,ipma.essential,ipma.property_type,ipma.property_type_name) plus per-property rollups such asipma.ispe.association_count,ipma.ispe.primary_association_count, andipma.irot.essential_count, item-info rows fromiinf/infe(item.info_count,item.id,item.type,item.type_name,item.semantic,item.name,item.content_type,item.content_encoding,item.uri_type, anditem.semantic_*_countaggregate rows for common item roles; emitted even whenmetahas nopitm, plusprimary.item_type,primary.item_type_name,primary.item_semantic,primary.item_name,primary.content_type,primary.content_encoding,primary.uri_typealiases whenpitmis present), boundediref.*relation fields (ref_type,ref_type_name,from_item_id,to_item_id,edge_count), typed derived relation rows (iref.auxl.*,iref.dimg.*,iref.thmb.*,iref.cdsc.*, and other safe ASCII FourCC relation families), direction-correct endpoint role and named item-id aliases (from_role,to_role, auxiliary/master, derived/source, thumbnail/master, and descriptive/described item IDs), per-type relation counters (iref.<type>.edge_count) and per-type unique source/target counters (iref.<type>.from_item_unique_count,iref.<type>.to_item_unique_count), per-type graph-summary aliases (iref.graph.<type>.edge_count,iref.graph.<type>.from_item_unique_count,iref.graph.<type>.to_item_unique_count), typed relation item summaries (iref.<type>.item_count,iref.<type>.item_id,iref.<type>.item_out_edge_count,iref.<type>.item_in_edge_count), relation-graph summaries (iref.item_count,iref.from_item_unique_count,iref.to_item_unique_count, row-wiseiref.item_id+iref.item_out_edge_count+iref.item_in_edge_count), separate primary inbound derived-item and outbound derived-source summaries, bounded primary-linked image-role rows (primary.linked_item_role_count, row-wiseprimary.linked_item_id+primary.linked_item_type+primary.linked_item_type_name+primary.linked_item_name+primary.linked_item_semantic+primary.linked_item_rolewheniinf/infedata exists), compact primary sidecar summaries with unique linked-node counts (primary.sidecar_count,primary.has_metadata_sidecar,primary.metadata_sidecar_count,primary.has_image_sidecar,primary.image_sidecar_count, and per-roleprimary.*_sidecar_countfields), compact primary-scene summaries (primary.scene_primary_item_count,primary.scene_linked_item_count,primary.scene_node_count,primary.scene_edge_count,primary.scene_*_node_count, andprimary.scene_*_edge_count), whole-scene policy summaries (scene.item_count,scene.known_item_count,scene.image_node_count,scene.metadata_node_count,scene.content_bound_metadata_node_count,scene.edge_count,scene.item_group_count, bounded item-group semantic, entity-index, and entity-role rows foraltr,ster, andpymd,scene.has_content_bound_metadata,scene.content_bound_metadata_policy, andscene.multi_image_candidate,scene.multi_image_policy), graph-component summaries (scene.graph_node_count,scene.graph_component_count,scene.graph_image_component_count,scene.graph_multi_image_component_count,scene.graph_content_bound_metadata_component_count,scene.graph_observed_edge_count, per-component rows (scene.component.index,scene.component.role,scene.component.item_id, known/unknown and semantic*_node_countfields,scene.component.isolated, typed auxiliary/derived/thumbnail/ content-description*_edge_countfields, and alpha/depth/disparity/matte auxiliary edge counts),scene.primary_graph_component_node_count,scene.primary_graph_component_*_node_count,scene.primary_graph_component_edge_count,scene.primary_graph_component_has_content_bound_metadata,scene.primary_graph_component_multi_image_candidate,scene.primary_graph_component_multi_image_policy, andscene.primary_graph_component_metadata_policy), and bounded derived-image construction rows (derived_image.*) forgrid,iovl, andiden, including ordered source IDs, descriptor/source/count validity, grid rows/columns/tile coordinates/output dimensions, overlay canvas/background/signed offsets, identity sources, descriptor-reference depth, graph cycle/self-reference/missing-source/depth/truncation validity, and primary aliases. Descriptor reads use complete method-0 file extents, method-1idatextents, or bounded recursive method-2 item-offset chains. External data references other than tiled-imagedetiURL state and incomplete extents remain structural-only.tiliitems expose boundedtilCversion-0 tile dimensions, up to eight extra dimensions, required single-ispe/single-tilCrelationship checks, ceil-divided tile grids, overflow-checked expected tile counts, mappeddref/detistate, internaltile_item_typeand nestedtipaproperty associations, external URL components, logical offset-table rows, explicit or sequentially inferred sizes, empty tiles, and separate core/layout/complete validity. Offset validation scans at most 262144 entries and emits at most 64 rows. Also emitsauxC-based aux semantics (aux.item_count,aux.item_id,aux.semantic,aux.type,aux.subtype_hex,aux.subtype_kind,aux.subtype_text,aux.subtype_uuid,aux.subtype_u32,aux.subtype_u64,aux.alpha_count,aux.depth_count,aux.disparity_count,aux.matte_count,primary.auxl_count,primary.auxl_semantic,primary.depth_count,primary.depth_item_id,primary.alpha_count,primary.alpha_item_id,primary.disparity_count,primary.disparity_item_id,primary.matte_count,primary.matte_item_id,primary.dimg_count,primary.dimg_item_id,primary.thmb_count,primary.thmb_item_id,primary.cdsc_count,primary.cdsc_item_id, ...). Full multi-image scene modeling beyond these bounded aggregate surfaces is still follow-up work.auxCsubtype interpretation now includesascii_zandu64bekinds in addition to earlier numeric/FourCC/UUID/ASCII forms.Parsing is intentionally bounded (depth/box count caps) and ignores unknown properties.
derived_image.constructionand primary construction aliases resolve to the source-boundcontainer_graph.derived_image_constructionconcept. Compatible-file diagnostics keep this evidence; rendered-image diagnostics use the dedicateddrop.derived_image_constructionmessage token.tiled_image.configurationresolves separately to the source-boundcontainer_graph.tiled_image_configurationconcept. Rendered-image diagnostics usedrop.tiled_image_configuration.
JUMBF/C2PA decode (draft phase-3):
src/openmeta/jumbf_decode.ccRouted from container scan blocks tagged as
ContainerBlockKind::Jumbf(BMFFjumb/C2PA hints and JXLjumbboxes).Emits structural fields as
MetaKeyKind::JumbfField(box.*,c2pa.*, including JUMBF labels from parsedjumdboxes) and decoded CBOR keys asMetaKeyKind::JumbfCborKey(*.cbor.*).Current CBOR path supports bounded definite and indefinite forms, with composite-key fallback naming (
k{map_index}_{ major}) and broader scalar decode coverage (simple values + half/float/double bit-preserving paths).Draft semantic projection emits stable
c2pa.semantic.*fields (manifest_present,active_manifest_present,active_manifest_count,active_manifest.prefix,claim_present,assertion_present,ingredient_present,signature_present,assertion_key_hits,ingredient_key_hits,cbor_key_count,signature_count,claim_generatorwhen ASCII-safe), plus draft per-claim fields (claim_count,assertion_count,ingredient_count,claim.{i}.prefix,claim.{i}.assertion_count,claim.{i}.key_hits,claim.{i}.ingredient_count,claim.{i}.signature_count,claim.{i}.signature_key_hits,claim.{i}.claim_generatorwhen ASCII-safe), per-assertion fields (claim.{i}.assertion.{j}.prefix,claim.{i}.assertion.{j}.key_hits), and per-ingredient fields (claim.{i}.ingredient.{j}.prefix,claim.{i}.ingredient.{j}.key_hits,claim.{i}.ingredient.{j}.title,claim.{i}.ingredient.{j}.relationship,claim.{i}.ingredient.{j}.thumbnail_urlwhen ASCII-safe), plus bounded ingredient summary counts (ingredient_relationship_count,ingredient_thumbnail_url_count,ingredient_claim_count,ingredient_claim_with_signature_count,ingredient_claim_referenced_by_signature_count, per-claim linked-ingredient summary fields such asclaim.{i}.linked_ingredient_signature_count,claim.{i}.linked_ingredient_title_count,claim.{i}.linked_ingredient_relationship_count,claim.{i}.linked_ingredient_thumbnail_url_count,claim.{i}.linked_ingredient_relationship_kind_count, and explicit-reference split variants likeclaim.{i}.linked_ingredient_explicit_reference_title_count, plus aggregate linked-claim topology counts likeingredient_linked_claim_countandingredient_linked_claim_direct_source_count,ingredient_manifest_count,ingredient_signature_count,ingredient_linked_signature_count,ingredient_linked_direct_claim_count,ingredient_linked_cross_claim_count,ingredient_linked_signature_direct_source_count,ingredient_linked_signature_cross_source_count,ingredient_linked_signature_mixed_source_count,ingredient_linked_signature_direct_title_count,ingredient_linked_signature_cross_title_count,ingredient_linked_signature_direct_relationship_count,ingredient_linked_signature_cross_relationship_count,ingredient_linked_signature_direct_thumbnail_url_count,ingredient_linked_signature_cross_thumbnail_url_count,ingredient_linked_signature_title_count,ingredient_linked_signature_relationship_count,ingredient_linked_signature_relationship_kind_count,ingredient_linked_signature_relationship.<value>_count,ingredient_linked_signature_thumbnail_url_count,ingredient_linked_signature_explicit_reference_direct_title_count,ingredient_linked_signature_explicit_reference_cross_title_count,ingredient_linked_signature_explicit_reference_title_count,ingredient_linked_signature_explicit_reference_relationship_count,ingredient_linked_signature_explicit_reference_relationship_kind_count,ingredient_linked_signature_explicit_reference_relationship.<value>_count,ingredient_linked_signature_explicit_reference_thumbnail_url_count,ingredient_linked_signature_explicit_reference_direct_claim_count,ingredient_linked_signature_explicit_reference_cross_claim_count,ingredient_linked_signature_explicit_reference_direct_source_count,ingredient_linked_signature_explicit_reference_cross_source_count,ingredient_linked_signature_explicit_reference_mixed_source_count, plus corresponding..._unresolved_*and..._ambiguous_*split aggregates,ingredient_explicit_reference_signature_count,ingredient_explicit_reference_unresolved_signature_count,ingredient_explicit_reference_ambiguous_signature_count,claim.{i}.ingredient_relationship_count,claim.{i}.ingredient_thumbnail_url_count,manifest.{i}.ingredient_relationship_count,manifest.{i}.ingredient_thumbnail_url_count,manifest.{i}.ingredient_claim_count) and path-sanitized relationship alias counts such asingredient_relationship.parentOf_count, plus per-manifest active-state fields (manifest.{i}.is_active,manifest.{i}.ingredient_count), plus draft per-claim signature fields (claim.{i}.signature.{k}.prefix,claim.{i}.signature.{k}.key_hits,claim.{i}.signature.{k}.algorithmwhen available), plus draft per-signature fields (signature_count,signature_key_hits,signature.{k}.prefix,signature.{k}.key_hits,signature.{k}.algorithmwhen available,signature.{k}.reference_key_hits,signature.{k}.linked_claim_count,signature.{k}.linked_ingredient_claim_count,signature.{k}.linked_direct_ingredient_claim_count,signature.{k}.linked_cross_ingredient_claim_count,signature.{k}.linked_ingredient_title_count,signature.{k}.linked_ingredient_relationship_count,signature.{k}.linked_ingredient_relationship_kind_count,signature.{k}.linked_ingredient_relationship.<value>_count,signature.{k}.linked_ingredient_thumbnail_url_count,signature.{k}.direct_claim_has_ingredients,signature.{k}.cross_claim_link_count,signature.{k}.explicit_reference_present,signature.{k}.explicit_reference_resolved_claim_count,signature.{k}.explicit_reference_unresolved,signature.{k}.explicit_reference_ambiguous,signature.{k}.linked_claim.{m}.prefix), plus reference-link counters (reference_key_hits,cross_claim_link_count,explicit_reference_signature_count,explicit_reference_unresolved_signature_count,explicit_reference_ambiguous_signature_count,claim.{i}.referenced_by_signature_count), and linkage counters (signature_linked_count,signature_orphan_count).Draft verify scaffold (
c2pa.verify.*) now includes:signature-shape validation (
invalid_signature) for malformed payloads;OpenSSL-backed cryptographic verification (
verified/verification_failed) when a signature entry provides algorithm + signing input + public key material (public_key_der/public_key_pemorcertificate_der).opt-in trusted-chain enforcement via
verify_require_trusted_chain/--c2pa-verify-require-trusted-chain; without this option, signature verification and certificate-chain trust are reported as separate signals.COSE_Sign1 support (array or embedded CBOR byte-string forms): extracts
algfrom protected headers, reconstructs Sig_structure signing bytes when payload is present, extractsx5chainfrom unprotected headers, and accepts raw ECDSA signatures (r||s) by converting to DER for OpenSSL.detached payload resolution (
payload=null) using explicit reference-linked candidates first (for exampleclaims[n]/ claim-label references in decoded claim/signature fields, scalar index references, and indexed array-element reference keys such asclaimRef[0]), then including plural reference-key variants (references,refs,claim_references) plus hyphenated variants (claim-reference,claim-uri,claim-ref-index), nested URI-like map fields such asreferences[].href/references[].link, query-style index tokens in URI text (claim-index=...,claim_ref=...), and percent-encoded URI/label forms where present. Candidate ordering is deterministic with sorted index-like references resolved before sorted label-based references, then best-effort fallback probing via claim bytes, single-claimclaims[*]arrays, nearby/nested claim JUMBF boxes, and additional cross-manifest candidates. Current tests include conflicting mixed references and multi-claim/multi-signature cross-manifest precedence cases, nestedreferences[]map forms, duplicate overlapping explicit references, unresolved explicit-reference no-fallback behavior, conflict/consistentindex + claim_reference + hrefnested-map ambiguity/consistency cases, and percent-encoded query-index URI variants.draft profile checks (
profile_status/profile_reason) from decodedc2pa.semantic.*shape fields (manifest/claim/signature linkage);draft certificate trust checks (
chain_status/chain_reason) whencertificate_deris present (certificate parse, time validity, and OpenSSL trust-store verification). Full C2PA/COSE manifest binding and policy validation is still pending.
GeoTIFF GeoKey decoding (derived keys):
src/openmeta/geotiff_decode.ccVendor MakerNote decoders:
src/openmeta/exif_makernote_*.cc(Canon, Nikon, Sony, Olympus, Pentax, Casio, Panasonic, Kodak, Ricoh, Samsung, FLIR, etc.)Shared internal-only helpers:
src/openmeta/exif_tiff_decode_internal.h(not installed; used to keep vendor logic out of the public API)Tests:
tests/makernote_decode_test.ccandtests/jumbf_decode_test.ccWhen adding or changing MakerNote code, prefer extending the vendor files and keeping the EXIF/TIFF core container-agnostic. Add/adjust a unit test for any new subtable or decode path.Internal helper conventions (used by vendor decoders):read_classic_ifd_entry(...)+ClassicIfdEntry: parse a single 12-byte classic TIFF IFD entry.resolve_classic_ifd_value_ref(...)+ClassicIfdValueRef: compute the value location/size for a classic IFD entry (inline vs out-of-line), usingMakerNoteLayout+OffsetPolicy.MakerNoteLayout+OffsetPolicy: makes "value offsets are relative to X" explicit for vendor formats.OffsetPolicysupports both the common unsigned base (default) and a signed base for vendors that require it (eg Canon).ExifContext: a small, decode-time cache for frequently accessed EXIF values (avoids repeated linear scans ofstore.entries()).MakerNote tag-name tables are generated from
registry/exif/makernotes/*.jsonland looked up via binary search (exif_makernote_tag_names.cc).Canonical EXIF names stay context-free via
exif_tag_name(...). When corpus compatibility requires a decode-time alias split, stamp the variant on theEntryprovenance and resolve it only on explicit display surfaces throughexif_entry_name(..., ExifTagNamePolicy::ExifToolCompat).Photoshop IRB stays lossless at the raw-resource layer (
PhotoshopIrb). Add interpreted IRB fields only for fixed-layout resources, bounded descriptor-header summaries, or bounded scalar/class/alias/reference descriptor item bodies, and emit them as separatePhotoshopIrbFieldentries instead of weakening the raw payload surface. The current bounded interpreted subset includesResolutionInfo,AlphaChannelsNames,DisplayInfo,PStringCaption,BorderInformation,BackgroundColor,Photoshop2Info,Photoshop2ColorTable,VersionInfo,PrintFlags, print-flag byte fields,EffectiveBW,QuickMaskInfo,RawImageMode,TargetLayerID,LayersGroupInfo,JPEG_Quality,GridGuidesInfo, legacy halftone/transfer/duotone/EPS byte summaries,CopyrightFlag,URL,GlobalAngle,SpotHalftone,JumpToXPEP,ColorSamplersResource,ColorSamplersResource2,Watermark,ICC_Untagged,EffectsVisible,IDsBaseValue,UnicodeAlphaNames,IndexedColorTableCount,TransparentIndex,GlobalAltitude,SliceInfo,WorkflowURL,AlphaIdentifiers,URL_List,IPTCDataBytes,IPTCDigest,PrintScaleInfo,PixelInfo,AutoSaveFilePath,AutoSaveFormat,XMLData,ImageReadyVariables,ImageReadyDataSets, working-path and numbered clipping-path record summaries, descriptor-header, scalar/class/alias/enum, boundedobjproperty/class/enumerated/offset/identifier/index/name reference streams, and bounded nested list/object summaries forLayerComps,MeasurementScale,HDRToningInfo,PrintInfo,TimelineInfo,SheetDisclosure,OnionSkins,CountInfo,PrintInfo2,PrintStyle,PathSelectionState, andOriginPathInfo,PhotoshopBGRThumbnail,PhotoshopThumbnail,LayerSelectionIDs,LayerGroupsEnabledID,ChannelOptions,PrintFlagsInfo,ClippingPathName,MacintoshPrintInfo,MacintoshNSPrintInfo,WindowsDEVMODE,AlternateDuotoneColors,AlternateSpotColors, ObsoletePhotoshopTag1, ObsoletePhotoshopTag2, and ObsoletePhotoshopTag3.Descriptor
objtraversal is capped at 64 reference items per value and 128 per descriptor. Unknown, incomplete, or excess items stop traversal, setDescriptorItemParseTruncated, and never emit a partial reference item.Legacy 8-bit Photoshop text stays opt-in and explicit. The IRB decoder exposes a bounded
PhotoshopIrbStringCharsetpolicy and currently uses it only forAlphaChannelsNames,PStringCaption, andClippingPathName, defaulting to Latin for ExifTool-compatible behavior instead of guessing from bytes.ChannelOptionsstays bounded and explicit: emit one count row, then oneChannelIndexrow plus the channel fields in stable order for each 13-byte record instead of inventing dynamic field names.PrintFlagsInfois bounded to the stableexiv2-documented 10-byte layout: version, center-crop flag, bleed-width value, and bleed-width scale.GeoTIFF key-name table is generated from
registry/geotiff/keys.jsonland looked up via binary search (geotiff_key_names.cc).
Tests (GoogleTest)¶
Requirements:A GoogleTest package that provides
GTest::gtest_main(orGTest::Main).
Note: if your GoogleTest was built againstlibc++(common with Clang), build OpenMeta against the same C++ standard library. Otherwise you may see link errors involvingstd::__1vsstd::__cxx11.If external test tools were built withlibc++and need a custom runtime lookup path, setOPENMETA_TEST_RUNTIME_LIBRARY_PATHat configure time. This is applied to CTest-launched tests throughLD_LIBRARY_PATHon Linux andDYLD_LIBRARY_PATHon macOS.Build + run:cmake -S . -B build-tests -G Ninja -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_PREFIX_PATH=/mnt/f/UBSd \ -DOPENMETA_BUILD_TESTS=ON cmake --build build-tests ctest --test-dir build-tests --output-on-failure
A full CTest run executes the complete unit suite once and each registered CLI, allocation, package, install, and enabled Python check once. Aggregate read, transfer, CLI, and fuzzy release gates are focused custom targets, not CTest tests. Building anopenmeta_gate_*target executes its checks. Choose a focused target or the full CTest run for a validation batch; running both repeats coverage. Individual smoke checks remain available throughctest -Rafter building their binaries.The CLI smoke and release gates use Python to create deterministic fixtures. SetOPENMETA_PYTHON_EXECUTABLEwhen the intended interpreter is not namedpython3or is outsidePATH.tests/public_metadata_fixtures.hprovides compact, source-built public integration fixtures for TIFF/DNG with a representative Nikon MakerNote, WebP, AVIF, JP2, JXL, RAF, X3F, and CRW. These fixtures contain no copied third-party files and are suitable for downstream smoke tests that need stable metadata carriers without external assets. The RAF and X3F fixtures include declared embedded JPEG metadata and a synthetic entropy interval for proving that positional scans do not fetch image data.Optional CLI integration test for preview index suffixing:cmake -S . -B build-tests -G Ninja -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_PREFIX_PATH=/mnt/f/UBSd \ -DOPENMETA_BUILD_TESTS=ON \ -DOPENMETA_MULTI_PREVIEW_SAMPLE=/path/to/file_with_multiple_previews cmake --build build-tests ctest --test-dir build-tests -R openmeta_cli_preview_index --output-on-failure
IfOPENMETA_MULTI_PREVIEW_SAMPLEis not set (or the file is missing),openmeta_cli_preview_indexis skipped.Fast public smoke gate formetavalidate(self-contained, no corpus needed):cmake --build build-tests --target openmeta_gate_metavalidate_smoke
Fast public smoke gate formetareadsafe-text placeholder behavior:cmake --build build-tests --target openmeta_gate_metaread_safe_text_smoke
Fast public smoke gate formetareadPhotoshop IRB field visibility:cmake --build build-tests --target openmeta_gate_metaread_photoshop_irb_smoke
Fast public smoke gate formetatransferthin wrapper behavior:cmake --build build-tests --target openmeta_gate_metatransfer_smoke
Fast public smoke gate for Pythonopenmeta.transfer_probethin wrapper behavior (requires-DOPENMETA_BUILD_PYTHON=ON):cmake --build build-tests --target openmeta_gate_python_transfer_probe_smoke
Fast public smoke gate for Pythonopenmeta.python.metatransferedit mode behavior (requires-DOPENMETA_BUILD_PYTHON=ON):cmake --build build-tests --target openmeta_gate_python_metatransfer_edit_smoke
Stronger transfer release gate:in a non-Python test tree it runs:
MetadataTransferApi.*XmpDump.*ExrAdapter.*DngSdkAdapter.*openmeta_cli_metatransfer_smokeopenmeta_cli_metatransfer_image_usability
in a Python-enabled test tree it also runs:
openmeta_python_transfer_probe_smokeopenmeta_python_metatransfer_edit_smoke
Build + run:cmake --build build-tests --target openmeta_gate_transfer_release
The external image-usability gate can also use existing BMFF target files when local tools cannot create them:OPENMETA_BMFF_HEIF_TEST_TARGET,OPENMETA_BMFF_AVIF_TEST_TARGET, andOPENMETA_BMFF_CR3_TEST_TARGET. Configured targets exercise the ICC property, XMP item, MakerNote, and EXIF image-property transfer/read-back paths. For real configured targets, the gate infers target-owned image dimensions, channel count, bit depth, sample format, and photometric layout before transfer, so it does not intentionally write mismatched image geometry. The configured XMP assertion is based on OpenMeta's BMFF summary; ExifTool title validation is also applied for formats where ExifTool exposes the generic BMFF XMP item. ExifTool is also used for BMFF EXIF/ICC reader checks when available. If the localoiiotoolbuild cannot decode a configured BMFF target after rewrite,OPENMETA_FFMPEG_EXECUTABLEcan provide the decode fallback.ExifTool is an optional external validation tool in these tests, not an OpenMeta runtime dependency. Keep it patched when running validation against untrusted files. This matters especially on macOS, where older ExifTool releases have had metadata-write command-injection issues in their own platform-specific tooling.The public GitHub Actions workflow.github/workflows/ci.ymlruns two Linux variants of the full CTest suite, building binaries before running each registered check once:self-contained non-Python, non-DNG-SDK
Python-enabled, non-DNG-SDK, with
nanobindinstalled into the CI interpreter viapip
Read release gate:core self-contained decode and adapter suites such as:
ContainerScan.*ContainerPayload.*ExifTiffDecode.*SimpleMetaRead.*XmpDecodeTest.*JumbfDecode.*OcioAdapter.*ExrAdapter.*ValidateFile.*
Build + run:cmake --build build-tests --target openmeta_gate_read_release
CLI release gate:self-contained non-transfer CLI smokes:
openmeta_cli_metaread_safe_text_smokeopenmeta_cli_metaread_photoshop_irb_smokeopenmeta_cli_metavalidate_smokeopenmeta_cli_numeric_parse_smoke
Build + run:cmake --build build-tests --target openmeta_gate_cli_release
Coverage note:Public tree tests focus on deterministic unit/fuzz/smoke behavior.
Corpus-scale compare/baseline workflows are external to the public tree and should be run in your CI/release validation pipeline.
libFuzzer Targets¶
Requirements:Clang with libFuzzer support.
Notes:On Linux, Clang's bundled libFuzzer runtime is typically built against
libstdc++. WhenOPENMETA_USE_LIBCXX=ON, OpenMeta keeps tests/tools onlibc++but builds fuzz targets againstlibstdc++to match libFuzzer.libFuzzer treats metadata as untrusted input; always run under sanitizers and with explicit size limits.
Build + run (example 5s smoke run):cmake -S . -B build-fuzz -G Ninja -DCMAKE_BUILD_TYPE=Debug \ -DOPENMETA_BUILD_FUZZERS=ON cmake --build build-fuzz ASAN_OPTIONS=detect_leaks=0 ./build-fuzz/openmeta_fuzz_exif_tiff_decode -max_total_time=5
Corpus runs (seed corpora)¶
If you pass corpus directories to libFuzzer, it treats the first directory as the main corpus and may add/reduce files there. To avoid modifying your seed corpus directories, use an empty output directory first:mkdir -p build-fuzz/_corpus_out ASAN_OPTIONS=detect_leaks=0 ./build-fuzz/openmeta_fuzz_container_scan \ build-fuzz/_corpus_out \ /path/to/seed-corpus-a /path/to/seed-corpus-b \ -runs=1000
Public seed corpus is available in-tree:mkdir -p build-fuzz/_corpus_out ASAN_OPTIONS=detect_leaks=0 ./build-fuzz/openmeta_fuzz_container_scan \ build-fuzz/_corpus_out \ tests/fuzz/corpus/container_scan \ -runs=1000
Thecontainer_scanseed set includes BMFFilocmethod-2 edge cases:valid
irefv1 (32-bititem-id) resolution,missing
irefmapping,out-of-range explicit
extent_index,idx_size=0extent/reference mismatch fallback behavior.
FuzzTest¶
Requirements:A FuzzTest package that provides
fuzztest::fuzztestandfuzztest::fuzztest_gtest_main.
Build + run:cmake -S . -B build-fuzztest -G Ninja -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_PREFIX_PATH=/mnt/f/UBSd \ -DOPENMETA_BUILD_FUZZTEST=ON -DOPENMETA_FUZZTEST_FUZZING_MODE=ON cmake --build build-fuzztest ASAN_OPTIONS=detect_leaks=0 ./build-fuzztest/openmeta_fuzztest_metastore --list_fuzz_tests ASAN_OPTIONS=detect_leaks=0 ./build-fuzztest/openmeta_fuzztest_metastore --fuzz=MetaStoreFuzz.meta_store_op_stream --fuzz_for=5s
Python (nanobind)¶
Requirements:Python
>= 3.9+ development headers/librariesnanobindinstalled as a CMake package (findable viaCMAKE_PREFIX_PATH)
Build:cmake -S . -B build-py -G Ninja -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_PREFIX_PATH=/mnt/f/UBS \ -DOPENMETA_BUILD_PYTHON=ON -DOPENMETA_BUILD_TOOLS=OFF cmake --build build-py PYTHONPATH=build-py/python python3 -c "import openmeta; print(openmeta.read('file.jpg').entry_count)"
Notes:openmeta.read(...)releases the Python GIL while doing file I/O and decode, so it can be called from multiple Python threads in parallel (useful for corpus comparisons).openmeta.validate(...)is the library-backed validation API used byopenmeta.python.metavalidate; it returns decode/CCM issue summaries without Python-side validation logic.Python bindings are thin wrappers over C++ decode logic. Resource/safety limits should be configured via
openmeta.ResourcePolicyand passed toopenmeta.read(...).
Example policy usage:PYTHONPATH=build-py/python python3 - <<'PY' import openmeta policy = openmeta.ResourcePolicy() policy.max_file_bytes = 0 policy.exif_limits.max_total_entries = 200000 doc = openmeta.read("file.jpg", policy=policy) print(doc.entry_count) PY
C++ policy setup:#include "openmeta/resource_policy.h" openmeta::OpenMetaResourcePolicy policy = openmeta::recommended_resource_policy(); policy.jumbf_limits.max_box_depth = 24; // optional override
JUMBF preflight depth estimate (before full decode):#include "openmeta/jumbf_decode.h" const openmeta::JumbfStructureEstimate est = openmeta::measure_jumbf_structure(bytes, policy.jumbf_limits); if (est.status == openmeta::JumbfDecodeStatus::LimitExceeded) { // reject or route to stricter handling }
Other preflight estimate entry points follow the same limit model:#include "openmeta/container_scan.h" #include "openmeta/exif_tiff_decode.h" #include "openmeta/exr_decode.h" #include "openmeta/icc_decode.h" #include "openmeta/iptc_iim_decode.h" #include "openmeta/jumbf_decode.h" #include "openmeta/photoshop_irb_decode.h" #include "openmeta/xmp_decode.h" const openmeta::ScanResult scan_est = openmeta::measure_scan_auto(file_bytes); const openmeta::ContainerRandomAccessScanResult jpeg_scan_est = openmeta::measure_scan_jpeg_random_access( jpeg_range, jpeg_scan_scratch, read_limits); const openmeta::ContainerRandomAccessScanResult bmff_scan_est = openmeta::measure_scan_bmff_random_access( bmff_range, container_scan_scratch, read_limits); const openmeta::ExifDecodeResult exif_est = openmeta::measure_exif_tiff(exif_bytes, exif_options); const openmeta::XmpDecodeResult xmp_est = openmeta::measure_xmp_packet(xmp_bytes, xmp_options); const openmeta::IccDecodeResult icc_est = openmeta::measure_icc_profile(icc_bytes, icc_options); const openmeta::IptcIimDecodeResult iptc_est = openmeta::measure_iptc_iim(iptc_bytes, iptc_options); const openmeta::PhotoshopIrbDecodeResult irb_est = openmeta::measure_photoshop_irb(irb_bytes, irb_options); const openmeta::ExrDecodeResult exr_est = openmeta::measure_exr_header(exr_bytes, exr_options); const openmeta::JumbfDecodeResult jumbf_est = openmeta::measure_jumbf_payload(jumbf_bytes, jumbf_options);
Example scripts (repo tree):PYTHONPATH=build-py/python python3 -m openmeta.python.openmeta_stats file.jpg PYTHONPATH=build-py/python python3 -m openmeta.python.metaread file.jpg PYTHONPATH=build-py/python python3 -m openmeta.python.metavalidate file.dng PYTHONPATH=build-py/python python3 -m openmeta.python.metadump file.jpg PYTHONPATH=build-py/python python3 -m openmeta.python.metadump file.jpg output.xmp PYTHONPATH=build-py/python python3 -m openmeta.python.metadump --format portable file.jpg PYTHONPATH=build-py/python python3 -m openmeta.python.metadump --format portable --portable-exiftool-gpsdatetime-alias file.jpg PYTHONPATH=build-py/python python3 -m openmeta.python.metadump --format portable --c2pa-verify --c2pa-verify-backend auto file.jpg PYTHONPATH=build-py/python python3 -m openmeta.python.metadump --format portable --portable-include-existing-xmp --xmp-sidecar file.jpg PYTHONPATH=build-py/python python3 -m openmeta.python.metatransfer file.jpg PYTHONPATH=build-py/python python3 -m openmeta.python.metatransfer --target-jpeg target.jpg -o edited.jpg source.jpg PYTHONPATH=build-py/python python3 -m openmeta.python.metatransfer --target-tiff target.tif --dry-run source.jpg PYTHONPATH=build-py/python python3 -m openmeta.python.metatransfer --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 edited.jpg input_with_c2pa.jpg PYTHONPATH=build-py/python python3 -m openmeta.python.metatransfer --c2pa-policy rewrite --dump-c2pa-handoff handoff.omc2ph input_with_c2pa.jpg PYTHONPATH=build-py/python python3 -m openmeta.python.metatransfer --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 --dump-c2pa-signed-package signed.omc2ps input_with_c2pa.jpg PYTHONPATH=build-py/python python3 -m openmeta.python.metatransfer --load-c2pa-signed-package signed.omc2ps --target-jpeg target.jpg -o edited.jpg input_with_c2pa.jpg PYTHONPATH=build-py/python python3 -m openmeta.python.metatransfer --dump-transfer-payload-batch payloads.omtpld input.jpg PYTHONPATH=build-py/python python3 -m openmeta.python.metatransfer --load-transfer-payload-batch payloads.omtpld PYTHONPATH=build-py/python python3 -m openmeta.python.metatransfer --dump-transfer-package-batch package.omtpkg input.jpg PYTHONPATH=build-py/python python3 -m openmeta.python.metatransfer --load-transfer-package-batch package.omtpkg
Python Wheel¶
Requirements:scikit-build-coreinstalled in your Python environment.A wheel builder:
pip(recommended) oruv(works even if your venv has nopip).
Build:Or usingpython3 -m pip wheel . -w dist --no-deps
uv:After installing the wheel, example modules are available as:uv --no-cache build --wheel --no-build-isolation -o dist -p "$(command -v python3)" .
Or via CMake:python3 -m openmeta.python.openmeta_stats file.jpg python3 -m openmeta.python.metaread file.jpg python3 -m openmeta.python.metatransfer file.jpg
cmake -S . -B build-wheel -G Ninja -DCMAKE_BUILD_TYPE=Release \ -DOPENMETA_BUILD_WHEEL=ON \ -DOPENMETA_PYTHON_EXECUTABLE=/path/to/venv/bin/python3 cmake --build build-wheel --target openmeta_wheel
The CMake wheel target and install-time wheel script forward the active compiler flags, selected Python paths,OPENMETA_USE_LIBCXX, and optional feature toggles into the nested scikit-build configure step. This keeps wheel ABI choices aligned with the outer CMake build, including libc++-based Linux builds. Package lookup hints are forwarded as well. PreferCMAKE_PREFIX_PATHfor a complete dependency prefix. If nanobind was packaged with an externaltsl-robin-mapdependency and CMake cannot resolve it from that prefix, pass-Dtsl-robin-map_DIR=/path/to/share/cmake/tsl-robin-map; the wheel configure inherits that explicit package directory.WhenOPENMETA_BUILD_WHEEL=ON,cmake --installalso builds a wheel and copies it into${CMAKE_INSTALL_PREFIX}/share/openmeta/wheels(and also copies the Python helper scriptsmetaread.py,metavalidate.py,metadump.py,metatransfer.py, andopenmeta_stats.pyinto the same directory):cmake --install build-wheel --prefix /tmp/openmeta-install ls /tmp/openmeta-install/share/openmeta/wheels
If you are building offline (or want strict control of the build environment), installscikit-build-coreinto your Python environment and enable:-DOPENMETA_WHEEL_NO_BUILD_ISOLATION=ON.Interop Surfaces¶
Interop surfaces are split deliberately:export-only naming/traversal surface:
openmeta/interop_export.hwith the shared export naming styles. This is the intended base for host-owned metadata mapping layers.export-only adapter:
openmeta/ocio_adapter.hfor deterministic OCIO-style metadata trees.host-apply adapter:
openmeta/exr_adapter.hfor EXR-native per-part attribute export.direct bridge:
openmeta/dng_sdk_adapter.hfor applications that already use Adobe DNG SDK objects/files.narrow translator:
openmeta/libraw_adapter.hfor explicit orientation mapping into LibRaw's flip convention.
Current Python binding entry points:Document.export_names(style=..., include_makernotes=...)Document.ocio_metadata_tree(...)Document.unsafe_ocio_metadata_tree(...)Document.dump_xmp_sidecar(format=...)Document.phaseone_raw_geometry()andDocument.phaseone_raw_processing()for normalized Phase One/Leaf RAW source metadata queries.Document.vendor_raw_processing(family)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/Microsoft grouped RAW/source-processing field summaries.
Current C++ interop entry points:visit_metadata(...)use the shared naming styles when a host-owned metadata mapping layer needs deterministic exported names
build_exr_attribute_batch(...)build_exr_attribute_part_spans(...)build_exr_attribute_part_views(...)replay_exr_attribute_batch(...)the batch carries:
part_index,name,type_name,valuebytes, andis_opaque
safe API:
build_ocio_metadata_tree_safe(..., InteropSafetyError*)unsafe API:
build_ocio_metadata_tree(...)build_ocio_metadata_tree(..., const OcioAdapterRequest&)build_ocio_metadata_tree(..., const OcioAdapterOptions&)
Python interop behavior:Document.export_names(style=ExportNameStyle.FlatHost, ...)exposes the stable v1 flat-host naming contract used by host-side metadata mapping layers. See flat_host_mapping.md.Document.ocio_metadata_tree(...)is safe-by-default and raises on unsafe raw byte payloads; useDocument.unsafe_ocio_metadata_tree(...)for legacy/raw fallback output.
Current C++ sidecar entry points:dump_xmp_sidecar(..., const XmpSidecarRequest&)(stable flat request API)dump_xmp_sidecar(..., const XmpSidecarOptions&)(advanced/legacy shape)
Draft C++ transfer entry points (prepare/emit scaffold):PreparedTransferBundle(target-ready payload container)backend emitter contracts:
JpegTransferEmitterTiffTransferEmitterJxlTransferEmitterWebpTransferEmitterExrTransferEmitter
prepare_metadata_for_target(..., PreparedTransferBundle*)currently prepares JPEG/TIFF transfer blocks plus the current bounded JXL/WebP/BMFF transfer set: EXIF APP1 (JPEG) / JXLExif/ WebPEXIF/ BMFF EXIF item, XMP (JPEG APP1 / TIFF tag 700 / JXLxmlbox / WebPXMPchunk / BMFF XMP item), ICC (JPEG APP2 / TIFF tag 34675 / JXL encoder ICC profile / WebPICCPchunk), IPTC (JPEG APP13 / TIFF tag 33723 or projected into JXL/WebP/BMFF XMP), bounded JUMBF/C2PA routes, with explicit warnings for unsupported/skipped entries.emit_prepared_bundle_jpeg(...)is implemented for route-based JPEG marker emission (jpeg:appN...,jpeg:com).emit_prepared_bundle_tiff(...)is implemented for route-based TIFF tag emission (tiff:ifd-exif-app1,tiff:tag-700-xmp,tiff:tag-34675-icc,tiff:tag-33723-iptc) and commit hook.Current CLI TIFF rewrite path supports classic TIFF (little- and big-endian) for ExifIFD materialization (
tiff:ifd-exif-app1).compile_prepared_bundle_jpeg(...)+emit_prepared_bundle_jpeg_compiled(...)provide route-compile + reusable emit plan for high-throughput "prepare once, emit many" use.compile_prepared_bundle_tiff(...)+emit_prepared_bundle_tiff_compiled(...)provide the same reusable route-compile emit plan for TIFF tag emission.apply_time_patches(...)applies fixed-width in-place updates overbundle.time_patch_map(for example EXIFDateTime*,SubSec*,OffsetTime*, GPS date/time slots) without full re-prepare.TIFF edit path mirrors JPEG edit path:
plan_prepared_bundle_tiff_edit(...)apply_prepared_bundle_tiff_edit(...)(classic TIFF rewrite for prepared EXIF/XMP/ICC/IPTC updates).
Writer/sink edit path is available for both targets:
TransferByteWriterSpanTransferByteWriterPreparedTransferExecutionPlanTimePatchViewwrite_prepared_bundle_jpeg(...)write_prepared_bundle_jpeg_compiled(...)write_prepared_bundle_jpeg_edit(...)write_prepared_bundle_tiff_edit(...)apply_time_patches_view(...)compile_prepared_transfer_execution(...)execute_prepared_transfer_compiled(...)write_prepared_transfer_compiled(...)emit_prepared_transfer_compiled(..., JpegTransferEmitter&)emit_prepared_transfer_compiled(..., TiffTransferEmitter&)ExecutePreparedTransferOptions::emit_output_writerExecutePreparedTransferOptions::edit_output_writerJPEG can stream either metadata-only emit bytes or edited output directly. TIFF edit output streams original input plus a planned metadata tail, avoiding a temporary full-file rewrite buffer.
prepare_metadata_for_target_file(...)provides the file-levelread/decode -> prepare bundlestep.execute_prepared_transfer(...)runs the sharedtime_patch -> compile -> emit -> optional editflow on an already prepared bundle.compile_prepared_transfer_execution(...)compiles a reusable execution plan that stores target-specific route mapping plus emit policy.build_prepared_transfer_adapter_view(...)flattens the same compiled route mapping into one target-neutral operation list for JPEG/TIFF/JXL/WebP/BMFF host integrations.emit_prepared_transfer_adapter_view(...)replays that compiled view into one generic host sink without route parsing.apply_time_patches_view(...)accepts non-owning patch spans for per-frame patching without owned update buffers.Stable
PreparedTransferHandoffInstanceclones compact payload and typed operation state once per worker. Its strict fixed-width patch batches fully validate before mutation and perform no allocation, route parsing, or operation recompilation during field-query/patch/index/replay.execute_prepared_transfer_compiled(...)runs the same sharedtime_patch -> emit -> optional editflow using a precompiled execution plan.write_prepared_transfer_compiled(...)is the narrow encoder-integration helper forprepare once -> compile once -> patch -> writeworkflows.SpanTransferByteWriteris the fixed-buffer adapter for encoder paths that want preallocated output memory and deterministic overflow reporting before any JPEG marker bytes are written.PreparedTransferPackagePlanis the shared final-output packaging layer for current JPEG/TIFF rewrite paths plus direct JPEG/JXL/WebP/BMFF emit packaging.TransferPackageChunkKind::SourceRangecopies bytes from the original input stream.TransferPackageChunkKind::PreparedTransferBlockserializes one prepared block directly for JPEG, JXL, WebP, PNG, JP2, or BMFF targets. BMFF direct packages carry stable item/property payload bytes; the file edit path is what wraps those payloads into a bounded top-levelmetagraph.TransferPackageChunkKind::PreparedJpegSegmentinjects one prepared JPEG marker segment from the bundle.TransferPackageChunkKind::InlineBytescarries deterministic generated bytes such as the patched TIFF IFD0 offset or appended TIFF tail.
PreparedTransferPackageBatchis the owned replay form of that package layer. It materializes each package chunk into stable bytes so host code can cache or hand off the final metadata package without retaining the original input stream or prepared bundle storage.serialize_prepared_transfer_package_batch(...)anddeserialize_prepared_transfer_package_batch(...)persist that owned batch for cross-process or cross-layer replay.collect_prepared_transfer_payload_views(...)andbuild_prepared_transfer_payload_batch(...)provide the matching target-neutral semantic surface one level earlier, directly over prepared bundles.serialize_prepared_transfer_payload_batch(...)anddeserialize_prepared_transfer_payload_batch(...)persist that semantic payload batch when a host wants cross-process handoff before final package materialization.collect_prepared_transfer_package_views(...)is the target-neutral semantic view above that persisted batch. It exposes semantic package chunks (Exif,Xmp,Icc,Iptc,Jumbf,C2pa, orUnknown) without pushing route parsing into host adapters.replay_prepared_transfer_package_batch(...)is the matching target-neutral callback replay path over the same persisted batch.OpenMeta no longer ships an in-library host-specific payload/package bridge above the target-neutral package and adapter surfaces.
PreparedTransferAdapterViewis the parallel adapter-facing surface for host integrations that want explicit per-block operations without route parsing.build_exr_attribute_batch(...),build_exr_attribute_part_spans(...),build_exr_attribute_part_views(...), andreplay_exr_attribute_batch(...)are the EXR-native bridge for OpenEXR header-attribute workflows. They stay outside thePreparedTransferBundlepath because EXR metadata is attribute-native, not block-native.build_prepared_transfer_emit_package(...),build_prepared_transfer_adapter_view(...),emit_prepared_transfer_adapter_view(...),build_prepared_bundle_jpeg_package(...),build_prepared_bundle_tiff_package(...), andwrite_prepared_transfer_package(...)expose that shared contract.emit_prepared_transfer_compiled(..., TiffTransferEmitter&)is the intended TIFF hot path; TIFF does not expose a metadata-only byte-writer emit contract.execute_prepared_transfer_file(...)wraps the fullread/decode -> prepare -> executeflow and is now the main thin-wrapper entry point for CLI/Python tooling.Python transfer entry point:openmeta.transfer_probe(...)(safe):calls the same file-level transfer execution API as the CLI, returning read/prepare/compile/emit summaries and prepared block routes/sizes;
supports
time_patches={Field: "Value" | b"..."}with shared C++ patch logic insideexecute_prepared_transfer(...);exposes
time_patch_*summary fields (time_patch_status_name,time_patch_patched_slots, ...);if
include_payloads=True, returnsoverall_status=unsafe_datawitherror_code=unsafe_payloads_forbidden.
openmeta.unsafe_transfer_probe(...):same probe contract, but allows
include_payloads=Trueand returns raw payload bytes (bytes) inblocks[i].payload.intended for explicit raw/unsafe workflows only.
Snapshot/fileless Python helpers:
openmeta.read_transfer_source_snapshot_file(...)andopenmeta.read_transfer_source_snapshot_bytes(...)expose the reusable decoded-source contract directly.Document.build_transfer_source_snapshot()andopenmeta.build_transfer_source_snapshot(document)mirror the C++MetaStore -> TransferSourceSnapshotbuilder.openmeta.transfer_snapshot_probe(...)/openmeta.transfer_snapshot_file(...)expose the core snapshot-based execute/persist path, including host-ownedtarget_bytes.openmeta.unsafe_transfer_snapshot_probe(...)/openmeta.unsafe_transfer_snapshot_file(...)add optional edited-output bytes for explicit unsafe workflows.the Python transfer wrappers now distinguish
xmp_existing_sidecar_base_pathfromxmp_sidecar_base_path, and they also exposexmp_existing_destination_embedded_pathplusxmp_existing_destination_sidecar_statefor pathless host flows.openmeta.python.metatransferremains a thin command-line wrapper: its--xmp-writeback,--xmp-destination-embedded,--xmp-destination-sidecar,--output, and--forceflags map directly onto the C++ file-helper options and persistence flags. It reports the sidecar and cleanup paths returned by the C++ result instead of deriving a separate Python-side contract.
Transfer probe contract hardening (stable machine fields):overall_status,overall_status_nameerror_stage(none|api|file|prepare|emit)error_code,error_messagestage-specific stable code enums/strings:
file:
PrepareTransferFileCode/file_code_nameprepare:
PrepareTransferCode/prepare_code_nameemit:
EmitTransferCode/emit_code_name
Current adapter/name-policy behavior:ExportNamePolicy::ExifToolAliasapplies compatibility aliases for interop-name parity workflows.ExportNamePolicy::Specpreserves spec/native names.Shared flat-host interop naming keeps numeric unknown names (for example
Exif_0x....) for parity workflows.When DNG context is detected (
DNGVersionpresent in the same IFD), DNG color/CCM tags are exported with dedicated adapter namespaces:dng:*(portable) and a flat host-style variant.ICC entries are exported with adapter-friendly names:
icc:*(portable) and a flat host-style variant, alongside canonicalicc:header:*/icc:tag:*naming.
Adapter-focused tests (public tree):cmake --build build-tests --target openmeta_tests ./build-tests/openmeta_tests --gtest_filter='InteropExport.*:OcioAdapter.*:ExrAdapter.*' ./build-tests/openmeta_tests --gtest_filter='ExrAdapter.*' ./build-tests/openmeta_tests --gtest_filter='CrwCiffDecode.*'
Notes:InteropExporttests cover alias/spec behavior and the flat host-style naming contract.ExrAdaptertests cover EXR batch export and replay behavior.CrwCiffDecodetests cover CRW/CIFF derived EXIF mapping for legacy Canon RAW.
Doxygen (Optional)¶
Requirements:doxygen(optional:graphviz)
Generate API docs:cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DOPENMETA_BUILD_DOCS=ON cmake --build build --target openmeta_docs
Sphinx Docs (Optional)¶
Requirements:doxygenPython packages listed in
docs/requirements.txt(Sphinx + Breathe;furois optional)
Install the Python deps into your active environment (example withuv):uv pip install -r docs/requirements.txt
Build:cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DOPENMETA_BUILD_SPHINX_DOCS=ON cmake --build build --target openmeta_docs_sphinx
Install:cmake --install build --prefix /tmp/openmeta-install ls /tmp/openmeta-install/share/doc/OpenMeta/html/index.html
The exported CMake package is installed under${CMAKE_INSTALL_LIBDIR}/cmake/OpenMeta. On Unix this may resolve to a multiarch path such aslib/x86_64-linux-gnu/cmake/OpenMetawhen the install prefix is/usr.When bothOPENMETA_BUILD_SPHINX_DOCS=ONandOPENMETA_BUILD_DOCS=ON, the Doxygen HTML output is installed undershare/doc/OpenMeta/doxygen/html.The 0.5.8 structured capture batch adds OECF, SpatialFrequencyResponse, CFAPattern and DeviceSettingDescription throughtranslate_xmp_structured_capture_metadataand its Python counterpart. The 0.5.8 combined inventory was 65 distinct native tags across fifteen APIs (62 retained by compatible-file transfer). ABI 3 and host synchronization remain unchanged; big-endian snapshots for the four new fields need a 0.5.8 reader. See Structured capture data.EXIF text update (0.5.9)¶
The 0.5.9 text/version batch adds UserComment, both version fields and seven EXIF 3 text tags. The new EXIF text API also supports UTF-8 owner/lens fields. The combined capture inventory is 75 distinct ExifIFD tags across sixteen APIs; compatible-file transfer retains 72. Version and Artist/Software companion requirements are explicit. ABI 3, snapshot v1 layout and host synchronization responsibilities remain unchanged. BOM-less big-endian UserComment snapshots require a 0.5.9 reader. See the EXIF text/version translation contract for limits and the recorded OIIO/ExifTool reader limitations.EXIF 3.1 development and correction update (0.5.11)¶
The six EXIF 3.1 development/correction fields A40D–A412 are implemented as one C++ and Python transaction. DevelopmentType uses the published DevelopmentCharacterstic / FactoryDefault XMP resource, and DevelopmentTypeDescription uses TIFF type 129 for all UTF-8 text. Selected writeback requires the host to choose EXIF version 0300 or 0310; OpenMeta never changes ExifVersion or infers a version. Shared validators cover authoring, editing, translation, portable XMP and serialization. Standard fields are retained by transfer when present, including rendered-image transfer; no RAW or MakerNote processing history is inferred. See the translation contract.EXIF 3.1 LearningOptOutIn and profile authoring update (0.5.12)¶
The bounded C++/Python LearningOptOutIn transaction projects the exactexifEXusage/intention structure into native tag0x9287, with complete shape, first-usage, duplicate-usage, byte-order and explicit EXIF 0300/0310 checks. The profile transaction projects ImageDescription, Artist, scalar Copyright, ColorSpace and RelatedSoundFile with shared validation and transactional conflict/tombstone handling. No ICC, image or audio association is inferred, and complete-file profile validation remains outside these APIs. Existing JP2 and boxed JPH rewrite tests cover carrier replacement and codestream/unknown-box preservation; OIIO/iRAW consumer acceptance remains pending. See the translation contract.
- page Documentation
OpenMeta uses Doxygen for API extraction. For the published site docs, we render Doxygen XML via Sphinx + Breathe.
Requirements¶
doxygen(optional:graphvizfor 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.htmlinside the build directory.When
OPENMETA_BUILD_DOCS=ON, docs are also generated duringinstall: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 tobuild/docs/doxygen/xml/index.xml.Publish on GitHub Pages¶
The repository includes a GitHub Actions workflow at
.github/workflows/docs-pages.ymlthat 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
mainand 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/DoxyfileOutput goes to
build/docs/doxygen/html/index.html.What gets documented¶
Markdown:
README.mdis 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.hprovides 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 finalizedMetaStorewithout 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);
sourcemust be finalized. The output is replaced only after every operation has passed validation and the entire edit has committed. On failure,editedis unchanged andfailed_operation_indexidentifies the rejected operation when available.Operation Semantics¶
|Operation
Behavior
AddCreates an absent singleton or appends a creator/keyword value. Adding an existing singleton is an explicit conflict.
SetReplaces one active value. Existing key, origin, block, wire provenance, and flags are preserved;
Dirtyis added.Remove| Marks one active value asDeleted | 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,
occurrenceis 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
SetandRemovereturnAmbiguousTarget; useRemoveAllfollowed byAddwhen that repair is intended. Missing targets are errors rather than silent no-ops.Provenance And Blocks¶
Setchanges only the value and dirty flag.Removechanges only entry flags. Both therefore retain the original block and wire provenance.Addemits 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¶
AddandSetuse 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:
1024operations1 MiBof UTF-8 text perAddorSetoperation8 MiBof UTF-8 text per request
MetadataEditingRequest::limitsmay 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 raiseValueErrorwith the C++ status and rejected operation index.Current Scope¶
The logical API edits the 24 fields listed in creation.md. The exact-key API below covers supported typed EXIF/IPTC/XMP/custom entries. Structural block editing, a full EXIF/IPTC/XMP synchronization engine and direct in-place file patching remain separate concerns. Supported edited creation dates can be projected explicitly into native EXIF/IPTC groups before persistence; see translation.md. Lower-level
MetaEditremains available for entry-ID-based host code, while transfer and writer APIs handle container persistence.Exact typed keys (0.5.6)¶
edit_metadata_typed(...)adds an experimental v1 C++ contract for exact EXIF/TIFF, IPTC-IIM and XMP keys, including private EXIF and custom XMP. It usesMetadataAuthoringEntryand the borrowedMetaValueViewhelpers from generic authoring. It copies all supplied keys and payloads. The logical-field API above continues to provide its own field-specific aliases and repeated-list behavior.#include "openmeta/metadata_editing.h" openmeta::MetadataTypedEditingOperation operation; operation.kind = openmeta::MetadataEditingOperationKind::Set; operation.entry.key = openmeta::make_exif_tag_key_view("exififd", 0xa405); operation.entry.value = openmeta::make_value_view_u16(50); const auto result = openmeta::edit_metadata_typed( source, std::span(&operation, 1), &source);
The finalized base and output may alias. Every supplied Add/Set value and the complete final candidate must pass structural and selected schema validation before publication. A failed request leaves both stores unchanged and reports an operation index or final candidate entry when available. Values overwritten later in the request must still be valid. A malformed unrelated base entry can therefore fail final validation; the caller can select schema policy through
MetadataTypedEditingOptions::validation.Operation
Exact-key behavior
Add
Default
FailIfPresentrejects an active exact key. ExplicitAppendpermits another occurrence, subject to final schema singleton checks. New entries are dirty and have no original source block.Set
Default
kMetadataTypedEditingUniqueOccurrencerequires exactly one active match. A numeric occurrence selects the zero-based current active match. The value and wire hints are replaced; source entry identity, block and order remain. Omitted wire hints request inference, and obsolete wire type names are cleared.Remove
Uses the same occurrence rules, or
kMetadataEditingAllOccurrencesfor all active matches. Tombstones preserve identity and provenance. Missing targets fail. Value and wire hints are ignored.Operations observe earlier edits, including additions and shifted occurrences. Removing all duplicate singleton entries followed by Add can repair a store in one transaction. XMP path indices remain part of the exact key; deleting
subject[1]does not renumbersubject[2]. This API performs no alias matching, namespace migration, container restructuring or automatic translation.Defaults bound the request to 4096 operations, 8 MiB of borrowed key/payload bytes, 200000 output entries, 64 MiB of output arena/value bytes and 4096 bytes per key component. Remove-all expansion counts against the operation budget. Output limits include retained tombstones and arena bytes; editing does not compact them. Existing lower store ceilings remain in force. Preparation may allocate. The host must synchronize conflicting access to shared objects; there are no library atomics or mutexes in this path.
The combined capture fixture now edits typed XMP, translates sixteen API groups, serializes/restores a transfer snapshot, and checks native and portable values through JPEG, classic TIFF and BigTIFF add/replace workflows. Exact-key authoring and editing remain C++ APIs; Python retains logical editing and mirrors the capture translation calls.
The 0.5.8 structured capture batch adds OECF, SpatialFrequencyResponse, CFAPattern and DeviceSettingDescription through
translate_xmp_structured_capture_metadataand its Python counterpart. The 0.5.8 combined inventory was 65 distinct native tags across fifteen APIs (62 retained by compatible-file transfer). ABI 3 and host synchronization remain unchanged; big-endian snapshots for the four new fields need a 0.5.8 reader. See Structured capture data.EXIF text update (0.5.9)¶
The 0.5.9 text/version batch adds UserComment, both version fields and seven EXIF 3 text tags. The new EXIF text API also supports UTF-8 owner/lens fields. The combined capture inventory is 75 distinct ExifIFD tags across sixteen APIs; compatible-file transfer retains 72. Version and Artist/Software companion requirements are explicit. ABI 3, snapshot v1 layout and host synchronization responsibilities remain unchanged. BOM-less big-endian UserComment snapshots require a 0.5.9 reader. See the EXIF text/version translation contract for limits and the recorded OIIO/ExifTool reader limitations.
EXIF 3.1 development and correction update (0.5.11)¶
Typed editing and native validation use the same A40D–A412 contracts as
translate_xmp_development_correction_metadata: packed DevelopmentType, publishedDevelopmentCharactersticspelling, UTF-8 type-129 description and bounded correction codes. The reverse translator requires an explicit host EXIF version policy of 0300 or 0310 and commits the complete selected batch atomically. Transfer retains present values, including rendered-image transfer; it does not infer RAW or MakerNote processing history. See the translation contract.EXIF 3.1 LearningOptOutIn and profile authoring update (0.5.12)¶
Typed editing and native validation now share the bounded LearningOptOutIn and profile translation contracts. LearningOptOutIn requires a complete
exifEXusage/intention structure and an explicit EXIF 0300/0310 host policy. Profile writeback covers ImageDescription, Artist, scalar Copyright, ColorSpace and RelatedSoundFile; it does not infer ICC, image or audio authority or impose complete-file companions. Failed validation, limits, conflicts and tombstones remain transactional. See the translation contract.Profile editing through file writeback (0.5.14)¶
The grouped profile lifecycle covers exact typed XMP Add/Set/Remove operations,
DirtyOnlyprofile translation, store validation, portable XMP, serialized transfer snapshots and JPEG/classic TIFF/BigTIFF writeback. A second JPEG pass edits the first output and removes Artist with explicitReplaceExisting, checking that the previous native and XMP values disappear from the existing carrier. Custom XMP survives whenPreserveCustomis selected. Invalid values and native conflicts leave the source and the previously translated result unchanged.TIFF and BigTIFF merge native IFD0 updates into the destination. Omitting Artist from a prepared snapshot does not remove an existing destination IFD0 Artist, even when the new XMP packet omits it. In 0.5.14 the second-pass regression recorded this boundary: description replacement and XMP removal succeeded, while the old native Artist remained. In 0.6.0 the same lifecycle carries the explicit native tombstone and removes Artist; a separate omission-only control continues to verify destination preservation.
Since 0.6.0, supported native tombstones can request that deletion explicitly; see the contract below. The omission-only behavior remains unchanged.
Each API call is a separate transaction. The host publishes the completed sequence only after all required calls succeed. The host also supplies the destination image ColorSpace during transfer preparation; translating source ColorSpace does not bypass the existing image-property filtering policy. These checks do not establish ICC agreement, an audio association or complete-file profile conformance.
Explicit native TIFF IFD0 deletion (0.6.0)¶
Preparation carries dirty native tombstones for IFD0 ImageDescription, Artist and Copyright in
PreparedTransferBundle::tiff_ifd0_removals. BothDirtyandDeletedare required, the IFD key must be exactlyifd0, and EXIF transfer must be enabled. A live same-key entry wins over historical tombstones. Source absence alone preserves destination tags.TIFF/BigTIFF edit plan/apply, stream and edit-package paths consume the explicit list. A manual list must be sorted, unique and limited to those three tags; contradictory replacements fail before output. Fresh emitters and codec handoffs that cannot delete destination entries reject the bundle. This is an ABI-4 change: rebuild against 0.6.0. See migration details.
Technical identity deletion (0.6.2)¶
The same bounded removal list also accepts IFD0 Make
010F, Model0110and Software0131. Edittiff:Make,tiff:Modelorxmp:CreatorTool, then calltranslate_xmp_technical_metadatawithDirtyOnlyandReplaceExistingto produce the native dirty tombstones. Snapshot preparation and TIFF/BigTIFF edit, stream and package paths retain the requests. An absent source value preserves the existing native tag. A live native value wins over historical tombstones; a manually supplied removal conflicting with a replacement fails before output. The group is tested in both byte orders for classic TIFF and BigTIFF, with unrelated descriptive values and strip bytes preserved.In 0.6.2, the six supported tags form a sorted unique list. Its contract excludes DateTime and its ExifIFD companions, other IFDs/pages, structural tags and MakerNotes. Version 0.7.0 adds the timestamp contract below. Removing Make or Model does not remove private camera records; removing Software does not remove separate software-detail fields. Hosts own those companion decisions. Fresh emitters and codec handoffs still reject deletion-bearing bundles. ABI 4 and snapshot v1 are unchanged; these additional tags require a 0.6.2 or newer library.
Grouped timestamp lifecycle (0.7.0)¶
All three EXIF timestamp families now support explicit native deletion and companion synchronization across primary IFD0 and ExifIFD. Accepted XMP date owners produce missing-companion removal intents even when the native source keys are absent. Preparation enables ExifIFD merging for dirty timestamp edits; unselected timestamp families and unrelated native destination entries survive. Source omission still preserves values. Manual lists are validated before output and do not implicitly synchronize XMP. The bundle layout requires matching consumer builds; the current development ABI label remains 4 and is unfrozen. See migration and authority rules.
Capture and lens editing (0.7.1)¶
Use logical or exact-key XMP edits, then stage capture, Flash, sensitivity and camera-text translation before snapshot preparation and TIFF/BigTIFF editing. Accepted deletions carry native intent even when the source native key was missing. Clean exact native values gain Dirty authority without changing their bytes or wire hints. Omission preserves destination values; budgets and conflict policies are checked before each transaction is published.
Full sensitivity owns its validated seven-tag group, including optional absence; basic ISO owns only the base tag. Lens make/model/serial are independent fields. TIFF edits preserve unspecified native records, opaque MakerNote bytes and original external offsets, standard pointers and media. The selected fields, contract versions and exclusions are defined in translation and migration. The development ABI label stays 4 and remains unfrozen; build matching headers and libraries.
- page Standard EXIF authoring inventory
Audit date: 2026-09-17. Implementation baseline: OpenMeta C++ 0.5.9, ABI 3, commit
6d04da1. This inventory records current behavior and selects the next batch. It does not add fields or change the library version.0.5.10 implementation update: the validation batch selected below is now implemented. All 64 routed fields have fixed schema entries; five registered Interop fields and three structural pointers are also recognized. MeteringMode type/value checks and legal Interop ID handling are covered by combined authoring/editing/serialization regressions. See the validation contract. The counts and runtime observations below retain the historical 0.5.9 audit baseline.
0.5.11 implementation update: the six EXIF 3.1 development/correction fields A40D–A412 now have a shared transactional C++/Python translator, native schemas, portable XMP and type-129 serialization. The published
DevelopmentCharactersticspelling and the explicit 0300/0310 host policy are preserved. LearningOptOutIn is covered by the next bounded structured contract.0.5.12 implementation update:
LearningOptOutIn9287 now has a bounded C++/Python transaction with exactexifEXstructure and native type-7 validation. The profile transaction also covers IFD0ImageDescription,Artist, scalarCopyright, ExifIFDColorSpaceandRelatedSoundFile. These routes define source encoding, conflict and limit behavior; they do not create a mandatory complete-file profile or infer ICC, image or audio facts.
- page FlatHost Mapping Contract
ExportNameStyle::FlatHostis 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 originalEntry::value. Pythonexport_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
FlatHostnames.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
EntryIdand imports by identity.
Value Projection¶
FlatHostis a naming contract, not a value-conversion contract.C++ receives the original
EntrythroughExportItem::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¶
FlatHostintentionally 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 exampleExif:ExposureTime,Exif:ISO,Exif:CreateDate.GPS IFD tags
Prefix with
GPS:, for exampleGPS:GPSLatitude.MakerNote IFDs
Emit only when
include_makernotesis true, usingMakerNote:<ifd>:<tag-name-or-hex>.XMP simple properties
Emit selected known namespaces as
XMP:,TIFF:,Exif:, orDC:plus the simple property name.ICC header fields and tags
Emit
ICC:<field>orICC: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 byFlatHost.Name Policy¶
ExportOptions::name_policycontrols tag aliasing:ExportNamePolicy::ExifToolAliasis the default and uses OpenMeta’s ExifTool-compatible aliases where OpenMeta has a clean-room mapping.ExportNamePolicy::Specpreserves native/spec-style tag names where available and usesTag_0x....for unknown EXIF tags.
The policy does not change ordering, duplicate preservation, or value projection.
Typed Import¶
FlatHostnames are lossy and are not parsed back into arbitrary keys.FlatHostImportTarget::SourceEntryverifies the originalEntryIdand its exported name before replacing the typed value.FlatHostImportTarget::UniqueNameresolves exactly one exported name and rejects missing or duplicate matches.FlatHostImportTarget::ExplicitKeyappends a new entry from a caller-suppliedMetaKeyView. This is the path for custom XMP and metadata that did not exist in the source store.FlatHostImportTarget::RemoveSourceEntryandRemoveUniqueNameretain the matching source entry as aDirty | Deletedtombstone. 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¶
FlatHostskips: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_makernotesis falsecomplex 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(...)inopenmeta/metadata_fuzzy_search.h. Python exposes the same bounded operation throughDocument.fuzzy_search(...)andTransferSourceSnapshot.fuzzy_search(...).Ranking Contract¶
Results use deterministic ordering:
Higher score.
Exact, alias, then general fuzzy provenance.
Lower stable entry ID.
Exact normalized phrases score
100. Exact curated aliases score96. Misspelled curated aliases use whole-phrase and per-token edit similarity and score at most95; this prevents a shared word such assensororrectanglefrom 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
GPSLatitudebecomesgps 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 at the lowest project priority, after Adapters and Utilities. 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 Generic Typed Metadata Authoring
openmeta/metadata_authoring.hprovides the C++ v1 construction path for applications that already know the exact metadata keys and types they need to write. It complements the logical-field API inmetadata_creation.h; it does not replace that simpler API.The API currently authors these writable families:
EXIF/TIFF and DNG-style tags by IFD token plus numeric tag ID
XMP properties by namespace URI plus property path
IPTC-IIM datasets by record plus dataset number
Unknown/private EXIF tags and custom XMP namespace URIs do not require an OpenMeta registry update. Inputs are borrowed for the call and copied into a new finalized
MetaStore.
- 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.hand 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. }
HostAdoptionProfileis 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. Usemetadata_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, andkRandomAccessSourceContractVersionSnapshot read
read_transfer_source_snapshot_random_access(...), its scratch/options/result types,complete(), andkReadTransferSourceSnapshotContractVersionRead diagnostics
collect_read_transfer_source_diagnostics(...), caller-buffered diagnostic records and names/messages, andkReadTransferSourceDiagnosticsContractVersionSnapshot state
The decoded-store
TransferSourceSnapshotobject contract andkTransferSourceSnapshotContractVersion; optional raw-carrier data may be preserved, but passthrough policy is not part of this profileSnapshot persistence
serialize_transfer_source_snapshot(...),deserialize_transfer_source_snapshot(...), bounded transactional parsing, and canonical wire format v1Flat host reconciliation
Stable
FlatHost + ExportNamePolicy::Specexport names plus typed add/update/remove import, tombstones, transactionality, andkFlatHostImportContractVersionCodec operation schema
TransferAdapterOpKind,PreparedTransferAdapterOp, explicit target fields, andkPreparedTransferAdapterContractVersionBreaking 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:
Read through
read_transfer_source_snapshot_random_access(...).Require
result.complete()when the workflow needs complete metadata, or collect and apply policy to structured diagnostics.Serialize the snapshot when it must outlive source storage or cross a host object/process boundary.
Deserialize transactionally.
Export
FlatHostnames withExportNamePolicy::Specand retain source entry identities in the host.Import changed values, explicit typed additions, and removals. Replace the snapshot store only after
FlatHostImportResult::ok().Pass the reconciled snapshot to
prepare_transfer_handoff(...)for stable target-specific typed operations.
Import keeps source entry positions stable, represents removals as
Dirty | Deletedtombstones, 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. The underlying bundle/view builders remain experimental; use Prepared Transfer Handoff v1 to keep those internals behind a stable opaque owner and allocation-free replay contract.
Companion Target Handoff¶
Prepared Transfer Handoff v1 is a separate versioned contract because it was added after the fixed Host Adoption Profile v1 descriptor. Check
prepared_transfer_handoff_contract_version()independently. Together, the two contracts cover positional read, persisted/reconciled snapshot state, and prepare-once typed encoder operations without changing the Profile v1 ABI. Hosts using per-worker fixed-width updates must also checkprepared_transfer_handoff_instance_contract_version().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_readsand the backing implementation supports concurrent exact reads. Do not share mutable scratch, accounting, import results, prepared bundles, or writers between concurrent operations. An immutablePreparedTransferHandoffsupports concurrent const access with independent callback state. Independently ownedPreparedTransferHandoffInstanceobjects may patch and replay concurrently; one instance requires exclusive access while patching.
- 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
MetaStorehand 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 stable target preparation and typed operation replay, see prepared_transfer_handoff.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.hfocused query helpersStructured interpreted metadata records
Cross-family concept conflicts
User-facing orientation display
Common EXIF/TIFF/DNG and selected MakerNote value labels
JPEG/TIFF/DNG/JXL/WebP/PNG/JP2/BMFF/EXR encoder path from a snapshot
prepare_transfer_handoff(...)+ indexed operation views or callback replayExperimental file-based encoder preparation
prepare_metadata_for_target_file(...)+ adapter view or backend emitterAdobe DNG SDK objects/files
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 EXIFOffsetTime*andSubSecTime*companions are assembled with theirDateTime*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 combineGPSDateStampwithGPSTimeStamponly within the same XMP property scope, and GPS altitude candidates report whetherGPSAltitudeRefmarked the height as below sea level. Camera position accepts XMP coordinates only from the EXIF XMP schema. EXIF/XMP destination coordinates and IPTC ExtensionLocationShown/LocationCreatedcoordinates use distinct roles, so they are not conflated with camera position. Structured-location candidates carry alocation_scopesuch asLocationShown[1]; conflicts and preference are resolved independently within each scope. Usemetadata_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 arecord_kindandrecord_scope, such aspersonplusPerson[1], so hosts can keep associated names, identifiers, descriptions, contacts, constraints, and release records together. IPTC image boundaries use theimage_region_boundaryrecord kind. A complete boundary adds aregion_boundarycandidate with explicitimage_region_shapeandimage_region_coordinate_unitfields. Rectangle values userectas x, y, width, height; circles use a three-value x, y, radius vector; polygons use a flattened x, yvector_setplus scopedvec2vertex 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, orrequires_target_image_spec, pluscompatible_file_safeandrendered_image_safebooleans 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 selectedTransferSafetyMode, 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, passMetadataRawDataDescriptorto 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.sensitivityis a separate policy signal withnone,personal_contact,person_identity,location, andlegal_rightsvalues. A candidate markedsafecan 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 layersexport-only adapter:
build_ocio_metadata_tree(...)for OCIO-style metadata treeshost-apply adapter:
build_exr_attribute_batch(...)for EXR/OpenEXR header workflowsdirect bridge:
dng_sdk_adapter.hfor applications that already use Adobe DNG SDK objectsnarrow translator:
libraw_adapter.hfor orientation mapping into LibRaw flip spaceorientation utility:
orientation.hfor EXIF/TIFF labels, rotation degrees, mirrored-state checks, and width/height-swap checksvalue-name utility:
exif_value_names.hfor 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 labelsstructured interpretation utility:
metadata_interpretation.hfor query-backed semantic recordsconcept-resolution utility:
metadata_concepts.hfor 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.hbefore 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 retainexact_match,fuzzy_match, andfuzzy_scorecompatibility fields.For a free-text search box, use
openmeta/metadata_fuzzy_search.hinstead 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 returnUnsupportedQueryText, with no implicit transliteration. Thin PythonDocumentandTransferSourceSnapshotwrappers 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::Specwhen the host’s tables use specification names such asExif:ISOSpeedRatingsandExif:ExposureBiasValue. The defaultExifToolAliaspolicy is intended for ExifTool-compatible display/parity names.For writeback,
import_flat_host_metadata(...)accepts ordered typed values and returns a detached finalizedMetaStore. Existing values may be selected by the sourceEntryId, or by name only when thatFlatHostname is unique. Duplicate names are intentionally ambiguous. New custom XMP, EXIF, IPTC, or other entries must include an explicitMetaKeyView; OpenMeta does not guess a namespace or numeric tag from a lossy flat name.RemoveSourceEntryandRemoveUniqueNamerequests use an empty value and retain aDirty | Deletedtombstone. 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.hdefines a borrowed fixed-size source with either caller-owned contiguous memory or an exact synchronousread_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 throughExifRandomAccessDecodeResult::nested_payloads_skipped; hosts must checkcomplete()before claiming full nested parity. Undeclared source-wide fallback searches, selected BMFF enrichment, and whole-file raw carriers also remain explicit positional residuals. Usecollect_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 three public patterns for encoder-owned output:
prepare a stable opaque handoff and replay typed operations
implement a backend emitter such as
JpegTransferEmitterorJxlTransferEmitteruse the lower-level experimental bundle/adapter view APIs
Stable Handoff Pattern¶
Use this when the host already has a decoded
TransferSourceSnapshotand owns the target encoder:#include "openmeta/prepared_transfer_handoff.h" openmeta::TransferStatus emit_to_codec( void* codec, const openmeta::PreparedTransferHandoffOperationView* view) noexcept { // Dispatch on view->operation.kind and use the explicit target fields. // EXR uses view->exr_name/type/value; other targets use view->payload. return openmeta::TransferStatus::Ok; } openmeta::PrepareTransferRequest request; request.target_format = openmeta::TransferTargetFormat::Jxl; openmeta::PreparedTransferHandoff handoff; openmeta::PreparedTransferHandoffResult prepared = openmeta::prepare_transfer_handoff( snapshot, request, openmeta::EmitTransferOptions {}, &handoff); if (prepared.ok()) { openmeta::replay_prepared_transfer_handoff( handoff, emit_to_codec, codec); }
Preparation owns allocation and route compilation. Successful operation access and replay are allocation-free and can be repeated without rebuilding the operation vector. See prepared_transfer_handoff.md for lifetime, concurrency, and deliberate-boundary details.
For realtime outputs with changing fixed-width time fields, create one
PreparedTransferHandoffInstanceper worker from the immutable handoff. Worker creation may allocate; strict transactional patching and replay do not:openmeta::PreparedTransferHandoffInstance worker; openmeta::create_prepared_transfer_handoff_instance(handoff, &worker); constexpr char encoded_time[] = "2030:12:31 23:59:59"; const openmeta::TimePatchView patch { openmeta::TimePatchField::DateTime, std::as_bytes(std::span<const char>(encoded_time, sizeof(encoded_time))) }; openmeta::patch_prepared_transfer_handoff_instance( &worker, std::span<const openmeta::TimePatchView>(&patch, 1U)); openmeta::replay_prepared_transfer_handoff_instance( worker, emit_to_codec, codec);
Patch values are serialized bytes. EXIF ASCII date/time values include the terminating NUL, so
encoded_timeabove has the required 20-byte width. Do not share one mutable instance across workers; independent instances own separate payload storage. Generic hosts can callprepared_transfer_handoff_instance_time_patch_field(...)during setup to obtain the exact width and slot count without exposing payload offsets.Target-neutral prepared metadata patching¶
Use
openmeta/metadata_patch.hfor host-owned canonical TIFF/EXIF and portable XMP payloads. EXIF requests select typed key occurrences; XMP requests select emitted namespace URI/simple-property identities with exact escaped widths. One plan can contain both families. A single batch validates all updates before writing either payload, so a rejected XMP update cannot leave newer EXIF bytes.Preparation and worker creation may allocate. Patching, payload access and library replay do not. Independent worker instances own their storage and survive plan destruction. The host supplies a fresh
options.plan_idfor each successful preparation and synchronizes conflicting object access and lifetimes. The patch API has no atomics, mutexes or global ID allocator. The host adds container framing and controls frame publication. See canonical_patching.md for examples and migration_0_5.md for the removed pre-0.5 EXIF patch interface.Experimental 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”.
kPreparedTransferAdapterContractVersionversions 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
JpegMarkerjpeg_marker_codeand marker payloadTiffTagBytestiff_tagand tag value bytesJxlBox/JxlIccProfilebox_type,compress, or direct ICC payloadWebpChunk/PngChunkchunk_typeand chunk payloadJp2Boxbox_typeand box payloadBmffItem/BmffPropertyitem/property type, subtype, MIME-XMP flag, and payload
ExrAttributecall
get_prepared_transfer_adapter_exr_attribute_view(...)for borrowed name, type, and valuevalidate_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 toTransferAdapterSink::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(...), andclose_boxes(...).OpenMeta does not ship a TurboJPEG-specific wrapper yet. The intended integration path is still through
JpegTransferEmitteror 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_carriersor passReadTransferSourceSnapshotOptionswithpreserve_raw_carriersset. Each raw carrier records its route, semantic kind, payload bytes, and snapshot-local decoded entry ids attributed to that carrier. Callraw_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 assnapshot.raw_carrier_passthrough_audit(...). Snapshot preparation defaults to decoded re-emission. Hosts that need bounded raw reuse can setPrepareTransferRequest::raw_carrier_passthrough_modetoTransferRawCarrierPassthroughMode::WhenSafe, or passraw_carrier_passthrough_mode=openmeta.TransferRawCarrierPassthroughMode.WhenSafeto 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-levelprepare_metadata_for_target_snapshot(...)entry point remains available. If the host already has a decodedMetaStore, build a reusable snapshot withbuild_transfer_source_snapshot(store). If it already owns the source bytes in memory, useread_transfer_source_snapshot_bytes(bytes)instead of the file-path reader. In Python, a previously decodedDocumentcan be turned into a reusable snapshot throughdoc.build_transfer_source_snapshot()oropenmeta.build_transfer_source_snapshot(doc). If it also owns the destination bytes in memory, call the overloadexecute_prepared_transfer_snapshot(snapshot, target_bytes, options). If it already holds a prepared bundle, useexecute_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:
Deserialize the source snapshot.
Compare the host’s current FlatHost attributes with its saved export.
Import changed values, explicit additions, and removals.
Replace only the snapshot store after a successful transaction.
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::PreparedTransferHandoff handoff; openmeta::prepare_transfer_handoff( snapshot, request, openmeta::EmitTransferOptions {}, &handoff);
Import preserves every source entry position and appends additions, so raw carrier
decoded_entry_idsremain 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 toedit_target_pathunlessxmp_existing_sidecar_base_pathis set explicitly. For embedded-only writeback with sidecar cleanup and no filesystem path, setxmp_existing_destination_sidecar_stateexplicitly 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, andxmp_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:
--outputis the sidecar base forsidecarandembedded_and_sidecarwriteback, so the generated sidecar isoutput-stem.xmp.--xmp-writeback sidecarsuppresses generated embedded XMP.--xmp-writeback embedded_and_sidecarwrites generated XMP to both the edited output and the generated sidecar.embedded-only writeback preserves an existing destination sidecar unless
--xmp-destination-sidecar strip_existingis selected.sidecar-only writeback preserves existing destination embedded XMP unless
--xmp-destination-embedded strip_existingis selected.--forcemaps 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, ordisabled.boundedmeans the capability exists within OpenMeta’s documented contract, not that it is arbitrary metadata-editor parity.disabledis 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::safetyfor the broad source/destination relationship:Mode
Use when
Transfer policy
CompatibleFileMetadata 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
RenderedImagePixels 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.TransferTargetImageSpecand 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,
metatransferandpython -m openmeta.python.metatransferexpose 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
metareadcommand prints compactphaseone_raw_geometry=...andphaseone_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 = truefor 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 = trueand provideraw_descriptor.has_plane_index = trueplusraw_descriptor.plane_indexfor the raw buffer being checked. Non-primary planes are then reported as not applicable; unknown plane selection remains conditional.Since 0.5.13, pass the same descriptor to
PrepareTransferRequestand sethas_source_raw_data_descriptor = trueto apply these curve decisions during preparation. Recognized RAW curve and linearity entries classified as not applicable are omitted from both native and generated/existing XMP payloads. Preparation reportsRawDataDescriptorFilteredand counts each removed entry once. Unknown encoding or missing required plane context retains conditional candidates. Unrestricted descriptors retain curves; black levels and unrelated settings remain subject to their own policies. Rendered-image safety retains its broader filtering and takes precedence in the policy reason. This applies to direct and snapshot preparation, without modifying the source store.Concept diagnostics are preflight guidance. They do not account for every target carrier capability or explicit family policy; inspect the prepared bundle’s policy decisions for the effective serialized result.
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"], )
metareadprintsvendor_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. Author And Serialize Metadata¶
Use the transactional generic builder instead of manually appending unchecked entries when the application knows exact metadata keys and values.
#include "openmeta/metadata_authoring.h" const std::array entries = { openmeta::MetadataAuthoringEntry { openmeta::make_exif_tag_key_view("ifd0", 0x010F), openmeta::make_value_view_text( "Vendor", openmeta::TextEncoding::Ascii), }, }; openmeta::MetaStore store; const auto authored = openmeta::create_metadata_store(entries, &store);
The builder deep-copies borrowed values, applies resource limits, finalizes a temporary store, and calls detached structural/schema validation before replacing the output. Optional image context lets a codec provide dimensions, samples per pixel, and color-plane facts it actually owns.
When a host owns unfamiliar container framing, call
serialize_exif_tiff()to measure and write unwrapped TIFF/EXIF bytes. Retain that immutable payload for repeated replay. Do not select a fakeTransferTargetFormat; container-specific box, chunk, or marker framing stays host-owned. See generic_authoring.md and canonical_serialization.md.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, paired IPTC created and digital-creation date/time datasets project to strict standard XMP date properties, 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
Descriptiveconcept 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, XMPCreatorToolsource 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-safensu_<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_profilesemantic role, while camera RAW profile/look/tone-curve/style fields and vendor source color tables have a separatesource_color_transformrole 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
MetadataRawDataDescriptorso 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, MotorolaCustomRenderedlabels, Nintendo category labels, Sanyo main/MOV public-context scalar labels, current Canon RF lens-type labels, current Nikon ZLensData0800LensIDlabels, 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/idatlayouts, item-property associations, primary item/display/color summaries, JUMBF/C2PA structure, and boundedgrid/iovl/idenconstruction descriptors. Derived descriptor reads support method-0 file extents, method-1idatextents, 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.tiliimage items expose boundedtilCversion-0 dimensions, extra dimensions, property relationships, tile grids, expected tile counts,dref/detimapping, internaltile_item_type/tipaassociations, 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%.
Full C2PA manifest/policy semantics. Independent tiled-image conformance was qualified on 2026-09-22.
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, opaquealisandtdtabyte counts) with type-name/type-code fields, parsed maximum depth, and parsed per-type counters, ordered boundedobjreference 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.
PrepareTransferRequestcan carry aMetadataRawDataDescriptor; 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 has the lowest priority and resumes after Adapters and Utilities for its Unicode/multilingual and optional-index milestones.
The 0.8.4 spatial lifecycle extends this sequence through focal-plane X/Y/unit and both subject arrays. These five fields use the existing bounded TIFF/BigTIFF merge, native deletion intent and source snapshot path; unrelated destination metadata and media remain preserved. This is a bounded editing milestone, not a new read-coverage or downstream acceptance claim.
Interpretation Maintenance Priorities¶
The complete bounded BMFF tiled-image contract was independently qualified on 2026-09-22 with internal, sequential, external-URL and malformed conditional fixtures. The gate checks decoded core, layout and complete validity fields through the public Python reader.
The 0.5.13 transfer-diagnostic batch aligns recognized RAW curve/linearity decisions with direct and snapshot preparation for compression and primary-plane restrictions. Grouped tests cover retained/conditional/omitted values, native and XMP payloads, unique entry counts and rendered-safety precedence. This is a bounded policy correction, not general per-family diagnostic completion.
Continue transfer diagnostic policy coverage beyond RAW applicability, using the existing stable message and localizable argument tokens.
Extend pantry payload semantics only when another stable, bounded schema is validated; keep arbitrary payloads raw and source-bound.
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.
Keep transfer-safety classification conservative when interpretation is incomplete.
Rational and identity native editing (0.8.5)¶
SubjectDistance, DigitalZoomRatio, ExposureIndex, FlashEnergy, LensSpecification and ImageUniqueID now participate in bounded TIFF/BigTIFF/DNG merge and removal through existing native Dirty/deletion intent. Translation contracts are version 2; exact native components and provenance remain, with transactional budgets and host synchronization. This closes this six-field editing lifecycle, not arbitrary EXIF editing, new reading semantics or downstream acceptance.
Additional capture and environment native edits (0.8.6)¶
The nine additional-capture/environment fields have grouped native edit authority and TIFF/DNG merge/removal coverage. Exact promotion retains one-byte UNDEFINED codes, raw rational components, unknown sentinel bits and provenance. This edit milestone does not establish broader reader parity, vendor MakerNote interpretation, all-RAW acceptance, codec conformance or downstream application adoption. Bounded original-backed evidence belongs in the private repository; reader code is unchanged.
- 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_profilePrimary JPEG metadata emitter (APP1/APP2/APP13 direct control)
libtiff
TIFFSetField,TIFFCreateEXIFDirectory,TIFFCreateGPSDirectory,TIFFWriteCustomDirectory,TIFFMergeFieldInfoPrimary TIFF metadata emitter (native tag and IFD path)
libjxl
JxlEncoderUseBoxes,JxlEncoderAddBox,JxlEncoderCloseBoxes,JxlEncoderSetICCProfilePrimary JXL metadata emitter (
Exif,xml,jumb, optionalbrob) plus encoder ICC profileOpenEXR
Header::insert, typed attributes,OpaqueAttributefor unknown attr typesEXR 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 (
http://ns.adobe.com/xap/1.0/\\0+ packet).Write IPTC/IRB as APP13 (
Photoshop 3.0resource block layout).Write ICC as APP2 chunk chain (
ICC_PROFILEheader + 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&)orwrite_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,jumbboxes throughJxlEncoderAddBox.Set ICC through
JxlEncoderSetICCProfile; ICC is not a JXL metadata box.Exifbox 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 asjxl:icc-profileand 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-C2PAJumbfCborKeyroots into generic JXLjumbboxes. IPTC requested for JXL is projected into thexmlXMP 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, andbuild_prepared_jxl_encoder_handoff(...)/serialize_prepared_jxl_encoder_handoff(...)add the owned persisted form of that handoff: one optionaljxl:icc-profilepayload 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(...)pluswrite_prepared_transfer_package(...)can also serialize direct JXL box bytes from prepared bundles, andexecute_prepared_transfer(...)can use that same box-only serializer throughemit_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 sourcejumbboxes are distinguished as generic JUMBF vs C2PA for that replacement decision. When Brotli support is available, the same family check also covers compressedbrob(realtype=jumb)source boxes. The byte-writer/file-edit path still does not serializejxl:icc-profile; ICC remains encoder-only. The bounded external-signer path now also supports JXLjumbstaging 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:
EXIFXMPICCPbounded
C2PA
The prepared
EXIFchunk payload is the TIFF byte stream only. It does not include the JPEG APP1Exif\0\0preamble.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(...), andemit_prepared_transfer_compiled(..., WebpTransferEmitter&).IPTC requested for WebP is projected into the existing
XMPchunk; OpenMeta does not create a raw IPTC-IIM WebP carrier.build_prepared_transfer_emit_package(...)pluswrite_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
VP8Xfeature bits. It does not synthesize a missingVP8Xchunk.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-exifbmff:item-xmpbmff:item-jumbbmff: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\0bytes
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-iccpayload 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 intobmff: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(…)pluswrite_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 –target-heif|–target-avif|–target-cr3 –source-meta … -o …performs bounded metadata edits for targets with no foreign top-levelmetabox, 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, andirefwithcdscreferences 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 existingidat, with data reference index 0 or a validated self-contained data reference. 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. One nested method-2 level ending at method 0 or 1 is also supported, with explicit nonzero lengths, checked logical/physical slices and a shared work bound; deeper chains and cycles reject before output.Since 0.8.1, retaineddimglists preserve every target occurrence in source order after managed endpoint remapping, including repeated grid/overlay inputs. Removing an input of a retained source rejects before output; removing the source drops its whole relation. Existing orderedilocreferences and deduplication of other relation types remain unchanged. This does not enable arbitrary scene editing or change the CR3 source-offset preservation guard.Foreign-metaICC property merge is bounded tobmff:property-colr-icc. OpenMeta removes prior ICCcolr/profandcolr/rICCproperties fromiprp/ipco, compacts/remaps existingipmaassociations, 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. A foreigniprpmay contain multiple validipmaboxes; OpenMeta validates all of them, combines entries by item ID, deduplicates property associations while preserving essential bits, and emits one consolidatedipmatable in first-seen source order. 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 metadatametaboxes 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 fromMetaStorebuild_exr_attribute_part_spans(...)groups that batch into contiguous per-part spansbuild_exr_attribute_part_views(...)exposes zero-copy grouped per-part views over the same batchreplay_exr_attribute_batch(...)replays the grouped batch through explicit host callbacksknown 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_nameis availableambiguous 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:
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.
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)pluscommit_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:
Keepdefault,Dropsupported,Invalidatecurrently resolves toDrop, and unavailableRewriteresolves toDroprather than silently preserving raw bytes.Keepcarries the original opaque payload, but does not relocate vendor-private offsets, repair checksums, or prove semantic readability after the surrounding EXIF layout changes. Usemakernote_transfer_audit_from_store(...)for the generic machine-readable trust boundary andmakernote_layout_transfer_audit_from_store(...)for bounded Nikon type 1/type 3 offset-layout evidence plus conservative Canon source-dependent IFD recognition. Canon notes retain an explicitly ambiguous source offset basis. Nikon 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
JumbfCborKeyroots into generic APP11 JUMBF payloads; explicit raw JUMBF -> JPEG APP11 append is available throughappend_prepared_bundle_jpeg_jumbf(...); and JPEG rewrite/edit removes existing APP11 JUMBF when the resolved policy isDrop. 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:
Invalidateon JPEG now emits a draft unsigned APP11 C2PA invalidation payload.PreparedTransferPolicyDecisionexposesmode,source_kind, andprepared_outputso adapters can branch without parsing free-form messages.PreparedTransferBundle::c2pa_rewriteexposes 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_chunksas preserved source ranges plus prepared JPEG segments; for the bounded BMFF edit path it uses preserved source ranges plus one prepared metadata-onlymetabox.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(...)anddeserialize_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(...)anddeserialize_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_generatorrequirements, 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 againstmanifest_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
Readyrewrite state withoutSignedRewriteprepared 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, JXLjumbboxes, or bounded BMFFbmff:item-c2paitems 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-signedremains for compatibility.PreparedTransferPackagePlannow 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.PreparedTransferPackageBatchis 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(...)anddeserialize_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(...)andbuild_prepared_transfer_payload_batch(...)now provide the matching target-neutral semantic payload surface directly over prepared bundles.serialize_prepared_transfer_payload_batch(...)anddeserialize_prepared_transfer_payload_batch(...)persist that earlier semantic payload batch for cross-process or cross-layer handoff before final package materialization.PreparedMetadataPatchPlanis the separate target-neutral realtime path for canonical EXIF and portable XMP bytes. Typed EXIF values and simple XMP scalar identities compile to opaque handles. Per-worker mixed batches are transactional and allocation-free. Container framing remains host-owned.Host metadata tables that use specification naming should export with
ExportNameStyle::FlatHostplusExportNamePolicy::Spec. This preserves names such asExif:ISOSpeedRatingsandExif:ExposureBiasValueinstead 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.create_metadata_store(...)builds a fresh finalized store from exact borrowed EXIF/TIFF/DNG-style, XMP, and IPTC-IIM entries when no source snapshot exists.validate_store(...)supplies structured schema and image-context diagnostics before encoder handoff.serialize_exif_tiff(...)exposes the deterministic unwrapped TIFF/EXIF payload directly. Hosts can measure exact storage, retain immutable bytes, and apply their own container framing without selecting a fake transfer target. Existing transfer preparation wraps this same canonical payload.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
Keepstill resolves toDrop.Rewriteresolves toDropwith explicitSignedRewriteUnavailableuntil 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¶
JPEG and TIFF direct backends (highest transfer value).
JXL box emitter parity for EXIF/XMP plus bounded JUMBF/C2PA preserve or projection.
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.
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
MetaStorewhere display-name mapping exists
what can be dumped or exported today
Status Labels¶
Yes: supported in current codePartial: supported, but still bounded or best-effortNo: 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
brobmetadata 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
Exifpreamble.EXR header metadata compare is passing for the documented name/type/value-class contract.
Sidecar export paths (
losslessandportable) 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
Keeppreserves the original raw payload as unverified opaque bytes; it does not relocate nested offsets, repair vendor checksums, or prove semantic readability after repacking. ExplicitRewritedrops when those operations are unavailable. Hosts can inspect this boundary withmakernote_transfer_audit_from_store(...). The separatemakernote_layout_transfer_audit_from_store(...)recognizes canonical Nikon type 1/type 3 offset layouts, validates standard embedded-TIFF structure for type 3, and reports plausible Canon source-dependent IFD notes with an explicitly ambiguous source offset basis. It does not claim Canon rewrite safety or vendor-private offset/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
xmpmetanamespace prefixes.BMFF edge-path tests include
ilocconstruction-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
Minolta MRW
Yes
Partial
Contiguous
\0MRMsegment discovery, bounded TTW TIFF metadata and native PRD/WBG/RIF fields; Sony\0MRIrecords decode through their enclosing TIFF private carrier; no native writerCRW / 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
brobwrapped metadata is decoded and box scan supports bounded positional callbacksHEIF / AVIF / CR3
Yes
Partial
EXIF, XMP, ICC, CR3 maker blocks, BMFF derived fields including
avif/avis/avioAVIF brands, and bounded JUMBF/C2PA; structural/item scan supports bounded positional callbacks without readingmdatpayloadsEXR
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
Minolta MRW
Bounded TTW TIFF carrier through
scan_mrw/scan_autoMinolta MakerNotes plus bounded PRD/WBG/RIF fields with make/model conditions
No native writer
The TIFF lane recognizes both Olympus ORF headers
IIROand olderIIRS. MRW discovery stops at the declared metadata boundary and does not search the pixel tail. Standalone input uses big-endian\0MRM; supported Sony private carriers use little-endian\0MRIwith buffered or positional TIFF reads. Standalone positional MRW discovery remains outside this lane. Unknown native segments are skipped; source TIFF private carriers remain available as raw entries.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 identityICC (
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
ftypbrand names includingavif/avis/avioAVIF-compatible brands, item-info,ipco,ipma,iref,grpl,iloc/idat, boundedgrid/iovl/idenconstruction 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 rolesJUMBF / 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_headerstable header-extension adjustment fields are decoded as
x3f_header_extknown
PROPproperties are decoded asx3f_propsection-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:
Photoshop2InfoPhotoshop2ColorTableResolutionInfoAlphaChannelsNamesDisplayInfoPStringCaptionBorderInformationBackgroundColorVersionInfoPrintFlagsprint-flag byte fields
EffectiveBWQuickMaskInfoRawImageModeJPEG_QualityGridGuidesInfolegacy halftone, transfer-function, duotone-image, and EPS byte summaries
PhotoshopBGRThumbnail/PhotoshopThumbnailheadersSpotHalftoneUnicodeAlphaNamesAlphaIdentifiersJumpToXPEPPrintScaleInfoPixelInfoAutoSaveFilePathAutoSaveFormatXMLDataImageReadyVariablesImageReadyDataSetsLightroomWorkflowIPTCDataBytesColorSamplersResource/ColorSamplersResource2headers and recordsWorkingPathand numbered path resources as byte counts plus record counts/selectorsdescriptor-header summaries, bounded scalar, class, alias, enum, and
objreference 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 asLayerComps,MeasurementScale,HDRToningInfo,PrintInfo,TimelineInfo,SheetDisclosure,OnionSkins,CountInfo,PrintInfo2,PrintStyle,PathSelectionState, andOriginPathInfoChannelOptionsPrintFlagsInfoClippingPathNameMacintoshPrintInfo,MacintoshNSPrintInfo,WindowsDEVMODE,AlternateDuotoneColors,AlternateSpotColors, ObsoletePhotoshopTag1, ObsoletePhotoshopTag2, and ObsoletePhotoshopTag3 byte countsembedded 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
PhotoshopIrbraw 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, andGlbC, opaque byte counts foralisandtdta, nested object/list paths, depths, list indices, list/object counts, and parsed-value count fields are emitted. Boundedobjstreams 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
objvalue and 128 reference items across one descriptor. Unknown, incomplete, or excess reference data stops traversal and emitsDescriptorItemParseTruncated; 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:
source-bound CR3 compressor text, CTBO carrier locations, and repeated CMP1 record dimensions/offsets from the recognized CRAW sample-entry layout; these derived values are not writable or projected into portable XMP
ftyp.*, including brand names and compatible-brand countsprimary 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
ipcoproperty-container summaries with total, known, unknown, and per-known-type property countsipmaitem-property association rows with item ids, property indices, essential flags, and known property type namesper-known-property
ipma.<type>association, primary-association, and essential-count rollups for common primary-item propertiesiinf/infeitem-info rowsitem 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 forauxl,dimg,thmb, andcdsc; literalfrom_item_idandto_item_idrows remain unchangedbounded
grplitem-group rows and per-group-type summaries, including group semantics and ordered entity roles foraltr,ster, andpymdbounded
iloc/idatitem-data layout summaries, including construction methods, extent counts, total extent byte counts, idat byte counts, and primary-item location aliasesbounded
grid,iovl, andidenderived-image construction rows with ordereddimgsource 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-boundcontainer_graphconcept for query/transfer diagnosticstilitiled-image items and boundedtilCversion-0 configuration fields, including tile width/height, up to eight extra dimensions, required single-ispe/single-tilCassociation checks, ceil-divided tile rows/columns, overflow-checked expected tile counts,dinf/dref/detimapping, internaltile_item_typeand nestedtipaassociations, bounded external URL components, logical-ilocoffset tables, explicit or sequentially inferred tile sizes, empty-tile state, complete-configuration validity, and source-bound query/transfer diagnosticsgraph summaries
auxC-typed auxiliary semanticsbounded 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
colrsummaries fornclx/nclccolor fields and ICC profile-size carriersprimary
pasp,pixi, andclapitem-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
idatextents, and bounded method-2 item-offset chains. Method-2 resolution follows orderedirefilocreferences, 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-imagedetiURL 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
Exifdirect
xmldirect
jumbdirect
c2pawrapped
brobforms for those same realtypes
Other
brobrealtypes are still out of scope.JUMBF / C2PA¶
Current support is intentionally draft:
structural BMFF box decode
JUMBF box labels from parsed
jumdboxesbounded CBOR traversal
draft
c2pa.semantic.*projectionoptional 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_onlyverify_require_trusted_chainand--c2pa-verify-require-trusted-chainadditionally require a trusted chain bound to the signature key, but do not establish asset bindingOpenMeta 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
metareadHuman-readable metadata listing
Shows decoded entries with mapped names where available
metavalidateMetadata validation
Reports decode-status and validation issues with machine-readable issue codes
metadumpSidecar and preview dump tool
Supports
losslessandportablesidecar output plus preview extractionthumdumpPreview extractor
Extracts embedded preview candidates
metatransferTransfer/edit smoke tool
Exercises the transfer core for supported target families
Main Current Gaps¶
additional
JXL brobrealtypes beyondExif,xml,jumb, andc2pafull
JUMBF/C2PAsemantics and policy validationdeeper 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
preparereuse prebuilt metadata payloads during
compileandemitkeep per-frame work limited to optional time patching plus final container write calls
Current Status¶
Current planning estimate for this lane: about
85-90%.Source-side readiness is already strong:
tracked EXIF read gates are green on
HEIC/HEIF,CR3, and mixed RAW corporatracked 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::safetycan distinguish compatible metadata repackage/recompression from rendered-image export, so callers can select a safe coarse policy without hand-picking individual tagsprepared 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, boundedExifIFD -> InteropIFDpreservation when a replaced ExifIFD omits its own interop child, file helper, streaming edit pathBroader TIFF rewrite coverage is still narrower than JPEG
DNG
First-class
Dedicated public target layered on the TIFF backend; prepared bundle, compiled emit, minimal
DNGVersionsynthesis when missing, bounded DNG preview/aux merge policy, read-backed file-helper roundtrip, and the same boundedSubIFD/preview-tail/interop preservation contract as TIFFNot 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
jp2hsynthesis is still out of scopeJXL
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-
metaitem merge/replacement/strip, compactilocfield normalization, managed item-ID remapping acrossiref/version-0grpl/ipma, deterministic multi-ipmaconsolidation, plus bounded ICC property merge, file-helper roundtripDirect payload output is a host handoff rather than a standalone BMFF file; arbitrary foreign
metascene/property-graph rewrite is still unsupportedEXR
Stable bounded host target
Prepared bundle, compiled emit, direct backend attribute emit, prepared-bundle to
ExrAdapterBatchbridge, CLI/Python transfer surfaceHost-emission only for the current roadmap; no OpenMeta file rewrite/edit path
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 -> emitprepare -> compile -> patch -> emit/edit
Core Utility Layers¶
These support the public transfer flow:
TransferByteWriterSpanTransferByteWriterprepared payload and package batch persistence
adapter views for host integrations
stable opaque prepared handoffs with allocation-free typed operation replay
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-backsource DNG-like TIFF with
subifd0+ifd1-> BigTIFF edit/apply -> read-backsource DNG-like TIFF with
subifd0+ifd1-> DNG edit/apply -> read-backsource TIFF/BigTIFF with existing
subifd0 -> nextauxiliary chain -> replacesubifd0-> preserve downstream auxiliary tailsource 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/profproperty payloads, high-level byte-writer handoff with capacity preflight and item/property summaries, plus owned package replay for constrained foreign-metagraph mergessource 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.
The focused in-tree transfer release gate is the custom target
openmeta_gate_transfer_release. Building it executes the selected unit and smoke checks. Full CTest runs cover these checks once through the complete unit suite and individual smoke registrations; aggregate gates are not CTest tests.In a non-Python test tree it runs:
MetadataTransferApi.*XmpDump.*ExrAdapter.*DngSdkAdapter.*openmeta_cli_metatransfer_smokeopenmeta_cli_metatransfer_image_usability
In a Python-enabled test tree it also runs:
openmeta_python_transfer_probe_smokeopenmeta_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
ifd1chain rewrite support, including preserving an existing downstream page tail whenifd1is replacedbounded TIFF/DNG-style SubIFD rewrite support, including preserving an existing downstream auxiliary tail when
subifdNis replacedbounded front-subset
SubIFDreplacement that preserves trailing existing children from the target filebounded
ExifIFDreplacement that preserves an existing targetInteropIFDwhen the source replacement omits its own interop childtarget-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_specto 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::RenderedImageadditionally 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.configurationas source-container-bound: compatible-file mode can keep the evidence, while rendered-image mode reportsdrop.tiled_image_configuration. This diagnostic does not authorize copying sourcetilCbytes 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
MetaStoreand 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 rawExifIFD:MakerNotepayload 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
DNGVersionsynthesis when the source metadata lacks itexplicit public target modes:
ExistingTargetTemplateTargetMinimalFreshScaffold
bounded preview-page chain rewrite/merge
bounded raw-image
SubIFDrewrite/mergepreservation 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
ExifIFDreplacement that preserves an existing targetInteropIFDwhen 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,
ExistingTargetandTemplateTargetnow require an explicit target path; onlyMinimalFreshScaffoldkeeps 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=ONand adng_sdkpackage is discoverable,openmeta/dng_sdk_adapter.hexposes a bounded Adobe DNG SDK bridge for:applying prepared OpenMeta DNG bundles onto
dng_negativeupdating an existing
dng_streamvia the SDK’s metadata-update patha direct file-helper for
source file -> existing DNG filein-place updatea matching direct Python binding over that file-helper
a thin CLI wrapper via
metatransfer --update-dng-sdk-file
This adapter is optional. Core
Dngtransfer support remains available without the Adobe SDK.The OpenMeta build must use a C++ runtime/standard library compatible with the discovered
dng_sdkpackage.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:
eXIfXMP
iTXtiCCPbounded rewrite/edit for managed metadata chunks
WebP¶
Implemented as a bounded RIFF metadata target:
EXIFXMPICCPbounded
C2PAbounded rewrite/edit for managed metadata chunks
EXIFchunk payloads use direct TIFF bytes, without the JPEG APP1Exif\0\0preamble
JP2¶
Implemented as a bounded box target:
Exifxmlbounded
jp2h/colrbounded rewrite/edit for top-level managed metadata
replacement of managed
colrin an existingjp2h
JXL¶
Implemented as a bounded box target:
Exifxmlbounded
jumbbounded
c2paencoder ICC handoff
bounded box-based edit path
HEIF / AVIF / CR3¶
Implemented as a bounded BMFF target family:
bmff:item-exifbmff:item-xmpbounded
bmff:item-jumbbounded
bmff:item-c2pabounded
bmff:property-colr-iccbounded OpenMeta-managed metadata-only
metarewrite pathCR3 edits preserve the original offsets of every retained top-level source box. Appending metadata and replacing an EOF metadata box remain supported; removing or resizing an earlier metadata box is rejected when it would move retained boxes. The guard also recognizes CR3 major/compatible brands when a host selects another BMFF target. CTBO and track offsets are not rewritten.
constrained foreign top-level
metaitem merge for parseableiinf,ilocversion 0/1/2,pitm, optional singleidat, and primary-itemcdscreferencesbounded 32-bit item-id insertion for foreign item graphs, including automatic
ilocversion 2 upgrade when an otherwise supportedilocversion 0/1 graph exhausts the 16-bit item-id spaceinserted metadata item records keep
ilocconstruction method 0 and use absolute file-offset extents for broad reader compatibilitycompact valid
ilocgraphs with an omitted zero extent-offset field or narrow offset/length fields are normalized to explicit 32-bit fields when metadata insertion requires representable absolute offsets and lengths; omitted extent lengths remain unsupported because their source-to-end semantics cannot be preserved safely while the graph growsretained foreign item locations support construction method 0 file offsets and construction method 1
idatextents with data reference index 0 or an explicitly self-contained version-0dinf/drefurlorurnentryretained 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; referenced method-0/1 targets may use data reference index 0 or an explicitly self-containeddinf/drefentry, validated before graph rewriting; missing references, removed referenced items, non-self-contained data references, and other construction methods fail safelysince 0.6.2, a retained method-2 item may reference one further method-2 item, ending at method 0 or 1. The new nested form requires explicit nonzero lengths and checked logical slices within the referenced item, plus bounded terminal file/idat ranges. Cycles, a third method-2 level, missing/removed targets and unsupported references reject before output. Nested validation has a shared limit of 2^20 lookup and extent visits; exhaustion returns
LimitExceededbefore output. No complete item is materialized. Orderedilocreferences retain repeated target IDs so explicit and implicit extent indices continue to select the same source slices. Since 0.8.1, retaineddimgreferences also preserve every target occurrence in source order, including repeated grid or overlay inputs. Managed endpoint replacement preserves that sequence after remapping. Removing an input of a retaineddimgsource rejects before output; removing the source drops its whole relation. Other relation types keep their existing deduplication and stale-reference cleanup. This is bounded graph preservation, not scene editing. Resizingmetaalso rebases method-0 file offsets with a validated self-contained nonzero data-reference index.unambiguous one-old-to-one-new managed Exif, XMP, JUMBF, and C2PA item replacement remaps retained
irefendpoints, version-0grplitem-group members, andipmaitem associations; strip and ambiguous replacement paths remove references to deleted managed item IDs instead of leaving them stalemultiple valid foreign
ipmaboxes are validated and merged by item ID into one consolidated table in first-seen source order; repeated property associations are deduplicated while preserving an essential bit asserted by any source tablerebuilt foreign
ilocgraphs compact foldable self-contained base offsets to a zero-width base-offset field when safebounded foreign top-level
metaICC property merge by replacing prior ICCcolr/profandcolr/rICCproperties, remappingipma, and associating the transferredcolr/profproperty with the primary item and any retained item that previously referenced a replaced ICC property while preserving the prior essential association bitbounded foreign top-level
metaXMP replacement and strip support for parseable item graphs that satisfy the same primary-item contractfail-safe rejection for unsupported foreign top-level
metashapes 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-exrtransfer 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 probePython helper wrappers:
openmeta.python.probe_exr_attribute_batch(...)andopenmeta.python.get_exr_attribute_batch(...)
That keeps EXR host integrations on the transfer path: callers can prepare one
TransferTargetFormat::Exrbundle, then materialize a nativeExrAdapterBatchwithout re-projecting from the sourceMetaStore.Current EXR transfer scope is intentionally conservative and final for the current roadmap:
safe flattened
stringheader attributesbackend emission through
ExrTransferEmitterno OpenMeta file-based EXR metadata rewrite/edit path
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. The current product decision keeps EXR file ownership in the host writer; a future bounded fixed-size patch helper requires a concrete host contract and remains separate from general OpenMeta file rewriting.
Transfer Policies¶
The public transfer contract now models five policy subjects:
MakerNote
JUMBF
C2PA
XMP EXIF projection
XMP IPTC projection
Each uses explicit
TransferPolicyActionvalues:KeepDropInvalidateRewrite
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_exifxmp_project_iptcxmp_existing_namespace_policyKnownPortableOnlyPreserveCustom
xmp_conflict_policyxmp_existing_sidecar_modeon the file-read/prepare path:IgnoreMergeIfPresent
xmp_existing_sidecar_precedenceon the file-read/prepare path:SidecarWinsSourceWins
xmp_existing_destination_embedded_modeon the file-read/prepare and file-helper execution paths:IgnoreMergeIfPresent
xmp_existing_destination_embedded_precedenceon the file-read/prepare and file-helper execution paths:DestinationWinsSourceWins
xmp_writeback_modeon the file-helper execution path:EmbeddedOnlySidecarOnlyEmbeddedAndSidecar
xmp_destination_embedded_modeon the file-helper execution path:PreserveExistingStripExisting
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_modeEdited file
Sibling
.xmpDefault cleanup behavior
EmbeddedOnlyKeep generated XMP in the managed embedded carrier
No generated sidecar output
Preserve any existing sibling
.xmpunlessxmp_destination_sidecar_mode=StripExistingSidecarOnlySuppress generated embedded XMP carriers
Return generated sidecar output
Preserve existing embedded XMP unless
xmp_destination_embedded_mode=StripExistingEmbeddedAndSidecarKeep generated XMP in the managed embedded carrier
Return the same generated XMP as sibling
.xmpoutputNo 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
.xmpsidecars from the destination path can be merged into generated portable XMP before transfer packaging when explicitly requestedthat 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
.xmpsidecarthe public
metatransferCLI and Python transfer wrapper can now persist that generated XMP as a sibling.xmpsidecar when sidecar or dual-write XMP writeback is selectedthe public
metatransferCLI and Python transfer wrapper now also expose the bounded destination-embedded merge and precedence controls directlysidecar-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, andjxl
embedded-only writeback now has an explicit destination sidecar policy:
preserve an existing sibling
.xmpby defaultstrip an existing sibling
.xmpwhen 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.xmpsidecar, and remove a stale sibling.xmpwithout reimplementing wrapper-side file logicthe Python binding now exposes the same persistence path through
transfer_file(...)andunsafe_transfer_file(...), and the public Python wrapper uses that core helper instead of maintaining its own sidecar write and cleanup implementationthe 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(), andtransfer_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, andcr3
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:
DateTimeDateTimeOriginalDateTimeDigitizedSubSecTime*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:
broader portable mappings beyond the current bounded generated set
reverse and direct-family projection for arbitrary user edits
semantic reconciliation beyond explicit property-order conflict handling
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,
Keepmeans unverified opaque byte carry-forward, and unavailableRewritefails closed toDrop. The generic public audit reports that nested-offset relocation, vendor checksum repair, semantic validation, and raw-carrier passthrough are unavailable. The vendor-layout audit distinguishes canonical Nikon type 1 notes, whose offsets depend on the outer TIFF, from type 3 notes with an embedded TIFF at byte 10. It also recognizes bounded Canon raw-IFD payloads when Canon source-make evidence is present and reports that their offset basis requires the original source-container context. Bounded Nikon 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.Since 0.5.14, both audits count raw payloads only at
exififd:0x927C, and Canon classification uses camera-make evidence only fromifd0:0x010F. Same-numbered tags in other IFDs do not establish raw-payload availability or vendor layout. Deleted entries do not contribute evidence. Decoded vendor sub-IFDs retain their separate, non-serializable classification.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
0x927Cpayload 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 scope¶
The architectural decision is complete for the current roadmap: EXR remains a stable bounded host-emission target plus bridge helpers. OpenMeta will not add a general EXR file rewrite path. Late-bound fixed-width values remain a host-writer concern unless a concrete reusable patch contract is proposed.
Recommended Next Priorities¶
Keep transfer ahead of further read-breadth work.
Stabilize the current target family:
JPEG
TIFF
PNG
WebP
JP2
JXL
bounded BMFF
Decide how deep EXR should go beyond the current bounded target.
Add more transfer-focused roundtrip and compare gates where they improve confidence for adopters.
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 boundedSubIFDreplacement; add compare-backed roundtrip gates for classic TIFF and BigTIFFRaise 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, andMinimalFreshScaffold; add compare-backed roundtrip gates forDNGVersion, preview chains, and rawSubIFDmerge behaviorStabilize 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, XMPiTXt, andiCCP; add compare-backed roundtrip gates for embedded-only, sidecar-only, and dual-carrier XMP flows where applicablePromote 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 boundedC2PA; add compare-backed roundtrip gatesPromote 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
colrreplacement behavior; add compare-backed roundtrip gatesPromote bounded box rewrite into a stable JP2 metadata contract with explicit preserve/replace guarantees for unmanaged boxes
Revisit
jp2hsynthesis only if it becomes necessary for common export parityJXL
Lock current box rewrite rules for
Exif,xml,jumb, boundedc2pa, and encoder-side ICC handoff; add compare-backed roundtrip gates for edit/apply pathsPromote 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
brobrealtype coverage only after the current direct and bounded compressed routes are stableHEIF / AVIF / CR3
Lock the bounded metadata-only
metaedit contract, item/property preservation rules, and compare-backed roundtrip gatesStabilize the bounded BMFF writer contract for metadata items, ICC property handling, and existing OpenMeta-authored
metareplacementDeepen BMFF scene semantics and relation modeling where current bounded fields are too small for parity workflows
EXR
Keep the public target as a stable attribute-emitter contract across C++, CLI, and Python, with compare-backed gates
Keep existing-file preservation and late-bound value patching owned by the host EXR writer
Revisit only if a concrete host-neutral contract can avoid general EXR file rewriting
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¶
Fix public regressions and lock the sync/writeback contract.
Turn the current target family into a stable first-class writer set.
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: about8major work packagesto reach broader overall parity closer to
ExifTool: about12-15major 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 blockerPartial: real support exists, but competitor-visible limits still remainMissing: 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
The bounded preserve/replace behavior is explicit and release-gated across the first-class target family
Done0TIFF,DNG,PNG,WebP,JP2,JXL,HEIF/AVIF/CR3General EXIF / IPTC / XMP sync engine
One of the biggest remaining gaps for general editing adoption
Partial1-2Cross-cutting
Compare-backed release validation
Repeatable release-facing read-back and compare gates cover the primary writer family and writeback modes
Done0Cross-cutting
MakerNote rewrite trust
Generic preserve/rewrite/drop trust is explicit; Nikon type 1/type 3 and Canon source-dependent layout evidence are present, but vendor-private relocation, checksum repair, and semantic guarantees still trail mature tools
Partial1JPEG,TIFF,DNG, RAW-derived lanesTIFF / DNG deeper rewrite guarantees
The bounded root/ExifIFD/preview/SubIFD contract and compare-backed target modes are complete for the current scope
Done0TIFF,DNGBMFF writer depth beyond current bounded contract
Needed for stronger
HEIF/AVIF/CR3parity beyond the current metadata-onlymetamodelPartial1HEIF,AVIF,CR3Modern container read-depth follow-through
Remaining visible read gaps are mostly here
Partial1HEIF/AVIF,JXLLong-tail native format semantics
Matters more against
ExifToolthan againstExiv2Partial2-3RAF,X3F,CRW/CIFF,Photoshop IRBEXR target decision
EXR is a stable bounded host-emission target for the current roadmap; file rewrite remains out of scope
Done0EXRJUMBF / C2PA deeper semantics
Current support is bounded and useful, but not full trust-policy parity
Partial1-2JPEG,PNG,WebP,JXL,BMFFFull arbitrary metadata editing parity
Mature competitors expose a broader open-ended editor surface
MissingStrategic / 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
JPEGStrongStrongneeds continued compare-backed hardening and deeper mixed-bundle parity, not a new baseline writer
TIFFStrongPartialdeeper rewrite guarantees for more existing-graph and tail-preservation cases
DNGStrongPartialmore predictable preserve/merge behavior across target modes and raw
SubIFDchainsPNGStrongPartialstable unmanaged-chunk preservation contract and broader compare-backed validation
WebPStrongPartialstable unrelated-chunk preservation contract and broader compare-backed validation
JP2StrongPartialstronger managed-box preservation guarantees and more roundtrip validation
JXLStrongon current lanesPartialmore explicit box-preservation guarantees and deeper
brobrealtype follow-throughHEIF / AVIF / CR3Strongon tracked lanesPartialBMFF writer depth and deeper scene/relation semantics beyond the bounded current model
EXRBounded but realStable bounded host emissionfile-level rewrite is out of scope; late-bound patching remains host-owned
RAF / X3FPartialnot a main writer lane
deeper RAF model-specific native tables and X3F image-processing sections beyond current carrier/header/property lanes
CRW / CIFFPartialbounded
legacy native depth still trails mature tools
Photoshop IRBPartialbounded preservation
interpreted subset still smaller than mature tools
JUMBF / C2PAPartialbounded
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/C2PAsemanticsbroader host-side EXR attribute typing only when demanded by a concrete writer
Execution Order¶
Use this as the practical delivery order for the remaining parity work.
Priority legend:
Now: should be in the next active delivery sliceNext: should start after theNowslice is stableLater: important for broader parity, but not the next blocker
Work package
Priority
Why this order
Public writer contract for primary targets
DoneThe bounded contract and release gates are complete
General EXIF / IPTC / XMP sync engine
NowThis is still one of the biggest adoption blockers for general edit workflows
Compare-backed release validation
DonePrimary targets and writeback modes have release-facing compare gates
TIFF / DNG deeper rewrite guarantees
DoneThe bounded target modes and graph-preservation contract are release-gated
BMFF writer depth beyond current bounded contract
NowHEIF/AVIF/CR3are real targets; compactilocnormalization is complete and broader bounded graph depth remainsMakerNote rewrite trust
In progressGeneric behavior fails closed; Nikon type 1/type 3 and Canon source-dependent layouts are classified, while vendor-private relocation and integrity lanes remain
Modern container read-depth follow-through
NextVisible gap, but less urgent than finishing the current writer baseline
EXR target decision
DoneEXR remains a stable bounded host-emission target; file rewrite is out of scope
RAW curve/data applicability model
In progressCoarse 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
LaterMatters more for broad
ExifToolparity than for the first still-image writer milestoneJUMBF / C2PA deeper semantics
LaterCurrent bounded behavior is already useful; deeper trust semantics should wait until the core writer contract is stable
Full arbitrary metadata editing parity
LaterStrategic follow-up, not part of the next parity-closing milestone
Suggested delivery sequence:
Extend explicit native writeback beyond the completed date, technical, capture, geometry, descriptive, flat IPTC Core location, and editorial mappings. The 0.4.128 location batch covers five singleton fields; 0.4.129 adds Headline, Instructions, and Transmission Reference. Version 0.4.130 adds creator job title, caption writer, category, supplemental categories, and urgency, plus combined atomic writeback of all 20 supported text/priority groups. Together with the date API this covers the 24 active IPTC assignments in the documented ExifTool copy inventory, with explicit exclusions and no overall parity claim. Version 0.4.131 adds primary GPS latitude/longitude and altitude/reference writeback, including exact rational precision and GPS version companions. Additional capture fields and destination GPS remain separate feature batches. Version 0.4.132 adds explicit selection of one structured location and atomic five-field flat-XMP/IPTC reconciliation, with record multiplicity, conflict, dirty removal, and persistence contracts. Reverse construction of structured locations and geographic inference remain outside this bounded projection. Version 0.4.133 adds GPS UTC date/time and speed/track/image-direction writeback with exact fractions, explicit timezone normalization, reference pairs, and snapshot persistence. Receiver quality metadata is covered by version 0.4.135. Version 0.4.134 adds destination latitude/longitude, bearing/reference, and distance/unit writeback with exact precision, paired transactions, historical unit-label compatibility, and JPEG/Classic TIFF/BigTIFF persistence. Version 0.4.135 adds receiver status, measure mode, DOP, differential correction, and horizontal error. Version 0.4.136 adds satellites, map datum, processing method, and area information, with explicit text encoding. Together the five GPS APIs cover all 32 native GPS IDs in the repository under bounded version/encoding/precision contracts. Version 0.4.137 adds twelve closed capture-setting enums and explicit five-field flat-XMP-to-structured-location construction. Version 0.4.138 adds exact SubjectDistance, DigitalZoomRatio, ExposureIndex, and FlashEnergy writeback with explicit sentinel rules. Versions 0.5.2 and 0.5.3 add LensSpecification, ImageUniqueID and APEX reverse APIs. Version 0.5.4 adds complete focal-plane/subject groups. The 0.5.4 milestone audit identifies portable precision, sensitivity alias and malformed-value gaps; version 0.5.5 closes them with exact primary capture fractions, scalar validity checks and managed alias reconciliation. Version 0.4.139 adds complete scalar/five-child Flash bitfield writeback with reserved-bit and whole-structure removal rules. Version 0.4.140 adds LightSource writeback for 32 defined codes, rejects ambiguous Daylight text, and preserves the code 1/25 distinction in generated portable XMP. Version 0.4.141 adds a complete seven-tag sensitivity group, with explicit type relationships, LONG companions, latitude dependencies and whole-group conflict/removal rules. Version 0.4.142 adds six independent camera/lens/spectral printable-ASCII fields in one combined batch, including canonical portable namespaces and shared transaction, persistence and platform checks. The capture-related APIs now cover 65 distinct ExifIFD targets across fifteen APIs, including camera text and excluding GPS. ISO and ExposureBiasValue each overlap two APIs. Version 0.5.6 adds exact-key typed editing, additional capture scalars and six environment fields. Version 0.5.7 adds six encoding/composite fields, including bounded binary exposure structure and byte-order conversion. Version 0.5.8 adds four structured capture fields. Existing target-image filtering retains 62 of the 65 source tags. Portable capture round-trip closure builds on 0.5.5; see
docs/capture_sync_milestone.mdfor evidence, gaps and acceptance checks. Geographic inference and arbitrary structured-location merging remain excluded. Seedocs/translation.md.Retain the completed writer-baseline and compare-backed release gates while extending validated foreign
BMFFgraph shapes.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.
Follow through on modern-container read depth and long-tail native semantics. EXR remains a stable bounded host-emission target; file rewriting is outside the current contract.
Now Slice Implementation Board¶
This board turns the current
Nowslice 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 boundedBMFF[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.mddefines per-target preserve/replace rules and the remaining bounded limits. The BMFF section now makes the item-id width rule explicit: supported foreignilocversion 0/1 graphs can be upgraded to outputilocversion 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.mdnow defines the bounded public policy, including carrier precedence, generated-vs-existing conflict behavior, writeback modes, namespace handling, strict paired IPTC creation-date projection, and non-goals. The release-facing transfer tests cover source/destination carrier precedence, generated EXIF/IPTC versus existing XMP conflicts, canonical managed namespace replacement, paired IPTC date/time composition, JPEG/TIFF read-back, 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 boundedBMFFtarget outputs, including fail-safe rejection for unsupported foreign top-levelmetaBMFF 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 anilocv2 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 boundedSubIFDreplacement[x] lock explicit DNG behavior for
ExistingTarget,TemplateTarget, andMinimalFreshScaffold[x] add compare-backed roundtrip gates for preview chains, raw
SubIFDmerge behavior, andDNGVersionpersistence[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.mddefines 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,SubIFDauxiliary-tail preservation, existing root/preview/SubIFDXMP carrier replacement, embedded-versus-sidecar precedence, andDNGVersionread-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/DNGrewrite guarantees are strong enough to stop being a primary parity blocker[x] the next work slice can move to bounded
BMFFdepth 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
FlatHostmapping 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
TransferSourceSnapshotmode that keeps original carrier provenance and bounded payload bytes alongside decodedMetaStorestate[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
FlatHostimport by exact source identity, unique exported name, or explicitMetaKeyView; reject ambiguous name-only inverse mapping[x] add FlatHost remove-by-identity and remove-by-unique-name operations that preserve stable
Dirty | Deletedtombstones 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 bytesandvisit_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.
[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.[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.
[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.
[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.
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 throughTransferRawCarrierPassthroughMode::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 inspectTransferSourceSnapshot::raw_carriersand 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.
The 0.5.8 structured capture batch adds OECF, SpatialFrequencyResponse, CFAPattern and DeviceSettingDescription through
translate_xmp_structured_capture_metadataand its Python counterpart. The 0.5.8 combined inventory was 65 distinct native tags across fifteen APIs (62 retained by compatible-file transfer). ABI 3 and host synchronization remain unchanged; big-endian snapshots for the four new fields need a 0.5.8 reader. See Structured capture data.EXIF text update (0.5.9)¶
The 0.5.9 text/version batch adds UserComment, both version fields and seven EXIF 3 text tags. The new EXIF text API also supports UTF-8 owner/lens fields. The combined capture inventory is 75 distinct ExifIFD tags across sixteen APIs; compatible-file transfer retains 72. Version and Artist/Software companion requirements are explicit. ABI 3, snapshot v1 layout and host synchronization responsibilities remain unchanged. BOM-less big-endian UserComment snapshots require a 0.5.9 reader. See the EXIF text/version translation contract for limits and the recorded OIIO/ExifTool reader limitations.
EXIF 3.1 development and correction update (0.5.11)¶
The six development/correction fields A40D–A412 now have a shared transactional translator, native schema validation, portable XMP and type-129 serialization. The host must provide EXIF version 0300 or 0310 for selected writeback; no version is inferred or changed. Compatible-file and rendered-image transfer retain these standard processing-history fields when present. OpenMeta does not infer processing history from RAW or MakerNote data. See the translation contract.
Grouped timestamp destination editing (0.7.0)¶
Prepared bundles carry bounded primary IFD0 and ExifIFD timestamp removals, with an explicit ExifIFD merge mode for dirty timestamp edits. Accepted XMP owners control companion absence as well as values, even when native source keys were missing. Edit/stream/package paths preserve unselected target native records in that mode. Fresh emit/codec consumers reject removal-bearing bundles. Public bundle layouts remain unfrozen under development ABI label 4; rebuild consumers against matching headers and libraries. Source snapshot v1 is unchanged. See migration for tags, conflict policies and exclusions.
Capture and lens destination editing (0.7.1)¶
The bounded ExifIFD removal and merge mode also covers ExposureTime, FNumber, ISO/sensitivity, Flash, FocalLength and lens make/model/serial. Exact dirty native values and deletion intents select preservation of unspecified destination entries. Snapshot v1, edit/stream/package consumption, manual-conflict checks, EXIF opt-out and unsupported-consumer rejection stay unchanged. Full sensitivity owns seven members; basic ISO owns its base tag only. See migration for the 22-tag allowlist, contract versions, unfrozen ABI-4 policy and exclusions.
APEX and capture-settings destination editing (0.7.2)¶
The bounded ExifIFD removal and merge mode now covers all five APEX singleton fields and twelve closed-enum capture settings. General capture and APEX share ExposureBias ownership; hosts disable one overlap when composing and stage the separate transactions before publication. Deletion intent for missing keys, clean-exact Dirty authority, omission/conflict rules and preflight budgets match the existing bounded lifecycle. The complete allowlist grows from 22 to 39 tags; no new bundle layout or snapshot format is needed. Capture contract 3 and APEX/settings contracts 2 describe the changes. ABI 4 and package-minor policy remain. See migration for exact tags and exclusions.
GPS destination editing (0.8.0)¶
All five GPS translators now carry absent-native deletion and exact clean Dirty ownership into bounded GPS IFD merges. Prepared bundles add sorted GPS value-tag removals and an opt-in merge flag; source snapshot v1 is unchanged. Native tags 1 through 31 are bounded owners, with tag 0 maintained structurally. Unselected and unknown destination GPS fields survive; version cleanup is destination-aware. Conflicting versions/clear/manual edits fail before output. The public layout requires rebuilding matching consumers, with package minor 0.8 and unfrozen ABI4. See migration for the exact contract and consumer limits.
Spatial destination lifecycle (0.8.4)¶
The five native spatial fields now use bounded ExifIFD merge/removal authority: focal-plane X/Y/unit as one translator group and two independent subject arrays. Accepted exact native values retain their wire provenance while gaining Dirty; complete deletion carries intent for absent source keys. Omission preserves the destination. Existing snapshot v1/vector/stream/package paths carry this state. The allowlist extends39 to44 without a bundle-layout change. Spatial contract2, unfrozen ABI4 and host synchronization remain. Grouped qualification covers classic/BigTIFF endians and bounded original-backed TIFF/DNG writes; reader, codec, SDK, general private relocation and downstream qualification remain separate.
Rational and identity destination lifecycle (0.8.5)¶
The four capture rationals, LensSpecification and ImageUniqueID now share the bounded native ExifIFD merge/removal lifecycle. Accepted clean exact native values retain their actual components/text and provenance while gaining Dirty; complete eligible deletion carries absent-key intent. The sorted allowlist grows 44 to 50, using existing bundles and source snapshot v1. Rational/identity contracts advance to 2 without signature, option or layout changes. ABI 4 and host synchronization remain. Grouped destination qualification covers exact sentinels, lens unknowns, ID text and bounded original-backed preservation. Reader, codec, SDK and downstream qualification remain separate.
Additional capture and environment lifecycle (0.8.6)¶
The additional-capture and environment translation contracts are version 2. The nine fields are FocalLengthIn35mmFilm, FileSource, SceneType, Temperature, Humidity, Pressure, WaterDepth, Acceleration and CameraElevationAngle. Accepted exact clean native values gain
Dirtywhile retaining raw rational components, unknown numerators and reserved denominator bits, one-byte UNDEFINED codes, flags and wire provenance. Complete eligible deletion creates or reusesDirty|Deletednative intent even when the key is absent. Omitted and ineligible sources preserve the destination;PreserveExistingretains an active owner without promotion. Existing budgets include promotion, intent and duplicate removal; failure leaves source and output unchanged.The shared ExifIFD merge/removal allowlist grows from 50 to 59.
Dirtyselects merge mode; the prepared EXIF payload may also include clean live source entries. Unspecified destination entries are preserved when absent from that payload. Existing signatures, options, prepared bundle layout, snapshot v1 and package selection policy remain the same. Keep development ABI label 4 and rebuild consumers against matching headers and libraries. This batch changes no reader, pixel/RAW transfer exclusion, vendor interpretation or codec contract.
- page Migrating to OpenMeta 0.5.0
This guide describes the 0.5 release. For the current minimum-version package policy, see Shared Library Contract.
Version 0.5.0 introduces a breaking prepared-patch API. Applications using the old interface must use an earlier release or migrate and rebuild. No legacy header aliases, old patch symbols or compatibility wrappers are provided.
Before 0.5
Since 0.5.0
openmeta/exif_tiff_patch.hExifTiffPatch*typesMetadataPatch*typesPreparedExifTiffPatchPlan/PreparedExifTiffPatchInstancePreparedMetadataPatchPlan/PreparedMetadataPatchInstanceprepare_exif_tiff_patch_planprepare_metadata_patch_plancreate_prepared_exif_tiff_patch_instancecreate_prepared_metadata_patch_instancepatch_prepared_exif_tiff_instancepatch_prepared_metadata_instanceexif_tiff_patch_contract_versionmetadata_patch_contract_versionexif_tiff_patch_code_namemetadata_patch_code_nameoptions.serializationoptions.exif; store validation usesoptions.validatepayload()payload(MetadataPatchPayload::ExifTiff)orpayload(MetadataPatchPayload::Xmp)EXIF request/value shapes retain their typed meaning. Add XMP requests by emitted namespace URI and simple property path, with an exact
escaped_width. Mixed EXIF/XMP batches are atomic across both payloads. Keep numeric TIFF updates typed; XMP updates accept logical text and preserve its spelling. See canonical_patching.md for an example.Set the new required
options.plan_idto a fresh host-issued nonzero 48-bit ID for each successful preparation. The host coordinates ID assignment and must not reuse an ID while an old plan, worker or handle using it remains usable. Default options with ID zero fail withInvalidOptions. The patch API has no internal atomics, mutexes or global ID allocator; the host synchronizes shared objects, borrowed payload access and lifetimes.Patch handles belong to the supplied preparation generation. Rebuilding an identical packet does not make previous handles valid for the new plan. Old instances remain usable with their own handles even after the original plan is destroyed. Handles and worker state are process-local and are not snapshot serialization content.
Build and binary boundary¶
The C++ shared-library ABI advances from 2 to 3.
OpenMeta_ABI_VERSIONin the installed package reports 3; it is release-controlled rather than a cache option. ELF uses the ABI-3 SONAME, macOS uses ABI 3, and Windows usesopenmeta-3.dll. The Windows import archive remainsopenmeta_shared.lib. Static consumers and Python/native extensions must also rebuild against the new headers and libraries. Use separate install prefixes when retaining an older SDK alongside 0.5.0.CMake package compatibility now requires the same major and minor version.
find_package(OpenMeta 0.4 CONFIG REQUIRED)does not accept a 0.5 package. Migrated consumers can requestfind_package(OpenMeta 0.5 CONFIG REQUIRED). A consumer that specifies no version accepts responsibility for the selected SDK.Existing reader and codec integrations¶
This release does not require a change to the read/export/snapshot profile.
HostAdoptionProfileV1remains a separate reader integration contract; the new patch API has its own version query. Existing prepared-transfer codec operations remain available and continue to own their target-specific behavior.Compared with 0.4.141, the previous 0.4.142 release already changed boundary whitespace preservation for six camera/lens/spectral XMP fields. That observable readback change is separate from the prepared-patch refactor.
- page Migrating to OpenMeta 0.6.0
This guide describes the 0.6 release. For the current minimum-version package policy, see Shared Library Contract.
This guide describes the 0.6 release boundary. Current 0.7 builds also use the unfrozen development ABI label 4; matching numbers do not establish binary compatibility. Rebuild against matching release headers/libraries. See the 0.7 guide.
OpenMeta 0.6.0 adds explicit native TIFF IFD0 deletion instructions to
PreparedTransferBundle. Its C++ layout changes, so applications and plugins must rebuild against the new headers and library. C++ ABI 4 replaces ABI 3; the Windows runtime isopenmeta-4.dll, and ELF/macOS use ABI major 4.The installed CMake package uses
SameMinorVersion. Requestfind_package(OpenMeta 0.6 CONFIG REQUIRED)after migration. A 0.5 request does not accept the 0.6 package. Keep the older SDK for consumers that have not rebuilt. Do not mix 0.5 headers or objects with the 0.6 library.Explicit TIFF deletion¶
The owned
tiff_ifd0_removalslist names supported tags to remove from an existing TIFF/BigTIFF IFD0. This first contract coversImageDescription(0x010E),Artist(0x013B) andCopyright(0x8298). Other IFDs, page directories, structural/storage tags and MakerNotes are outside this contract.Version 0.6.2 adds Make (
0x010F), Model (0x0110) and Software (0x0131) to the same list without changing ABI 4 or snapshot v1. Request 0.6.2 or newer when using these additions; older 0.6 libraries reject their manual removal instructions. Other companion fields remain host-owned.Preparation collects exact native
ifd0entries marked bothDirtyandDeletedwhen EXIF transfer is enabled. A live entry of the same key takes precedence over historical tombstones. Duplicate tombstones yield one sorted instruction. Clean tombstones and absent source properties do not request deletion. Settinginclude_exif_app1 = falsedisables collection. Snapshot v1 already stores the required flags, so its encoding does not change.For manually assembled bundles, use a sorted, unique list of supported tags. Invalid lists and a simultaneous serialized replacement of a removed tag fail before output. Use the existing TIFF edit plan/apply, stream-write or edit package paths. Fresh tag emitters, the DNG SDK adapter and typed codec handoffs cannot express destination deletion and reject a deletion-bearing bundle before callbacks. Keep the input and prepared bundle unchanged between planning and applying.
TiffEditPlanis a summary, not a fingerprint of the exact edits; replan after changing the bundle.Translation’s
ReplaceExistingpolicy operates on the source store. To remove an existing destination native tag, the source must retain the explicit native tombstone through preparation. Omitting the source field alone still preserves the destination field. XMP remains governed by its own preparation and carrier replacement policies; a manually requested native deletion is not an implicit XMP synchronization request.The Python transfer probe reports
tiff_ifd0_removalsin its diagnostic result. It remains a path-based probe; this release does not add an in-memory Python prepared-bundle authoring API.Preparation and edit planning may allocate. Existing host-owned synchronization rules remain unchanged. No atomics or mutexes are added, and this change does not claim general TIFF deletion or complete-file profile conformance.
- page Migrating to OpenMeta 0.7
This guide describes the 0.7 release. For the current minimum-version package policy, see Shared Library Contract.
OpenMeta 0.7.2 retains the unfrozen development ABI label 4. Public C++ layouts and APIs may change while that label stays 4. Rebuild applications and plugins against matching release headers and library whenever they change; the label alone does not establish compatibility with older ABI-4 binaries. The initial local 0.7.0 build used label 5; 0.7.1 returns to 4 under this policy. The current Windows runtime is
openmeta-4.dll; ELF/macOS use ABI major 4.PreparedTransferBundlecarriestiff_exif_removalsandtiff_merge_existing_exif. The installed package still usesSameMinorVersion: requestfind_package(OpenMeta 0.7 CONFIG REQUIRED). A 0.6 request does not accept the 0.7 package. This package discovery rule does not freeze C++ layouts. Do not mix headers, objects or libraries from different development snapshots.Timestamp authority¶
The date and technical translation contracts are version 2. An accepted
xmp:CreateDate, XMPexif:DateTimeOriginal, orxmp:ModifyDateowns its complete native EXIF timestamp family. The lexical timezone and fraction control the corresponding offset and subsecond tags. A value without them produces explicit native dirty tombstones, including when the native keys were absent from the translation input. A dirty owner tombstone removes the base timestamp and both companions. Source omission or an ineligible source property preserves the destination.PreserveExistingretains the whole group when any native member is active.FailOnConflictrequires absence or exact equivalence;ReplaceExistingreconciles the group. Accepted absent members carry removal intents under any of these policies. Accepted clean, exact timestamp members are marked dirty so preparation retains the merge authority; these same-value updates count against the operation limit. Synthesized intents count againstmax_added_entriesandmax_operations, and repeated translation reuses existing dirty tombstones. IPTC and other technical singleton behavior remains unchanged.Each translator is transactional. Creation-date and technical translation are separate calls; hosts stage their results and publish only after every required call succeeds. Fractional dates still require disabling lossy IPTC mappings.
Capture and lens authority¶
In 0.7.1 capture, Flash, sensitivity and camera-text translation contracts became version 2; 0.7.2 advances capture to version 3 for ExposureBias ownership. Accepted ExposureTime, FNumber, base ISO, Flash, FocalLength and lens make/model/ serial owners carry native deletion intent even when their source native keys are missing. Accepted clean exact native values gain Dirty with a same-value update that retains their bytes and wire provenance. Omission and existing conflict policies remain. Added intents and authority updates count against entry/operation limits before publication; repeated calls reuse them.
Full sensitivity owns PhotographicSensitivity and tags
8830–8835as one validated group. Optional absent members carry deletion intent only after the complete source passes validation. Basic ISO owns only8827and preserves sensitivity companions; disable its mapping when the full group owns that source. Lens make/model/serial are independent singletons. LensSpecification, camera-owner/body-serial and other capture translators retain their existing behavior; 0.7.2 adds the APEX and settings lifecycle described below. Hosts stage the separate translator calls before publishing an aggregate result.TIFF preparation enables preservation of unspecified destination ExifIFD fields for these dirty native edits. In addition to timestamp tags, bounded ExifIFD removal accepts ExposureTime
829A, FNumber829D, PhotographicSensitivity8827, SensitivityType and extended sensitivity8830–8835, Flash9209, FocalLength920A, LensMakeA433, LensModelA434and LensSerialNumberA435. Snapshot v1 remains unchanged.APEX and capture-settings authority (0.7.2)¶
APEX and capture-settings translation contracts are version 2. General capture is version 3 because its ExposureCompensation mapping shares the APEX bias owner. Each of the five APEX fields and twelve closed capture settings is an independent singleton. Accepted dirty owner deletion carries exact native Dirty+Deleted intent even when the source native key is missing. Accepted clean exact values gain Dirty without changing their scalar, rational encoding or wire provenance. Omitted or ineligible owners preserve destination values.
Existing conflict policies, exact APEX units, brightness unknown sentinel, accepted enum codes, alias and source-shape validation remain. Intent additions, clean-marker promotion and same-value authority updates consume preflight entry/operation budgets. Repeated calls reuse intent; each translator commits once or leaves the output unchanged. Hosts stage separate calls before publishing an aggregate result and disable one overlapping ExposureBias mapping when both APEX and general capture are used. No exposure or camera-state inference occurs.
TIFF/BigTIFF edits use the existing removal list and ExifIFD merge flag for the 17 additional tags:
8822,9201–9205,9207,A217,A401–A403,A406–A40AandA40C. The complete allowlist has 39 tags. Unselected native records, opaque MakerNote bytes and original offsets, standard pointers and media remain preserved. Snapshot v1, bundle/API layouts, development ABI 4, package-minor policy and unsupported-consumer rejection are unchanged.TIFF edit requests¶
The sorted unique
tiff_ifd0_removalslist adds DateTime0x0132to the six previously supported root tags. The new sorted uniquetiff_exif_removalslist accepts the capture/lens/APEX/settings tags above and these primary ExifIFD timestamps:Family
Base timestamp
Offset
Subsecond
Modified
IFD0
0x01320x90100x9290Original
0x90030x90110x9291Digitized
0x90040x90120x9292Preparation collects exact native
ifd0/exififddirty tombstones with EXIF output enabled. Live same-key entries win over old tombstones. Snapshot v1 already retains these flags, so its encoding is unchanged.Preparation enables
tiff_merge_existing_exiffor exact dirty native timestamp and selected capture/lens members. That explicit mode, and any ExifIFD per-tag removal, retains unspecified destination ExifIFD entries while applying replacements and removals. Unselected timestamp families, capture fields, standard pointers and opaque MakerNote bytes survive. Private offset/checksum repair is outside this contract. Outside this mode, the existing ExifIFD replacement behavior remains. A present-empty source ExifIFD still requests whole-directory clearing; combining that clear with merge or ExifIFD removals is invalid. Merge mode preserves existing destination records; source transfer filtering does not redact them.TIFF/BigTIFF edit plan/apply, streams and edit packages consume both lists. Unsupported tags, unsorted/duplicate lists and simultaneous replacement/removal fail before output or callbacks. Fresh emitters, codec handoffs and the DNG SDK adapter reject either nonempty removal list. Use TIFF editing when carrying removal intents, including editing a fresh empty TIFF scaffold. A manual native removal list does not implicitly translate or synchronize XMP.
Keep the input and prepared bundle unchanged between planning and applying, and replan after any change. The Python transfer probe reports both removal lists and the merge flag; it remains a path-based diagnostic API. Preparation and planning may allocate. Host-owned synchronization and existing patch, handoff and snapshot contracts remain unchanged. No general multi-page TIFF deletion, complete-file profile or codec conformance is implied.
- page Migrating to OpenMeta 0.8
OpenMeta 0.8.0 retains the unfrozen development ABI label 4. The public
PreparedTransferBundlelayout changes: rebuild applications and plugins against matching headers and libraries. Requestfind_package(OpenMeta 0.8 CONFIG REQUIRED). The installedSameMajorVersionpolicy accepts older 0.x minimum requests, such asfind_package(OpenMeta 0.7 CONFIG REQUIRED). Higher minimums and mismatchedEXACTrequests are rejected; version ranges retain their bounds. Package selection does not guarantee unchanged experimental APIs or binary compatibility. ABI label 4 alone does not establish compatibility with older binaries.Bounded metadata work¶
Patch 0.8.2 adds
JumbfDecodeLimits::max_semantic_work. It bounds aggregate JUMBF/C2PA box, projection, reference, link, comparison and sorting work that can otherwise multiply independently bounded collection sizes. Zero selects the finite default; it does not disable this limit. Exhaustion returnsJumbfDecodeStatus::LimitExceeded. Increase the value explicitly only for a trusted workload that needs more semantic projection work.The zlib and Brotli payload paths now enforce
PayloadLimits::max_output_bytesbefore each decoder call. An output that ends exactly at the limit still succeeds. Output that requires another byte returnsPayloadStatus::LimitExceededwithout writing beyond the configured limit. Zero retains its documented unlimited meaning for this payload limit.JumbfDecodeLimitsis an experimental public layout. OpenMeta keeps development ABI label 4 for this patch, but applications and plugins must rebuild against matching 0.8.2 headers and libraries.Bounded BMFF edits¶
Patch 0.8.1 preserves ordered repeated
dimginputs during bounded BMFF edits. Removal of an input of a retained derived-image relation now rejects before output instead of silently shortening the list. Removing the source still drops its whole relation. This patch changes no public signatures or layouts.GPS edit ownership¶
The primary, navigation, destination, quality and text GPS translation contracts are version 2. Their signatures, options, accepted formats, precision limits and version rules stay the same. Together they cover the 31 native GPS value tags and the structural
GPSVersionIDtag.Each accepted source group owns its native members: coordinates own reference and DMS values, altitude owns reference and magnitude, UTC timestamps own time and date, and navigation/destination pairs own reference and value. Other GPS fields are independent. Omitted or ineligible sources preserve destination values. The existing conflict policy applies to the complete source-native group. PreserveExisting skips an active native group even when it is an exact match; it does not promote clean values into edit authority.
An accepted dirty deletion creates or reuses native
Dirty|Deletedintent even when the native members were absent. Accepted exact clean values gainDirtywhile retaining their native fractions, array/text bytes and wire provenance. All additions, authority updates and duplicate removals consume the existing preflight budgets. Repeated calls reuse intent; failure leaves source and output unchanged, including aliased output.Each translator is transactional. Hosts stage the five calls before publishing an aggregate result and synchronize access to shared objects.
Prepared TIFF and BigTIFF edits¶
PreparedTransferBundleaddstiff_gps_removals, a sorted unique list of native GPS IDs 1 through 31, andtiff_merge_existing_gps, which defaults to false. With EXIF output enabled, dirty supported native GPS edits select bounded merge mode. A live native member wins over a tombstone for the same key. Tag 0 alone never selects this mode. Source snapshot v1 retains the flags and regenerates these fields without changing its format. Python snapshot probes expose both.Bounded editing preserves unselected destination GPS fields, including unknown tags. Removing selected GPS fields does not clear the directory. The final GPS version and pointer are removed only when no non-version GPS value remains. An explicit empty GPS payload still means whole-directory clearing; combining it with bounded merge/removals or conflicting manual pointer edits is rejected.
An active bounded merge requires one valid supplied native GPSVersionID. Supplied and existing destination versions must agree. Conflicts fail before output; no automatic version upgrade or altitude reference reinterpretation occurs. Include the target native GPSVersionID in the translation input when editing a version other than the default 2.3.0.0. Removal-only edits retain the destination version while other GPS values survive. Existing exact rational, encoded-text and legacy sea-level altitude contracts continue to apply.
TIFF/BigTIFF edit, stream and package paths carry this intent. Fresh creation can consume merge-only metadata because it has no destination values to preserve. Consumers whose schemas cannot represent removal reject it before writing. The DNG SDK adapter also rejects GPS merge mode because it cannot preserve unselected destination GPS fields under this contract. These changes do not add private-record offset repair or codec conformance guarantees.
Spatial destination editing in 0.8.4¶
Spatial translation contract 2 adds Dirty authority for accepted exact native values and complete native deletion intent for absent keys. Focal-plane X/Y/unit remain one group; SubjectArea and SubjectLocation remain independent arrays. Existing parsing and coordinate semantics are unchanged. PreserveExisting keeps an active owner whole. New intent and promotions consume existing bounds.
The existing native ExifIFD merge/removal fields now cover all five spatial tags (44 allowlisted tags total) for TIFF/BigTIFF/DNG destination edits. Prepared bundle layout, signatures, options and source snapshot version 1 remain unchanged. Non-edit consumers reject removal intent. Rebuild against matching headers and libraries: development ABI 4 is unfrozen. SameMajorVersion package selection continues to allow later source versions; it does not promise experimental API or binary compatibility. OIIO/iRAW adoption remains a separate acceptance gate.
Rational and identity destination editing in 0.8.5¶
Rational and identity translation contracts are version 2. SubjectDistance, DigitalZoomRatio, ExposureIndex and FlashEnergy are four independent scalar owners. LensSpecification owns its four-element array; ImageUniqueID is independent. Accepted exact clean natives gain Dirty while retaining rational components, lens unknown markers, ID case/NUL and wire provenance. Complete eligible deletion carries native intent even for absent keys. Omission and ineligible sources preserve destination values; PreserveExisting retains an active owner without promotion. Existing budgets include intent, promotion and duplicate-removal costs.
The shared ExifIFD merge/removal allowlist grows from 44 to 50 using existing prepared fields. Dirty selects bounded merge; ordinary prepared EXIF may include clean live source entries too. Destination entries absent from the prepared payload are preserved. Native wire values, SubjectDistance numerator sentinels, lens unknown aperture rules and 32-hex identity semantics are unchanged.
Public signatures, options, bundle layout and snapshot v1 remain unchanged. Development ABI 4 is unfrozen; rebuild consumers against matching headers and libraries. SameMajorVersion package selection is unchanged. Hosts stage separate translator calls before publishing and synchronize shared objects. These changes do not add reader, codec, SDK, private-offset repair or downstream qualification.
Native ImageUniqueID text may retain its single terminal NUL. Detached validation and serialization both use the actual 33-byte wire representation, rather than counting or emitting another terminator. Invalid hex, embedded/multiple NULs and incorrect wire-count hints remain invalid.
Additional capture and environment editing in 0.8.6¶
The additional-capture and environment translation contracts are version 2. The nine fields are FocalLengthIn35mmFilm, FileSource, SceneType, Temperature, Humidity, Pressure, WaterDepth, Acceleration and CameraElevationAngle. Accepted exact clean native values gain
Dirtywhile retaining raw rational components, unknown numerators and reserved denominator bits, one-byte UNDEFINED codes, flags and wire provenance. Complete eligible deletion creates or reusesDirty|Deletednative intent even when the key is absent. Omitted and ineligible sources preserve the destination;PreserveExistingretains an active owner without promotion. Existing budgets include promotion, intent and duplicate removal; failure leaves source and output unchanged.The shared ExifIFD merge/removal allowlist grows from 50 to 59.
Dirtyselects merge mode; the prepared EXIF payload may also include clean live source entries. Unspecified destination entries are preserved when absent from that payload. Existing signatures, options, prepared bundle layout, snapshot v1 and package selection policy remain the same. Keep development ABI label 4 and rebuild consumers against matching headers and libraries. This batch changes no reader, pixel/RAW transfer exclusion, vendor interpretation or codec contract.
- page Prepared Transfer Handoff
Prepared Transfer Handoff v1 is the stable target-preparation boundary for applications that own an encoder, writer, SDK object, or realtime transcoding pipeline. It prepares target-specific metadata once and exposes immutable, typed operations without exposing
PreparedTransferBundle, route strings, or other transfer internals.The contract is declared in
openmeta/prepared_transfer_handoff.h.Runtime Contract¶
#include "openmeta/prepared_transfer_handoff.h" if (openmeta::prepared_transfer_handoff_contract_version() != openmeta::kPreparedTransferHandoffContractVersion) { // Reject an incompatible linked OpenMeta library. } if (openmeta::prepared_transfer_handoff_instance_contract_version() != openmeta::kPreparedTransferHandoffInstanceContractVersion) { // Disable the mutable per-worker path. }
PreparedTransferHandoffis move-only and has a fixed opaque-pointer public layout. The linked OpenMeta library owns and destroys all prepared state.Prepare Once¶
openmeta::PrepareTransferRequest request; request.target_format = openmeta::TransferTargetFormat::Webp; request.profile.safety = openmeta::TransferSafetyMode::RenderedImage; openmeta::PreparedTransferHandoff handoff; const openmeta::PreparedTransferHandoffResult prepared = openmeta::prepare_transfer_handoff( snapshot, request, openmeta::EmitTransferOptions {}, &handoff); if (!prepared.ok()) { const std::string_view reason = openmeta::prepared_transfer_handoff_code_message(prepared.code); // Apply host policy or report `reason`, `prepare_code`, and `adapter_code`. }
Preparation copies the decoded snapshot state needed by target serialization, applies the requested transfer policy, packages payloads, compiles the typed operation vector, and classifies each operation by metadata family. All allocation and route interpretation happen in this phase. A failed call does not replace an existing valid handoff.
Stable v1 requires
TransferRawCarrierPassthroughMode::Disabled. Opt-in raw-carrier reuse remains an experimental policy and is rejected rather than silently changing stable handoff behavior.Consume Typed Operations¶
Use
prepared_transfer_handoff_operation(...)for indexed access. The returned view contains:semantic_kind: EXIF, XMP, ICC, IPTC, JUMBF, C2PA, or unknown;operation: the stable enum-based marker, tag, box, chunk, item, property, or EXR operation and its target-specific fields;payload: the borrowed prepared carrier payload;exr_name,exr_type_name,exr_value, andexr_is_opaquefor EXR attributes.
Hosts must treat
operation.block_indexas an opaque correlation value. It is not an index into host-visible storage. ForExrAttribute, pass the explicit EXR fields to the writer; the generic payload remains available only for diagnostics.Views borrow immutable handoff storage. They remain valid until the handoff is successfully prepared again, reset, moved from, or destroyed.
Replay Without Recompilation¶
replay_prepared_transfer_handoff(...)calls anoexceptfunction pointer once per operation. A successful replay performs no allocation, route parsing, operation-vector construction, validation rebuild, locking, or hidden retry. The callback returnsTransferStatus::Okto continue; any other status stops replay and reports the failed operation index.The same immutable handoff can be replayed repeatedly. Concurrent const access is supported when every replay uses independent callback state and the host does not reset, move, destroy, or prepare the handoff concurrently.
Per-Worker Mutable Instances¶
Use
PreparedTransferHandoffInstancewhen frame or output metadata has fixed-width time fields that change for each encoded image. Prepare one immutable template, create one independently owned instance per worker, then patch and replay that worker’s instance:openmeta::PreparedTransferHandoffInstance worker; openmeta::PreparedTransferHandoffResult created = openmeta::create_prepared_transfer_handoff_instance(handoff, &worker); openmeta::PreparedTransferHandoffTimePatchFieldView field; const openmeta::PreparedTransferHandoffPatchResult described = openmeta::prepared_transfer_handoff_instance_time_patch_field( worker, openmeta::TimePatchField::DateTime, &field); constexpr char encoded_time[] = "2030:12:31 23:59:59"; static_assert(sizeof(encoded_time) == 20U); // EXIF ASCII including NUL const openmeta::TimePatchView patch { openmeta::TimePatchField::DateTime, std::as_bytes(std::span<const char>(encoded_time, sizeof(encoded_time))) }; const std::array<openmeta::TimePatchView, 1> patches = { patch }; if (created.ok() && described.ok() && field.width == sizeof(encoded_time) && openmeta::patch_prepared_transfer_handoff_instance(&worker, patches) .ok()) { openmeta::replay_prepared_transfer_handoff_instance( worker, emit_to_codec, codec); }
Instance creation may allocate. It copies one contiguous payload buffer and the compact operation, semantic, EXR-view, block-range, and patch-slot state. It does not copy route strings, transfer-policy diagnostics, or generated sidecars, and it does not recompile operations. The instance owns all copied state and remains valid if the template is reset, moved, prepared again, or destroyed.
prepared_transfer_handoff_instance_time_patch_field(...)reports the exact serialized width and number of matching slots without exposing payload offsets. This lets generic hosts size patch buffers forSubSec*and other fields whose width is source-dependent. An absent field or non-uniform/invalid slot layout is reported before patching.Patching and replay allocate nothing. Stable instance v1 requires every patch field to be valid, unique, and present in the prepared slot map. Values are serialized bytes and must exactly match every corresponding slot width; for EXIF ASCII date/time fields that normally includes the terminating NUL. Inputs that alias mutable instance payload storage are rejected. The complete batch is validated before any byte changes, so every failure leaves the instance unchanged.
Each worker must own a separate instance. Independent instances may patch and replay concurrently. A single instance requires exclusive ownership while it is patched; indexed views or replay must not run concurrently with patch, reset, move, or destruction. A borrowed operation view keeps its address but its payload contents may change after a successful patch.
Target Coverage¶
Handoff v1 exposes typed operations for:
Target
Operation
JPEG
marker code and payload
TIFF, DNG
TIFF tag and payload
JPEG XL
box or ICC-profile operation
WebP
RIFF chunk type and payload
PNG
chunk type and payload
JP2
box type and payload
HEIF, AVIF, CR3
BMFF item/property fields and payload
EXR
attribute name, type, value, and opacity
Format capability and metadata-family support remain separate questions. Use
metadata_capability(...)before assuming that a requested family can be serialized into a target.Deliberate Boundary¶
Stable Handoff v1 does not include:
source reading or snapshot persistence;
raw-carrier passthrough;
direct access to prepared bundles, blocks, routes, or execution plans;
variable-width or structural metadata mutation;
prepared payload/package persistence;
editing or rewriting destination container bytes;
encoder-specific object ownership or scheduling.
Those APIs remain available where documented, but their current contracts are experimental. Keeping them outside Handoff v1 allows the internal writer and package models to evolve without breaking high-performance codec integrations.
- 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
MetaStorebuild 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 stable prepare-once codec operations, see prepared_transfer_handoff.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 isOpenMeta::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 toMetaStore.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 assource_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 retainsexact_match,fuzzy_match, andfuzzy_scorecompatibility 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(...)andTransferSourceSnapshot.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 usesafe,source_bound,rendered_unsafe, orrequires_target_image_specto 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, passMetadataRawDataDescriptorto 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, setraw_descriptor.requires_compressed_raw_encoding = truebefore requesting concept diagnostics. If that curve/LUT only applies to the primary raw plane, also setraw_descriptor.requires_primary_raw_plane = trueand providehas_plane_index/plane_indexfor 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 withmetadata_concept_gps_altitude_reference_name(...).For user-facing orientation display, use
openmeta/orientation.hinstead 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 numericMetaStorevalues.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
storeunchanged. 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);
storeis 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.formattoXmpSidecarFormat::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::TiffTransferTargetFormat::DngTransferTargetFormat::PngTransferTargetFormat::WebpTransferTargetFormat::Jp2TransferTargetFormat::Jxlbounded BMFF targets such as
Heif,Avif, andCr3
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_carriersor passpreserve_raw_carriers=Truein Python. The snapshot then keeps bounded raw carrier records with originalContainerBlockRefranges, route hints, and payload bytes up tomax_raw_carrier_bytes. Each carrier also reports the snapshot-local decoded entry ids attributed to it. Transfer still uses decoded re-emission by default. Useraw_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 assnapshot.raw_carrier_passthrough_audit(...). To allow the bounded passthrough path during snapshot preparation, setPrepareTransferRequest::raw_carrier_passthrough_modetoTransferRawCarrierPassthroughMode::WhenSafe, or passraw_carrier_passthrough_mode=openmeta.TransferRawCarrierPassthroughMode.WhenSafeto 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 encoder, use the stableprepare_transfer_handoff(...)path for decoded re-emission. The lower-level experimentalprepare_metadata_for_target_snapshot(...)entry point remains available when direct bundle access or experimental raw-carrier reuse is required. If the host already has a decodedMetaStore, build a reusable snapshot withbuild_transfer_source_snapshot(store). If it already owns the source bytes in memory, useread_transfer_source_snapshot_bytes(bytes)instead of the file-path reader. For large assets exposed through a host positional-read callback, useread_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 bothcomplete()andresidual_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. Usecollect_read_transfer_source_diagnostics(...)for machine-readable failure, scratch, MakerNote, and residual details. In Python, if the host already hasdoc = openmeta.read(...), calldoc.build_transfer_source_snapshot()oropenmeta.build_transfer_source_snapshot(doc)instead of reopening the file. If it also owns the destination bytes in memory, call the overloadexecute_prepared_transfer_snapshot(snapshot, target_bytes, options). If it already holds a prepared bundle, useexecute_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 toedit_target_pathunlessxmp_existing_sidecar_base_pathis set explicitly. For embedded-only writeback with sidecar cleanup and no filesystem path, setxmp_existing_destination_sidecar_stateexplicitly 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 oldertransfer_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, ordisabled.boundedmeans the capability exists within OpenMeta’s documented contract.disabledis 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:
implement a backend emitter such as
JpegTransferEmitterorJxlTransferEmitteror 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
JpegTransferEmitterand 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 sidecarsuppresses generated embedded XMP and writes the generated packet asoutput-stem.xmp.--xmp-writeback embedded_and_sidecarwrites both carriers. Embedded-only writeback preserves an existing sidecar unless--xmp-destination-sidecar strip_existingis set; sidecar-only writeback preserves existing embedded XMP unless--xmp-destination-embedded strip_existingis set.--forcecontrols 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¶
Detailed read support: metadata_support.md
Target-by-target transfer status: metadata_transfer_plan.md
Host-side encoder and SDK integration: host_integration.md
Build, test, and deeper API notes: development.md
- 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)callbacka 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. FujifilmFUJIFILM/GENERALEnotes 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(...), andscan_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 useExrRandomAccessScratch::read_window; the largest attribute value selected for decode must fitvalue, orvalue_scratch_neededreports 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
PROPsections, 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, whilescan_x3f_random_access(...)follows declaredIMA2/IMAGSECiJPEG 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_windowmust hold 20 bytes for BigTIFF entries. Larger windows batch adjacent structural reads.valuemust 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_neededreports 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
ScratchTooSmallwhen a larger probe is needed. Usemeasure_scan_jpeg_random_access(...)with the same scratch and limits to obtainscan.neededwithout block output storage.For PNG, WebP, GIF, JP2, JXL, and ISO-BMFF sources, call the corresponding
scan_*_random_access(...)ormeasure_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
TransferSourceSnapshotowns its finalizedMetaStore, 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, butcomplete()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 itsMetaStoreand 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_readsis true and the host context actually supports concurrent positional reads. Each operation must use separate decoder scratch andRandomAccessReadStateobjects.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¶
RandomAccessSourceis 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 returnRandomAccessIoCode::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/idenconstructions, recursive item-offset descriptor resolution, graph-cycle/source validation, and complete boundedtiliconfiguration/reference/offset-table interpretationCR3-specific private records and deeper scene/property-graph semantics
Keep the independent tiled-image gate in release validation, 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
Minolta MRW
Contiguous big-endian MRW TTW and native PRD/WBG/RIF fields; Sony embedded little-endian MRI through buffered or positional TIFF
Unknown native segments and standalone callback discovery
Add native segments only with original evidence and explicit bounds
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
Legacy read corrections (0.8.3)¶
The shared TIFF lane accepts both Olympus
IIROand olderIIRSheaders in buffered and positional decoding. Standalone big-endian MRW discovery scans exact TTW TIFF spans inside declared metadata segments and excludes the pixel tail. Version 0.8.7 adds PRD/WBG/RIF fields and Sony embedded MRI; standalone MRW positional discovery remains separate work.Nikon D300 ShotInfo uses the same
0210prefix for two layouts: 5,291 bytes select layout A and 5,303 bytes select layout B. The choice governs native shutter count, AF adjustment, ISO code, decrypted firmware and custom settings. Unknown lengths retain opaque source data. ExifTool value conversions are not a raw-value equivalence rule.Nikon D50 encrypted records use the documented nonnumeric serial-key fallback, two-byte ShotInfo counter and ColorBalance0205 white-balance region. Sony Tag9400c ModelReleaseYear uses a single byte. These corrections retain the source payload; other raw scales and ExifTool conversions remain distinct.
Minolta MakerNote value pointers resolve against their enclosing TIFF stream, including values outside the declared MakerNote byte count. Buffered and positional reads retain enclosing range and resource limits; this does not permit references outside the TIFF metadata carrier.
Grouped comparisons keep direct MakerNotes, NikonCapture/Custom tables and Canon CIFF directories distinct. Matching names or flat IDs do not establish semantic parity; partial, ambiguous and clipped values remain unqualified.
Mixed camera corpus expansion (0.8.7)¶
The grouped reader update adds Canon CIFF CameraSettings, ShotInfo, SensorInfo, CustomFunctions, ColorBalance and sequential AFInfo fields. Known signed defaults and unsigned overrides keep their native types. ShotInfo uses the correct word index; each expanded table keeps its source identity. FocalLength and RawJpgInfo retain one structured projection rather than duplicate aliases.
Minolta MRW PRD/WBG/RIF fields and Sony little-endian embedded MRI records stop at the declared metadata boundary. Sony RAW image offsets are distinguished from valid metadata SubIFDs. TIFF Model/Make are available before private MRI expansion, including unsorted root directories. WBG channel naming and conditional RIF fields use documented make/model gates.
Nikon additions cover ColorBalanceA/B and early C, LensData 0202, the gated D4S selector field and Nikon Capture records. Capture record hashes retain all 32 bits in their namespace. Known fields are typed; unknown records and XML stay opaque. Raw crop doubles retain their encoded scale; geometry queries normalize the confirmed CropData bounds by two and reject nonfinite bounds.
Sony CameraSettings and older private CameraInfo/FocusInfo/MoreInfo records use payload length, model, byte order and bit masks. Kodak private-IFD discovery and legacy CameraInfo roots retain enclosing-TIFF offsets and prefer a complete directory at its recorded pointer over nearby recovery candidates. Unknown Sony MoreInfo records retain their bounded byte spans in a separate native table. Encoded metering metadata remains source bytes; the reader does not construct ExifTool’s TIFF representation. Tag900b uses its cipher prefix and model gates. Pentax/Samsung DNG private carriers distinguish supported TemperatureInfo models from unknown large payloads. Sigma/Hasselblad offsets, old RAF header bounds and SD9/SD10 X3F discovery are corrected without reading image payloads as metadata.
The Sony A100’s nonzero Minolta MakerNote pointer has a separate enclosing-TIFF subtree. Its CameraInfo, image-stabilization, white-balance and settings layouts use their own source formats and byte order, with an exact A100 model gate. Unrecognized Sony private carriers and non-bare Hasselblad notes retain opaque handling instead of inheriting a directory error from an unrecognized layout.
These native entries retain encoded numeric values unless an existing documented semantic representation applies. ExifTool
-nstill applies ValueConv: Canon APEX and focal units, Kodak reciprocal white balance, Nikon Capture exposure/crop scales and MRW colour temperature need explicit comparison rules. Matching names, flat ID unions or preserved raw parents alone do not establish field parity. Unknown layouts, damaged originals and pixel/compression records remain separate from the confirmed native-field scope.CR3 carrier inventory (0.6.2)¶
The bounded Canon UUID path currently recognizes these records:
Record
Current handling
Limit
CMT1,CMT2,CMT4Discover a classic TIFF stream and use the generic TIFF decoder.
The scanner requires a valid classic-TIFF header; this does not define additional Canon private-field meanings.
CMT3Decode the dedicated TIFF stream with Canon MakerNote tokens and expand known binary subtables. Fall back to generic TIFF decoding with Canon tokens when needed.
decode_makernote=falseskips this stream.CNCVWith MakerNote decoding enabled, expose bounded
CanonCR3_compressor-version text as the derived BMFF fieldcr3.compressor_version. The opaque scanner block remains available.Accept at most 256 bytes of printable ASCII with optional trailing zero padding. Other prefixes, embedded NULs, controls and non-ASCII bytes remain opaque. This does not parse version components or authorize writing codec settings.
CTBOWith MakerNote decoding enabled, expose validated absolute box offsets and sizes for XMP (ID 1), preview (ID 2), and media data (ID 3).
Derived
cr3.ctbo.xmp.offset/.size,cr3.ctbo.preview.offset/.size, andcr3.ctbo.media.offset/.sizeare source-bound, not writable metadata. Validate the complete table and known target boxes before emitting fields. Unknown IDs retain opaque treatment.CCTP,CNTH,CNOP,CNDM,CMP1Descend into plausible nested boxes; otherwise expose leaf payloads as opaque scanner MakerNote blocks.
The simple metadata reader does not interpret these opaque leaf blocks into entries.
The Canon UUID walk has separate depth, box-count and pending-range bounds. Unknown children are searched only when they begin with a plausible nested box. Other unknown payloads are skipped; general raw preservation does not imply that every private CR3 record is exposed or safely relocatable. The ordinary EXIF MakerNote tag and the separate
PRVWJPEG preview route retain their own contracts.Grouped synthetic regressions exercise all eleven listed IDs, classic-TIFF header rejection, opaque leaf boundaries, and CMT3 Canon CameraSettings expansion, disabling and truncation. They qualify these existing routes, not broader private semantics or real-file prevalence. The current original-file inventory contains 23 CR3 files, each with a 30-byte
CNCVrecord and one of five compressor-version strings. Both independent record extraction and the OpenMeta reader agree with ExifTool for all 23 values. The historical 24-file EXIF comparison does not list per-file inputs and does not establish the identity of this current cohort. Further private-field decoding needs an original witness with recorded model/version, offsets, byte order, bounds and expected values.CTBO uses a big-endian count followed by 20-byte ID/offset/size rows. The known IDs refer to complete boxes, including headers: XMP and preview require their documented UUIDs, and media requires
mdat. These fields describe the original carrier locations; they do not identify the active metadata item after an edit, decode image data, authorize relocation, or project into portable XMP. ExifTool documents this layout in its Canon reader and QuickTime writer but does not expose CTBO values while reading. CTBO comparisons therefore use independent wire extraction, separately from ExifTool’s compressor-version comparison. The reader accepts 1–64 rows with an exact payload length; 64 is an implementation bound, not a Canon format limit. Duplicate known IDs, invalid known target ranges, mismatched box headers and size-zero-to-EOF target headers remain opaque. Normal and extended-size headers are supported. Zero-size table rows emit no location fields, and unknown IDs are not followed.CR3 editing preserves every retained top-level source box at its original offset. An edit that would move one rejects before output; CTBO and track offsets are not repaired. Appending metadata and replacing EOF metadata remain supported. General CR3 scene/property rewriting remains outside this contract.
Since 0.6.2, the scanner also discovers
CMP1inside boundedCRAWsample entries instbl/stsd. This route requires version/flags zero, a normal sample-entry header, the recognized0x00010001extension at byte 86, and a complete child-box list beginning at byte 90. Unknown entry layouts are skipped. The scanner charges entries and child boxes to its existing box-count budget and keeps memory and positional-callback scanning equivalent without readingmdatpayloads.With MakerNote decoding enabled, a normal 60-byte
CMP1box with a 52-byte payload and the prefixff00003001000000exposes nonzero big-endian dimensions at payload offsets 16 and 20 ascr3.cmp1.widthandcr3.cmp1.height. Each record has its own source block and an absolutecr3.cmp1.offset, so repeated records remain distinguishable. These are derived source values, not writable metadata or portable XMP. They do not assign main/raw/preview track roles or rendered-image dimensions; sample-entry dimensions can differ. Other signatures, sizes, and the separate Canon UUIDCMP1route remain uninterpreted. Independent wire extraction and ExifTool agree on the dimensions of all 46 records in the current 23-file original cohort.Priority¶
The bounded tiled-image contract was independently qualified on 2026-09-22 with four internal fixtures covering explicit internal offsets, sequential size inference, external tile URLs, and a malformed conditional payload. The remaining BMFF work is deeper scene/property semantics and CR3 private records.
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.
Continue high-visibility native read gaps: more model-specific RAF native sections, long-tail CRW/CIFF private tables, and deeper X3F section interpretation.
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.
Add X3F image-processing section decode only when the fields can be named, typed, and safety-classified.
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:
MetadataRawDataEncodingdescribes the host or decoder view of stored raw pixels, such as uncompressed, packed, lossless-compressed, lossy-compressed, rendered, or unknown.MetadataRawDataDescriptoris the public carrier for dimensions, channel-count, bit-depth, compression code, storage encoding, optional raw plane index, and optionalrequires_compressed_raw_encoding/requires_primary_raw_planeflags when a host or decoder can provide them.MetadataRawApplicabilityStatemarks 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 = trueand providehas_plane_index/plane_indexfor 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/setthenwrite_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 underopenexr:*.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:
MetaStorealready supports duplicate keys, per-block origin, deterministic indexing, and binary-search lookups.MetaValuealready supports scalar, array, bytes, text, and rational values.Existing block model can represent per-part metadata boundaries.
Current implementation snapshot:
MetaKeyKind::ExrAttributeis available (part_index+name).decode_exr_header(...)is implemented and wired intosimple_meta_readfallback 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_typecarries EXR type code (WireFamily::Other), andwire_countcurrently stores attribute byte size.
Remaining gaps for production-level EXR workflows:
Persisting original EXR
type_namefor 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 insimple_meta_read).
Design Direction (v1)¶
Add EXR key space and provenance:
MetaKeyKind::ExrAttributewith fields:part_index,name.Reserve block
format/containercode for EXR header metadata blocks.
Add EXR wire typing:
Extend wire metadata to carry EXR type id +
type_namestring when needed.Keep unknown/custom attributes as raw bytes + declared type name.
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.
Add EXR decode entry point:
decode_exr_header(...)that fillsMetaStorefrom EXR parts/attributes.Keep image pixel I/O out of scope; metadata only.
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.
- page Metadata Translation
openmeta/metadata_translation.hprovides bounded explicit projection between metadata families. Current contracts translate edited XMP creation dates into native EXIF/IPTC date groups, exact technical XMP/TIFF properties into native EXIF fields, typed capture properties into native EXIF scalars, target-bound image geometry into native TIFF/EXIF groups, and exact descriptive, flat location, and editorial XMP properties into native IPTC-IIM datasets before writing.The APIs are experimental and versioned by
kMetadataDateTranslationContractVersion == 2andkMetadataTechnicalTranslationContractVersion == 2andkMetadataCaptureTranslationContractVersion == 1andkMetadataGeometryTranslationContractVersion == 1andkMetadataDescriptiveTranslationContractVersion == 1andkMetadataLocationTranslationContractVersion == 1andkMetadataEditorialTranslationContractVersion == 1andkMetadataIptcTranslationContractVersion == 1andkMetadataGpsTranslationContractVersion == 1andkMetadataStructuredLocationTranslationContractVersion == 1andkMetadataGpsNavigationTranslationContractVersion == 1andkMetadataDevelopmentCorrectionTranslationContractVersion == 2andkMetadataLearningOptOutInTranslationContractVersion == 2andkMetadataProfileTranslationContractVersion == 1.Development/correction and learning lifecycle (0.8.11)¶
The six existing development/correction fields A40D-A412 and LearningOptOutIn 9287 now use translation contract 2. Exact valid clean native matches gain Dirty while retaining values, wire hints/counts, origin and endian provenance. Dirty matches remain unchanged. Complete ReplaceExisting deletion retains typed native intent even when a key is absent; clean tombstones are promoted and dirty ones reused. Promotions and deletion intents consume operation limits, and new intents also consume entry limits. Conflict, source-mask and rollback rules remain.
Selected sources still require explicit host exif_version 300 or 310; translation never infers or changes ExifVersion or processing history. These APIs do not validate a complete destination EXIF profile. All seven fields use selective TIFF/BigTIFF/DNG merge and removal in both safety modes, including restored snapshots. The shared native allowlist grows from 77 to 84. Existing/template DNG version retention, source-pixel filters, ABI 4, snapshot v1 and host-owned synchronization remain unchanged.
LearningOptOutIn uses checked 16-bit word conversion from native provenance to canonical little endian and then to the target TIFF byte order. Unrelated UNDEFINED payloads remain opaque. Canonical encoding validates learning values before copying them.
For native TIFF type-129 text, a counted payload may retain one explicit wire NUL. Validation and serialization both use the logical UTF-8 byte length plus one terminator. Ordinary authored text and the reader’s normalized text omit that NUL from their payload. Embedded NULs and mismatched wire counts still fail.
Workflow¶
Translation is a separate step. Creation, editing, transfer, and writing do not invoke it implicitly:
Read, create, or edit a finalized
MetaStore.Call
translate_xmp_creation_dates(...),translate_xmp_technical_metadata(...),translate_xmp_capture_metadata(...),translate_xmp_image_geometry(...),translate_xmp_descriptive_metadata(...),translate_xmp_location_metadata(...),translate_xmp_editorial_metadata(...),translate_xmp_iptc_metadata(...),translate_xmp_gps_metadata(...),translate_xmp_structured_location_metadata(...),translate_xmp_gps_navigation_metadata(...),translate_xmp_learning_opt_out_in_metadata(...),translate_xmp_profile_metadata(...), or the required combination with explicit mapping and conflict options.Pass the returned finalized store to transfer preparation or a writer.
This separation prevents a transfer from unexpectedly replacing native camera dates merely because decoded XMP is present. The default source mode is
DirtyOnly, so only caller-modified XMP values and tombstones are eligible.Date Mappings¶
XMP source
Native destination
Precision requirements
xmp:CreateDateEXIF
DateTimeDigitized,OffsetTimeDigitized, andSubSecTimeDigitizedTime is required. Timezone and up to nine fractional digits are preserved in companion tags.
xmp:CreateDateIPTC
DigitalCreationDateandDigitalCreationTimeDate-only or whole seconds are accepted. Fractional seconds are rejected.
photoshop:DateCreatedIPTC
DateCreatedandTimeCreatedDate-only or whole seconds are accepted. Fractional seconds are rejected.
XMP
exif:DateTimeOriginalEXIF
DateTimeOriginal,OffsetTimeOriginal, andSubSecTimeOriginalTime is required. Timezone and up to nine fractional digits are preserved in companion tags.
Accepted values use a full Gregorian
YYYY-MM-DDdate, optionally followed byTandhh:mm:ss, up to nine fractional digits, andZor a+/-HH:MMtimezone. Invalid dates, malformed values, and conversions that would discard precision fail instead of being normalized or truncated. Lexical-00:00is preserved as a negative-zero offset.Each mapping can be disabled independently. For example, callers that need to retain fractional
xmp:CreateDatecan disable its IPTC projection while keeping exact EXIF projection.Technical EXIF Mappings¶
XMP source
Native EXIF destination
Requirements
xmp:ModifyDateIFD0
DateTimeplus ExifIFDOffsetTimeandSubSecTimeTime is required. Timezone and up to nine fractional digits are preserved in companion tags.
tiff:MakeIFD0
MakeNon-empty 7-bit ASCII without embedded NUL bytes.
tiff:ModelIFD0
ModelNon-empty 7-bit ASCII without embedded NUL bytes.
xmp:CreatorToolIFD0
SoftwareNon-empty 7-bit ASCII without embedded NUL bytes.
Namespaces and property paths must match exactly. These mappings are intended for edited or newly created host metadata, not for copying source-bound camera processing data. Each singleton and the complete
ModifyDatecompanion group reconcile independently, so a conflict inMakedoes not silently changeModel.Since 0.6.2,
ReplaceExistingtranslation of dirty tombstones fortiff:Make,tiff:Modelandxmp:CreatorToolcan remove their existing native IFD0 tags in TIFF/BigTIFF files. Preparation carries the explicit native removal list; source omission still preserves the destination. Version 0.7.0 adds the grouped DateTime/OffsetTime/SubSecTime deletion contract. See technical identity deletion.Grouped EXIF timestamp synchronization (0.7.0)¶
An accepted date owner controls its base timestamp, offset and subseconds. Timezone and fractional digits in the lexical XMP value are the only authority for companion presence. Missing companions produce native dirty tombstones also when absent from the source store, so destination-only stale values can be removed. A dirty owner tombstone produces all three removal intents. Omitted or ineligible owners preserve destination values. Existing group conflict policies remain. Accepted clean, exact timestamp members are marked dirty to retain merge authority and count as updates against the operation limit. Synthesized intents count against added-entry and operation limits, and repeat calls reuse them. IPTC behavior is unchanged.
TIFF preparation enables explicit ExifIFD merging for dirty timestamp members, retains both native removal lists through snapshots, and preserves unselected destination records during edits. Each translator is a separate transaction; hosts stage multiple calls before publishing the result. See the 0.7 migration guide for supported tags, unfrozen ABI-4 policy and exclusions.
Grouped capture and lens lifecycle (0.7.1)¶
In 0.7.1, capture, Flash, sensitivity and camera-text contracts became version 2. In 0.7.2, capture advances to version 3 for the bias lifecycle described below. Accepted ExposureTime, FNumber, base ISO, Flash, FocalLength and lens make/model/ serial owners carry native deletion intent even when their source native keys are missing. Accepted clean exact native values gain Dirty with a same-value update that retains their bytes and wire provenance. Omission and existing conflict policies remain. Added intents and authority updates count against entry/operation limits before publication; repeated calls reuse them.
Full sensitivity owns PhotographicSensitivity and tags
8830–8835as one validated group. Optional absent members carry deletion intent only after the complete source passes validation. Basic ISO owns only8827and preserves sensitivity companions; disable its mapping when the full group owns that source. Lens make/model/serial are independent singletons. In 0.7.1 ExposureBiasValue, LensSpecification, camera-owner/body-serial and other capture translators retained their earlier behavior; 0.7.2 extends the bias and settings owners below. Hosts stage the separate translator calls before publishing an aggregate result.TIFF preparation enables preservation of unspecified destination ExifIFD fields for these dirty native edits. In addition to timestamp tags, bounded ExifIFD removal accepts ExposureTime
829A, FNumber829D, PhotographicSensitivity8827, SensitivityType and extended sensitivity8830–8835, Flash9209, FocalLength920A, LensMakeA433, LensModelA434and LensSerialNumberA435. See migration and exclusions.APEX and capture-settings lifecycle (0.7.2)¶
APEX and capture-settings translation contracts are version 2. General capture is version 3 because its ExposureCompensation mapping shares the APEX bias owner. Each of the five APEX fields and twelve closed capture settings is an independent singleton. Accepted dirty owner deletion carries exact native Dirty+Deleted intent even when the source native key is missing. Accepted clean exact values gain Dirty without changing their scalar, rational encoding or wire provenance. Omitted or ineligible owners preserve destination values.
Existing conflict policies, exact APEX units, brightness unknown sentinel, accepted enum codes, alias and source-shape validation remain. Intent additions, clean-marker promotion and same-value authority updates consume preflight entry/operation budgets. Repeated calls reuse intent; each translator commits once or leaves the output unchanged. Hosts stage separate calls before publishing an aggregate result and disable one overlapping ExposureBias mapping when both APEX and general capture are used. No exposure or camera-state inference occurs.
TIFF/BigTIFF edits use the existing removal list and ExifIFD merge flag for the 17 additional tags:
8822,9201–9205,9207,A217,A401–A403,A406–A40AandA40C. The complete allowlist has 39 tags. Unselected native records, opaque MakerNote bytes and original offsets, standard pointers and media remain preserved. Snapshot v1, bundle/API layouts, development ABI 4, package-minor policy and unsupported-consumer rejection are unchanged.Capture EXIF Mappings¶
XMP source
Native EXIF destination
Required native type
exif:ExposureTimeExifIFD
ExposureTimeOne unsigned
RATIONAL, greater than zeroexif:FNumberExifIFD
FNumberOne unsigned
RATIONAL, greater than zeroexif:ISO,exif:ISOSpeedRatings, orexif:ISOSpeedRatings[1]ExifIFD
ISOSpeedRatingsOne
SHORTin1..65535exif:FocalLengthExifIFD
FocalLengthOne unsigned
RATIONAL, greater than zeroexif:ExposureCompensationorexif:ExposureBiasValueExifIFD
ExposureBiasValueOne signed
SRATIONALRational sources may be typed scalar XMP values or full text integers, decimals, scientific decimals, and
numerator/denominatorvalues. Focal length also accepts the OpenMeta portablemmsuffix. Conversion uses integer arithmetic and reduces the exact source value before checking the 32-bit EXIF numerator and denominator limits. It never uses a floating-point approximation. For example,2.8becomes14/5and8e-3becomes1/125.This exactness is intentionally strict. A bounded repeating decimal such as
0.333333333333333does not fit nativeSRATIONALexactly and returnsValueOutOfRange; provide1/3or a typed signed rational when exact thirds are required. ISO rejects multi-value arrays, decimals, zero, and values above65535instead of selecting, truncating, or changing the native TIFF type.Portable and standard aliases target the same native singleton. If more than one eligible alias is present, the source is ambiguous and translation fails rather than selecting one.
The 0.5.4 capture synchronization milestone inventories all ten capture APIs, their 46 distinct native targets, shared-target composition and the portable round-trip fixes in 0.5.5. Primary ExifIFD FNumber, FocalLength and DigitalZoomRatio now emit exact numerator/denominator values. FocalLength is in millimeters; the portable value no longer has the display suffix
mm. Invalid scalar types/counts and values leave valid existing XMP available. Previously rounded packets must be regenerated from native EXIF to recover original precision. Reader and host display mappings remain unchanged.Capture settings writeback¶
translate_xmp_capture_settings_metadata(...)and PythonDocument.translate_capture_settings_metadata(...)add twelve independent SHORT singleton mappings withMetadataCaptureSettingsTranslationOptions, contract version 2. Exact unindexed paths usehttp://ns.adobe.com/exif/1.0/.XMP path
ExifIFD tag
Accepted codes
Flag
ExposureProgram
0x8822
0..8
exposure_program_to_exif
MeteringMode
0x9207
0..6, 255
metering_mode_to_exif
SensingMethod
0xA217
1..5, 7, 8
sensing_method_to_exif
CustomRendered
0xA401
0..1
custom_rendered_to_exif
ExposureMode
0xA402
0..2
exposure_mode_to_exif
WhiteBalance
0xA403
0..1
white_balance_to_exif
SceneCaptureType
0xA406
0..3
scene_capture_type_to_exif
GainControl
0xA407
0..4
gain_control_to_exif
Contrast
0xA408
0..2
contrast_to_exif
Saturation
0xA409
0..2
saturation_to_exif
Sharpness
0xA40A
0..2
sharpness_to_exif
SubjectDistanceRange
0xA40C
0..3
subject_distance_range_to_exif
Sources accept signed or unsigned scalar integers in the listed sets, unsigned decimal integer text, or exact existing OpenMeta enum labels. SceneCaptureType also accepts the portable label
Night scenefor code 3. Text must use Ascii, Utf8, or Unknown encoding. Case changes, whitespace, signs in text, decimals, fractions, floats, arrays, and unknown codes fail. ExposureProgram code 9/Bulb remains a read-only extension. No camera state or rendering behavior is inferred.Defaults are DirtyOnly/FailOnConflict with every field enabled. Eligible duplicate sources fail; clean sources are ignored in DirtyOnly, following the existing numeric capture contract. Native values must be one SHORT and equal to the selected code. PreserveExisting keeps existing fields, FailOnConflict protects non-equivalent values, and ReplaceExisting repairs types/duplicates. Dirty source tombstones remove the corresponding field under ReplaceExisting. All selected fields share one atomic transaction, including source/output aliasing and owned provenance. Existing numeric capture options remain unchanged.
Limits are 12 added entries, 1024 operations, 128 source text bytes per selected active property, and 1536 total source text bytes. Limits may be lowered and never cause truncation. Preparation may allocate. EXIF versions are retained; the API does not create or upgrade version metadata.
Capture coverage has no fixed all-tags denominator. Camera/lens/spectral text and direct APEX values have separate contracts below, as do focal-plane/subject arrays. These twelve settings do not close arbitrary EXIF writeback.
Exact capture rational writeback¶
translate_xmp_capture_rational_metadata(...)and PythonDocument.translate_capture_rational_metadata(...)useMetadataCaptureRationalTranslationOptions, contract version 2, for four independent unsigned RATIONAL singletons. Exact unindexed source paths usehttp://ns.adobe.com/exif/1.0/.XMP path
ExifIFD tag
Value contract
Flag
SubjectDistance
0x9206
Meters; zero unknown; wire numerator UINT32_MAX infinity
subject_distance_to_exif
DigitalZoomRatio
0xA404
Nonnegative ratio; zero means digital zoom unused
digital_zoom_ratio_to_exif
ExposureIndex
0xA215
Positive exposure index
exposure_index_to_exif
FlashEnergy
0xA20B
Nonnegative BCPS energy; no Flash-state inference
flash_energy_to_exif
Sources accept scalar nonnegative integers, unsigned rationals, and the existing exact integer/decimal/scientific/fraction text grammar, including a leading plus. Signed rational and floating-point values, arrays, whitespace, unit suffixes, zero denominators, malformed numbers, and unsupported precision fail. Text must use Ascii, Utf8, or Unknown encoding. Checked uint64 parsing precedes reduction; the reduced numerator and denominator must fit uint32. No rounding occurs.
SubjectDistance adds exact
UnknownandInfinitylabels. Integer/fraction text and typed integer/unsigned-rational inputs with numerator UINT32_MAX select infinity before reduction; their denominator must be positive and fit uint32. New unknown/infinity values use 0/1 and UINT32_MAX/1. Equivalent existing sentinel encodings retain their denominator. Decimal/scientific text denotes a finite number; if its reduced numerator would equal UINT32_MAX, translation fails to avoid encoding a finite distance as infinity. Other finite inputs that only reduce to that reserved numerator also fail. Native sentinel equivalence is checked before ordinary rational cross-multiplication.Defaults are DirtyOnly/FailOnConflict with all fields enabled. Missing sources retain native fields; eligible duplicates fail. PreserveExisting retains native values, FailOnConflict requires typed equivalence, and ReplaceExisting repairs values/types/duplicates or removes a dirty source tombstone’s native field. All selected fields commit atomically, including source/output aliasing and owned provenance. Limits are four additions, 1024 operations, 128 source text bytes per property, and 512 total text bytes. Preparation may allocate.
Accepted exact clean native values gain Dirty while retaining native components and wire provenance. Complete eligible deletion creates or reuses Dirty|Deleted native intent even when the native key was absent. PreserveExisting keeps an active owner without promotion; omitted or ineligible sources preserve the destination. Intent, promotions and duplicate removals consume the existing preflight budgets. Repeated calls reuse intent; failure preserves source and output. The host synchronizes shared objects.
The canonical EXIF tags 0xA215 and 0xA20B are the only ExposureIndex/FlashEnergy targets; older TIFF/EP aliases remain untouched. No APEX conversion, unit conversion, version creation/upgrade, or geographic/flash-state inference occurs. Existing numeric and settings option layouts remain unchanged. In 0.5.5, primary native DigitalZoomRatio output retains exact fractions, including zero. Source spelling can still differ from generated equivalent numeric values. Use
xmp_include_existing=TrueandXmpConflictPolicy.ExistingWinsto retain authoritative source spelling; chooseCanonicalizeManagedwhen generated values must replace managed source aliases. These are explicit authority choices.Complete Flash writeback¶
translate_xmp_flash_metadata(...)and PythonDocument.translate_flash_metadata(...)useMetadataFlashTranslationOptions, contract version 1, to write one ExifIFD Flash (0x9209) SHORT. Select either an exact scalarexif:Flashor all five children in the EXIF namespace:Flash/Fired: bit 0, Boolean.Flash/Return: bits 1..2, codes 0, 2, or 3; code 1 is reserved.Flash/Mode: bits 3..4, codes 0..3.Flash/Function: bit 5, Boolean; True means no flash function.Flash/RedEyeMode: bit 6, Boolean.
Children also accept the
Flash/exif:Namespelling. Boolean values accept integer 0/1 or exact textTrue,False,0,1. Mode and Return accept nonnegative scalar integers or unsigned decimal integer text. Scalar Flash accepts those integer forms or exact OpenMeta Flash labels. Bits 7 and above, reserved Return code 1, floats, rationals, arrays, whitespace, signs in text, case changes, and unknown labels fail. Text encodings are Ascii, Utf8, or Unknown. All 96 combinations of defined bits are accepted; physical consistency is not inferred from other capture fields.Defaults are DirtyOnly/FailOnConflict. One dirty child selects the complete structure, including its clean companions. A partial structure fails without borrowing missing bits from native EXIF. Duplicate child aliases, scalar plus structured sources, qualifiers, nested children, and indexed forms fail. Clean unselected sources are retained. A dirty scalar tombstone or all five dirty child tombstones removes native Flash under ReplaceExisting; partial child removal fails. Missing sources retain native Flash. FlashEnergy is independent.
Native equivalence requires one SHORT with the same bits. PreserveExisting keeps native fields, FailOnConflict protects non-equivalent values, and ReplaceExisting repairs types/duplicates. All operations commit atomically, including aliased source/output and owned provenance. Limits are one added entry, 1024 operations, 16 inspected Flash source properties, 128 text bytes per active property, and 640 total text bytes. Limits may be lowered; preparation may allocate. Existing capture option layouts remain unchanged. EXIF version fields are retained.
For portable XMP readback, use
include_existing_xmp=Trueandconflict_policy=XmpConflictPolicy.ExistingWinsto retain a complete source structure or scalar spelling. Snapshot transfer usesxmp_include_existingandxmp_conflict_policyfor the same choices. Native-only portable output continues to use the existing Flash projection.LightSource writeback¶
translate_xmp_light_source_metadata(...)and PythonDocument.translate_light_source_metadata(...)useMetadataLightSourceTranslationOptions, contract version 1, to write one ExifIFD LightSource (0x9208) SHORT from exactexif:LightSource.Accepted codes are
0..4,9..34, and255: 32 values from the existing OpenMeta name table. This includes unknown (0), other (255), warm white fluorescent (16), and the newer light-source/LED codes 25..34. Undefined codes fail. No source means no change; the API does not create a default Unknown.Sources accept nonnegative signed or unsigned scalar integers, unsigned decimal integer text, and exact unique OpenMeta labels. Explicit aliases
TungstenandCloudy weathermap to 3 and 10. Numeric1and25remain distinct, while textDaylightreturnsAmbiguousSourcebecause both codes use that display label. Native values, conflict policies, EXIF versions, white balance, Flash, DNG calibration illuminants and color temperature never resolve this ambiguity. Callers must supply an explicit numeric code when the source label is ambiguous.Text must use Ascii, Utf8, or Unknown encoding. Signs in text, whitespace, case changes, floating-point/scientific notation, fractions, arrays, unsupported encodings and unknown labels fail. Eligible indexed, qualified or nested LightSource paths return
UnsupportedSourceShape. Foreign namespaces and other property names are ignored. Clean sources are ignored in default DirtyOnly mode; All selects active sources. Duplicate eligible sources fail.Native equivalence requires one SHORT with the selected code. Default FailOnConflict protects different values and wrong types. PreserveExisting retains native data; ReplaceExisting repairs types and duplicates. A dirty source tombstone removes native LightSource under ReplaceExisting. Tombstone contents are not parsed, so an ambiguous old label can still be explicitly removed. Clean tombstones are ignored. Source omission retains native metadata.
Limits are one addition, 1024 operations, 128 text bytes per active property, and 128 total text bytes. Limits may be lowered; invalid settings fail. All changes share the existing atomic capture transaction, including aliased source/output and owned provenance. Preparation may allocate. Existing capture option layouts and EXIF version metadata are retained. This field operation does not claim full EXIF-version conformance or infer other capture metadata.
Portable native-to-XMP output now emits numeric
1and25for these two LightSource values, preserving their distinction. Other defined values retain the existing unique labels. Every defined native code survives portable dump, XMP decode and this reverse API. Existing XMP retained with ExistingWins keeps its original spelling, including ambiguousDaylight; previously lost numeric identity cannot be recovered from that text alone. Human-readable native names and DNG calibration-illuminant display names remain unchanged.Target-Bound Image Geometry¶
translate_xmp_image_geometry(...)projects edited XMP image geometry only when it agrees with a host-suppliedTransferTargetImageSpec:XMP source
Native EXIF destination
Required target fact
tiff:OrientationIFD0
Orientationas oneSHORThas_orientationand the same EXIF index in1..8tiff:ImageWidth,exif:ExifImageWidth, orexif:PixelXDimensionplus a matching height aliasIFD0
ImageWidth/ImageLengthand ExifIFDPixelXDimension/PixelYDimension, each as oneLONGhas_dimensionsand the same nonzero stored width/heightHeight aliases are
tiff:ImageLength, portabletiff:ImageHeight,exif:ExifImageHeight, andexif:PixelYDimension. Standard and portable aliases may coexist when all values agree. Duplicate exact properties or contradictory aliases fail instead of selecting one.Width and height always describe the stored target raster. They are not post-orientation display dimensions and are never swapped for orientation indices
5..8. For example, a stored640x480raster with orientation6must use target width640, target height480, and orientation6; a host that physically rotates the pixels must instead provide the new stored dimensions and the orientation that applies to those output pixels.An active source without the corresponding target fact returns
TargetImageSpecRequired. A source value that disagrees with the target, or a dirty deletion while the target still declares that fact, returnsTargetImageSpecMismatch. Width and height are one complete group: mixed active/deleted state or only one axis returnsIncompleteSourceGroup.Descriptive Mappings¶
XMP source
Native IPTC-IIM destination
Maximum encoded bytes
dc:title[@xml:lang=x-default]ObjectName(2:5)64
dc:description[@xml:lang=x-default]Caption-Abstract(2:120)2000
dc:creator[n]repeated
By-line(2:80)32 per value
dc:subject[n]repeated
Keywords(2:25)64 per value
dc:rights[@xml:lang=x-default]CopyrightNotice(2:116)128
photoshop:CreditCredit(2:110)32
photoshop:SourceSource(2:115)32
The default-language and indexed paths must match exactly. Creator and keyword items retain numeric XMP index order. Duplicate singleton properties or duplicate active indexes are ambiguous and fail rather than selecting a value. IPTC-IIM limits are byte limits; text is never truncated.
Non-ASCII values remain UTF-8. Translation emits IPTC
CodedCharacterSet(1:90) withESC % Gwhen the marker is absent and every existing active IPTC value is ASCII or will be replaced by the same transaction. An incompatible charset marker or unrelated legacy high-bit data returnsNativeEncodingConflictwithout modifying the output.Location Mappings¶
translate_xmp_location_metadata(...)acceptsMetadataLocationTranslationOptionsand returnsMetadataDescriptiveTranslationResult. It uses the descriptive source modes, conflict policies, statuses, and mapping diagnostics. The existing descriptive API still selects only its original seven mappings.Exact XMP source
Native IPTC-IIM destination
Maximum encoded bytes
photoshop:CityCity(2:90)32
Iptc4xmpCore:LocationSub-location(2:92)32
photoshop:StateProvince-State(2:95)32
photoshop:CountryCountry-PrimaryLocationName(2:101)64
Iptc4xmpCore:CountryCodeCountry-PrimaryLocationCode(2:100)3
These are the flat legacy location mappings in the IPTC Photo Metadata Standard. Each mapping is an independent singleton. Namespace URIs and property paths must match exactly; duplicate active sources are rejected even when equal. Empty values, invalid UTF-8/XML text, embedded NULs, and excess bytes fail without changing the output. Removal uses a dirty tombstone.
Country codes require exactly two or three uppercase ASCII letters and are preserved byte for byte. Code membership, conversion between two and three letters, and agreement with the country name belong to the caller. Structured
LocationCreated/LocationShownproperties, indexed or qualified forms, and GPS are not aliases and are not selected by this API. The operation does not infer whether a flat location describes the camera or the depicted subject.UTF-8 charset promotion follows the descriptive policy above, including rejection of incompatible markers and unrelated legacy high-bit IPTC values. Limits are 1024 matched source properties, 4096 operations, 8 MiB of inspected text/charset-safety bytes, and six added entries (five datasets plus one charset marker). Options can lower these limits. New entries copy source provenance; updates preserve the existing native entry’s provenance. Translation is a preparation operation that may allocate; it is not an allocation-free replay API.
Structured Location Reconciliation¶
translate_xmp_structured_location_metadata(...)acceptsMetadataStructuredLocationTranslationOptionsand returns the sharedMetadataDescriptiveTranslationResult. Contract version 1 selects one structured location and reconciles its five supported text fields into both flat legacy XMP and native IPTC-IIM. Existing flat-location and combined IPTC APIs keep their original mapping sets.The root namespace must be
http://iptc.org/std/Iptc4xmpExt/2008-02-29/.location_kinddefaults toMetadataStructuredLocationKind::Shown;Createdrequires an explicit choice. Shown and Created never fall back to each other. These properties distinguish the depicted place from the place where the camera was. Choosing Created authorizes copying that camera-location description into the legacy fields whose historical semantics are ambiguous. See the IPTC Photo Metadata specification.Structured child
Flat XMP destination
Native IPTC
Maximum UTF-8 bytes
Cityphotoshop:City2:90
32
SublocationIptc4xmpCore:Location2:92
32
ProvinceStatephotoshop:State2:95
32
CountryNamephotoshop:Country2:101
64
CountryCodeIptc4xmpCore:CountryCode2:100
3
Paths are
LocationShown[n]/City,LocationCreated[n]/City, and the equivalent paths for the other four children. The existing scalarLocationCreated/Cityresource form is accepted as record index 1. Mixed scalar and indexed Created forms fail. Indexes must be positive decimal uint32 values without leading zeros.location_index == 0selects the sole represented record when present; an absent root kind is a no-op, and multiple records fail with AmbiguousLocation. A positive option selects that exact index and fails with LocationNotFound if absent. It never selects the first record implicitly or merges records. Any represented child, including an unsupported child, counts for record selection. Selection precedes DirtyOnly filtering.XML decoding uses one-based RDF order; authored stores can have sparse indexes. Canonical unqualified child names and
Iptc4xmpExt:-qualified equivalents are accepted. Duplicate field sources are ambiguous, including equal values, qualified/unqualified aliases, or mixed active and dirty-deleted entries. Other namespaces, nested Address children, language/index qualifiers, location names and IDs, WorldRegion, and structured GPS fields are retained without projection. Nonstandard scalar LocationShown and malformed indexed paths fail with UnsupportedSourceShape. The API operates on decoded paths and does not infer a missing RDF container type.Defaults are DirtyOnly and FailOnConflict. Only the selected structured leaf flags trigger a field in DirtyOnly mode; dirty flat/native destinations do not. All selects clean active leaves too. Each flat XMP/native IPTC pair is one conflict group:
PreserveExisting retains both destinations if either already exists.
FailOnConflict requires each existing destination to match and fills a missing counterpart. Mismatches and duplicate destinations fail atomically.
ReplaceExisting updates both destinations and removes duplicate entries. A dirty structured leaf tombstone removes both corresponding destinations.
Missing structured fields preserve existing destination fields. Clean tombstones and whole-structure/array tombstones do not request field deletion. This is a field patch operation; it does not establish geographic consistency between supplied fields and retained fields. Text must be nonempty valid UTF-8/XML text. Byte limits never truncate. Country codes require two or three uppercase ASCII letters; registry membership and name/code agreement remain caller responsibilities.
Limits are 1024 inspected structured properties across the chosen root kind, 4096 destination operations, 8 MiB of source text and charset-safety inspection, and 11 added entries: five flat XMP properties, five IPTC datasets, and a possible UTF-8 marker. Existing destination entries also count against the operation inspection limit. Each limit can be lowered. The shared IPTC charset policy rejects unsafe promotion of retained legacy high-bit values. Result entry counters include both destination families; group counters count five fields.
NativeConflictcovers either destination family.The source stays immutable. Failure leaves the output unchanged; output/source aliasing is supported. New entries own copied source provenance, while updates retain existing destination provenance. Preparation may allocate.
translated = document.translate_structured_location_metadata( location_kind=openmeta.MetadataStructuredLocationKind.Shown, location_index=2, source_mode=openmeta.MetadataDescriptiveTranslationSourceMode.All, conflict_policy=openmeta.MetadataDescriptiveTranslationConflictPolicy.ReplaceExisting, )
The returned document is detached. Persist both XMP and IPTC from its snapshot to keep both destinations synchronized. For Python
transfer_snapshot_file, setxmp_include_existing=True: that transfer API defaults to projecting native metadata only. This option retains the reconciled flat XMP and structured records. GPS translation is a separate explicit contract; structured location coordinates are not aliases for primary EXIF GPS.Structured location construction¶
translate_xmp_location_to_structured_metadata(...)and PythonDocument.translate_location_to_structured_metadata(...)copy the five flat legacy XMP location fields into one selected IPTC Extension record.MetadataLocationCreationTranslationOptionshas contract version 1.Exact flat source
Selected structured child
photoshop:City
City
Iptc4xmpCore:Location
Sublocation
photoshop:State
ProvinceState
photoshop:Country
CountryName
Iptc4xmpCore:CountryCode
CountryCode
The caller must choose both
location_kind(Shown or Created) and a positivelocation_index. C++ defaults to Unspecified/zero and rejects those values; Python requires both arguments. Created permits index one only. Shown permits an existing record or append at the next index. Existing indexes must be dense from one, with a maximum of 1024. Sparse indexes, mixed scalar/indexed Created records, opaque root/record placeholders, and competing nested or language-qualified shapes for a selected field fail. Other namespaces and nested Address fields are not aliases. No Created/Shown selection or geographic information is inferred.New records use indexed
LocationShown[n]orLocationCreated[1]paths with IPTC Extension children. Existing scalar Created records retain their resource shape. Portable XMP emits indexed locations as RDF Bags. The decoder omits redundant child prefixes within the same namespace; record order and field values are preserved. RDF indexes identify current order, not stable record IDs.City, sublocation, and state use the existing 32-byte flat-location limit; country uses 64 bytes. CountryCode requires two or three uppercase ASCII letters, without checking country membership. Other fields require nonempty valid UTF-8 text, with Ascii/Utf8/Unknown source encoding. Existing flat location text validation applies. There is no normalization or truncation.
Defaults are DirtyOnly/FailOnConflict with five enabled flags. Missing source fields retain destinations. Duplicate selected sources fail. Each destination leaf is a conflict group; PreserveExisting keeps it, FailOnConflict requires equivalence, and ReplaceExisting replaces it and removes duplicate aliases. A dirty flat-field tombstone removes that selected structured leaf. Unrelated fields and records remain untouched. Removal of an entire non-last record fails to prevent renumbering another record during serialization. Removing the last record is allowed. All selected changes commit atomically, including aliased source/output calls. Preparation may allocate.
Limits are five additions, 1024 operations, 1024 total inspected destination properties plus selected source candidates, and the existing descriptive total text budget. Native IPTC fields and charset markers are not modified or used as implicit sources. Native-only callers must explicitly prepare flat XMP first. To persist the constructed XMP, transfer requires
xmp_include_existing=Trueandxmp_conflict_policy=openmeta.XmpConflictPolicy.ExistingWins.Python example:
created = document.translate_location_to_structured_metadata( openmeta.MetadataStructuredLocationKind.Shown, 1, source_mode=openmeta.MetadataDescriptiveTranslationSourceMode.All, )
Editorial Mappings¶
translate_xmp_editorial_metadata(...)acceptsMetadataEditorialTranslationOptionsand returnsMetadataDescriptiveTranslationResult. Each mapping has an independent flag;DirtyOnlyandFailOnConflictare the defaults. Descriptive and location calls retain their existing mapping sets.Exact XMP source
Native IPTC-IIM destination
Maximum encoded bytes
photoshop:HeadlineHeadline(2:105)256
photoshop:InstructionsSpecialInstructions(2:40)256
photoshop:TransmissionReferenceOriginalTransmissionReference(2:103)32
The mappings and limits follow the IPTC Photo Metadata Standard 2025.1. Sources must be exact singleton properties in the Photoshop namespace
http://ns.adobe.com/photoshop/1.0/. Title, description, rights usage terms, and other job identifiers are not aliases. Empty text, invalid UTF-8/XML, embedded NULs, duplicate active singletons, and excess encoded bytes fail transactionally. Values are never truncated. Dirty tombstones request removal underReplaceExisting.The shared IPTC transaction enforces charset safety, preserves unrelated native data, copies source provenance for new entries, and retains native provenance for updates. Limits are 1024 matched source properties, four added entries (three datasets plus one UTF-8 charset marker), 4096 operations, and 8 MiB of inspected text/charset-safety bytes. Options may lower these limits; disabling every mapping is invalid. This preparation operation may allocate.
Python exposes the same operation as
Document.translate_editorial_metadata, withheadline_to_iptc,instructions_to_iptc, andtransmission_reference_to_iptcflags. It returns a detached document and raisesValueErrorwith mapping diagnostics on failure. For clean metadata read from a file, explicitly selectMetadataDescriptiveTranslationSourceMode.All.Combined IPTC Writeback¶
translate_xmp_iptc_metadata(...)acceptsMetadataIptcTranslationOptionsand returnsMetadataDescriptiveTranslationResult. It selects the seven descriptive, five location, and three editorial groups above, plus the five workflow mappings below. All 20 text/priority groups share one transaction, including charset promotion and resource accounting. The existing subgroup APIs retain their original options and mappings. Date/time fields remain intranslate_xmp_creation_dates(...); composing the two calls does not make them one transaction.Exact Photoshop XMP source
Native IPTC-IIM destination
Contract
AuthorsPositionBy-lineTitle(2:85)Singleton text, at most 32 UTF-8 bytes
CaptionWriterWriter-Editor(2:122)Singleton text, at most 32 UTF-8 bytes
CategoryCategory(2:15)One to three ASCII letters, case preserved
SupplementalCategories[n]Repeated
SupplementalCategories(2:20)Text, at most 32 UTF-8 bytes per value
UrgencyUrgency(2:10)One text digit from
1to8, or a signed/unsigned integer scalar in that rangeThese contracts use the Adobe Photoshop XMP namespace, IPTC IIM 4.2, and IPTC Photo Metadata 2025.1. Category, Supplemental Categories, and Urgency are legacy IIM fields. This API supports their explicit writeback; it does not convert them to modern taxonomy. Category does not consult a provider registry. The caller must supply a creator and associate AuthorsPosition with the first creator. Translation neither infers that association nor creates a missing creator.
Supplemental Categories use exact indexed paths with positive numeric indexes. Gaps are accepted. Values are written in index order, and equal values at different indexes remain separate datasets. Duplicate active indexes fail. New repeated native entries receive placement ranks that preserve that order; source block and wire provenance remain owned by the output. Updates retain the existing native ranks. An unindexed scalar or empty Bag is not a removal request; remove the indexed entries with dirty tombstones. Urgency emits an ASCII digit, never a binary integer. Values
0and9, floats, rationals, arrays, and alternative textual spellings such as05,+5, or5.0are rejected. IPTC-to-portable-XMP projection now also carries native Urgency.All mappings default to enabled, with DirtyOnly/FailOnConflict policies. Each has an independent boolean flag. Disabling every mapping is invalid. Limits across the whole call are 1024 matched source properties, 1025 added entries (up to 1024 values plus one charset marker), 4096 operations, and 8 MiB of inspected text/charset-safety bytes. Callers may lower these limits.
A failure in any selected group leaves the source and output unchanged. This also permits a non-ASCII replacement when another selected group removes the legacy IPTC bytes that would otherwise block UTF-8 promotion. Preparation may allocate; it is not an allocation-free replay operation.
Python exposes
Document.translate_iptc_metadata(...)with the same flags, policies, limits, detached output, and ValueError diagnostics. For example:translated = document.translate_iptc_metadata( source_mode=openmeta.MetadataDescriptiveTranslationSourceMode.All, conflict_policy=openmeta.MetadataDescriptiveTranslationConflictPolicy.ReplaceExisting, category_to_iptc=False, urgency_to_iptc=False, )
The combined API and existing date API cover the 24 active IPTC destination assignments in ExifTool’s
xmp2iptc.argsinventory checked on 2026-09-09. This is a field inventory, not semantic or behavioral parity: the two commented taxonomy mappings, Photoshop IPTCDigest, arbitrary IPTC datasets, and ExifTool’s conversion/overwrite conventions are excluded.GPS destination lifecycle (0.8.0)¶
All five GPS translators use contract version 2. Accepted dirty deletion owns all native group members even when absent from the source store; accepted exact clean members gain Dirty authority without changing their actual native encoding. Omission preserves the destination. Intent additions and authority updates count against the existing preflight limits, and repeated calls reuse history.
Prepared TIFF/BigTIFF merges preserve unselected destination GPS fields. Version cleanup depends on the final destination directory: unrelated values retain it. Active source/destination version conflicts fail before output instead of upgrading or reinterpreting altitude. Hosts stage the five separate transactions. See the 0.8 migration guide for bundle changes and rebuild rules.
Primary GPS Writeback¶
translate_xmp_gps_metadata(...)acceptsMetadataGpsTranslationOptionsand returnsMetadataGpsTranslationResult. Contract version 1 covers three primary EXIF GPS groups, each with an independent flag. It does not select structured IPTC locations, destination coordinates, GPS time, navigation data, or nonstandard standalone XMP latitude/longitude reference properties.Exact
http://ns.adobe.com/exif/1.0/XMP sourceNative
gpsifdfieldsFlag
GPSLatitudeLatitudeRef (1), Latitude (2)
latitude_to_exifGPSLongitudeLongitudeRef (3), Longitude (4)
longitude_to_exifGPSAltitudeandGPSAltitudeRefAltitudeRef (5), Altitude (6)
altitude_to_exifCoordinates accept unsigned integer degrees followed by decimal minutes, or integer minutes and decimal seconds:
35,48.125Nor139,34,55.25W. Separators are commas; the final character must be uppercase N/S for latitude or E/W for longitude. Signs, whitespace, decimal degrees, exponent notation, and rational components are rejected. Latitude is bounded by 90 degrees and longitude by 180; minutes and seconds must be less than 60. At the maximum degree, all remaining components must be zero. Hemisphere is preserved at zero.The parser uses integer arithmetic and emits normalized integer degrees, integer minutes, and reduced rational seconds as RATIONAL[3], with an ASCII reference. Fractions must fit exact unsigned 32-bit numerator/denominator components; unsupported precision fails without rounding. Trailing decimal zeros do not consume precision. Parsing uses checked 64-bit intermediates; overflow also returns UnsupportedPrecision, even if further algebraic reduction could fit the native fields. Native equivalence compares typed components as rational numbers; it does not rearrange a different native DMS tuple into an equivalent whole angle. Use ReplaceExisting to canonicalize such tuples.
Altitude uses a nonnegative unsigned rational, nonnegative integer scalar, or exact unsigned text (
123.45,2469/20, or0). Floats, signed text, exponent notation, units, arrays, and zero denominators are rejected. A separateGPSAltitudeRefis mandatory. This contract uses the legacy Adobe XMP sea-level convention: text0/1, or an integer scalar 0/1. It does not infer a missing reference from the sign or from existing native metadata.GPSVersionID is structural companion metadata. A missing version becomes BYTE[4]
2.3.0.0when a selected active result needs it. An existing version must be one well-formed BYTE[4] entry; malformed or duplicate active versions fail. Existing version bytes are retained. Altitude supports2.0.0.0through2.4.0.0: legacy versions use native sea-level references 0/1; version 2.4 uses 2/3 for the same meaning. Unknown versions fail altitude translation. No geoid, ellipsoid, horizontal datum, or unit conversion is performed, and native GPSVersionID is not upgraded. The XMP GPSVersionID property is not copied or used to infer an altitude convention. Callers with modern ellipsoidal-height XMP must not pass it under this legacy sea-level contract.Coordinate syntax and legacy XMP altitude semantics follow the Adobe EXIF namespace and CIPA’s EXIF/XMP mapping. The version-2.4 native reference distinction follows EXIF 3.0 section 4.6.7.1.6.
Defaults are DirtyOnly and FailOnConflict. One dirty altitude member selects both active XMP members, including a clean companion. Missing, duplicate, or mixed active/deleted altitude members fail. A complete dirty altitude tombstone pair removes both native fields under ReplaceExisting; one coordinate tombstone removes its native value/reference pair. PreserveExisting preserves the existing native group as a unit when either field exists, even when the group is partial. FailOnConflict rejects mismatched or partial existing groups. ReplaceExisting updates fields and removes duplicates. If deletion removes the last GPS value, its version tag is also removed; unrelated GPS fields keep the version.
The whole call is atomic. It leaves source and output unchanged on failure and copies provenance into output-owned storage. Calls may allocate during preparation. Limits are seven added entries including GPSVersionID, 1024 native operations, 128 text bytes per selected active source, and 512 total text bytes. Coordinates and altitude can be disabled independently; disabling every group is invalid. Existing translation APIs and their default mapping sets are unchanged.
Python exposes the same C++ policy and diagnostics:
translated = document.translate_gps_metadata( source_mode=openmeta.MetadataGpsTranslationSourceMode.All, conflict_policy=openmeta.MetadataGpsTranslationConflictPolicy.ReplaceExisting, )
Pass the detached result to transfer preparation to persist it. Portable XMP now writes all four GPSVersionID components. Its existing coordinate/altitude formatters can round native rational values; this reverse API cannot recover precision already lost before the XMP source was created. This contract covers primary position writeback, not all GPS metadata or complete ExifTool parity.
GPS Time And Navigation Writeback¶
translate_xmp_gps_navigation_metadata(...)uses independentMetadataGpsNavigationTranslationOptionsand the shared GPS result, source mode, conflict policy, and diagnostic enums. Contract version 1 adds four atomic groups. The existing primary GPS API retains its options and mapping set.Exact EXIF XMP source
Native
gpsifdfieldsFlag
GPSTimeStampTimeStamp (7) and DateStamp (29)
timestamp_to_exifGPSSpeedRefandGPSSpeedSpeedRef (12) and Speed (13)
speed_to_exifGPSTrackRefandGPSTrackTrackRef (14) and Track (15)
track_to_exifGPSImgDirectionRefandGPSImgDirectionImgDirectionRef (16) and ImgDirection (17)
image_direction_to_exifSources must use the exact
http://ns.adobe.com/exif/1.0/namespace and unindexed, unqualified paths. XMP combines the native GPS date and time into one GPSTimeStamp property. Split GPSDateStamp/time, GPSDateTime aliases, capture-date fallback, receiver status/quality, destination GPS, and structured IPTC locations are outside this contract. Field identities and unit/reference codes follow the Adobe EXIF namespace and CIPA EXIF/XMP mapping.GPSTimeStamp requires text
YYYY-MM-DDTHH:MM:SS[.fraction]Zor the same complete date/time followed by+HH:MMor-HH:MM. The timezone is mandatory. Numeric offsets through 23:59 normalize to UTC, including day/month/year rollover; both zero-offset signs mean UTC. Years must remain 0001 through 9999 after normalization. Gregorian calendar rules apply. Hours are 00-23, minutes 00-59, and seconds are less than 60. Leap seconds, partial dates/times, lowercase separators, whitespace, and inferred timezones are rejected.Output contains an ASCII
YYYY:MM:DDdate and an unsigned RATIONAL[3] time: integer UTC hours, integer UTC minutes, and reduced exact rational seconds. Fractions never round. Reduced numerator and denominator must each fit uint32; checked uint64 parser intermediates can also reject unsupported precision. Trailing decimal zeros do not consume precision. A supported fractional input can still fail when its whole-second numerator cannot fit uint32 after reduction.Speed and angles accept nonnegative integer scalars, unsigned rational scalars, or exact unsigned integer/decimal/fraction text, matching primary GPS altitude syntax. Floats, signed text, exponents, units inside numeric values, arrays, and zero denominators are rejected. Speed has no additional bound beyond the native rational capacity. Track and image direction are bounded by 359.99 inclusive, without rounding or modulo reduction.
Reference properties are text. Speed accepts
K,M, orN, plus the exact existing OpenMeta portable aliaseskm/h,mph, andknots. Track and image direction acceptTorM, plusTrue NorthandMagnetic North. Output uses the compact ASCII letter code. Case, spelling, and whitespace are exact; no localized names or other synonyms are accepted. Units and north references are preserved without conversion or inference from native metadata.All flags default to enabled, with DirtyOnly/FailOnConflict. A dirty reference or numeric member selects its complete active XMP pair, including a clean companion. Missing, duplicate, or mixed active/deleted members fail. A dirty timestamp tombstone removes both date and time; removing a navigation pair requires both members to be dirty tombstones. Clean tombstones are ignored. Missing groups preserve native fields.
Each native pair uses the primary GPS conflict rules: PreserveExisting keeps the whole group if either member exists; FailOnConflict requires a complete matching pair; ReplaceExisting repairs partial pairs and removes duplicates. Native rational equivalence is exact by component. Native text may include its one trailing wire NUL. Existing equivalent values retain their encoding and provenance. All selected groups share one atomic transaction.
An active timestamp requires native GPSVersionID 2.2.0.0 through 2.4.0.0 under this versioned contract. Older and unknown versions fail without an upgrade. Speed/track/direction retain any well-formed BYTE[4] version. Missing versions become 2.3.0.0 when selected active output needs one. Malformed or duplicate active versions fail. Removing the last GPS value also removes its version; unrelated GPS fields retain it. Source XMP GPSVersionID is not copied.
Limits are nine added entries including GPSVersionID, 1024 native operations, 128 text bytes per selected active property, and 896 total text bytes. Limits can be lowered. Failure leaves source and output unchanged, including when they alias. New entries own copied source provenance; preparation may allocate.
translated = document.translate_gps_navigation_metadata( source_mode=openmeta.MetadataGpsTranslationSourceMode.All, conflict_policy=openmeta.MetadataGpsTranslationConflictPolicy.ReplaceExisting, )
Persist the detached result through a transfer snapshot with EXIF enabled. When retaining source XMP too, set
xmp_include_existing=Trueandxmp_conflict_policy=openmeta.XmpConflictPolicy.ExistingWinsin Python transfer helpers. Inclusion alone keeps the historical precedence of generated EXIF values, which can change reference spelling or timestamp formatting. ExistingWins preserves supplied XMP values over generated counterparts. The portable writer’s native-only decimal formatting is not an exact arbitrary-rational round trip.Destination GPS Writeback¶
translate_xmp_gps_destination_metadata(...)uses independentMetadataGpsDestinationTranslationOptionsand the shared GPS result, source mode, conflict policy, and diagnostic enums. Contract version 1 adds four atomic groups; the primary GPS and navigation APIs keep their existing scopes.Exact EXIF XMP source
Native
gpsifdfieldsFlag
GPSDestLatitudeDestLatitudeRef (19) and DestLatitude (20)
latitude_to_exifGPSDestLongitudeDestLongitudeRef (21) and DestLongitude (22)
longitude_to_exifGPSDestBearingRefandGPSDestBearingDestBearingRef (23) and DestBearing (24)
bearing_to_exifGPSDestDistanceRefandGPSDestDistanceDestDistanceRef (25) and DestDistance (26)
distance_to_exifSources use exact unindexed, unqualified paths in
http://ns.adobe.com/exif/1.0/. Coordinates use the primary GPS text syntax:degrees,decimalMinutesNordegrees,minutes,decimalSecondsN, with the appropriate N/S or E/W hemisphere. Bounds are 90/180 degrees and minutes or seconds below 60; components after a maximum degree must be zero. Output is ASCII hemisphere plus exact reduced unsigned RATIONAL[3], including the hemisphere of zero. Unsupported precision fails without rounding.Bearing and distance use the navigation exact nonnegative integer/rational scalar or unsigned integer/decimal/fraction text syntax. Bearing is in [0, 359.99], with
T/Mor exactTrue North/Magnetic Northaliases. Distance acceptsK/M/Nfor kilometers, miles, and nautical miles, plus exactKilometers,Miles, andNautical milesaliases. These distance units follow CIPA DC-X010-2017, section 8.3. Portable XMP now emitsNautical milesfor destination unit N; it previously emitted the incorrect labelKnots. The reverse API accepts that historical capitalized spelling as N distance without converting the number. Lowercaseknots,km/h, andmphare speed references and are rejected for distance. No bearing, distance, primary position, datum, north reference, or unit is inferred or converted. Numeric precision follows the primary GPS parser limits.Defaults are DirtyOnly/FailOnConflict with all four groups enabled. One dirty bearing/distance member selects the complete active pair, including its clean companion. Missing, duplicate, and mixed deleted/active members fail. A dirty coordinate tombstone removes both native coordinate fields; bearing/distance removal requires both XMP members to be dirty tombstones. Clean tombstones are ignored. Missing groups preserve their native values.
Native pairs follow the primary GPS conflict policy. PreserveExisting retains a whole group when either native member exists. FailOnConflict requires a complete equivalent pair. ReplaceExisting repairs partial or malformed groups and removes duplicates. Equivalence compares typed rational components exactly; text may include its one wire NUL. A well-formed native BYTE[4] GPSVersionID is retained without interpreting or upgrading it. Missing versions default to 2.3.0.0 when active output needs one. Malformed or duplicate active versions fail. Removing the final GPS value removes its version; unrelated GPS retains it.
Limits are nine added entries including the version, 1024 operations, 128 text bytes per selected active source, and 768 total text bytes. Limits may be lowered. All selected groups share one transaction; failures leave source and output unchanged, including aliasing. New entries own their provenance. Preparation may allocate. Python returns a detached document:
destination = document.translate_gps_destination_metadata( source_mode=openmeta.MetadataGpsTranslationSourceMode.All, conflict_policy=openmeta.MetadataGpsTranslationConflictPolicy.ReplaceExisting, )
Persist the result through transfer preparation. To retain original XMP values and spelling, Python transfer requires both
xmp_include_existing=Trueandxmp_conflict_policy=openmeta.XmpConflictPolicy.ExistingWins. Native-only portable coordinate/rational formatting can be approximate; reverse translation cannot recover precision already lost from its input. Receiver status/quality, DOP, and geographic computation remain outside this contract.GPS receiver quality writeback¶
translate_xmp_gps_quality_metadata(...)and PythonDocument.translate_gps_quality_metadata(...)add five independent singleton mappings withMetadataGpsQualityTranslationOptions, contract version 1. Exact unindexed paths usehttp://ns.adobe.com/exif/1.0/.XMP source
Native tag/type
Flag
GPSStatus9 / ASCII
status_to_exifGPSMeasureMode10 / ASCII
measure_mode_to_exifGPSDOP11 / RATIONAL
dop_to_exifGPSDifferential30 / SHORT
differential_to_exifGPSHPositioningError31 / RATIONAL
horizontal_error_to_exifStatus accepts exact A/V or Measurement Active/Measurement Void text. Measure mode accepts nonnegative integer 2/3 or exact text
2/3. Differential accepts integer 0/1, exact text0/1, or No Correction/Differential Corrected. No other enum spellings, decimal/fraction coercion, or unknown codes are accepted. DOP and horizontal error use the existing exact nonnegative rational parser; floats, signed text, exponents, zero denominators, and unsupported precision fail. DOP is retained without calculating an accuracy estimate. Horizontal error is in meters; no unit conversion or receiver-state inference occurs. The field identities follow CIPA EXIF/XMP mapping.The v1 version contract accepts GPS 2.2 through 2.4 for differential correction and GPS 2.3 through 2.4 for horizontal error. Earlier or unknown versions fail when the corresponding active field is selected. Other quality fields retain any well-formed native BYTE[4] version. Versions are never upgraded. A missing native version defaults to 2.3.0.0; source XMP GPSVersionID is not copied.
Defaults are DirtyOnly/FailOnConflict and five enabled flags. One dirty source tombstone removes its native singleton. Missing fields and clean tombstones retain native data. Duplicate sources fail. PreserveExisting retains existing native values; FailOnConflict requires typed equivalence; ReplaceExisting repairs malformed values and duplicates. Native ASCII permits one trailing wire NUL; rational equivalence is exact. All five selected fields share one atomic transaction. Removing the last GPS field also removes its version, while unrelated GPS retains it. New entries own their provenance, and failures preserve source/output even when they alias.
Limits are six added entries including version, 1024 operations, 128 text bytes per selected active source, and 640 total text bytes. Limits can be lowered. Preparation may allocate. Existing primary, navigation, and destination APIs keep their scopes. Python returns a detached document for transfer preparation. Source XMP preservation still requires both
xmp_include_existing=Trueandxmp_conflict_policy=openmeta.XmpConflictPolicy.ExistingWinsduring transfer.GPS text writeback¶
translate_xmp_gps_text_metadata(...)and PythonDocument.translate_gps_text_metadata(...)add four independent singleton mappings withMetadataGpsTextTranslationOptions, contract version 1. Exact unindexed paths usehttp://ns.adobe.com/exif/1.0/.XMP source
Native tag/type
Flag
GPSSatellites8 / ASCII
satellites_to_exifGPSMapDatum18 / ASCII
map_datum_to_exifGPSProcessingMethod27 / UNDEFINED encoded text
processing_method_to_exifGPSAreaInformation28 / UNDEFINED encoded text
area_information_to_exifSatellites and datum require ASCII. Processing method and area accept valid UTF-8, including supplementary Unicode characters. Source Text values must use Ascii, Utf8, or Unknown encoding; Unknown is interpreted as UTF-8. Empty text is an active value, and spaces are retained exactly. NUL, C0/C1 controls, malformed UTF-8, and unsupported source types/encodings fail. There is no truncation, Unicode normalization, datum conversion, receiver-state inference, or parsing of satellite lists or processing-method names.
Method and area are stored as UNDEFINED bytes with an eight-byte character-code identifier. ASCII content uses the ASCII prefix; non-ASCII content uses the UNICODE prefix followed by a UTF-16LE byte-order marker and exact UTF-16 payload. Supplementary characters use surrogate pairs. New encoded payloads omit the optional terminator; ordinary ASCII fields receive their wire terminator during serialization. Native equivalent text accepts the ASCII prefix or UNICODE with an explicit LE/BE byte-order marker and at most one trailing terminator. JIS, unknown identifiers, malformed text, and Unicode without a byte-order marker are non-equivalent. FailOnConflict protects these native values; PreserveExisting keeps them, while ReplaceExisting replaces them with canonical new output. Portable XMP recognizes the same supported encoded forms and emits decoded text. Unsupported forms are omitted from native-to-XMP projection without modifying the original native entries.
The v1 method/area version contract accepts GPS 2.2 through 2.4; earlier or unknown versions fail when an active encoded field is selected. Satellites and datum retain any well-formed native BYTE[4] version. Missing versions default to 2.3.0.0, with no upgrade or source-XMP version copy.
Defaults are DirtyOnly/FailOnConflict and four enabled flags. Selection, singleton conflicts, duplicate repair, dirty tombstone removal, version cleanup, owned provenance, and source/output aliasing follow the quality GPS contract. All selected fields commit atomically. Empty strings do not request deletion. Limits are five added entries including version, 1024 native operations, 4096 source text bytes per selected active property, and 16384 total text bytes. Encoded output is bounded by twice the source byte limit plus its prefix/BOM; encoding overhead does not consume the source-text budget. Limits may be lowered. Preparation may allocate.
Python returns a detached document. Persist it through transfer preparation; retain source XMP using both
xmp_include_existing=Trueandxmp_conflict_policy=openmeta.XmpConflictPolicy.ExistingWins. The five GPS translation APIs now cover the repository’s 32 standard native GPS tag IDs, including paired companions and automatically maintained GPSVersionID. This is bounded writeback coverage; it does not imply support for every possible encoding, version, or arbitrary metadata synchronization policy.Conflict And Removal Policy¶
All translation APIs apply the following behaviors to each complete native group. Location and editorial translation reuse the descriptive conflict-policy enum.
Policy
Behavior
PreserveExistingKeep the complete native group when any member already exists.
FailOnConflictRequire the group to be absent or already exactly equivalent. This is the default.
ReplaceExistingReplace the group, tombstone duplicates, and tombstone stale companion fields.
A dirty deleted XMP source is propagated only with
ReplaceExisting; the corresponding native group is tombstoned. Duplicate eligible XMP source properties are rejected as ambiguous rather than choosing one occurrence.The operation is transactional. The source is immutable and the output store is replaced only after all selected mappings parse, reconcile, and finalize. New native entries retain the source XMP block and wire provenance, with any referenced wire-type name copied into output-owned storage. Date
max_added_entriesandmax_operationsmay lower the public hard limits of 16 added entries and 1024 native operations. Technical translation has separate hard limits of 6 added entries, 1024 operations, 4096 bytes per text property, and 16 KiB total source text. Calls keep no global state and are safe when each concurrent call owns its output store.Capture translation separately permits at most 5 added entries, 1024 operations, 128 bytes per text property, and 640 total source text bytes. Its tag-specific conversion always emits scalar
RATIONAL,SHORT, orSRATIONALvalues, so generic writer type inference cannot select a different TIFF type.Geometry translation permits at most 5 added entries, 1024 operations, 32 bytes per textual property, and 160 total source text bytes. One dirty width or height member makes the complete active dimension group eligible in
DirtyOnlymode. A complete dirty width/height tombstone pair may remove the native group underReplaceExistingonly when the target spec does not still declare dimensions; orientation follows the same target-contradiction rule.Descriptive translation separately bounds matched source properties, added entries, operations, and total text bytes. In
DirtyOnlymode, one dirty member makes the complete repeated creator/keyword group eligible, so unchanged active members are retained while dirty tombstones can remove native values underReplaceExisting.C++ Example¶
#include "openmeta/metadata_transfer.h" #include "openmeta/metadata_translation.h" openmeta::MetadataDateTranslationOptions options; options.conflict_policy = openmeta::MetadataDateTranslationConflictPolicy::ReplaceExisting; openmeta::MetaStore translated; const openmeta::MetadataDateTranslationResult result = openmeta::translate_xmp_creation_dates(edited, options, &translated); if (result.status != openmeta::MetadataDateTranslationStatus::Ok) { // translated is unchanged. } openmeta::MetadataTechnicalTranslationOptions technical_options; technical_options.conflict_policy = openmeta::MetadataTechnicalTranslationConflictPolicy::ReplaceExisting; openmeta::MetaStore technical; const auto technical_result = openmeta::translate_xmp_technical_metadata( translated, technical_options, &technical); openmeta::MetadataCaptureTranslationOptions capture_options; capture_options.conflict_policy = openmeta::MetadataCaptureTranslationConflictPolicy::ReplaceExisting; openmeta::MetaStore capture; const auto capture_result = openmeta::translate_xmp_capture_metadata( technical, capture_options, &capture); openmeta::TransferTargetImageSpec target; target.has_dimensions = true; target.width = output_width; target.height = output_height; target.has_orientation = true; target.orientation = output_orientation; openmeta::MetaStore geometry; const auto geometry_result = openmeta::translate_xmp_image_geometry( capture, target, openmeta::MetadataGeometryTranslationOptions {}, &geometry); openmeta::MetadataDescriptiveTranslationOptions descriptive_options; descriptive_options.conflict_policy = openmeta::MetadataDescriptiveTranslationConflictPolicy::ReplaceExisting; openmeta::MetaStore descriptive; const auto descriptive_result = openmeta::translate_xmp_descriptive_metadata( geometry, descriptive_options, &descriptive); openmeta::MetadataLocationTranslationOptions location_options; location_options.conflict_policy = openmeta::MetadataDescriptiveTranslationConflictPolicy::ReplaceExisting; openmeta::MetaStore location; const auto location_result = openmeta::translate_xmp_location_metadata( descriptive, location_options, &location);
Python¶
Python calls the same C++ transaction and returns a detached
Document:translated = edited.translate_creation_dates( conflict_policy=openmeta.MetadataDateTranslationConflictPolicy.ReplaceExisting, ) translated = translated.translate_technical_metadata( conflict_policy=openmeta.MetadataTechnicalTranslationConflictPolicy.ReplaceExisting, ) translated = translated.translate_capture_metadata( conflict_policy=openmeta.MetadataCaptureTranslationConflictPolicy.ReplaceExisting, ) translated = translated.translate_image_geometry(target_image_spec) translated = translated.translate_descriptive_metadata( conflict_policy=openmeta.MetadataDescriptiveTranslationConflictPolicy.ReplaceExisting, ) translated = translated.translate_location_metadata( conflict_policy=openmeta.MetadataDescriptiveTranslationConflictPolicy.ReplaceExisting, )
Invalid or lossy requests raise
ValueErrorcontaining the C++ status, mapping, and source entry ID. The originalDocumentis not mutated.Scope¶
This milestone is intentionally limited to exact creation-date, common technical and capture EXIF, target-bound orientation/stored dimensions, primary GPS coordinates/time/navigation, combined descriptive/editorial/workflow IPTC, flat IPTC Core locations, capture settings, and explicit structured-location reconciliation/construction. It does not yet provide arbitrary EXIF/IPTC/XMP translation, broader target image-layout/storage projection, multilingual-alternative selection, timezone inference, numeric approximation or value repair, or automatic synchronization during transfer.
Sensitivity companion writeback¶
translate_xmp_sensitivity_metadata(...)and PythonDocument.translate_sensitivity_metadata(...)use independentMetadataSensitivityTranslationOptions, contract version 1. The seven ExifIFD fields form one transaction and one result group:XMP property in
http://cipa.jp/exif/1.0/(exifEX)Native tag
Type/range
PhotographicSensitivity
0x8827
SHORT, 1..65535
SensitivityType
0x8830
SHORT, 0..7
StandardOutputSensitivity
0x8831
LONG, 1..4294967295
RecommendedExposureIndex
0x8832
LONG, 1..4294967295
ISOSpeed
0x8833
LONG, 1..4294967295
ISOSpeedLatitudeyyy
0x8834
LONG, 1..4294967295
ISOSpeedLatitudezzz
0x8835
LONG, 1..4294967295
Input values are unsigned scalar integers or decimal integer text with optional leading
+. Signed scalars, fractions, labels, zero sensitivity values, overflow, and malformed/indexed/qualified fields fail. This positive-value restriction is OpenMeta’s bounded writeback policy. Exact namespaces are required. Legacy OpenMetaexif:ISO,exif:ISOSpeedRatings, andexif:ISOSpeedRatings[1]are base aliases; the six companion names in the olderexifnamespace are also accepted for historical portable packets. Duplicate properties or aliases fail even when equal. The existing ISO-only API retains its 1..65535 contract.An active group requires both base sensitivity and type. Type 0 means unknown; 1 selects SOS, 2 REI, 3 ISO speed, 4 SOS+REI, 5 SOS+ISO, 6 REI+ISO, and 7 all three. Any supplied selected parameters must equal the base value below 65535, or use base 65535 for values at or above that limit. Plural selected parameters must equal each other as full LONG values, including above the SHORT limit. Unselected parameters may differ. Optional selected parameters may be absent; a marker without its extended value remains a marker. No type or missing high-range value is inferred. Latitude values require both latitude fields and ISOSpeed. EXIF versions and unrelated exposure fields are retained.
Defaults are DirtyOnly/FailOnConflict. One dirty recognized member selects the whole group, including clean active companions. All selects active sources and dirty tombstones. No selected source retains the native group. Once selected, missing or deleted optional sources specify absent target fields. A dirty base tombstone with no active group members requests complete removal; an orphan companion tombstone or partial required pair fails. Source XMP entries remain available for caller-controlled serialization.
PreserveExisting retains the complete native group if any member exists. FailOnConflict requires the entire group to be absent or exactly equivalent, including presence, SHORT/LONG types and duplicate counts. ReplaceExisting updates the group and removes stale/duplicate native members. Validation runs before all policies, and failures preserve separate or aliased output. Limits are seven added entries, 1024 operations, 128 text bytes per property and 896 text bytes in total; callers may lower them. Preparation may allocate.
Portable native output now uses
exifEXfor the six companions. A base with native SensitivityType usesexifEX:PhotographicSensitivity; an ISO-only base retainsexif:ISO. These seven properties participate in the existingCanonicalizeManagednamespace policy. Complete generated groups round-trip through this API, including the full unsigned LONG range. Existing source XMP can be retained with ExistingWins; independently authored duplicate base aliases still require caller resolution. Snapshot persistence covers JPEG, Classic TIFF and BigTIFF creation, replacement and removal.The wire and companion rules follow the CIPA EXIF 2.32 English translation (section 4.6.6 and Annex G) and EXIF 2.31 XMP mapping tables. This bounded API is not a claim of complete current EXIF conformance or automatic reconciliation with every legacy ISO-array convention.
References: CIPA EXIF translation, CIPA EXIF metadata for XMP.
Camera, lens and spectral text writeback¶
translate_xmp_camera_text_metadata(...)and PythonDocument.translate_camera_text_metadata(...)use independentMetadataCameraTextTranslationOptionsand the existing technical source-mode, conflict-policy, result and diagnostic enums. Contract version 1 adds six independent native targets in one transaction.Exact XMP property
Native ExifIFD tag
Option
exif:SpectralSensitivity0x8824ASCIIspectral_sensitivity_to_exifexifEX:CameraOwnerName0xa430ASCIIcamera_owner_name_to_exifexifEX:BodySerialNumber0xa431ASCIIbody_serial_number_to_exifexifEX:LensMake0xa433ASCIIlens_make_to_exifexifEX:LensModel0xa434ASCIIlens_model_to_exifexifEX:LensSerialNumber0xa435ASCIIlens_serial_number_to_exifHere
exifishttp://ns.adobe.com/exif/1.0/andexifEXishttp://cipa.jp/exif/1.0/. The five identity fields also accept the same property names in the historical OpenMetaexifnamespace. Prefix spelling is irrelevant; namespace URI and property path must match.aux:Lens,aux:SerialNumber,OwnerName, genericLensaliases and MakerNote identity inference are excluded. The tag types follow Exif 2.32; the canonical XMP identity mappings follow CIPA metadata interchange guidance.An active value must be nonempty
TextwithAsciiorUtf8encoding, containing only printable ASCII bytes0x20..0x7e. Leading/trailing spaces, punctuation and serial-number leading zeros are preserved. XMP decoding retains their boundary whitespace in description attributes, resource values and element text. Empty values, other value kinds or encodings fail withInvalidSourceValue; NUL, controls, DEL and non-ASCII bytes fail withNonAsciiSource. The bounded printable subset permits lossless portable XML round trips. No trimming, transliteration, Unicode conversion or ASTM spectral-curve grammar validation is performed. The latter remains the caller’s responsibility; this API transports the supplied text.All six switches default to true.
DirtyOnlyselects each dirty property individually.Allalso selects active clean entries; deleted entries still requireDirty. Missing or disabled properties retain native metadata. Eligible duplicates, including canonical/legacy alias pairs with equal values, fail withAmbiguousSource. Indexed, qualified or nested forms of a selected property fail withUnsupportedSourceShape. A selected dirty tombstone ignores its payload and removes only that native field underReplaceExisting.Each field has its own conflict decision and result group.
FailOnConflictrejects a mismatch,PreserveExistingretains the conflicting field while other fields can translate, andReplaceExistingupdates the singleton and removes native duplicates. Native equivalence requiresTextwithAsciiorUtf8encoding and matching bytes after native terminal NUL bytes are removed; byte blobs, numbers and other encodings are conflicts. New values use native ASCII. All source validation, conflict decisions and resource checks finish before one commit. Failure leaves separate or aliased output unchanged. Source provenance and text ownership survive the source store’s lifetime.Limits are 6 added entries, 1024 edit operations, 4096 bytes per property and 24576 total source-text bytes. Limits must be nonzero and at most those ceilings. At least one switch must be enabled. Existing technical and capture option layouts and existing enum values are unchanged.
Portable native identity fields now use canonical
exifEXnames. That namespace is declared only when needed. Spectral sensitivity remains inexif.CanonicalizeManagedrecognizes all six fields. If callers retain legacy source XMP along with generated canonical identity properties, both aliases can remain under ordinary preservation policies; reverse translation rejects their ambiguity. UseCanonicalizeManagedwhen replacing those managed aliases.Shared tests cover all six fields, conflict and removal transactions, source shapes and budgets, portable XML and namespace policies, serialized snapshots through JPEG/Classic TIFF/BigTIFF, the Python wrapper and an installed shared library consumer. Related fields are implemented and reviewed together, with focused checks during development and one final platform matrix per stable batch. Lens specification and image identity use the separate contract below. APEX and focal-plane/subject arrays are covered by the combined batches below.
Lens specification and image identity writeback¶
translate_xmp_identity_metadata(...)and PythonDocument.translate_identity_metadata(...)useMetadataIdentityTranslationOptions, contract version 2, and the existing capture source modes, conflict policies, statuses and result counters. The two fields have independent switches and conflict decisions, followed by one commit.Source
Native ExifIFD field
Option
exifEX:LensSpecification0xA432, four unsigned RATIONALslens_specification_to_exifexif:ImageUniqueID0xA420, ASCII, 33 bytes on wireimage_unique_id_to_exifLens specification also accepts the historical OpenMeta
exifnamespace alias. The four ordered components are minimum focal length, maximum focal length, minimum F-number at the minimum focal length, and minimum F-number at the maximum focal length. Focal lengths must be positive, with minimum <= maximum. Apertures must be positive or exactly0/0, the EXIF unknown-aperture marker. The API does not infer missing values, constrain one aperture relative to the other, or parse lens model descriptions.Accepted lens shapes are one
URationalarray of exactly four elements, or four scalar properties namedLensSpecification[1]through[4]. Indexed values accept unsigned integer/rational scalars or ASCII/UTF-8 numeric text: integer, decimal, scientific notation ornumerator/denominator. Conversion is exact and reduced to unsigned 32-bit components; unrepresentable values fail. Floating point scalars, units, opaque lists, sparse/noncanonical indexes, nested fields, root/index mixtures and mixed or duplicate namespace aliases fail. The store retains flattened indexes, not the original RDF Seq/Bag container kind; hosts must supply the four components in the documented order. Portable output uses a standardexifEXRDF Seq with exact fraction text and preserves0/0.Under
DirtyOnly, any dirty lens member selects the whole lens group, including clean companions. A root tombstone must stand alone. Four dirty indexed tombstones also remove the group; partial deletion fails. Missing sources and clean tombstones do nothing.Allselects clean active sources too. Image ID selection is independent and accepts only the exact scalar property.Image IDs require exactly 32 hexadecimal ASCII characters (
0-9,a-f,A-F), stored as ASCII/UTF-8 Text. No trimming, case folding, hyphen removal or ID creation occurs. Leading zeros and letter case survive. A native equivalent must be ASCII/UTF-8 Text with those same bytes, optionally followed by one NUL. The serializer writes one terminator for the required 33-byte wire representation. Generic validation and validated authoring allow0/0only in the exact unsigned lens aperture slots (native array, XMP root array or scalar[3]/[4]). Other zero-denominator values remain errors. The translation contract also checks positive values, focal ordering and completeness. Native lens equivalence requires a four-element URational array with equal rational values and exact unknown markers; equivalent unreduced values remain. Malformed native types or duplicate native tags are conflicts.FailOnConflictrejects differences,PreserveExistingretains existing native fields, andReplaceExistingapplies updates, duplicate repair and requested removals. Every source check and budget check precedes mutation of either field. Failure retains both a separate output and an aliased input/output unchanged. Preparation and commit may allocate; synchronization of shared objects is the host’s responsibility. The API has no internal synchronization or ID allocator.Limits are 2 added native entries, 1024 edit operations, 128 text bytes per source member, and 544 total text bytes (four lens members plus a 32-byte image ID). Callers can lower these positive limits. Typed lens arrays are fixed at 32 bytes and do not consume the text budget. Source properties count actual selected entries; successful translations count at most two groups.
Portable native output skips malformed lens/ID values.
CanonicalizeManagedrecognizes the canonical lens array and removes managed source copies before native projection. Preservation policies may retain a historical alias alongside a generated canonical value, which reverse translation rejects as ambiguous. XMP decoding preserves boundary whitespace forexif:ImageUniqueID, so invalid padded IDs are rejected consistently for attributes, resources and element text.The structural contract follows the Exif 2.3 field definitions and CIPA Exif/XMP mappings. It does not validate UUID generation/version, global uniqueness, or an application’s capture-time identity retention policy. Hosts decide whether an explicit replacement or removal is appropriate for their workflow and Exif version. No existing EXIF version is upgraded implicitly.
Combined tests cover C++, Python, installed shared consumers, exact portable round trips, and serialized snapshots through JPEG, Classic TIFF and BigTIFF. The APEX and focal-plane/subject batches below extend this coverage.
Accepted exact clean natives gain Dirty while retaining lens fractions/unknown markers, ID case/NUL and wire provenance. Complete eligible deletion creates or reuses Dirty|Deleted intent even for absent keys. PreserveExisting retains an active owner without promotion; omitted or ineligible sources preserve the destination. Intent, promotions and duplicate removals consume existing budgets. Repeated calls reuse intent; failure retains source and output unchanged.
APEX writeback (contract version 2)¶
translate_xmp_apex_metadata(source, MetadataApexTranslationOptions{}, &output)writes five scalar properties in one transaction. Python exposes the same contract asDocument.translate_apex_metadata(...). The result, source modes, conflict policies and diagnostics use the existing capture types.Exact source in
http://ns.adobe.com/exif/1.0/ExifIFD target
Native type
Independent option
ShutterSpeedValue0x9201SRATIONAL, count 1shutter_speed_value_to_exifApertureValue0x9202RATIONAL, count 1aperture_value_to_exifBrightnessValue0x9203SRATIONAL, count 1brightness_value_to_exifExposureBiasValueorExposureCompensation0x9204SRATIONAL, count 1exposure_bias_value_to_exifMaxApertureValue0x9205RATIONAL, count 1max_aperture_value_to_exifAll inputs are direct APEX values. There is no conversion from seconds or f-numbers, inference from ExposureTime/FNumber, exposure-equation check, version upgrade, or consistency check between the five fields. The two aperture fields accept zero and positive values. The signed fields accept either sign. The usual brightness/bias range of -99.99 to 99.99 is not a hard limit.
The structural types and brightness sentinel follow CIPA DC-008-2012, camera information tags and Annex C. The XMP property names follow CIPA DC-X010-2017, Exif mappings. This contract does not claim full conformance to every tag or later Exif revision.
Exact numbers and unknown brightness¶
Sources may be scalar signed/unsigned integers, the target rational type, or ASCII/UTF-8/Unknown-encoding text containing an integer, decimal, scientific number or
numerator/denominator. Signed integers for aperture fields must be nonnegative. Signed rational fields requireSRational, and unsigned rational fields requireURational. Floating-point, arrays, structured children, qualifiers, units, whitespace in numeric text and zero/negative denominators fail. XMP decoding retains its existing whitespace normalization; this batch does not change reader behavior. Exact fractions reduce to 32-bit components; numeric text parsing uses bounded 64-bit intermediates. Overflow fails without approximation. Denominators are positive, at mostINT32_MAXfor signed fields orUINT32_MAXfor unsigned fields.Brightness reserves a wire numerator of -1 (
0xffffffff) for unknown, regardless of its positive denominator. Explicit fraction text-1/n, a typedSRational{-1, n}, or exact textUnknownselects this sentinel before reduction and creates or replaces the value with-1/1. Equivalent native unknown scalars retain their original encoding when gaining Dirty authority. Sentinel fraction denominators must fitINT32_MAX. Integer and decimal/scientific inputs are finite:-1,-1.0and a signed integer -1 write-2/2. A finite-0.5or explicit-2/4writes-2/4. Reduced finite fractions with numerator -1 use-2/(2n); if the doubled denominator cannot fit, translation returnsValueOutOfRange. Unknown and finite native brightness values never compare equal during conflict handling. Positive-denominator native unknown fractions compare equivalent to each other.Selection, conflicts and bounds¶
All five switches default to true. At least one must be enabled. DirtyOnly selects eligible dirty scalar sources; All also selects active clean sources. Deleted sources require Dirty in either mode. Missing sources retain native values. Each field reconciles independently with PreserveExisting, FailOnConflict or ReplaceExisting, and duplicate eligible aliases fail even when their values agree. Indexed/structured shapes of enabled properties fail. Unrelated names, namespaces and disabled mappings are ignored.
Native equivalence requires the correct scalar type/count and equal rational value, with the brightness sentinel rule above. ReplaceExisting repairs wrong types and duplicate native entries. A dirty tombstone removes all native instances under ReplaceExisting, including explicit intent for an absent key since 0.7.2. Accepted exact clean native values gain Dirty authority while retaining scalar and wire provenance. Parsing, conflicts and shared limits complete before one commit. Failure preserves both separate and aliased output; success owns its values and provenance. Preparation may allocate. The host synchronizes conflicting access to shared stores.
Default and hard maximum budgets are five added entries, 1024 edit operations, 128 bytes per text property and 640 total text bytes. Duplicate repair and removal consume the operation budget. Lower positive caller limits are allowed. The exposure-bias mapping and its diagnostic
XmpExposureCompensationare shared with the general capture API. Options and parsing stay the same; 0.7.2 extends native lifecycle authority in both bias entry points.Portable output change in 0.5.3¶
Generated portable XMP now emits exact fractions for all five native APEX tags. For example, native shutter
6/1emitsShutterSpeedValue=6/1; native aperture4/1emitsApertureValue=4/1. Previous releases emitted seconds (1/64) and f-numbers (4.0) under these names. Old generated packets cannot be identified reliably from their values; regenerate them from native EXIF before reverse translation. No heuristic migration is performed.Brightness and exposure compensation also use fractions instead of rounded floating-point text. Existing correctly typed scalar XMP APEX rationals also retain their exact wire fractions, including noncanonical unknown brightness. The existing portable
ExposureCompensationalias remains. Unknown brightness emits-1/1; finite wire fractions retain their numerator so the sentinel distinction survives. Wrong native types/counts and nonpositive denominators are omitted. Large representable APEX values remain exact without exponentiation or a physical aperture limit. Default existing-XMP precedence remains unchanged; CanonicalizeManaged permits valid native values to replace managed source properties. Host FlatHost/Spec projections are separate and unchanged.The APEX batch added four native targets, bringing capture-related coverage at 0.5.3 to 41 targets across nine APIs. The spatial batch below extends this. OIIO/iRAW application acceptance remains a separate downstream task.
Focal-plane and subject writeback (contract version 2)¶
translate_xmp_capture_spatial_metadata,MetadataCaptureSpatialTranslationOptionsand PythonDocument.translate_capture_spatial_metadataprovide three logical groups in one transaction. Sources usehttp://ns.adobe.com/exif/1.0/.XMP property
ExifIFD target
Native shape
Group switch
FocalPlaneXResolution0xa20eRATIONAL, count 1
focal_plane_to_exifFocalPlaneYResolution0xa20fRATIONAL, count 1
focal_plane_to_exifFocalPlaneResolutionUnit0xa210SHORT, count 1
focal_plane_to_exifSubjectArea0x9214SHORT array, count 2, 3 or 4
subject_area_to_exifSubjectLocation0xa214SHORT array, count 2
subject_location_to_exifFocal-plane X/Y values are pixels per explicit unit for the recorded image. All three source fields must be present together. Positive scalar signed or unsigned integers,
URational, or ASCII/UTF-8 integer, decimal, scientific and fraction text are accepted for X/Y. Fractions reduce exactly using bounded 64-bit intermediates and must fit unsigned 32-bit components. Zero, negative values, zero denominators, floating point and approximation are rejected. The unit accepts integer 2 or 3, integer text with an optional leading plus, or the exact portable labelsinchesandcm. Units 1, 4 and 5 and labelsmm/umare outside this writeback contract. There is no default or conversion.SubjectArea holds X/Y for a point; a circle adds diameter; a rectangle adds width and height. SubjectLocation holds X/Y independently. Values are preserved as supplied relative to the upper-left origin before orientation processing. No rotation, crop, image-dimension check, positive-size rule or consistency relation between the two arrays is inferred. Every element may be 0..65535.
Sources can be one root
U16array or dense indexed members[1]through[N]. Indexed members accept scalar signed/unsigned integers in range or ASCII/UTF-8 integer text, optionally prefixed with+. They reject decimal/fraction text, float/rational values, nested arrays, qualifiers, duplicate or sparse indexes, leading-zero indexes and mixed root/indexed forms. SubjectArea requires 2..4 members; SubjectLocation requires exactly two. The store flattens RDF arrays, so callers must supply the documented order; Seq/Bag provenance is not retained.All three switches default to true, and at least one must remain enabled. DirtyOnly selects a group when any member is dirty; All also selects active clean sources. Selected groups include all active clean companions and dirty tombstones. Clean tombstones are ignored. Duplicate active/dirty sources fail, even when values agree. Disabled groups and unrelated namespaces are ignored.
Every selected group must be wholly present or wholly deleted. An array root tombstone, or a complete dense deleted source array, removes the native array under ReplaceExisting. Focal-plane removal requires all three tombstones. Partial deletion fails instead of changing an array’s meaning or leaving units behind. A missing group retains native values. PreserveExisting preserves the entire group if any native member exists; FailOnConflict requires all native members to match; ReplaceExisting repairs partial groups, wrong types and duplicates. Equality checks exact native type/count, rational value and ordered array contents. Results count up to three logical groups and five native entries.
Since 0.8.4, accepted clean exact native fields gain Dirty authority through same-value updates retaining their original rational components, ordered arrays and wire provenance. Complete accepted deletion carries Dirty+Deleted intent for every owned native tag, even when it is absent from the source. Repeat calls reuse that intent. PreserveExisting retains the entire active native group without promotion. New markers, promotions and duplicate removals count against the existing limits before publication.
Prepared TIFF/DNG bundles use the existing native ExifIFD merge and removal fields for all five spatial tags. Unselected destination entries, MakerNotes and media ranges remain preserved. The bounded ExifIFD allowlist now has 44 tags. Dirty native owners select merge mode. Live entries included by ordinary EXIF preparation, including clean entries, supply destination values. Destination entries absent from the prepared EXIF payload retain their existing values. Source snapshot version 1 retains the flags needed to regenerate these intents. Fresh emission and non-edit consumers reject removal intent they cannot express. Signatures, options and bundle layout remain unchanged; spatial contract version 2 identifies the extended lifecycle. Development ABI remains unfrozen 4.
Parsing, conflicts and shared limits precede one commit, preserving separate and aliased output on failure. Success owns array storage and provenance. Default and hard bounds are five added entries, 1024 edit operations, 128 text bytes per property and 1152 total text bytes. Positive lower limits are allowed. Preparation may allocate; hosts synchronize conflicting shared-object access.
In 0.5.4, native and existing typed XMP focal-plane rationals emit exact fractions. Earlier rounded decimal packets cannot recover the original exact fraction; regenerate them from native EXIF when exact recovery is required. Subject arrays emit ordered sequences and participate in managed replacement as arrays. Invalid native spatial types/counts/spans and nonpositive resolutions are omitted before claiming a property. Valid existing XMP remains available. Existing unit read labels, including mm/um, and default existing-XMP precedence remain. Host FlatHost/Spec and reader decode paths are unchanged.
The field types and coordinate meanings follow CIPA DC-008-2012, camera information tags; the XMP namespace and ordered-array mappings follow CIPA DC-X010-2017. Requiring explicit complete groups and positive resolutions is this bounded OpenMeta contract. This is not full Exif conformance or downstream acceptance. The five new targets bring capture-related coverage to 46 targets across ten APIs.
Additional capture and environment fields (0.5.6)¶
Two explicit, bounded APIs extend the capture family to twelve calls and 55 distinct ExifIFD targets. Both reuse capture source modes, conflict policies, dirty tombstones, failure details and transaction rules. Python provides
Document.translate_capture_additional_metadata(...)andDocument.translate_environment_metadata(...)with the same defaults and limits. Each call publishes independently; hosts that need an entire multi-call workflow transaction should keep the candidate detached until every call succeeds.API / property
Native tag and shape
Accepted meaning
Additional: exif:FocalLengthIn35mmFilm
A405 SHORT, 1
Millimetres, 0 unknown, maximum 65535. FocalLengthIn35mmFormat is an explicit alias and remains the portable output spelling.
Additional: exif:FileSource
A300 UNDEFINED, 1
0 other, 1 transparent scanner, 2 reflex scanner, 3 digital still camera.
Additional: exif:SceneType
A301 UNDEFINED, 1
1 directly photographed image.
Environment: exifEX:Temperature
9400 SRATIONAL, 1
Degrees Celsius.
Environment: exifEX:Humidity
9401 RATIONAL, 1
Percent. No additional physical range is imposed.
Environment: exifEX:Pressure
9402 RATIONAL, 1
hPa.
Environment: exifEX:WaterDepth
9403 SRATIONAL, 1
Metres; negative above water level.
Environment: exifEX:Acceleration
9404 RATIONAL, 1
mGal (10^-5 m/s²).
Environment: exifEX:CameraElevationAngle
9405 SRATIONAL, 1
Degrees, finite values in [-180, 180).
Additional capture inputs accept scalar integer values and decimal integer text, with no labels, units, rounding or sensor-size inference. Native FileSource and SceneType remain one-byte
MetaValueKind::Bytes, and portable XMP emits integer text. Environment inputs accept the matching typed rational, integers and exact decimal/scientific/fraction text. Floating-point values and unit suffixes are rejected. The CIPA namespace URI ishttp://cipa.jp/exif/1.0/; legacy EXIF namespace environment properties are accepted as aliases. Duplicate eligible aliases, indexed/structured paths and malformed scalar shapes fail before mutation.For every environment tag, raw denominator
0xffffffffmeans unknown. SRATIONAL represents those bits as-1. Recognition precedes reduction, and unknown numerators are preserved. TypedSRational{-7, -1}and text-7/-1or-7/4294967295retain the same unknown value. Unsigned7/4294967295also retains its numerator. TextUnknownuses numerator zero. Other denominators must be positive; a finite fraction that reduces to the reserved denominator is rejected. Finite fractions reduce exactly within their native integer width.Portable output uses exact numerator/denominator text for these typed values.
CanonicalizeManagedremoves legacy namespace aliases only when a valid native replacement will be emitted. Invalid native shapes, codes and finite elevation ranges leave existing XMP available.PreserveAllretains explicit aliases, which can subsequently fail reverse translation as ambiguous.The per-call defaults are 3 or 6 added entries, 1024 primitive edit operations, 128 text bytes per property, and 384 or 768 total text bytes. Options may lower these bounds. Typed editing before translation is described in editing.md.
In 0.8.6, both contracts are version 2. Accepted exact clean native values gain
Dirtywhile retaining native fractions, unknown numerator/denominator bits, one-byte UNDEFINED codes and wire provenance. Native byte spans copy into the edit arena before publication. Complete eligible deletion creates or reusesDirty|Deletednative intent even for absent keys.PreserveExistingkeeps an active owner without promotion; omitted and ineligible sources preserve the destination. Existing preflight budgets include intent, promotion and duplicate removal. Repeated calls reuse intent and failure retains source/output unchanged. The shared ExifIFD merge/removal allowlist grows from 50 to 59 using existing prepared fields and snapshot v1. Signatures, options and bundle layout stay the same; development ABI 4 is unfrozen. Hosts synchronize shared objects.Contracts follow the native definitions in CIPA Exif 2.32 and the namespace/property mappings in CIPA Exif metadata for XMP.
Image encoding and composite capture (0.5.7)¶
C++
translate_xmp_image_encoding_metadataand PythonDocument.translate_image_encoding_metadatacover Gamma (A500), CompressedBitsPerPixel (9102), and ComponentsConfiguration (9101). Gamma usesexifEX(http://cipa.jp/exif/1.0/); legacyexifis an explicit alternative. The other two useexif(http://ns.adobe.com/exif/1.0/). Gamma and compressed bits per pixel accept finite nonnegative unsigned rationals, including zero. Explicit fractions retain their numerator and denominator. Unit suffixes and physical interpretation are not accepted. ComponentsConfiguration is exactly four codes in 0..6, supplied as a typed unsigned array or dense[1]..[4]properties. Native storage is UNDEFINED count four. No component order or uniqueness is inferred.C++
translate_xmp_composite_metadataand PythonDocument.translate_composite_metadatareconcile three native fields as one transaction:Native tag
Contract
CompositeImage A460
SHORT count one: 0 unknown, 1 non-composite, 2 general composite, 3 composite captured while shooting. Companions require code 2 or 3; code 3 requires both.
SourceImageNumberOfCompositeImage A461
SHORT count two: total >=2; used is 0 (unavailable) or 2..total.
SourceExposureTimesOfCompositeImage A462
Bounded UNDEFINED structure with seven summary rationals and an optional exposure list, described below.
Canonical XMP uses the full property names in
exifEX. Explicit alternatives are the legacy Adobeexifnamespace and ExifTool’s short rootsCompositeImageCountandCompositeImageExposureTimes. Mixing roots or namespaces within one property is ambiguous. The abandoned CIPA/2.32/namespace is not an implicit alias.The exposure structure has seven unsigned rational members, in this order:
TotalExposurePeriod,SumOfExposureTimesOfAll,SumOfExposureTimesOfUsed,MaxExposureTimesOfAll,MaxExposureTimesOfUsed,MinExposureTimesOfAll, andMinExposureTimesOfUsed. Each finite value is nonnegative seconds;0/0means unavailable. Native offsets 0..55 contain these seven rationals. A SHORTNumberOfSequences(m) follows at offset 56. If m is zero, the payload ends at 58 bytes and has no n or Values. Otherwise a positive SHORTNumberOfImagesInSequences(n) follows at offset 58, and exactly m*n rationals follow at offset 60. XMPValuesis an ordered sequence or typed URational array. Each list value has a positive denominator, including when its numerator is zero. The list contains at least two values and agrees with the total source count when that companion exists. Summary totals and extrema are not computed or cross-checked against the list.Both APIs use the capture source modes, conflict policies, result statuses and per-call transaction rules. Any selected composite member selects its complete source group, including clean companions.
ReplaceExistingalso removes missing native companions. Deleting CompositeImage together with its companions removes the group. Dirty tombstones can remove n and Values when changing m to zero. Duplicate, sparse, qualified, incomplete and mixed root/indexed structures fail without publishing the candidate. Limits include three added entries per API, the existing 1024-operation ceiling, 128 text bytes per property, 768 total text bytes for encoding and 1 MiB for composite capture. Composite translation has a configurable limit of at most 4096 exposure values.Typed native editing and validation enforce the same individual and group constraints. Portable output validates a native group before replacing source XMP, emits exact fractions and canonical structured fields, and can remove stale managed companions when a valid native code 0 or 1 replaces a composite group. Invalid native metadata does not suppress valid source XMP.
New A462 payloads are little-endian. Decoding a big-endian TIFF retains the raw bytes and sets
EntryFlags::ValueBigEndian. Typed Set and low-levelSetValueWithWireclear this flag for new little-endian data; plain low-levelSetValueretains it, so its caller must preserve the existing byte order. Canonical EXIF serialization writes little-endian values. Transfer converts the embedded structure to the destination TIFF byte order. Snapshot v1 layout and existing golden bytes are unchanged; snapshots using the new flag require OpenMeta 0.5.7 or later. Host-facing raw values remain intact.Target transfer continues to filter all three source encoding fields, including canonical CIPA Gamma, because these properties can depend on the source pixels. Direct EXIF serialization retains all six fields. The combined fixture therefore has 61 native tags before transfer and 58 retained source tags afterward. No codec processing, pixel rewrite or automatic image calibration is added.
The binary layout follows CIPA DC-008-Translation-2023-E, section 4.6.6.7.49, Figure 25. XMP uses CIPA DC-010-2024, section 6.5 and Table A.5: EXIF specification, EXIF/XMP mapping.
In 0.8.8, both translation contracts are version 2. Accepted exact clean native values gain
Dirtywithout replacing their stored fractions, byte spans, byte-order flags or wire provenance. Complete eligible deletion creates or reuses typedDirty|Deletedintent, including absent native fields. UnderReplaceExisting, a selected valid composite group also records removal of omitted companions: source-only codes 0/1/2 can clear a destination’s old group.PreserveExistingkeeps an active native group without promotion; omitted and ineligible source properties leave the store unchanged. Promotion, deletion intent and duplicate removal consume the existing entry/operation budgets. Preflight failure leaves source and output unchanged, and repeated calls reuse intent.The shared ExifIFD merge/removal allowlist grows from 59 to 62 with A460-A462. Existing TIFF/BigTIFF/DNG preparation, snapshot v1 and vector/stream/package paths carry eligible composite edits. The three encoding fields remain excluded from target transfer, even when dirty or deleted: Gamma, compressed bits per pixel and component configuration describe source pixels. Direct canonical EXIF serialization retains them; callers own their correspondence to encoded pixels. Destination encoding metadata is preserved during composite merge. For an existing DNG, retain its original
DNGVersionin the source metadata. DNG preparation synthesizes a version when the source lacks one; it cannot infer target context during preparation. No pixel transformation, RAW encoding or private-offset repair is performed. Append-based TIFF writing preserves retained image data; it does not promise whole-file identity after repeated edits. Public signatures, options and prepared-bundle/snapshot layouts remain unchanged; ABI 4 remains unfrozen and hosts synchronize shared objects.Structured capture data (0.5.8)¶
translate_xmp_structured_capture_metadata(source, options, &output)adds four independent field groups in one transaction. Python exposesDocument.translate_structured_capture_metadata(...)and returns a new document with the same policies and limits. Defaults select dirty sources and fail on native conflicts; preparation may allocate. The host synchronizes conflicting access to shared objects.EXIF field
Tag
Canonical
exif:structureOECF
8828
Columns, Rows, Names, Values (signed rational pairs)
SpatialFrequencyResponse
A20C
Columns, Rows, Names, Values (unsigned rational pairs)
CFAPattern
A302
Columns, Rows, Values (color codes 0 through 6)
DeviceSettingDescription
A40B
Columns, Rows, Values (ordered setting strings)
The namespace is
http://ns.adobe.com/exif/1.0/. Dimensions are positive SHORT values. Tables require one NUL-free ASCII name per column and exactly Columns times Rows values. CFA requires the same number of color codes. Device dimensions describe the display; they do not determine the number of settings. At least one setting is required; individual strings may be empty. No dimensions, photographic relationships or CFA byte-order heuristics are inferred. Legacy SpatialFrequencyResponse 920C is outside this contract.Table values preserve explicit numerator/denominator pairs without reduction. OECF accepts signed 32-bit components, including negative denominators; SpatialFrequencyResponse accepts unsigned 32-bit components. Zero denominators are rejected. Device settings accept valid UTF-8 representable in XML 1.0. Embedded NULs, invalid Unicode and disallowed XML characters are rejected. Spaces, tabs, CR/LF, DEL and supplementary characters retain their values.
The canonical spelling is
Columns. The published CIPA table spellingColumusis an explicit OECF/SFR input alias. Mixed aliases, qualifiers, sparse indices and root/child mixtures fail. Text lists use dense one-based paths such asOECF/Names[1]. Numeric Values may instead be typed rational arrays or unsigned integer arrays for CFA. A root Bytes value is an alternative validated little-endian native payload. Any selected member selects the whole structure, including clean companions. All-deleted source members remove the field; partially populated active structures fail. PreserveExisting, FailOnConflict and ReplaceExisting act independently on the four fields, but any error rolls back the entire call.Default hard limits are 256 columns, 4096 values per field, 4096 bytes per text property, 1 MiB total source text per call, 1 MiB native payload per field, four added entries and 1024 edit operations. Options may lower these limits. They cannot increase them. Typed native editing validates the same wire layout and character rules; raw decoding retains malformed data for inspection. Portable output skips malformed native structures without suppressing valid existing XMP.
Native UNDEFINED payloads use two SHORT dimensions. Tables then contain NUL-terminated ASCII names and rational pairs; CFA contains byte codes. Each device string has its own UTF-16 BOM and terminator. Newly authored strings use UTF-16LE; decoded strings may mix BOM byte orders.
EntryFlags::ValueBigEndianrecords the order of native headers and table rational components without changing the raw bytes. EXIF serialization and transfer convert those numbers to the destination order while preserving string bytes. Typed replacement supplies a new little-endian payload and clears the provenance flag. Snapshot v1 has no layout change, but snapshots carrying big-endian values for these four tags require OpenMeta 0.5.8 or later. Older 0.5.7 readers only understand this flag for composite exposure data. Snapshots produced before 0.5.8 can lack byte-order provenance for these four fields. Reopen the original container with 0.5.8 when recovering those big-endian values; the old raw payload alone does not establish its byte order.In 0.8.9, the structured translation contract is version 2. Accepted exact clean native values gain
Dirtywhile retaining their raw bytes, byte-order flags and wire provenance. Complete eligible deletion creates or reuses typedDirty|Deletednative intent, including absent fields.PreserveExistingretains active native owners; omission and ineligible source mappings leave them unchanged. Existing entry, operation and payload budgets apply before publication. Partial deletion, malformed source or preflight failure leaves the source and output unchanged. Repeated calls reuse native intent.The shared TIFF ExifIFD merge/removal allowlist grows from 62 to 66 with these four tags. Native edits use the existing TIFF/BigTIFF/DNG, snapshot v1 and vector/stream/package paths. Byte-order conversion changes dimension and table rational words while preserving ASCII names and each UTF-16 string’s BOM and bytes. Public signatures, options and storage layouts remain unchanged; ABI 4 remains unfrozen and hosts synchronize shared objects.
Compatible-file transfer retains these four fields. Rendered-image transfer removes CFAPattern from both EXIF and XMP under the existing calibration policy. It does not transform image samples or infer a replacement pattern. This filtering applies to prepared source metadata. During a selective TIFF merge, a pre-existing destination CFAPattern remains when no removal intent selects it. An explicit dirty native CFAPattern deletion removes it in either transfer safety mode. Filtering alone does not create destination deletion intent. For compatible-file editing of an existing DNG, retain its original DNGVersion as source context, as described for the encoding/composite lifecycle above. Rendered-image filtering also removes this source version; DNG preparation then generates a version. To preserve an existing DNG container during these rendered-source metadata probes, prepare through the TIFF native edit route. This does not qualify rendered DNG pixels or DNG scaffold generation.
The combined fixture now covers 65 distinct ExifIFD tags across fifteen APIs; target transfer retains 62 after its existing three encoding-field exclusions. The structured batch includes JPEG, classic TIFF and BigTIFF, both TIFF byte orders, snapshot persistence, source fallback, native-only and retained-XMP round trips, Unicode and transactional failures. This is a supported-profile inventory, not a claim of complete EXIF or arbitrary RDF editing.
Layout references: CIPA DC-008-Translation-2023-E, Figures 16, 20, 21 and 23; CIPA DC-010-2024-E, corresponding EXIF/XMP structure mappings. Source PDFs and independent encoded-file qualification remain in OpenMeta-internal.
EXIF text and version metadata (0.5.9)¶
translate_xmp_exif_text_metadataand PythonDocument.translate_exif_text_metadataadd one bounded transaction for the following properties. Exact canonical namespaces are required.XMP property
Native ExifIFD tag
Value contract
exif:ExifVersion
9000
Four ASCII digits in UNDEFINED count 4; no NUL.
exif:FlashpixVersion
A000
0100in UNDEFINED count 4; no NUL.exif:UserComment
9286
Character-set prefix plus text; XMP scalar or
[@xml:lang=x-default].exifEX:ImageTitle
A436
ASCII or UTF-8 text; empty means unknown.
exifEX:Photographer, ImageEditor
A437, A438
ASCII or UTF-8 text; require explicit native IFD0 Artist.
exifEX:CameraFirmware, RAWDevelopingSoftware, ImageEditingSoftware, MetadataEditingSoftware
A439–A43C
ASCII or UTF-8 text; require explicit native IFD0 Software.
exifEX:CameraOwnerName, LensMake, LensModel
A430, A433, A434
ASCII or UTF-8 text. These overlap the earlier camera-text API.
Versions use four digits exactly. The API validates their syntax; accepting a future EXIF version number does not establish conformance with that future specification. FlashpixVersion is restricted to the defined
0100value.Text accepts ASCII or UTF-8
MetaValuetext with valid XML 1.0 characters. Whitespace, empty strings, carriage returns and supplementary Unicode characters are preserved. A leading BOM, embedded NUL, invalid UTF-8, UTF-16 source text or numeric source fails. Native type 2 and type 129 counts include one terminal NUL. Type 129 carries UTF-8 without a BOM. Plain ASCII output uses type 2. Decoded type 129 is retained on serialization, including ASCII-only payloads.The seven new tags and non-ASCII owner/lens text require an explicit effective ExifVersion of
0300or later. The effective version is the native version after this call’s selected conflict policy. The library does not upgrade it silently. Artist and Software must already exist as nonempty native text, with exactly one active entry. The caller supplies those values through authoring/editing; the translator does not infer them from photographer, editor or software details. General store validation checks field shapes and encodings. It is not a complete EXIF mandatory-tag/profile validator. These version and companion requirements belong to this translation contract.UserComment authoring uses
ASCII\0\0\0for ASCII. Non-ASCII usesUNICODE\0followed by UTF-8 for EXIF 3, or UTF-16LE with a BOM for older or missing versions. UNDEFINED comments do not require a terminal NUL. Native projection recognizes explicit UTF-16 BOMs in either version family. Without a BOM,UNICODEfollows the declared EXIF version: UTF-8 for EXIF 3 and the TIFF byte order for legacy UTF-16. The existing nonstandardUTF8marker is accepted for reading only. JIS and undefined character sets remain opaque; no guessed conversion or new charset dependency is introduced. Raw snapshots preserve the original bytes. An explicit semantic replacement preserves text rather than padding or the original character-set choice. Exact clean promotion in 0.8.10 retains both.Version changes cannot reinterpret retained comments or downgrade retained EXIF 3 text. Supply the comment source with
ReplaceExisting, or a dirty comment tombstone, when changing its encoding family. An explicit UTF-16 BOM keeps legacy comments readable independently of the version and TIFF byte order. The decoder recordsValueBigEndianfor native UserComment. Snapshot v1 layout and ABI 3 remain unchanged; BOM-less big-endian comment snapshots require a 0.5.9 reader. Older snapshots may lack provenance; reopen their original files with 0.5.9 to recover it.Portable output emits UserComment as one
rdf:Altwithx-default. Other language alternatives remain in XMP, including underCanonicalizeManaged. The reverse API chooses only the scalar/default source. It rejects eligible scalar/default duplicates and unsupported structured/indexed shapes. No locale is selected automatically. Invalid native comments do not hide valid source XMP.The 0.8.10 native lifecycle uses EXIF text translation contract 2. Under FailOnConflict or ReplaceExisting, an exact clean valid native match gains Dirty while keeping raw bytes, encoding, endian flags and wire provenance. This includes comment prefixes, explicit BOMs and padding, and ASCII stored as type 129 under EXIF 3. Dirty exact matches remain unchanged; PreserveExisting retains active values. Explicit replacements use the authoring encodings above. A ReplaceExisting version-family change re-encodes a selected matching comment; a legacy downgrade also rewrites selected ASCII owner/lens type 129 as type 2. Unselected type 129 and EXIF 3-only tags still block a legacy downgrade. Artist/Software companion requirements apply to promotions too.
Complete selected deletion preserves active native values under PreserveExisting, conflicts under FailOnConflict, and removes them under ReplaceExisting. Without an active value it promotes a clean tombstone, reuses a dirty tombstone, or adds an empty typed Dirty|Deleted marker: Bytes/U8 for versions and UserComment, Text for the other ten fields. Promotions and new markers consume an operation; new markers also consume an addition. Omitted or disabled sources retain native state, and all preflight failures leave output unchanged. All 13 fields now support native TIFF/BigTIFF/DNG selective merge/removal, including snapshot v1. The shared ExifIFD allowlist grows from 66 to 77; no public layout changes.
Defaults follow the capture APIs:
DirtyOnlyandFailOnConflict.PreserveExisting,ReplaceExisting, dirty tombstones, independent field switches, aliased source/output and complete failure rollback are supported. One call can add at most 13 entries, record 1,024 operations, read 65,536 text bytes per property and 1,048,576 total text bytes. Preparation may allocate; this is separate from prepared allocation-free patch application. Conflicting shared-object access remains the host’s responsibility; no atomics or mutexes are added.Serializer type-129 support also covers the EXIF-permitted IFD0 text fields: ImageDescription, Make, Model, Software and Artist. Copyright remains outside this extension because its two-part NUL-separated form needs a separate contract. The older camera-text translator keeps its printable-ASCII contract. SpectralSensitivity, BodySerialNumber and LensSerialNumber remain outside the UTF-8 extension.
The combined capture fixture covers 75 distinct ExifIFD tags across sixteen APIs. Compatible-file transfer retains 72 after the existing three encoding filters. IFD0 companion fields are separate from that inventory.
Compatibility qualification found that the installed OIIO reader aborts with
std::bad_allocon type-129 JPEG metadata. An isolated diagnostic changed only those type codes and read successfully. This is an external reader limitation; valid EXIF 3 output keeps type 129. The installed ExifTool also interpretsUNICODEas legacy UTF-16 regardless of ExifVersion. Direct TIFF byte checks qualify EXIF 3 text, ExifTool checks XMP, and FFmpeg verifies unchanged decoded pixels. Downstream application acceptance remains on hold.The wire rules follow CIPA EXIF 3.0 Table 4 and the type-129/tag definitions, and CIPA DC-010-2024 EXIF/XMP mappings. The original PDFs and the character-code table image remain in the private qualification evidence.
EXIF 3.1 development and correction data (0.5.11)¶
translate_xmp_development_correction_metadataand PythonDocument.translate_development_correction_metadataproject six EXIF 3.1 ExifIFD fields in one bounded transaction. The canonical XMP namespace ishttp://cipa.jp/exif/1.0/(normallyexifEX).XMP property
Native tag
Native value
exifEX:DevelopmentTypeA40D
One SHORT. The high and low bytes are each 1, 2 or 4.
exifEX:DevelopmentTypeDescriptionA40E
UTF-8 text, TIFF type 129 even when the text is ASCII.
exifEX:DistortionCorrectionA40F
SHORT 0 or 1.
exifEX:ChromaticAberrationCorrectionA410
SHORT 0 or 1.
exifEX:ShadingCorrectionA411
SHORT 0 or 1.
exifEX:NoiseReductionA412
SHORT 0 through 3.
DevelopmentTypeis an RDF resource with exactly the published childrenDevelopmentCharactersticandFactoryDefault. The spelling ofDevelopmentCharactersticis part of the wire contract. Root values, additional children, indexed forms, duplicate eligible sources and partial deletion fail without publishing a candidate. The description requires valid UTF-8 XML text; whitespace is preserved and no BOM or character-set conversion is inferred.The caller supplies
exif_versionas an explicit host policy. A selected source requires exactly300or310;0returnsIncompleteSource. The translator never creates, upgrades, downgrades or otherwise changes nativeExifVersion. This records the DC-0080300and DC-0100310source discrepancy without silently choosing one edition. Defaults remainDirtyOnlyandFailOnConflict.PreserveExisting,ReplaceExisting, dirty tombstones, per-field switches and resource limits follow the capture translation contract. The call can add at most six entries, read 65,536 bytes per property and 1,048,576 total source text bytes. Preparation may allocate; the commit is one transaction and conflicting shared-object access remains host-owned.Native validation, typed editing, canonical portable XMP and TIFF serialization share the same value checks. Portable output emits the packed A40D value as the two-child resource and emits A40E with type 129. Compatible-file and rendered- image transfer retain these standard processing-history fields when they are present. OpenMeta does not infer correction history from RAW or MakerNote data, and it does not add a value when the source has none.
The combined capture inventory is now 81 distinct ExifIFD tags across seventeen APIs; the six fields are new and do not overlap the prior 75-tag set. The profile and LearningOptOutIn contracts below are separate from the capture inventory and do not impose a complete-file profile.
EXIF 3.1 LearningOptOutIn data (0.5.12)¶
translate_xmp_learning_opt_out_in_metadataandDocument.translate_learning_opt_out_in_metadataproject one exacthttp://cipa.jp/exif/1.0/structure into ExifIFD tag0x9287(TIFF type 7). The selected source hasLearningOptOutIn/NumberOfSetsand either a typedLearningOptOutIn/Valuesarray or dense scalar leavesLearningOptOutIn/Values[1]through[2*n]. Each pair is usage/intention: the first usage is zero, usage values are unique, usage is 0..4 and intention is 0..2. Root values, sparse indexes, duplicate sources and partial deletion fail atomically. A dirty tombstone removes the native tag only withReplaceExisting.The caller supplies
exif_versionas300or310when a source is selected; the translator never creates or changes ExifVersion. The default policy isDirtyOnlyplusFailOnConflict;PreserveExisting,ReplaceExisting, bounded set/text/operation limits and host-owned synchronization follow the other translation contracts. Native type-7 bytes retainValueBigEndianprovenance, while new payloads use canonical little-endian words. Portable XMP emits the same structure as anrdf:Seq.Profile and authoring data (0.5.12)¶
translate_xmp_profile_metadataandDocument.translate_xmp_profile_metadataprovide one bounded transaction for the following exact properties:XMP source
Native destination
Requirements
tiff:ImageDescriptionIFD0
0x010ENon-empty valid EXIF text; ASCII uses TIFF type 2 and UTF-8 uses type 129.
tiff:ArtistIFD0
0x013BSame text contract as ImageDescription.
tiff:CopyrightIFD0
0x8298One scalar native part; an existing two-part NUL value is preserved or conflicts under the selected policy.
exif:ColorSpaceExifIFD
0xA001Numeric
1or65535, or the labelssRGBandUncalibrated.exif:RelatedSoundFileExifIFD
0xA004Printable ASCII 8.3 filename without path separators.
Namespaces and paths must match exactly. No ICC profile, image dimension, color agreement, audio-file association or companion inference is performed. Each selected field reconciles independently; duplicate eligible sources, invalid values, limits and conflicts fail before publication. Dirty tombstones remove native values only with
ReplaceExisting. Preparation may allocate and the commit is transactional; callers synchronize conflicting access to a sharedMetaStore.The 0.5.14 grouped lifecycle checked this contract after typed editing and through snapshot serialization and JPEG/classic TIFF/BigTIFF readback, including removal from an existing JPEG output. TIFF’s IFD0 merge retains destination tags absent from the prepared source. Before 0.6.0, source tombstones did not request native destination deletion there. Transfer preparation still applies its image-property policy: the host must explicitly supply the destination ColorSpace when the output requires that field. See profile editing through file writeback.
Since 0.6.0, explicit dirty native tombstones for IFD0 ImageDescription, Artist and Copyright survive preparation as typed TIFF removal instructions. This closes the deletion gap for those three fields when editing an existing TIFF/BigTIFF. Omission remains distinct from deletion. See the 0.6 migration contract.
JP2 and JPH qualification boundary¶
The existing JP2 writer path also accepts boxed JPH brands. It replaces selected Exif/XML carriers, preserves unknown UUID boxes and the codestream, and updates an existing
jp2h/colrICC child without synthesizing a missingjp2h. Focused tests cover ordinary and extended boxes, zero-length terminal boxes, positional scans that skip codestream bytes, and bothjp2andjphbrands. Real-file ICC/read-back and OIIO/iRAW consumer acceptance remain external qualification gates.
- 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.
The 0.8.11 native lifecycle adds selective TIFF/BigTIFF/DNG merge and removal for DevelopmentType, DevelopmentTypeDescription, DistortionCorrection, ChromaticAberrationCorrection, ShadingCorrection, NoiseReduction and LearningOptOutIn. The seven fields retain processing history or learning intent in both safety modes. Dirty native intent is explicit; omitted fields retain destination values. Version policy remains host supplied, with no inferred ExifVersion upgrade or complete-file profile conformance claim. LearningOptOutIn numeric words follow target TIFF byte order. Canonical encoding validates them before copying; other UNDEFINED fields keep their existing behavior.
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_specwhen 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 asopenmeta.TransferTargetImageSpec; the C++ and Pythonmetatransfercommand wrappers expose matching--target-*flags for smoke tests and file-helper integration checks.When a host edits portable XMP orientation or dimensions before direct native writing,
translate_xmp_image_geometry(...)can project those values into canonical TIFF/EXIF tags. It still requires the same target image spec and fails if XMP disagrees with the actual output raster. Width and height are stored-raster dimensions, not display-oriented dimensions after applying the orientation transform.For coarse transfer safety, use
TransferProfile::safety. The defaultCompatibleFilemode is for metadata repackage or recompression into a compatible target and preserves source camera/color metadata after the target-owned image-layout filter above.RenderedImageis 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.hexposes transfer hints such assafe,source_bound,rendered_unsafe, andrequires_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 acceptMetadataRawDataDescriptorso RAW-processing diagnostics can account for a known stored-RAW or rendered source context. Candidates and diagnostics also report independentsensitivity;safemeans 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_descriptorand passsource_raw_data_descriptor.encoding = MetadataRawDataEncoding::Rendered. Preparation then filters RAW-processing metadata even underCompatibleFile; 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 = trueand providehas_plane_index/plane_indexfor 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.As of 0.5.13, preparation applies these compression and plane restrictions to recognized curve/linearity entries when
has_source_raw_data_descriptoris true. Direct and snapshot preparation share this filter. Unknown context keeps conditional entries, and the prepared policy decision reports the actual removed-entry count withRawDataDescriptorFiltered(orSafetyModeFilteredwhen rendered-image safety takes precedence). This does not infer a decoder stage or validate the host’s descriptor against a codestream.Metadata group
Examples
CompatibleFileRenderedImageNotes
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 timeKeep
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 modeKeep
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 nameKeep 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/LeafColorMatrix1,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 tablesKeep 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/LeafSensorWidth,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 fieldsKeep 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(), andvendor_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 metadataKeep; 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
Keepcarries the original rawExifIFD:MakerNotepayload as unverified opaque bytes;Dropomits it; unavailableInvalidateandRewritefail closed toDropDrop
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 andmakernote_layout_transfer_audit_from_store(...)for bounded layout evidence. The layout audit identifies Nikon type 1 notes as outer-TIFF-dependent, can validate standard embedded-TIFF offsets in canonical Nikon type 3 notes, and conservatively identifies plausible Canon source-dependent IFD notes when the EXIF camera make is Canon. Canon recognition explicitly reports an ambiguous source offset basis and does not make the note rewritable. The audit 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
JPEGAPP1 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
TIFFroot 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
DNGsame as TIFF plus DNG target-mode policy and minimal
DNGVersionsynthesisUses 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
PNGeXIf, XMPiTXt,iCCPInsert prepared chunks after
IHDR; replace matching managed chunks; preserve unrelated chunksRequires valid PNG with terminal
IENDWebPEXIF, XMP RIFF chunk,ICCP, boundedC2PAReplace matching managed RIFF chunks; preserve unrelated chunks; patch
VP8Xfeature bitsEXIF/XMP/ICC edits require an existing
VP8XchunkJP2top-level
Exif, top-level XMPxmlbox,jp2h/colrICCReplace matching top-level metadata boxes; rewrite
jp2honly to replace/insertcolr; preserve unrelated boxes and unrelatedjp2hchildrenDoes not synthesize
jp2h; requires one existingjp2hfor ICCJXLtop-level
Exif, XMPxmlbox,jumb,c2paReplace matching top-level boxes; preserve signature and non-managed boxes; classify
jumbas generic JUMBF or C2PAICC is encoder handoff only; file edit emits uncompressed prepared metadata boxes
HEIF/AVIF/CR3BMFF metadata items (
Exif, XMPmime, JUMBF/C2PA), boundedcolr/profICC properties, plus OpenMeta-authored metadata-onlymetaboxesPreserve non-
metatop-level boxes; replace prior OpenMeta-authored metadatameta; merge/replace/strip item metadata in parseable foreign top-levelmetagraphs by extendingiinf/iloc/idat/iref; remap unambiguous managed item replacements acrossiref/version-0grpl/ipma; consolidate multiple validipmatables; replace prior ICCcolrproperties and remapiprp/ipco/ipmafor bounded ICCDoes not rewrite arbitrary BMFF scene/property graphs
EXRsafe 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
When any decoded IPTC dataset is dirty, JPEG APP13 and TIFF tag 33723 payloads are rebuilt from the active decoded datasets. A preserved raw Photoshop IPTC resource is used only while those datasets remain untouched, so translated or edited native IPTC cannot be shadowed by stale raw bytes.
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
SubIFDreplacement with downstream auxiliary-tail preservationpreserving an existing target
InteropIFDwhen a replacedExifIFDomits 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
SubIFDstructures, 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 DNGExtraCameraProfiles(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_specor 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.
ExistingTargetandTemplateTargetrequire a backing target container.MinimalFreshScaffoldcan 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.Since 0.8.10, existing/template preparation does not generate a missing source DNGVersion and excludes a clean primary source DNGVersion from the update. The destination version therefore stays intact. An eligible dirty version can replace it under CompatibleFile; RenderedImage retains its RAW filtering and drops that source version edit. MinimalFreshScaffold still synthesizes 1.6.0.0 when required. Direct TIFF serialization options keep their existing behavior. Existing/template removal-only preparation succeeds without a fabricated EXIF block; the existing target supplies its DNG core metadata.
PNG¶
The PNG edit path requires a valid PNG signature, an
IHDRchunk, and a terminalIENDchunk.Prepared
eXIf, XMPiTXt, andiCCPchunks are inserted immediately afterIHDR. Existing chunks from those managed families are removed when a replacement or strip policy targets that family. XMP matching is limited toiTXtchunks using theXML:com.adobe.xmpkeyword.All unrelated chunks are preserved. Bytes following the terminal
IENDare 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 boundedC2PAchunks replace existing chunks from the same managed family. Unrelated chunks are preserved. When EXIF, XMP, or ICC is present after rewrite, OpenMeta patches the existingVP8Xfeature flags to match the final metadata state.Prepared WebP
EXIFchunks carry the TIFF byte stream directly. They do not include the JPEG APP1Exif\0\0preamble.The current WebP edit contract requires an existing
VP8Xchunk for EXIF, XMP, or ICC metadata edits. It does not synthesizeVP8X.JP2¶
The JP2 edit path requires a valid JP2 signature box and file-type box.
Prepared top-level
Exifand XMPxmlboxes replace existing top-level boxes from the same managed family. This includes the EXIF UUID4a706754-6966-6645-7869-662d3e4a5032and Adobe XMP UUIDbe7acfcb-97a9-42e8-9c71-999491e3afac. All matching carriers are removed for the selected family; replacement uses the preparedExiforxmlroute. Unselected families, unknown UUIDs, IPTC and GeoTIFF UUID boxes remain intact.The same box edit path accepts boxed JPH sources. It preserves codestream bytes without decoding them. Raw J2K/J2C codestreams require a host-supplied container and are not inputs to this edit path. A preserved zero-length box stays last; new metadata is inserted before it. Extended sizes and truncated UUID headers are checked before any edit output is produced.
ICC update uses the bounded
jp2h/colrroute. OpenMeta rewrites the existingjp2hbox to replace existingcolrchildren with the prepared ICCcolrpayload, while preserving unrelatedjp2hchildren. If nocolrchild exists, the preparedcolrchild is inserted. The contract requires one existingjp2hbox and does not synthesize a newjp2hbox.JXL¶
The JXL edit path requires a valid JXL container.
Prepared top-level
Exif, XMPxml,jumb, andc2paboxes 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 genericjumbreplacement 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
brobmetadata boxes by real type. The file edit path emits prepared metadata boxes directly; thejxl:icc-profileroute remains an encoder-side handoff and is not serialized by the file edit path.HEIF / AVIF / CR3¶
The bounded BMFF edit path preserves non-
metatop-level boxes as source ranges.When the target has no foreign top-level
metabox, OpenMeta writes one metadata-only top-levelmetabox using the public bounded contract. That box can contain prepared Exif, XMP, JUMBF, C2PA, and ICCcolrproperty payloads. A prior OpenMeta-authored metadatametabox is removed and replaced by the newly prepared box.When the target already has a foreign top-level
metabox, OpenMeta does not append a second competingmetagraph. For parseable HEIF/AVIF-style item graphs it merges, replaces, or strips bounded Exif/XMP/JUMBF/C2PA metadata items in the existingmetaby extendingiinf,iloc,idat, andirefwithcdscreferences to the primary item. This constrained merge requires a single parseableiinf,ilocversion 0/1/2,pitm, and at most oneidat. When inserted metadata needs an item ID wider than 16 bits, OpenMeta upgrades the rebuiltilocto version 2, emitsinfeversion 3 for those inserted items, and usesirefversion 1 for the correspondingcdscreferences. 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
idatpayload. To preserve broad reader compatibility, theirilocrecords keep construction method 0 and use absolute file-offset extents. Compact valid graphs with an omitted offset field or offset/length fields too narrow for the inserted payloads are normalized to explicit 32-bit fields. Omitted extent lengths are rejected because their source-to-end semantics cannot be preserved safely when the graph grows. When all retained self-contained item locations can be represented as absolute extents, OpenMeta compacts the rebuiltilocbase-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-0dinf/drefurlorurnentry. 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 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
irefrelation endpoints, version-0grplitem-group members, andipmaassociations. 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.If a supported foreign
iprpcontains multiple validipmaboxes, OpenMeta merges their entries by item ID and emits one deterministic consolidatedipmain first-seen item and property-association order. Repeated property associations are deduplicated, and the association remains essential when any source table marks it essential. Every input table is validated before output is produced; malformed tables, unsupported versions, aggregate table, entry, or association overflow fail the complete edit instead of producing a partial graph. Multiple competingipcoproperty containers remain unsupported.For bounded ICC transfer, OpenMeta removes prior ICC
colr/profandcolr/rICCproperties fromiprp/ipco, compacts/remaps existingipmaassociations, appends the transferredcolr/profproperty, 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
metabox and from parseable foreign top-levelmetaitem graphs that satisfy the same bounded primary-item contract. Foreign graphs withoutpitm, with unsupportediloc, 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 host 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 adouble, before writer construction, then patch exactly those value bytes after close. That operation remains owned by the host EXR writer for the current roadmap. OpenMeta supplies the prepared attribute value but does not patch an existing EXR file; variable-length header changes could otherwise 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
jp2hor WebPVP8Xstructuresfile-level EXR metadata rewrite
signed C2PA rewrite or trust-policy parity beyond the bounded staged handoff paths
- page XMP Sync And Writeback Policy
For the combined capture audit, shared-target composition and the 0.5.5 portable round-trip fixes, see Capture synchronization milestone.
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_exiftrueGenerate portable XMP properties from EXIF/TIFF/GPS fields.
PrepareTransferRequest::xmp_project_iptctrueGenerate portable XMP properties from IPTC-IIM fields.
PrepareTransferRequest::xmp_include_existingtrueInclude existing XMP already decoded into the source
MetaStore.PrepareTransferRequest::xmp_conflict_policyCurrentBehaviorEmit generated EXIF properties, then existing XMP, then generated IPTC properties.
xmp_existing_sidecar_modeIgnoreDo not merge a destination sidecar unless explicitly requested.
xmp_existing_destination_embedded_modeIgnoreDo not merge destination embedded XMP unless explicitly requested.
xmp_writeback_modeEmbeddedOnlyKeep generated XMP in the managed embedded carrier.
xmp_destination_embedded_modePreserveExistingPreserve existing embedded XMP when sidecar-only writeback suppresses generated embedded XMP.
xmp_destination_sidecar_modePreserveExistingPreserve an existing sibling
.xmpwhen embedded-only writeback is used.Native EXIF and IPTC carrier emission is independent from XMP projection. Turning off
xmp_project_exiforxmp_project_iptcsuppresses 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_precedencesidecar before source (
SidecarWins)source before sidecar (
SourceWins)destination embedded XMP vs source embedded XMP
xmp_existing_destination_embedded_precedencedestination before source (
DestinationWins)source before destination (
SourceWins)destination sidecar vs destination embedded XMP
xmp_existing_destination_carrier_precedencesidecar 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 whenxmp_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_precedencedecides 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_policydecides 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
CurrentBehaviorEXIF-derived, existing XMP, IPTC-derived
EXIF projection wins over existing XMP; existing XMP wins over IPTC projection.
ExistingWinsexisting XMP, EXIF-derived, IPTC-derived
Existing XMP wins over generated EXIF/IPTC projection.
GeneratedWinsEXIF-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_policyapplies inside the existing-XMP pass:PreserveAllkeeps existing standard portable namespace entries subject to the conflict order above.CanonicalizeManageddrops OpenMeta-managed standard portable properties from existing XMP when a generated replacement exists.
xmp_existing_namespace_policycontrols breadth:KnownPortableOnlykeeps only standard portable namespaces known to OpenMeta.PreserveCustomalso preserves safe simple or indexed properties from custom namespaces.
Paired IPTC Creation Dates¶
Portable IPTC projection composes these record-2 dataset pairs before applying the conflict policy:
IPTC-IIM datasets
Portable XMP property
DateCreated(2:55) plus optionalTimeCreated(2:60)photoshop:DateCreatedDigitalCreationDate(2:62) plus optionalDigitalCreationTime(2:63)xmp:CreateDateDates must use the IPTC
YYYYMMDDform and pass Gregorian calendar validation. Times must useHHMMSSwith an optional+HHMMor-HHMMoffset. OpenMeta normalizes accepted values to XMP date/date-time syntax, including a colon in the UTC offset.The first valid non-deleted date and time occurrence in each pair is used. A valid date emits as date-only when its time companion is absent or malformed. A time without a valid date emits nothing. Existing-XMP conflict behavior is the same as for other generated IPTC properties.
CanonicalizeManagedremoves an existing managed date only when strict composition produced a valid replacement.Writeback Modes¶
Writeback mode controls where the generated XMP packet goes after transfer execution.
Mode
Edited file
Sibling
.xmpCleanup behavior
EmbeddedOnlyGenerated XMP stays in the managed embedded carrier.
No generated sidecar output.
Existing sidecar is preserved unless
xmp_destination_sidecar_mode == StripExisting.SidecarOnlyGenerated embedded XMP blocks are suppressed.
Generated XMP is returned as sidecar output.
Existing embedded XMP is preserved unless
xmp_destination_embedded_mode == StripExisting.EmbeddedAndSidecarGenerated 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 whenremove_destination_xmp_sidecaris 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_pathwhen provided, otherwise from the edit/output target path. Hosts that do not have a filesystem path can setxmp_existing_destination_sidecar_stateexplicitly 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_sidecaris 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

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.
What OpenMeta DoesScan containers to locate metadata blocks in JPEG, PNG, WebP, GIF, TIFF/DNG, JP2, JXL, ISO-BMFF (HEIF/AVIF/CR3), CRW/CIFF, RAF, and X3F files.
Reassemble chunked payloads and optionally decompress supported carriers.
Decode metadata into a normalized
MetaStore.Create a fresh finalized metadata store from bounded logical portable fields.
Edit logical portable fields transactionally without mutating the source store.
Export sidecars and previews.
Prepare, compile, emit, and edit metadata transfers for bounded target families.
Camera RAW names do not all identify separate OpenMeta scanners. Many camera formats share a TIFF/EXIF metadata carrier, while CR3, CRW, RAF, and X3F need dedicated container handling.
Read lane
Camera RAW families
Current metadata scope
Shared TIFF/EXIF carrier
DNG, CR2, NEF/NRW, ARW, RW2, ORF, PEF, SR2/SRF, and other TIFF-based RAW
Strong common TIFF/EXIF decoding; MakerNote and vendor-private interpretation varies by family and model. Legacy SR2/SRF coverage includes the shared metadata carrier, not every native private structure.
Dedicated ISO-BMFF lane
CR3
Bounded EXIF/XMP/ICC, Canon maker blocks, and metadata item/property graph interpretation; not complete CR3 private-structure conformance.
Dedicated native lanes
CRW/CIFF, RAF, X3F
Partial native container and private metadata interpretation with raw preservation where the structure is not safely understood.
Vendor metadata for additional camera families is interpreted where layouts are stable and testable; that does not imply that every model-specific private table is named. In this documentation, camera RAW read support means metadata carrier discovery plus the documented structured interpretation. It does not mean RAW pixel decoding, raw-sample decompression, demosaicing, complete vendor private-data decoding, or native camera RAW writing. Apart from the bounded DNG and CR3 target contracts described below, read support does not imply write support.
For vendor-by-vendor depth and known gaps, see docs/raw_read_parity_plan.md.
Metadata FamiliesOpenMeta currently covers these major families:
EXIF, including pointer IFDs and broad MakerNote support.
Legacy Canon CRW/CIFF bridge with bounded native CIFF naming and projection.
XMP as RDF/XML properties.
ICC profile header and tag table.
Photoshop IRB, with raw preservation plus a bounded interpreted subset.
IPTC-IIM datasets.
JPEG comments, GIF comments, and PNG text chunks.
ISO-BMFF derived fields for brand, primary-item, item-semantic, relation, whole-scene graph policy, and auxiliary semantics.
JUMBF / C2PA draft structural and semantic projection.
EXR header attributes.
C2PA security warning: the optional verification scaffold is diagnostic only and must not be used as an asset-authenticity or trust gate. It does not currently establish the manifest’s hard binding to the complete asset. Cryptographic signature success is reported as
signature_verified_only.For the detailed support matrix, see docs/metadata_support.md.
Start HereIf you are new to the project, start with docs/quick_start.md.
That guide covers the shortest useful paths for:
reading and querying metadata in C++
building and editing
MetaStorecopying metadata into an existing JPEG, TIFF, or DNG target
building EXR and host-API metadata outputs
using the optional Adobe DNG SDK bridge
If you already own the encoder, SDK objects, or output container, follow docs/host_integration.md next. High-throughput and realtime hosts should also use docs/host_adoption_profile.md as the narrow versioned read/state compatibility boundary and docs/prepared_transfer_handoff.md for stable prepare-once typed codec handoff.
Documentationhttps://ssh4net.github.io/OpenMeta/: published documentation site
docs/quick_start.md: shortest adoption path
docs/host_integration.md: C++ host and encoder integration patterns
docs/host_adoption_profile.md: stable positional read, snapshot persistence, reconciliation, and diagnostic profile
docs/prepared_transfer_handoff.md: stable target preparation and allocation-free typed operation replay
docs/metadata_support.md: metadata support matrix
docs/metadata_transfer_plan.md: transfer status and roadmap
docs/fuzzy_search.md: optional ranked metadata-name search contract, quality gates, and benchmark
docs/creation.md: bounded fresh metadata construction, field mapping, validation, and Python use
docs/editing.md: transactional logical add, set, remove, provenance, conflict, and Python behavior
docs/shared_library.md: shared-library ABI, toolchain, runtime, and installed-consumer contract
docs/migration_0_7.md: development ABI-4 policy and grouped EXIF timestamp deletion and synchronization.
docs/migration_0_6.md: ABI-4 rebuild and explicit native TIFF deletion contract
docs/doxygen.md: API reference
SECURITY.md: security model and reporting
NOTICE.md: notices and third-party dependency information
EXIF and MakerNote display names have two layers:
Canonical names from
exif_tag_name(...)ExifTool-compatible display names from
exif_entry_name(..., ExifTagNamePolicy::ExifToolCompat)
That split lets OpenMeta keep stable internal naming while still matching common external tooling where compatibility matters.
Transfer and EditOpenMeta now has a real transfer core built around:
prepare_metadata_for_target(...)compile_prepared_transfer_execution(...)execute_prepared_transfer(...)execute_prepared_transfer_file(...)
Current target status is described in terms of bounded metadata operations, not complete arbitrary container or image writers:
Target
Current contract
JPEG
Strongest current managed-metadata edit path
TIFF
Strongest current managed-metadata edit path, with documented nested-IFD bounds
DNG
Strong TIFF-backed metadata target; not a general DNG image writer
PNG
Bounded managed-metadata edit path
WebP
Bounded managed-metadata edit path
JP2
Bounded managed-metadata edit path
JXL
Bounded managed-metadata edit path
HEIF / AVIF / CR3
Bounded ISO-BMFF metadata-graph edit path with managed item relation/property remapping
EXR
Bounded host attribute emission; no full EXR file rewrite
In practice:
JPEG, TIFF, and DNG are the strongest transfer targets today.
TIFF edit support now covers classic TIFF, BigTIFF, bounded preview-page chain rewrite (
ifd1,ifd2, and preserved downstream tails), and bounded SubIFD rewrite with preserved downstream auxiliary tails and preserved trailing existing children when only the front subset is replaced. ReplacedExifIFDblocks can also preserve an existing targetInteropIFDwhen the source does not supply its own interop child.DNG is now a dedicated public transfer target layered on the TIFF backend. The current bounded DNG contract covers read-backed file-helper roundtrips,
DNGVersionpreservation, minimalDNGVersionsynthesis when the source metadata lacks it, bounded preview-page chain rewrite/merge, bounded raw-imageSubIFDrewrite/merge, preserved downstream page/aux tails, preserved trailing existing auxiliary children, and boundedExifIFD -> InteropIFDpreservation. When a non-DNG source is merged into an existing DNG target, the target’s core DNG tags and preview/raw structure are preserved under that same bounded contract. The public DNG transfer contract is now explicit:ExistingTargetTemplateTargetMinimalFreshScaffoldExisting/template modes require a target path in the file-helper flow; minimal fresh scaffold keeps the metadata-only DNG prepare path available without claiming a full standalone DNG writer.
When built with
OPENMETA_WITH_DNG_SDK_ADAPTER=ONand adng_sdkpackage is available, OpenMeta also exposes dng_sdk_adapter.h as an optional host bridge for applying prepared DNG-target metadata onto Adobe DNG SDKdng_negative/dng_streamobjects. That bridge now includes:direct prepared-bundle apply/update entry points for SDK object owners
a public file-helper for
source file -> existing DNG filein-place metadata updatea matching thin Python binding over that file-helper
a thin CLI helper via
metatransfer --update-dng-sdk-file <target.dng>CoreDngtransfer support does not depend on that SDK. The OpenMeta build must use a C++ runtime/standard library compatible with the discovereddng_sdkpackage. Public automated CI intentionally excludes this SDK-backed lane because Adobe DNG SDK licensing and redistribution terms are not part of the public CI dependency story; SDK-backed coverage is treated as maintainer or release validation.
PNG, WebP, JP2, JXL, bounded BMFF, and EXR all have implemented, bounded transfer entry points. BMFF file edits can replace OpenMeta-authored metadata-only
metaboxes and can merge, replace, or strip bounded Exif/XMP/JUMBF/C2PA metadata items plus bounded ICCcolr/profproperties in a parseable foreign top-levelmetagraph. Arbitrary BMFF scene/property-graph rewrite remains out of scope for the bounded writer path.EXR is still narrower than the container-edit targets: it emits safe string header attributes through the transfer core, can materialize a prepared
ExrAdapterBatchfor host exporters, and Python can inspect that prepared EXR attribute batch through the directbuild_exr_attribute_batch_from_filebinding or the helper-layeropenmeta.python.get_exr_attribute_batch(...), but OpenMeta does not rewrite full EXR files yet.Writer-side sync behavior is now partially explicit instead of implicit: generated XMP can independently keep or suppress EXIF-derived and IPTC-derived projection during transfer preparation.
Generated portable XMP also has an explicit conflict policy for existing decoded XMP versus generated EXIF/IPTC mappings: current behavior,
existing_wins, orgenerated_wins.Generated portable XMP now also has an explicit existing-namespace policy: keep only OpenMeta’s known portable namespaces, or preserve safe custom existing namespaces with deterministic generated prefixes.
Transfer preparation can also fold an existing sibling
.xmpsidecar from the destination path into generated portable XMP when that bounded mode is requested, with explicitsidecar_winsorsource_winsprecedence against source-embedded existing XMP.Transfer preparation and file-helper execution can also fold existing embedded XMP from the destination file into generated portable XMP when that bounded mode is requested, with explicit
destination_winsorsource_winsprecedence against source-embedded existing XMP.File-helper execution,
metatransfer, and the Python transfer wrapper now share a bounded XMP carrier choice: embedded XMP only, sidecar-only writeback to a sibling.xmp, or dual embedded-plus-sidecar writeback when a generated XMP packet exists for the prepared transfer.metatransferand the Python transfer wrapper also expose the bounded destination-embedded merge controls directly instead of hiding them behind lower-level bindings.Sidecar-only writeback also has an explicit destination embedded-XMP policy: preserve existing embedded XMP by default, or strip it for
jpeg,tiff,png,webp,jp2, andjxl.Embedded-only writeback can also strip an existing sibling
.xmpdestination sidecar explicitly, so exports can move back to embedded-only XMP without leaving stale sidecar state behind.C++ hosts now also have a bounded persistence helper for file-helper results, so edited output bytes, generated sidecars, and stale-sidecar cleanup can be applied without copying wrapper logic.
Python hosts also have matching
transfer_file(...)andunsafe_transfer_file(...)bindings, and the public Python transfer wrapper now uses that same core-backed persistence path for real writes.Prepared bundles record resolved policy decisions for MakerNote, JUMBF, C2PA, EXIF-to-XMP projection, and IPTC-to-XMP projection.
This is still not a full MWG-style sync engine. OpenMeta does not yet try to solve all EXIF/IPTC/XMP conflict resolution or full canonical writeback policy.
For transfer details, see docs/metadata_transfer_plan.md.
ToolsOpenMeta ships a small set of CLI tools:
Tool
Purpose
metareadHuman-readable metadata dump
metavalidateMetadata validation and issue reporting
metadumpSidecar and preview dump tool
metatransferTransfer/edit smoke tool over the core transfer APIs
thumdumpPreview extractor
The optional Python bindings remain a thin layer over the same C++ read, query, fuzzy-search, creation, editing, and transfer core. Available Python features follow the capabilities compiled into the C++ library.
Layoutsrc/include/openmeta/: public headerssrc/openmeta/: library implementationsrc/tools/: CLI toolssrc/python/: Python bindings and helper scriptstests/: unit tests and fuzz targetsdocs/: design notes and developer documentation
Read-path coverage is broad and regression-gated. Write/edit support is real for the main transfer targets, but parts of that API surface are still draft and may change as the transfer contract stabilizes.
The following values are roadmap estimates for the currently tracked public scope. They are not percentages of every vendor tag or file in existence, full format conformance, direct competitor parity, or overall product completion.
Milestone
Status
Decoding/read milestone for the current target scope
About
98-100%Transfer / export milestone
About
85-90%Creation, Editing, Translation, Writing, Adapters, and Utilities have separate readiness levels. See docs/development.md for the full stage table.
Current baseline-gated snapshot on tracked corpora:
HEIC/HEIF, CR3, and mixed RAW EXIF tag-id compare gates are passing.
EXR header metadata compare is passing for name/type/value-class checks.
Portable and lossless sidecar export paths are covered by baseline and smoke gates.
MakerNote decode is baseline-gated with broad vendor support; unknown tags are preserved losslessly when no structured mapping exists.
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release cmake --build build
Useful options:
-DOPENMETA_BUILD_STATIC=ON|OFFand-DOPENMETA_BUILD_SHARED=ON|OFFto select library variants-DOPENMETA_BUILD_TOOLS=ON|OFF-DOPENMETA_BUILD_TESTS=ONfor GoogleTest-based unit tests-DOPENMETA_BUILD_FUZZERS=ONfor Clang + libFuzzer targets-DOPENMETA_BUILD_PYTHON=ONfor the optional nanobind bindings-DOPENMETA_BUILD_WHEEL=ONto add the isolated Python wheel target-DOPENMETA_WITH_ZLIB=ON,-DOPENMETA_WITH_BROTLI=ON, and-DOPENMETA_WITH_EXPAT=ONto request compressed metadata and structured XMP decoding. These capabilities are enabled only when CMake discovers the matching dependency.-DOPENMETA_ENABLE_RAPIDFUZZ=ONfor optional RapidFuzz-backed fuzzy search-DOPENMETA_ENABLE_C2PA_VERIFY=ONfor the draft diagnostic verification scaffold. Do not use its current result as an authenticity or trust gate.-DOPENMETA_USE_LIBCXX=ONwhen linking against dependencies built withlibc++-DOPENMETA_TEST_RUNTIME_LIBRARY_PATH=/path/to/runtime-libswhen CTest launches external tools that need a non-default C++ runtime lookup path-DOPENMETA_WITH_DNG_SDK_ADAPTER=ONto enable the optional Adobe DNG SDK bridge (requires a discoverabledng_sdkpackage; intentionally excluded from public GitHub Actions CI)-DOPENMETA_BUILD_DOCS=ONfor Doxygen HTML docs-DOPENMETA_BUILD_SPHINX_DOCS=ONfor Sphinx + Breathe HTML docs
Developer notes live in docs/development.md.
Quick UsageThe shortest CLI path is:
./build/metaread file.jpg ./build/metatransfer --source-meta source.jpg --target-jpeg rendered.jpg --output rendered_with_meta.jpg --force
For C++, host-API, and Python examples, use docs/quick_start.md.