photoprism/internal/meta/gps.go

102 lines
2.3 KiB
Go
Raw Normal View History

package meta
import (
"regexp"
"strconv"
"github.com/photoprism/photoprism/pkg/clean"
"github.com/dsoprea/go-exif/v3"
)
var GpsCoordsRegexp = regexp.MustCompile("[0-9\\.]+")
var GpsRefRegexp = regexp.MustCompile("[NSEW]+")
var GpsFloatRegexp = regexp.MustCompile("[+\\-]?(?:(?:0|[1-9]\\d*)(?:\\.\\d*)?|\\.\\d+)")
// GpsToLatLng returns the GPS latitude and longitude as float point number.
func GpsToLatLng(s string) (lat, lng float32) {
// Emtpy?
if s == "" {
return 0, 0
}
// Floating point numbers?
if fl := GpsFloatRegexp.FindAllString(s, -1); len(fl) == 2 {
if lat, err := strconv.ParseFloat(fl[0], 64); err != nil {
log.Infof("metadata: %s is not a valid gps position", clean.Log(fl[0]))
} else if lng, err := strconv.ParseFloat(fl[1], 64); err == nil {
return float32(lat), float32(lng)
}
}
// Parse string values.
co := GpsCoordsRegexp.FindAllString(s, -1)
re := GpsRefRegexp.FindAllString(s, -1)
if len(co) != 6 || len(re) != 2 {
return 0, 0
}
latDeg := exif.GpsDegrees{
Orientation: re[0][0],
Degrees: ParseFloat(co[0]),
Minutes: ParseFloat(co[1]),
Seconds: ParseFloat(co[2]),
}
lngDeg := exif.GpsDegrees{
Orientation: re[1][0],
Degrees: ParseFloat(co[3]),
Minutes: ParseFloat(co[4]),
Seconds: ParseFloat(co[5]),
}
return float32(latDeg.Decimal()), float32(lngDeg.Decimal())
}
// GpsToDecimal returns the GPS latitude or longitude as decimal float point number.
func GpsToDecimal(s string) float32 {
// Emtpy?
if s == "" {
return 0
}
// Floating point number?
if f, err := strconv.ParseFloat(s, 64); err == nil {
return float32(f)
}
// Parse string value.
co := GpsCoordsRegexp.FindAllString(s, -1)
re := GpsRefRegexp.FindAllString(s, -1)
if len(co) != 3 || len(re) != 1 {
return 0
}
latDeg := exif.GpsDegrees{
Orientation: re[0][0],
Degrees: ParseFloat(co[0]),
Minutes: ParseFloat(co[1]),
Seconds: ParseFloat(co[2]),
}
return float32(latDeg.Decimal())
}
// ParseFloat returns a single GPS coordinate value as floating point number (degree, minute or second).
func ParseFloat(s string) float64 {
// Empty?
if s == "" {
return 0
}
// Parse floating point number.
if result, err := strconv.ParseFloat(s, 64); err != nil {
log.Debugf("metadata: %s is not a valid gps position", clean.Log(s))
return 0
} else {
return result
}
}