Skip to content

Tag Database Architecture

The tag database provides O(1) lookup for 32,000+ metadata tag definitions auto-generated from ExifTool source.

Overview

MetricValue
Total Tags32,677
Modules Parsed140+
Lookup TimeO(1)
Memory~5-10MB (lazy loaded)

Workspace Architecture

The tag database is implemented as a separate workspace crate (oxidex-tags-*) to solve debug build memory issues.

Structure

oxidex/
├── oxidex-tags-core/     # Core types (TagDescriptor, TagId, etc.)
├── oxidex-tags-camera/   # Camera MakerNotes tags
├── oxidex-tags-media/    # Audio/video format tags
├── oxidex-tags-image/    # Image format tags (EXIF, PNG, etc.)
├── oxidex-tags-document/ # Document format tags (PDF, etc.)
├── oxidex-tags-specialty/# Specialized format tags (DICOM, etc.)
└── src/                  # Main crate (uses oxidex-tags-*)

Profile Configuration

toml
# In root Cargo.toml
[profile.dev.package.oxidex-tags-core]
opt-level = 2        # Always optimize tag crates
codegen-units = 16   # Parallel compilation

[profile.dev.package.oxidex-tags-camera]
opt-level = 2
codegen-units = 16

# ... similar for other tag crates

Why Separate Crates?

  • Debug builds: 100GB+ RAM → 11GB (91% reduction)
  • Main crate stays in debug mode (fast iteration)
  • Tag crates always optimized (prevents OOM)
  • Industry-standard pattern (used by rustc, diesel, syn)

Tag Generation Pipeline

Tags are regenerated by explicitly running the sync-tags binary against a locally-installed exiftool — never as a side effect of cargo build:

bash
cargo run --release --bin sync_tags
1. Run     → `exiftool -f -listx` dumps ExifTool's own resolved tag database as XML
2. Parse   → src/tag_sync/mod.rs::parse_listx reads id/name/writable/type/description
3. Route   → each tag's table name maps to one of 6 oxidex-tags-* domain crates
4. Generate → writes oxidex-tags-{domain}/src/{domain}_tags.yaml directly
5. Record  → `.exiftool-version` is updated with the exiftool release used

Because ExifTool has already resolved table-level WRITABLE inheritance by the time it emits -listx output, this captures per-tag type data that the old Perl-regex parser missed for the vast majority of tags.

Generated Code Structure

Each domain crate pre-compiles its YAML tag definitions to binary format at build time. The build.rs script eliminates the cold-start YAML parsing penalty by:

  1. Reading the YAML source file (e.g. oxidex-tags-camera/src/camera_tags.yaml)
  2. Deserializing with serde_yaml::from_str into TagDatabase structures
  3. Serializing to efficient binary format with bincode::serde
  4. Writing the binary blob to OUT_DIR for embedding via include_bytes!

This converts one-time deserialization work from runtime to compile time, avoiding repeated YAML parsing on every program start while keeping the source readable and maintainable.

Supported Formats

By Tag Count

ModuleTagsDescription
DICOM3,149Medical imaging
NikonCustom3,512Nikon custom settings
Nikon2,398Nikon MakerNotes
Sony1,148Sony MakerNotes
QuickTime1,069Video metadata
Canon930Canon MakerNotes
Casio930Casio MakerNotes
Pentax876Pentax MakerNotes
EXIF718Core EXIF specification

By Category

Standard Formats:

  • EXIF, GPS, XMP, IPTC, JFIF, TIFF

MakerNotes (30+ vendors):

  • Canon, Nikon, Sony, Olympus, Panasonic, Pentax, FujiFilm
  • Samsung, Minolta, Kodak, Casio, Ricoh, etc.

Video:

  • QuickTime, MP4, Matroska, Flash, ASF, MPEG, H264

Audio:

  • ID3, FLAC, Ogg, Vorbis, AAC, APE

Specialized:

  • DICOM (medical), FITS (astronomy), MXF, PDF, PostScript

RAW:

  • DNG, CR2, NEF, ARW, CanonRaw, SigmaRaw, MinoltaRaw

Graphics:

  • PNG, GIF, BMP, PSD, JPEG, JPEG2000, OpenEXR, ICO

Documents:

  • HTML, XML, SVG, VCard, LNK

Usage

Lookup by Tag Name

rust
use oxidex::tag_db::get_tag_descriptor;

if let Some(tag) = get_tag_descriptor("EXIF:Make") {
    println!("Tag: {} (ID: {:?})", tag.tag_name, tag.tag_id);
}

Get All Tags for Format

rust
use oxidex_tags_camera::canon::get_tags;

for (name, descriptor) in get_tags().iter() {
    println!("{}: {:?}", name, descriptor.value_type);
}

Rebuilding

To regenerate the tag database from a locally-installed exiftool:

bash
cargo run --release --bin sync_tags

This overwrites oxidex-tags-*/src/*_tags.yaml and .exiftool-version directly — review the resulting git diff before committing.

Performance

  • Lookup: O(1) via HashMap
  • Memory: ~5-10MB (heap-allocated lazily)
  • Build Time: ~4 minutes (cached after first build)
  • Compilation: Uses Lazy initialization to avoid static limits

Build Requirements

Memory

Build ModeMemory
Release~5GB
Debug (with workspace)~11GB
Debug (without workspace)100GB+ (OOM)

Recommendation: Always use release builds for final testing.

Commands

bash
# Development build
cargo build

# Release build (recommended for testing)
cargo build --release

# Run tests (release recommended)
cargo test --release --workspace

XML Parser Features

The XML tag parser (parse_listx in src/tag_sync/mod.rs) handles:

  • XML element parsing: <table> (table group) and <tag> (individual tag definitions)
  • Tag attributes: id, name, writable (boolean), type (optional)
  • Both element forms: self-closing tags (<tag/>) and full tags (<tag>...</tag>)
  • Nested descriptions: <desc lang='en'> text extraction (English locale only)
  • XML entity unescaping: &amp;, &#39;, etc. in description text
  • Writable inheritance resolution: ExifTool pre-resolves table-level inheritance in -listx output

Known Limitations

  • Some ExifTool composite tags are excluded (calculated values)
  • Shortcut tags are excluded (aliases to other tags)
  • Some tags have platform-specific or format-specific variations

Released under the GPL-3.0 License.