MCPcopy Index your code
hub / github.com/evanoberholster/imagemeta

github.com/evanoberholster/imagemeta @V1.0.0

Chat with this repo
repository ↗ · DeepWiki ↗ · release V1.0.0 ↗ · + Follow
2,529 symbols 8,700 edges 205 files 1,325 documented · 52% 1 cross-repo links
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

imagemeta

License Go Reference Go Report Card Coverage Build

imagemeta is a high-performance Go library for extracting EXIF and XMP metadata from images and camera RAW formats.

It is built for:

  • ExifTool-aligned decoding behavior
  • low-allocation parsing on hot paths
  • broad support for modern and legacy camera formats
  • structured MakerNote decoding (Canon, Nikon, Sony, Panasonic, Apple)

Features

  • Decode EXIF from JPEG, TIFF, CR2, CR3, DNG, NEF, ARW, RW2, HEIC/HEIF/AVIF, PNG, and CRW
  • Parse XMP sidecars and embedded XMP blocks
  • Read Canon/Nikon/Sony/Panasonic/Apple MakerNotes
  • Extract embedded CR3 previews
  • Fast image type detection
  • Allocation-conscious perceptual image hashing (imagehash)

Install

go get github.com/evanoberholster/imagemeta

Supported Formats

  • JPEG: .jpg, .jpeg
  • TIFF + TIFF-based RAW: .tif, .tiff, .cr2, .dng, .nef, .arw, .rw2
  • ISO-BMFF family: .cr3, .heic, .heif, .avif
  • PNG (EXIF-in-TIFF payload)
  • CIFF/CRW: .crw

Quick Start

package main

import (
    "fmt"
    "os"

    "github.com/evanoberholster/imagemeta"
)

func main() {
    f, err := os.Open("image.jpg")
    if err != nil {
        panic(err)
    }
    defer f.Close()

    ex, err := imagemeta.Decode(f)
    if err != nil {
        panic(err)
    }

    fmt.Println("type:", ex.ImageType)
    fmt.Println("make:", ex.Make)
    fmt.Println("model:", ex.Model)
    fmt.Println("datetime:", ex.DateTimeOriginal)
}

Decode API

Top-level decode entry points:

  • Decode(io.ReadSeeker)
  • DecodeJPEG(io.ReadSeeker)
  • DecodeTiff(io.ReadSeeker)
  • DecodeCR3(io.ReadSeeker)
  • DecodeCRW(io.ReadSeeker)
  • DecodeHeif(io.ReadSeeker)
  • DecodePng(io.ReadSeeker)
  • PreviewCR3(io.ReadSeeker)

XMP Parsing

Parse a sidecar .xmp file:

x, err := xmp.ParseXmp(file)

Parse embedded XMP from an image:

x, err := xmp.Parse(file)

Package: github.com/evanoberholster/imagemeta/meta/xmp

Image Type Detection

Use imagetype for quick format detection before decode:

t, err := imagetype.Scan(r)

Package: github.com/evanoberholster/imagemeta/imagetype

Perceptual Hashing

imagehash provides 64-bit and 256-bit perceptual hashing with low-allocation paths.

Package: github.com/evanoberholster/imagemeta/imagehash

Performance Notes

  • Designed for low allocation and high throughput
  • Uses pooled readers and fixed-size parsing structures on hot paths
  • Suitable for large-batch metadata extraction pipelines

Benchmarks

  • General benchmarks: bench_test.go
Benchmark ns/op B/op allocs/op
Canon/CR2 6646 2440 20
Canon/CR3 8015 3723 22
Canon/JPG 2058 176 9
Nikon/JPG 1747 104 7
Nikon/NEF 10306 736 19
Sony/ARW 6584 1512 12

Note: benchmark results vary by CPU, Go version, and sample files.

TODO

  • Expand ExifTool parity coverage across MakerNote fields (Nikon, Sony, Panasonic, Apple, DJI)
  • Resolve known reverse-offset parsing edge case in MakerNote decoding
  • Improve malformed metadata resilience with more targeted fuzz and corpus tests
  • Add more specific benchmarks to compare edge cases
  • Document compatibility matrix by camera model/format

Contributing

Pull requests and issue reports are welcome.

Before opening a PR, run:

go test ./...
golangci-lint run

Acknowledgements

imagemeta is heavily inspired and tested on:

Additional references:

  • go4 (BMFF/HEIF parser concepts)
  • lclevy/canon_cr3
  • Lasse Heikkilä's HEIF thesis work

LLMs were used to assist in writing code, the code has been reviewed and has passed stringent checks.

License

MIT

Extension points exported contracts — how you extend this code

MsgPackInterface (Interface)
Automated Tests for MessagePack [3 implementers]
meta/exifTypes_test.go
BufferedReader (Interface)
BufferedReader is compatible with *bufio.Reader. [2 implementers]
meta/utils/reader.go
Reader (Interface)
Reader that is compatible with imagemeta
meta/meta.go
ReaderOption (FuncType)
ReaderOption configures Reader behavior.
meta/exif/options.go
DecodeFn (FuncType)
DecodeFn is a function for decoding Metadata. For Exif Metadata use ExifHeader and ExifFn. For Xmp Metadata use XmpHea
meta/meta.go
ExifReader (FuncType)
ExifReader is invoked with Exif payload bytes and its parsed header.
meta/meta.go
XMPReader (FuncType)
XMPReader is invoked with XMP payload bytes and XPacket metadata.
meta/meta.go
PreviewImageReader (FuncType)
PreviewImageReader is invoked with preview image bytes and metadata header.
meta/meta.go

Core symbols most depended-on inside this repo

Value
called by 265
meta/xmp/tag.go
Uint32
called by 189
meta/logging/logging.go
u8At
called by 148
meta/exif/makernote/sony/utils.go
NewEntry
called by 126
meta/exif/tag/entry.go
u16At
called by 118
meta/exif/makernote/sony/utils.go
parseString
called by 104
meta/xmp/parser.go
Close
called by 103
meta/exif/reader.go
Reset
called by 100
meta/exif/reader.go

Shape

Function 1,172
Method 1,035
Struct 170
TypeAlias 142
FuncType 7
Interface 3

Languages

Go100%

Modules by API surface

meta/exif/makernote/canon/canon_gen.go200 symbols
meta/exif/model.go73 symbols
imagetype/imagetype.go72 symbols
meta/exif/makernote/canon/canon.go66 symbols
meta/exifTypes.go61 symbols
meta/exifTypes_gen.go60 symbols
meta/logging/logging.go51 symbols
meta/exif/canon_test.go50 symbols
meta/exif/canon.go48 symbols
meta/exif/values.go44 symbols
meta/exif/gpsinfo.go43 symbols
meta/isobmff/reader_test.go37 symbols

Used by 1 indexed graphs manifest dependencies, hub-wide

For agents

$ claude mcp add imagemeta \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact