This guide is for the normal OpenMeta use case: a C++ application that needs to read, query, prepare, and transfer image metadata.
OpenMeta is a metadata engine, not an image encoder. In practice that means:
- read metadata from an existing file
- query it through
MetaStore - build new metadata entries when needed
- inject metadata into an existing target file or template
- prepare metadata artifacts for a host API such as EXR or OpenImageIO
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.
If OpenMeta is installed as a package:
find_package(OpenMeta CONFIG REQUIRED)
add_executable(my_app main.cc)
target_link_libraries(my_app PRIVATE OpenMeta::openmeta)If you build OpenMeta from source in the same workspace, any normal
add_subdirectory(...) or install-and-find-package workflow is fine. The
public target alias is OpenMeta::openmeta.
Library and tools:
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build buildTests:
cmake -S . -B build-tests -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DOPENMETA_BUILD_TESTS=ON
cmake --build build-tests
ctest --test-dir build-testsIf 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-dngThis 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.
OpenMeta does not currently ship a fuzzy-search layer. The main lookup API is
exact-key lookup through MetaStore::find_all(...).
#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
If you need fuzzy or text-oriented search, build that on top of MetaStore
using your own index or display-name layer.
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:
For portable sidecar output:
#include "openmeta/xmp_dump.h"
std::vector<std::byte> xmp_bytes;
openmeta::XmpSidecarRequest request;
request.format = openmeta::XmpSidecarFormat::Portable;
request.include_exif = true;
request.include_iptc = true;
const openmeta::XmpDumpResult dump =
openmeta::dump_xmp_sidecar(store, &xmp_bytes, request);For lossless OpenMeta-native sidecars, switch request.format to
XmpSidecarFormat::Lossless.
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.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::Jxl- bounded BMFF targets such as
Heif,Avif, andCr3
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 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, OIIO, or its own EXR code.
For flattened metadata export:
#include "openmeta/oiio_adapter.h"
std::vector<openmeta::OiioTypedAttribute> attrs;
openmeta::OiioAdapterRequest request;
openmeta::collect_oiio_attributes_typed(store, &attrs, request);This is useful when the host wants typed name/value attributes instead of raw container payloads.
For host-owned encoders, the transfer core exposes two patterns:
- implement a backend emitter such as
JpegTransferEmitterorJxlTransferEmitter - or build a target-neutral adapter view and consume explicit operations
Minimal JPEG/JXL-style pattern:
#include "openmeta/metadata_transfer.h"
openmeta::PrepareTransferFileOptions prepare;
prepare.prepare.target_format = openmeta::TransferTargetFormat::Jxl;
openmeta::PrepareTransferFileResult prepared =
openmeta::prepare_metadata_for_target_file("source.jpg", prepare);
openmeta::PreparedTransferExecutionPlan plan;
openmeta::compile_prepared_transfer_execution(
prepared.bundle, openmeta::EmitTransferOptions {}, &plan);
// Then either:
// - implement openmeta::JxlTransferEmitter and call
// emit_prepared_transfer_compiled(...)
// - or build_prepared_transfer_adapter_view(...) and feed the ops into your
// own backend abstractionOpenMeta does not currently ship a TurboJPEG-specific wrapper, but the JPEG
transfer path is designed for that kind of integration through
JpegTransferEmitter and the adapter-view APIs.
For fuller C++ host-side examples, see host_integration.md.
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.
The CLI and Python bindings are useful, but they are thin layers over the same public C++ APIs.
CLI:
./build/metaread file.jpg
./build/metatransfer --source-meta source.jpg --target-jpeg rendered.jpg --output rendered_with_meta.jpg --forcePython:
PYTHONPATH=build-py/python python3 - <<'PY'
import openmeta
doc = openmeta.read("file.jpg")
print(doc.entry_count)
PY- 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