Last active
March 6, 2025 17:54
-
-
Save rorycl/cee0a2e4ebe4d3ee7713a3442e6e8ffb to your computer and use it in GitHub Desktop.
Example of using bep/imagemeta (https://github.com/bep/imagemeta)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"maps" | |
"os" | |
"regexp" | |
"slices" | |
"strings" | |
"time" | |
"github.com/bep/imagemeta" | |
) | |
// ExifInfo holds the decoded Exif data for an Image. The main fields | |
// are picked out by name, with other residual fields that match the | |
// package (private) filtering regex held in Tags. | |
type ExifInfo struct { | |
// GPS latitude in degrees. | |
Lat float64 | |
// GPS longitude in degrees. | |
Long float64 | |
// Image creation date/time. | |
Date time.Time | |
// Aperture | |
Aperture float64 | |
// F Number | |
FNumber float64 | |
// LensModel | |
LensModel string | |
// Original Image Width | |
Width uint32 | |
// Original Image Height | |
Height uint32 | |
// Original orientation | |
Orientation uint16 | |
// Shutterspeed | |
ShutterSpeed float64 | |
// A collection of tags for this Image matching the | |
// interestingTagsRegexp, GPS and Time matches. | |
Tags imagemeta.Tags | |
} | |
// Map returns a map[string]any of fields of ExifInfo. | |
func (e *ExifInfo) Map() map[string]any { | |
m := map[string]any{} | |
m["Lat"] = e.Lat | |
m["Long"] = e.Long | |
m["Date"] = e.Date | |
m["Aperture"] = e.Aperture | |
m["FNumber"] = e.FNumber | |
m["LensModel"] = e.LensModel | |
m["Width"] = e.Width | |
m["Height"] = e.Height | |
m["Orientation"] = e.Orientation | |
m["ShutterSpeed"] = e.ShutterSpeed | |
return m | |
} | |
// Keys returns the sorted keys of ExifInfo. | |
func (e *ExifInfo) Keys() []string { | |
return slices.Sorted(maps.Keys(e.Map())) | |
} | |
func main() { | |
// see hugo:resources/images/exif/exif.go | |
interestingTagsRegexp := regexp.MustCompile( | |
`Aperture|ShutterSpeed|Lens|FNumber|Height|Width|Orientation`, | |
) | |
img, err := os.Open("IMG_4708.JPG") | |
if err != nil { | |
fmt.Println(err) | |
os.Exit(1) | |
} | |
shouldInclude := func(ti imagemeta.TagInfo) bool { | |
if ti.Source == imagemeta.EXIF { | |
if strings.Contains(ti.Tag, "Time") { | |
return true | |
} | |
// GPS tags are needed for lat/long. | |
if strings.HasPrefix(ti.Tag, "GPS") { | |
return true | |
} | |
// Drop thumbnail tags. | |
if !strings.HasPrefix(ti.Namespace, "IFD0") { | |
return false | |
} | |
} | |
if interestingTagsRegexp.MatchString(ti.Tag) { | |
return true | |
} | |
return false // all other tags will be exlcuded | |
} | |
var ei ExifInfo | |
handleTag := func(ti imagemeta.TagInfo) error { | |
ei.Tags.Add(ti) | |
return nil | |
} | |
err = imagemeta.Decode( | |
imagemeta.Options{ | |
R: img, | |
ImageFormat: imagemeta.JPEG, | |
ShouldHandleTag: shouldInclude, | |
HandleTag: handleTag, | |
Sources: imagemeta.EXIF, | |
}, | |
) | |
if err != nil { | |
fmt.Println(err) | |
os.Exit(1) | |
} | |
ei.Date, _ = ei.Tags.GetDateTime() | |
ei.Lat, ei.Long, _ = ei.Tags.GetLatLong() | |
if tag, ok := ei.Tags.EXIF()["ApertureValue"]; ok { | |
ei.Aperture = tag.Value.(float64) | |
} | |
if tag, ok := ei.Tags.EXIF()["LensModel"]; ok { | |
ei.LensModel = tag.Value.(string) | |
} | |
if tag, ok := ei.Tags.EXIF()["ExifImageWidth"]; ok { | |
ei.Width = tag.Value.(uint32) | |
} | |
if tag, ok := ei.Tags.EXIF()["ExifImageHeight"]; ok { | |
ei.Height = tag.Value.(uint32) | |
} | |
if tag, ok := ei.Tags.EXIF()["Orientation"]; ok { | |
ei.Orientation = tag.Value.(uint16) | |
} | |
if tag, ok := ei.Tags.EXIF()["FNumber"]; ok { | |
if n, ok := tag.Value.(imagemeta.Rat[uint32]); ok { | |
ei.FNumber = n.Float64() | |
} | |
} | |
if tag, ok := ei.Tags.EXIF()["ShutterSpeedValue"]; ok { | |
ei.ShutterSpeed = tag.Value.(float64) | |
} | |
for _, k := range ei.Keys() { | |
fmt.Printf("%12s : %v\n", k, ei.asMap()[k]) | |
} | |
// ei.Tags = imagemeta.Tags{} // Remove all tags for printing | |
fmt.Printf("%#v\n", ei) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment