imagemeta icon indicating copy to clipboard operation
imagemeta copied to clipboard

Image Metadata (Exif and XMP) extraction for JPEG, HEIC, AVIF, TIFF and Camera Raw in golang. Focus is on providing features and improved performance.

Imagemeta

License Godoc ReportCard Coverage Status Build

Image Metadata (Exif and XMP) extraction for JPEG, HEIC, WebP, AVIF, TIFF, and Camera Raw in golang. Imagetype identifcation. Zero allocation Perceptual Image Hash. Goal is features that are performance oriented for working with images.

Documentation

See Documentation for more information.

Example Usage

Example usage:

package main

import (
	"flag"
	"fmt"
	"io"
	"os"

	"github.com/evanoberholster/imagemeta"
	"github.com/evanoberholster/imagemeta/exif"
	"github.com/evanoberholster/imagemeta/meta"
	"github.com/evanoberholster/imagemeta/xmp"
)

func main() {
	flag.Parse()
	if flag.NArg() != 1 {
		fmt.Fprintf(os.Stderr, "usage: main <file>\n")
		os.Exit(1)
	}
	f, err := os.Open(flag.Arg(0))
	if err != nil {
		fmt.Fatal(err)
	}
	defer func() {
		err = f.Close()
		if err != nil {
			panic(err)
		}
	}()

	m, err := imagemeta.Parse(f)
	if err != nil {
		panic(err)
	}
	fmt.Println(m.Exif())
	fmt.Println(m.Xmp())
	fmt.Println(m.ImageType())
	fmt.Println(m.Dimensions())
	fmt.Println(jpeg.DecodeConfig(m.PreviewImage()))

	e, _ := m.Exif()
	if e != nil {
		// ImageWidth and ImageHeight
		fmt.Println(e.Dimensions().Size())

		fmt.Println(e.Artist())
		fmt.Println(e.Copyright())

		fmt.Println(e.CameraMake())
		fmt.Println(e.CameraModel())
		fmt.Println(e.CameraSerial())

		fmt.Println(e.Orientation())

		fmt.Println(e.LensMake())
		fmt.Println(e.LensModel())
		fmt.Println(e.LensSerial())

		fmt.Println(e.ISOSpeed())
		fmt.Println(e.FocalLength())
		fmt.Println(e.LensModel())
		fmt.Println(e.Aperture())
		fmt.Println(e.ShutterSpeed())

		fmt.Println(e.Dimensions().Size())

		fmt.Println(e.Artist())
		fmt.Println(e.Copyright())

		fmt.Println(e.ISOSpeed())
		fmt.Println(e.FocalLength())
		fmt.Println(e.LensModel())
		fmt.Println(e.Aperture())
		fmt.Println(e.ShutterSpeed())

		fmt.Println(e.Aperture())
		fmt.Println(e.ExposureBias())

		fmt.Println(e.Artist())
		fmt.Println(e.Copyright())

		fmt.Println(e.CameraMake())
		fmt.Println(e.CameraModel())
		fmt.Println(e.CameraSerial())

		fmt.Println(e.LensMake())
		fmt.Println(e.LensModel())
		fmt.Println(e.LensSerial())

		// Example Tags
		fmt.Println(e.Dimensions())

		// Makernote Tags
		fmt.Println(e.CanonCameraSettings())
		fmt.Println(e.CanonFileInfo())
		fmt.Println(e.CanonShotInfo())
		fmt.Println(e.CanonAFInfo())

		// Time Tags
		fmt.Println(e.DateTime(time.Local))
		fmt.Println(e.ModifyDate(time.Local))
		fmt.Println(e.GPSDate(time.UTC))

		// GPS Tags
		fmt.Println(e.GPSCoords())
		fmt.Println(e.GPSAltitude())
		fmt.Println(e.GPSCoords())
		c, _ := e.GPSCellID()
		fmt.Println(c.ToToken())

		// Other Tags
		fmt.Println(e.ExposureProgram())
		fmt.Println(e.MeteringMode())
		fmt.Println(e.ShutterSpeed())
		fmt.Println(e.Aperture())
		fmt.Println(e.FocalLength())
		fmt.Println(e.FocalLengthIn35mmFilm())
		fmt.Println(e.ISOSpeed())
		fmt.Println(e.Flash())
		fmt.Println(e.ExposureValue())
		fmt.Println(e.ExposureBias())
	}
}

Imagehash

Zero allocation Perceptual Hash algorithm for 64bit and 256bit hash. Optimized for performance. Implementation follows: http://www.hackerfactor.com/blog/index.php?/archives/432-Looks-Like-It.html. Images will need to be resized prior to imagehashing, either 64x64 or 256x256 respectively.

name                       time/op
PHash64/Fast-12           40.8µs ± 1%
PHash64/Fast-Parallel-12  6.55µs ± 1%
PHash256/Fast-12            761µs ± 1%
PHash256/Fast-Parallel-12   122µs ± 1%

name                       alloc/op
PHash64/Fast-12           0.75B ±167%
PHash64/Fast-Parallel-12   0.00B     
PHash256/Fast-12            225B ±100%
PHash256/Fast-Parallel-12  0.69B ±336%

name                       allocs/op
PHash64/Fast-12             0.00     
PHash64/Fast-Parallel-12    0.00  
PHash256/Fast-12             0.00     
PHash256/Fast-Parallel-12    0.00     

Contributing

Suggestions and pull requests are welcome.

Benchmarks

This was benchmarked without the retrival of values. To run your own benchmarks see bench_test.go

BenchmarkImageMeta/.CR2/6D-12         			   80455	     20820 ns/op	   10218 B/op	      22 allocs/op
BenchmarkImageMeta/.CR2/7DMkII-12     	 		   75770	     17921 ns/op	   10219 B/op	      21 allocs/op
BenchmarkImageMeta/.CR2/CanonM6MkII-12         	   63640	     18128 ns/op	    9261 B/op	      21 allocs/op
BenchmarkImageMeta/.CR3/CanonR-12              	   72705	     16597 ns/op	    9236 B/op	      21 allocs/op
BenchmarkImageMeta/.CR3/CanonRP-12             	   59492	     17623 ns/op	    9216 B/op	      20 allocs/op
BenchmarkImageMeta/.CR3/CanonR3-12             	   57465	     20322 ns/op	   14632 B/op	      22 allocs/op
BenchmarkImageMeta/.CR3/CanonR5-12             	   55514	     19874 ns/op	   14632 B/op	      22 allocs/op
BenchmarkImageMeta/.CR3/CanonR6-12             	   76044	     16234 ns/op	    9234 B/op	      21 allocs/op
BenchmarkImageMeta/.HEIC/CanonR5-12            	   32150	     43434 ns/op	   10198 B/op	      21 allocs/op
BenchmarkImageMeta/.HEIC/CanonR6-12            	   34396	     37288 ns/op	   10196 B/op	      21 allocs/op
BenchmarkImageMeta/.JPG/GPS-12                 	  117636	      9807 ns/op	     280 B/op	       4 allocs/op
BenchmarkImageMeta/.JPG/GoPro6-12              	  154758	      6528 ns/op	     280 B/op	       4 allocs/op
BenchmarkImageMeta/.HEIC-12                    	    8442	    194884 ns/op	    4540 B/op	      15 allocs/op
BenchmarkImageMeta/.HEIC/iPhone11-12           	    6170	    185167 ns/op	    4569 B/op	      15 allocs/op
BenchmarkImageMeta/.HEIC/iPhone12-12           	   26725	     48433 ns/op	    1716 B/op	      11 allocs/op
BenchmarkImageMeta/.HEIC/iPhone13-12           	    6726	    152748 ns/op	    4561 B/op	      15 allocs/op
BenchmarkImageMeta/.NEF/Nikon-12               	   54534	     22582 ns/op	   10242 B/op	      23 allocs/op
BenchmarkImageMeta/.NEF/Nikon#01-12            	   53985	     23082 ns/op	   10244 B/op	      23 allocs/op
BenchmarkImageMeta/.RW2/Panasonic-12           	   52309	     20677 ns/op	    4555 B/op	      15 allocs/op
BenchmarkImageMeta/.ARW/Sony-12                	   99100	     11576 ns/op	    4769 B/op	      22 allocs/op
BenchmarkImageMeta/.WEBP/Webp-12               	 4978038	     285.9 ns/op	      24 B/op	       1 allocs/op
BenchmarkImageMeta/.DNG/Adobe-12               	   34141	     35345 ns/op	   20866 B/op	      30 allocs/op
BenchmarkImageMeta/.JPG/NoExif-12              	 1290793	     942.1 ns/op	     280 B/op	       4 allocs/op

Imagetype Identification

Images can be identified with: "github.com/evanoberholster/imagemeta/imagetype" package.

Benchmarks can be found with the imagemeta/imagetype package

Example:

package main

import (
   "fmt"
   "os"

   "github.com/evanoberholster/imagemeta/imagetype"
)

const imageFilename = "../../test/img/1.CR2"

func main() {
   var err error

   f, err := os.Open(imageFilename)
   if err != nil {
      panic(err)
   }
   defer f.Close()
   t, err := imagetype.Scan(f)
   if err != nil {
      panic(err)
   }
   fmt.Println(t)
}

TODO

  • [x] Stabilize ImageTypes API
  • [x] Add Exif parsing for individual image types (jpg, heic, cr2, tiff, dng)
  • [x] Add XMP parsing as "xmp" package
  • [x] Add Avif, Heic and CR3 image metadata support (riff format images)
  • [ ] Stabalize Imagemeta API
  • [ ] Improve test coverage
  • [ ] Create Thumbnail API
  • [ ] Add Webp image metadata support
  • [ ] Add Canon Exif Makernote support
  • [ ] Add Nikon Exif Makernote support
  • [ ] Add CRW image metadata support (ciff format images)
  • [ ] Documentation

Based on and Inspired by

Based on work by Dustin Oprea https://github.com/dsoprea/go-exif

Inspired by Phil Harvey http://exiftool.org

Some inspiration from RW Carlsen https://github.com/rwcarlsen/goexif

Special Thanks to:

  • The go4 Authors (https://github.com/go4org/go4) for their work on a BMFF parser and HEIF structure in golang.
  • Laurent Clévy (@Lorenzo2472) (https://github.com/lclevy/canon_cr3) for Canon CR3 structure.
  • Lasse Heikkilä (https://trepo.tuni.fi/bitstream/handle/123456789/24147/heikkila.pdf) for HEIF structure from his thesis.
  • Imagehash authors (https://github.com/corona10/goimagehash)

Contributors

LICENSE

Copyright (c) 2020-2021, Evan Oberholster & Contributors

Copyright (c) 2019, Dustin Oprea