Developer Notes¶
Repository layout (public):
src/include/openmeta/: public headerssrc/openmeta/: implementationsrc/tools/: CLI toolssrc/python/: Python bindings and helper scriptstests/: unit tests and fuzz targets
Read-path coverage snapshot¶
Tracked HEIC/HEIF, CR3, and mixed RAW EXIF compare gates are passing.
EXR header metadata compare gate is passing for the documented name/type/value-class contract.
MakerNote support is broad and baseline-gated; unknown tags remain lossless.
EXIF + MakerNotes (code organization)¶
Core EXIF/TIFF decoding:
src/openmeta/exif_tiff_decode.ccCRW/CIFF decode + derived EXIF bridge:
src/openmeta/crw_ciff_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)Unit tests for MakerNote paths:
tests/makernote_decode_test.cc
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.MakerNote tag-name tables are generated from
registry/exif/makernotes/*.jsonland looked up via binary search (exif_makernote_tag_names.cc).
Interop adapters¶
Core traversal API:
src/include/openmeta/interop_export.hOIIO adapter (flat name/value):
src/include/openmeta/oiio_adapter.hOCIO adapter (namespace tree):
src/include/openmeta/ocio_adapter.hEXR adapter (per-part attribute batch):
src/include/openmeta/exr_adapter.h
Notes:
ExportNamePolicy::ExifToolAliasandExportNamePolicy::Specare both covered by interop tests and used for split-parity workflows.OIIO export keeps numeric unknown names (
Exif_0x....) andExif:MakerNotewhen values are empty so parity checks remain stable.
Python binding entry points:
Document.export_names(...)Document.oiio_attributes(...)Document.unsafe_oiio_attributes(...)Document.oiio_attributes_typed(...)Document.unsafe_oiio_attributes_typed(...)Document.ocio_metadata_tree(...)Document.unsafe_ocio_metadata_tree(...)Document.dump_xmp_sidecar(...)(lossless or portable via format switch)
C++ adapter entry points:
safe API:
collect_oiio_attributes_safe(..., InteropSafetyError*)unsafe API:
collect_oiio_attributes(...)collect_oiio_attributes(..., const OiioAdapterRequest&)inopenmeta/oiio_adapter.h(stable flat request API)collect_oiio_attributes(..., const OiioAdapterOptions&)(advanced/legacy shape)safe typed API:
collect_oiio_attributes_typed_safe(..., InteropSafetyError*)unsafe typed API:
collect_oiio_attributes_typed(...)collect_oiio_attributes_typed(..., const OiioAdapterRequest&)(typed values)collect_oiio_attributes_typed(..., const OiioAdapterOptions&)(typed values) typed payload model:OiioTypedValue/OiioTypedAttributebuild_exr_attribute_batch(...)inopenmeta/exr_adapter.hexports one owned EXR-native attribute batch (part_index,name,type_name,value,is_opaque) 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 callbacks
Python typed behavior:
Document.oiio_attributes(...)is safe-by-default and raises on unsafe raw byte payloads; useDocument.unsafe_oiio_attributes(...)for legacy/raw fallback output.Document.oiio_attributes_typed(...)decodes text values to Pythonstrin safe mode and raises on unsafe/invalid text bytes.Document.unsafe_oiio_attributes_typed(...)returns raw text bytes for explicit unsafe workflows.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.safe API:
build_ocio_metadata_tree_safe(..., InteropSafetyError*)unsafe API:
build_ocio_metadata_tree(...)build_ocio_metadata_tree(..., const OcioAdapterRequest&)inopenmeta/ocio_adapter.h(stable flat request API)build_ocio_metadata_tree(..., const OcioAdapterOptions&)(advanced/legacy shape)
C++ XMP sidecar entry points:
dump_xmp_sidecar(..., const XmpSidecarRequest&)inopenmeta/xmp_dump.h(stable flat request API)dump_xmp_sidecar(..., const XmpSidecarOptions&)(advanced/legacy shape)
Optional dependencies¶
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) using a streaming parser with strict limits.zlib (
OPENMETA_WITH_ZLIB): inflates Deflate-compressed payloads such as 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.
CLI tool¶
metaread prints a human-readable dump of blocks and decoded entries
(EXIF/TIFF-IFD tags, XMP properties, IPTC-IIM datasets, ICC profile fields/tags,
and Photoshop IRB resource blocks). Output is ASCII-only and truncated by
default to reduce terminal injection risk.
metavalidate reports decode/validation issues in text or JSON and emits
machine-readable issue codes (for example xmp/output_truncated and
xmp/invalid_or_malformed_xml_text) suitable for CI gating.
Python¶
Python bindings use nanobind. The wheel also ships helper scripts as
openmeta.python.* modules.
python3 -m openmeta.python.metaread file.jpg
python3 -m openmeta.python.metadump --format portable file.jpg
python3 -m openmeta.python.metadump file.jpg output.xmp
python3 -m openmeta.python.metadump --format portable --c2pa-verify --c2pa-verify-backend auto file.jpg
python3 -m openmeta.python.metadump --format portable --portable-include-existing-xmp --xmp-sidecar file.jpg
Resource policy defaults¶
For C++ callers, initialize from recommended_resource_policy() and only
override fields you need:
#include "openmeta/resource_policy.h"
openmeta::OpenMetaResourcePolicy policy
= openmeta::recommended_resource_policy();
policy.jumbf_limits.max_box_depth = 24; // optional override
For JUMBF/C2PA preflight traversal checks, call
measure_jumbf_structure(bytes, policy.jumbf_limits) before full decode.
Other preflight estimate APIs use the same bounded-options model:
measure_scan_auto(file_bytes)measure_scan_jpeg(bytes),measure_scan_png(bytes),measure_scan_webp(bytes),measure_scan_gif(bytes),measure_scan_tiff(bytes),measure_scan_jp2(bytes),measure_scan_jxl(bytes),measure_scan_bmff(bytes)measure_exif_tiff(exif_bytes, exif_options)measure_xmp_packet(xmp_bytes, xmp_options)measure_icc_profile(icc_bytes, icc_options)measure_iptc_iim(iptc_bytes, iptc_options)measure_photoshop_irb(irb_bytes, irb_options)measure_exr_header(exr_bytes, exr_options)measure_jumbf_payload(jumbf_bytes, jumbf_options)
Documentation build¶
Sphinx docs require:
doxygenPython packages listed in
docs/requirements.txt
uv pip install -r docs/requirements.txt
cmake -S . -B build -DOPENMETA_BUILD_SPHINX_DOCS=ON
cmake --build build --target openmeta_docs_sphinx