Help us shape the future of Go! Take the 2026 Go Developer Survey

imagemeta

package module
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 20, 2026 License: MIT Imports: 15 Imported by: 16

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 perceptual hashing with allocation-free hot paths (pooled buffers, zero heap allocations per hash on steady state).

Package: github.com/evanoberholster/imagemeta/imagehash

Hash Size Input Notes
PHash64 64-bit 64x64 image DCT-based perception hash
PHash256 256-bit 256x256 image higher-precision variant
Ahash 64-bit 8x8 image average hash
PDQHash 256-bit any size Meta PDQ perceptual hash
BlurHash string 64x64 image compact placeholder via EncodeBlurHash

All hash types support Hamming Distance, hex String, binary Encode/Decode, Parse* round-trips and encoding.TextMarshaler for JSON use. PDQ additionally reports a quality score via NewPDQ256WithQuality; Meta recommends treating distance <= 31 (PDQMatchThreshold) as a match and discarding hashes at or below the quality threshold (PDQQualityThreshold).

h, err := imagehash.NewPHash64(img) // img must be 64x64
if err != nil {
    panic(err)
}
d := h.Distance(other) // Hamming distance

PDQ luminance uses NEON (arm64) and AVX2 (amd64) kernels with scalar fallback; output is bit-identical across implementations on the same architecture.

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

Documentation

Overview

Package imagemeta provides functions for parsing and extracting Metadata from Images. Different image types such as JPEG, Camera Raw, DNG, TIFF, HEIF, and AVIF.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNoExif               = meta.ErrNoExif
	ErrNoExifDecodeFn       = errors.New("error no Exif Decode Func set")
	ErrNoXmpDecodeFn        = errors.New("error no Xmp Decode Func set")
	ErrImageTypeNotFound    = imagetype.ErrImageTypeNotFound
	ErrMetadataNotSupported = errors.New("error metadata reading not supported for this imagetype")
)

Errors

View Source
var ErrNoPreview = errors.New("error no embedded preview image found")

ErrNoPreview is returned when a file contains no embedded preview image.

Functions

func Decode added in v0.2.0

func Decode(r io.ReadSeeker) (exif.Exif, error)

func DecodeARW added in v1.0.0

func DecodeARW(r io.ReadSeeker) (exif.Exif, error)

DecodeARW decodes a Sony ARW file from an io.Reader returning Exif or an error.

func DecodeCR2 added in v0.2.0

func DecodeCR2(r io.ReadSeeker) (exif.Exif, error)

DecodeCR2 decodes a CR2 file from an io.Reader returning Exif or an error.

func DecodeCR3 added in v0.2.0

func DecodeCR3(r io.ReadSeeker) (exif.Exif, error)

DecodeCR3 decodes a CR3 file from an io.Reader returning Exif or an error.

func DecodeCRW added in v1.0.0

func DecodeCRW(r io.ReadSeeker) (exif.Exif, error)

DecodeCRW decodes a CRW file from an io.ReadSeeker returning Exif or an error.

func DecodeHeif added in v0.2.0

func DecodeHeif(r io.ReadSeeker) (exif.Exif, error)

DecodeHeif decodes a Heif file from an io.Reader returning Exif or an error. Needs improvement

func DecodeJPEG added in v0.2.0

func DecodeJPEG(r io.ReadSeeker) (exif.Exif, error)

DecodeJPEG decodes a JPEG file from an io.Reader returning Exif or an error.

func DecodePng added in v0.2.0

func DecodePng(r io.ReadSeeker) (exif.Exif, error)

DecodePng decodes a PNG file from an io.Reader returning Exif or an error.

func DecodeTiff added in v0.2.0

func DecodeTiff(r io.ReadSeeker) (exif.Exif, error)

DecodeTiff decodes a Tiff/DNG file from an io.Reader returning Exif or an error.

func ExtractPreview added in v1.1.0

func ExtractPreview(r io.ReadSeeker, p PreviewImage, opts ...PreviewOption) ([]byte, error)

ExtractPreview reads the bytes of one preview and validates the JPEG SOI marker. The returned slice is newly allocated.

func PreviewCR3 added in v1.0.0

func PreviewCR3(r io.ReadSeeker) ([]byte, error)

PreviewCR3 previews a CR3 file from an io.Reader returning preview image binary or an error.

func PreviewTIFF added in v1.1.0

func PreviewTIFF(r io.ReadSeeker, opts ...PreviewOption) ([]byte, error)

PreviewTIFF returns the largest embedded JPEG preview of a TIFF-based (raw) file, e.g. NEF/CR2/ARW/DNG, analog to PreviewCR3.

func SetLogger added in v0.2.0

func SetLogger(w io.Writer, level slog.Level)

Types

type PreviewImage added in v1.1.0

type PreviewImage struct {
	// IFD names the directory the preview was found in ("IFD0", "IFD1",
	// "SubIFD1", ...).
	IFD string
	// Width and Height are the dimensions declared by the directory; zero
	// when the directory does not declare them.
	Width  uint32
	Height uint32
	Offset uint32
	Length uint32
}

PreviewImage describes an embedded JPEG preview of a TIFF-based (raw) file. Offset and Length locate the JPEG stream in the file.

func TIFFPreviews added in v1.1.0

func TIFFPreviews(r io.ReadSeeker, opts ...PreviewOption) ([]PreviewImage, error)

TIFFPreviews lists the embedded JPEG preview images of a TIFF-based raw file (e.g. NEF, CR2, ARW, DNG, PEF), largest first. The offsets are relative to the start of the file. Candidates are validated against the actual stream: only renderable JPEGs qualify, which keeps raw sensor payloads out (DNG stores those as lossless JPEG, uncompressed or vendor-compressed strips).

type PreviewOption added in v1.1.0

type PreviewOption func(*previewConfig)

PreviewOption configures preview extraction.

func WithMaxPreviewLength added in v1.1.0

func WithMaxPreviewLength(n int64) PreviewOption

WithMaxPreviewLength bounds the byte length of a preview that TIFFPreviews surfaces and ExtractPreview reads. A value <= 0 disables the limit (the preview is still bounded by the file size).

Directories

Path Synopsis
Package imagehash computes perceptual hashes and blur placeholders from an image: 64/256-bit pHash, 64-bit aHash, 256-bit PDQ and BlurHash strings.
Package imagehash computes perceptual hashes and blur placeholders from an image: 64/256-bit pHash, 64-bit aHash, 256-bit PDQ and BlurHash strings.
internal/pdq
Package pdq implements Meta's PDQ (Perceptual Difference Quantization) perceptual hashing algorithm.
Package pdq implements Meta's PDQ (Perceptual Difference Quantization) perceptual hashing algorithm.
internal/phash
Package phash contains the transforms used by the PHash perceptual hash.
Package phash contains the transforms used by the PHash perceptual hash.
Package imagetype provides types and functions for identifying Image document types
Package imagetype provides types and functions for identifying Image document types
gen command
Package meta contains meta types for image metadata
Package meta contains meta types for image metadata
exif
Package tiff reads Tiff Header metadata information from image files before being processed by exif package
Package tiff reads Tiff Header metadata information from image files before being processed by exif package
exif/makernote
Package makernote defines maker-note tag IDs, camera-make identification, and the shared EXIF maker-note container for vendor-specific metadata.
Package makernote defines maker-note tag IDs, camera-make identification, and the shared EXIF maker-note container for vendor-specific metadata.
exif/makernote/canon
Package canon provides data types and functions for representing Canon Camera Makernote values
Package canon provides data types and functions for representing Canon Camera Makernote values
exif/makernote/nikon
Package nikon contains Nikon-specific metadata models shared by the EXIF decoder and downstream callers.
Package nikon contains Nikon-specific metadata models shared by the EXIF decoder and downstream callers.
exif/makernote/sony
Package sony provides data types and functions for representing Sony Camera Makernote values.
Package sony provides data types and functions for representing Sony Camera Makernote values.
jpeg
Package jpeg reads metadata information (Exif and XMP) from a JPEG Image.
Package jpeg reads metadata information (Exif and XMP) from a JPEG Image.
png
Package png reads PNG Header metadata information from image files before being processed by exif package
Package png reads PNG Header metadata information from image files before being processed by exif package
xmp
Package xmp provides functions for decoding .xmp sidecar files and XMP embedded within image files
Package xmp provides functions for decoding .xmp sidecar files and XMP embedded within image files
xmp/cmd command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL