package exif import ( "log" "math" "time" "github.com/barasher/go-exiftool" "github.com/photoview/photoview/api/dataloader" "github.com/photoview/photoview/api/graphql/models" ) type externalExifParser struct { et *exiftool.Exiftool dataLoader *dataloader.ExiftoolLoader } func newExiftoolParser() (*externalExifParser, error) { et, err := exiftool.NewExiftool(exiftool.NoPrintConversion()) if err != nil { log.Printf("Error initializing ExifTool: %s\n", err) return nil, err } return &externalExifParser{ et: et, dataLoader: dataloader.NewExiftoolLoader(et), }, nil } // isFloatReal returns true when the float value represents a real number // (different than +Inf, -Inf or NaN) func isFloatReal(v float64) bool { if math.IsInf(v, 1) { return false } else if math.IsInf(v, -1) { return false } else if math.IsNaN(v) { return false } return true } // sanitizeEXIF removes any EXIF float64 field that is not a real number (+Inf, // -Inf or Nan) func sanitizeEXIF(exif *models.MediaEXIF) { if exif.Exposure != nil && !isFloatReal(*exif.Exposure) { exif.Exposure = nil } if exif.Aperture != nil && !isFloatReal(*exif.Aperture) { exif.Aperture = nil } if exif.FocalLength != nil && !isFloatReal(*exif.FocalLength) { exif.FocalLength = nil } if (exif.GPSLatitude != nil && !isFloatReal(*exif.GPSLatitude)) || (exif.GPSLongitude != nil && !isFloatReal(*exif.GPSLongitude)) { exif.GPSLatitude = nil exif.GPSLongitude = nil } } func (p *externalExifParser) ParseExif(media_path string) (returnExif *models.MediaEXIF, returnErr error) { // ExifTool - No print conversion mode if p.et == nil { et, err := exiftool.NewExiftool(exiftool.NoPrintConversion()) p.et = et if err != nil { log.Printf("Error initializing ExifTool: %s\n", err) return nil, err } } fileInfo, err := p.dataLoader.Load(media_path) if err != nil { return nil, err } newExif := models.MediaEXIF{} found_exif := false // Get camera model model, err := fileInfo.GetString("Model") if err == nil { found_exif = true newExif.Camera = &model } // Get Camera make make, err := fileInfo.GetString("Make") if err == nil { found_exif = true newExif.Maker = &make } // Get lens lens, err := fileInfo.GetString("LensModel") if err == nil { found_exif = true newExif.Lens = &lens } //Get time of photo date, err := fileInfo.GetString("DateTimeOriginal") if err == nil { layout := "2006:01:02 15:04:05" dateTime, err := time.Parse(layout, date) if err == nil { found_exif = true newExif.DateShot = &dateTime } } // Get exposure time exposureTime, err := fileInfo.GetFloat("ExposureTime") if err == nil { found_exif = true newExif.Exposure = &exposureTime } // Get aperture aperture, err := fileInfo.GetFloat("Aperture") if err == nil { found_exif = true newExif.Aperture = &aperture } // Get ISO iso, err := fileInfo.GetInt("ISO") if err == nil { found_exif = true newExif.Iso = &iso } // Get focal length focalLen, err := fileInfo.GetFloat("FocalLength") if err == nil { found_exif = true newExif.FocalLength = &focalLen } // Get flash info flash, err := fileInfo.GetInt("Flash") if err == nil { found_exif = true newExif.Flash = &flash } // Get orientation orientation, err := fileInfo.GetInt("Orientation") if err == nil { found_exif = true newExif.Orientation = &orientation } // Get exposure program expProgram, err := fileInfo.GetInt("ExposureProgram") if err == nil { found_exif = true newExif.ExposureProgram = &expProgram } // GPS coordinates - longitude longitudeRaw, err := fileInfo.GetFloat("GPSLongitude") if err == nil { found_exif = true newExif.GPSLongitude = &longitudeRaw } // GPS coordinates - latitude latitudeRaw, err := fileInfo.GetFloat("GPSLatitude") if err == nil { found_exif = true newExif.GPSLatitude = &latitudeRaw } if !found_exif { return nil, nil } returnExif = &newExif sanitizeEXIF(returnExif) return }