Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add location information to timeline #59

Merged
merged 8 commits into from
Aug 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions db/migrations/000013_add_gps_coords.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE infos DROP COLUMN "longitude" text;
ALTER TABLE infos DROP COLUMN "latitude" text;
2 changes: 2 additions & 0 deletions db/migrations/000013_add_gps_coords.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE infos ADD COLUMN "latitude" REAL;
ALTER TABLE infos ADD COLUMN "longitude" REAL;
10 changes: 10 additions & 0 deletions defaults.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,16 @@ tags:
# exif:
# enable: true

geo:
# Reverse geocode coordinates to location names. Runs fully locally
# via the "rgeo" Golang library. Currently only supported in the
# timeline layout.
#
# Can delay startup by up to a minute as the local geolocation
# database is loaded.
#
# reverse_geocode: true

media:
# Extract metadata from this many files concurrently
concurrent_meta_loads: 8
Expand Down
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ require (
github.com/go-chi/render v1.0.1
github.com/goccy/go-yaml v1.7.17
github.com/golang-migrate/migrate/v4 v4.15.0-beta.1
github.com/golang/geo v0.0.0-20200730024412-e86565bf3f35
github.com/gosimple/slug v1.10.0
github.com/hako/durafmt v0.0.0-20200605151348-3a43fc422dd9
github.com/imdario/mergo v0.3.12
github.com/imdario/mergo v0.3.13
github.com/joho/godotenv v1.3.0
github.com/karrick/godirwalk v1.15.6
github.com/kelindar/intmap v1.1.0
Expand All @@ -30,6 +31,7 @@ require (
github.com/prometheus/client_model v0.2.0
github.com/pyroscope-io/client v0.7.0
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd
github.com/sams96/rgeo v1.2.0
github.com/sheerun/queue v1.0.1
github.com/tdewolff/canvas v0.0.0-20200504121106-e2600b35c365
github.com/x448/float16 v0.8.4
Expand Down Expand Up @@ -74,6 +76,7 @@ require (
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/tdewolff/minify/v2 v2.7.1-0.20200112204046-70870d25a935 // indirect
github.com/tdewolff/parse/v2 v2.4.2 // indirect
github.com/twpayne/go-geom v1.4.4 // indirect
github.com/wcharczuk/go-chart v2.0.2-0.20191206192251-962b9abdec2b+incompatible // indirect
go.uber.org/atomic v1.7.0 // indirect
golang.org/x/mod v0.4.2 // indirect
Expand Down
17 changes: 12 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg=
github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=
Expand Down Expand Up @@ -249,6 +250,8 @@ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF0
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f h1:16RtHeWGkJMc80Etb8RPCcKevXGldr57+LOyZt8zOlg=
github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f/go.mod h1:ijRvpgDJDI262hYq/IQVYgf8hd8IHUs93Ol0kvMBAx4=
github.com/golang/geo v0.0.0-20200730024412-e86565bf3f35 h1:enTowfyfjtomBQhxX9mhUD+0tZhpe4rIzStO4aNlou8=
github.com/golang/geo v0.0.0-20200730024412-e86565bf3f35/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
Expand Down Expand Up @@ -357,8 +360,8 @@ github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSo
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
github.com/inconshreveable/log15 v0.0.0-20170622235902-74a0988b5f80/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
Expand Down Expand Up @@ -586,6 +589,8 @@ github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OK
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd h1:CmH9+J6ZSsIjUK3dcGsnCnO41eRBOnY12zwkn5qVwgc=
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
github.com/sams96/rgeo v1.2.0 h1:49cBHeXSADHGHYUsNByhzrzZXkOwYU4+/Vxv7lQn/mY=
github.com/sams96/rgeo v1.2.0/go.mod h1:ngWuABNhG1zT7afDMW5JGZHQgWeNUfPf8Ag5gaojKjA=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sheerun/queue v1.0.1 h1:TIAQyN0aRRvrJcNa2beZFfxwuxrfXBc9Mj+UWDNH7Ao=
github.com/sheerun/queue v1.0.1/go.mod h1:YtjrWT5jymvCLo/lEWDk3sv7A1Kgj0qcl3SZx7Zmcfo=
Expand Down Expand Up @@ -618,7 +623,7 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/tdewolff/canvas v0.0.0-20200504121106-e2600b35c365 h1:iNyEAGvN8yNc5/maTbLhStXRIqp+PSxpjG68KRtU3Y4=
github.com/tdewolff/canvas v0.0.0-20200504121106-e2600b35c365/go.mod h1:DCuQBGs+Nm73wH9S/z1tlUKDbAPCGa6W7A/DHU1ENmQ=
github.com/tdewolff/minify/v2 v2.7.1-0.20200112204046-70870d25a935 h1:nRG5jPGtwJpQ8KtrqhGVdLAuOnk4YWfNxh4Kx9XMuAw=
Expand All @@ -628,6 +633,8 @@ github.com/tdewolff/parse/v2 v2.4.2/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1I
github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4=
github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/twpayne/go-geom v1.4.4 h1:bcCPAvvNSzjmpUqR0Uqh39ClCKtPx6kZVR7EakQaVJI=
github.com/twpayne/go-geom v1.4.4/go.mod h1:Kz4sX4LtdesDQgkhsMERazLlH/NiCg90s6FPaNr0KNI=
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
Expand Down Expand Up @@ -1091,10 +1098,10 @@ gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gorm.io/driver/postgres v1.0.8/go.mod h1:4eOzrI1MUfm6ObJU/UcmbXyiHSs8jSwH95G5P5dxcAg=
gorm.io/gorm v1.20.12/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.21.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
Expand Down
46 changes: 40 additions & 6 deletions internal/image/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/golang-migrate/migrate/v4"
_ "github.com/golang-migrate/migrate/v4/database/sqlite"
"github.com/golang-migrate/migrate/v4/source/httpfs"
"github.com/golang/geo/s2"
)

var dateFormat = "2006-01-02 15:04:05.999999 -07:00"
Expand Down Expand Up @@ -79,6 +80,7 @@ type InfoExistence struct {
SizeNull bool
OrientationNull bool
DateTimeNull bool
LatLngNull bool
ColorNull bool
}

Expand Down Expand Up @@ -207,21 +209,25 @@ func (source *Database) writePendingInfosSqlite() {
defer upsertPrefix.Finalize()

updateMeta := conn.Prep(`
INSERT INTO infos(path_prefix_id, filename, width, height, orientation, created_at_unix, created_at_tz_offset)
INSERT INTO infos(path_prefix_id, filename, width, height, orientation, created_at_unix, created_at_tz_offset, latitude, longitude)
SELECT
id as path_prefix_id,
? as filename,
? as width,
? as height,
? orientation,
? as created_at_unix,
? as created_at_tz_offset
? as created_at_tz_offset,
? as latitude,
? as longitude
FROM prefix
WHERE str == ?
ON CONFLICT(path_prefix_id, filename) DO UPDATE SET
width=excluded.width,
height=excluded.height,
orientation=excluded.orientation,
latitude=excluded.latitude,
longitude=excluded.longitude,
created_at_unix=excluded.created_at_unix,
created_at_tz_offset=excluded.created_at_tz_offset;`)
defer updateMeta.Finalize()
Expand Down Expand Up @@ -395,7 +401,14 @@ func (source *Database) writePendingInfosSqlite() {
updateMeta.BindInt64(4, (int64)(imageInfo.Orientation))
updateMeta.BindInt64(5, imageInfo.DateTime.Unix())
updateMeta.BindInt64(6, int64(timezoneOffsetSeconds/60))
updateMeta.BindText(7, dir)
if IsNaNLatLng(imageInfo.LatLng) {
updateMeta.BindNull(7)
updateMeta.BindNull(8)
} else {
updateMeta.BindFloat(7, imageInfo.LatLng.Lat.Degrees())
updateMeta.BindFloat(8, imageInfo.LatLng.Lng.Degrees())
}
updateMeta.BindText(9, dir)

_, err := updateMeta.Step()
if err != nil {
Expand Down Expand Up @@ -664,7 +677,7 @@ func (source *Database) Get(id ImageId) (InfoResult, bool) {
defer source.pool.Put(conn)

stmt := conn.Prep(`
SELECT width, height, orientation, color, created_at
SELECT width, height, orientation, color, created_at, latitude, longitude
FROM infos
WHERE id == ?;`)
defer stmt.Reset()
Expand All @@ -691,6 +704,13 @@ func (source *Database) Get(id ImageId) (InfoResult, bool) {
info.DateTime, _ = time.Parse(dateFormat, stmt.ColumnText(4))
info.DateTimeNull = stmt.ColumnType(4) == sqlite.TypeNull

info.LatLngNull = stmt.ColumnType(5) == sqlite.TypeNull || stmt.ColumnType(6) == sqlite.TypeNull
if info.LatLngNull {
info.LatLng = NaNLatLng()
} else {
info.LatLng = s2.LatLngFromDegrees(stmt.ColumnFloat(5), stmt.ColumnFloat(6))
}

return info, true
}

Expand All @@ -702,7 +722,7 @@ func (source *Database) GetBatch(ids []ImageId) <-chan InfoListResult {
defer source.pool.Put(conn)

sql := `
SELECT id, width, height, orientation, color, created_at_unix, created_at_tz_offset
SELECT id, width, height, orientation, color, created_at_unix, created_at_tz_offset, latitude, longitude
FROM infos
WHERE id IN (`

Expand Down Expand Up @@ -745,6 +765,13 @@ func (source *Database) GetBatch(ids []ImageId) <-chan InfoListResult {
info.DateTime = time.Unix(unix, 0).In(time.FixedZone("tz_offset", timezoneOffset*60))
info.DateTimeNull = stmt.ColumnType(5) == sqlite.TypeNull

info.LatLngNull = stmt.ColumnType(7) == sqlite.TypeNull || stmt.ColumnType(8) == sqlite.TypeNull
if info.LatLngNull {
info.LatLng = NaNLatLng()
} else {
info.LatLng = s2.LatLngFromDegrees(stmt.ColumnFloat(7), stmt.ColumnFloat(8))
}

out <- info
}
close(out)
Expand Down Expand Up @@ -1273,7 +1300,7 @@ func (source *Database) List(dirs []string, options ListOptions) <-chan InfoList
}

sql += `
SELECT infos.id, width, height, orientation, color, created_at_unix, created_at_tz_offset
SELECT infos.id, width, height, orientation, color, created_at_unix, created_at_tz_offset, latitude, longitude
FROM infos
`

Expand Down Expand Up @@ -1369,6 +1396,13 @@ func (source *Database) List(dirs []string, options ListOptions) <-chan InfoList
info.DateTime = time.Unix(unix, 0).In(time.FixedZone("tz_offset", timezoneOffset*60))
info.DateTimeNull = stmt.ColumnType(5) == sqlite.TypeNull

info.LatLngNull = stmt.ColumnType(7) == sqlite.TypeNull || stmt.ColumnType(8) == sqlite.TypeNull
if info.LatLngNull {
info.LatLng = NaNLatLng()
} else {
info.LatLng = s2.LatLngFromDegrees(stmt.ColumnFloat(7), stmt.ColumnFloat(8))
}

out <- info
}

Expand Down
34 changes: 34 additions & 0 deletions internal/image/exiftool-mostlygeek.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package image
import (
"bufio"
"errors"
"math"
"photofield/tag"
"regexp"
"strconv"
"strings"
"time"

"github.com/golang/geo/s2"
"github.com/mostlygeek/go-exiftool"
)

Expand Down Expand Up @@ -50,6 +52,9 @@ func NewExifToolMostlyGeekLoader(exifToolCount int) (*ExifToolMostlyGeekLoader,
"-TimeStamp#",
"-FileModifyDate#",
"-FileCreateDate#",
// Location Info
"-GPSLatitude#",
"-GPSLongitude#",
)
return decoder, err
}
Expand All @@ -70,6 +75,8 @@ func (decoder *ExifToolMostlyGeekLoader) DecodeInfo(path string, info *Info) ([]
rotation := ""
imageWidth := ""
imageHeight := ""
latitude := ""
longitude := ""

// var gpsTime time.Time

Expand All @@ -93,6 +100,13 @@ func (decoder *ExifToolMostlyGeekLoader) DecodeInfo(path string, info *Info) ([]
imageWidth = value
case "ImageHeight":
imageHeight = value
case "GPSLatitude":
latitude = value
case "GPSLongitude":
longitude = value

// case "GPSDateTime":
// gpsTime, _ = parseDateTime(value)
default:
if name, ok := tag.ExifTagToName[name]; ok {
tags = append(tags, tag.NewExif(name, value))
Expand Down Expand Up @@ -139,6 +153,26 @@ func (decoder *ExifToolMostlyGeekLoader) DecodeInfo(path string, info *Info) ([]
info.Orientation = getOrientationFromRotation(rotation)
}

lat := math.NaN()
lng := math.NaN()
if latitude != "" && longitude != "" {
lat, err = strconv.ParseFloat(latitude, 64)
if err != nil {
lat = math.NaN()
}

lng, err = strconv.ParseFloat(longitude, 64)
if err != nil {
lng = math.NaN()
}
}

if !math.IsNaN(lat) && !math.IsNaN(lng) {
info.LatLng = s2.LatLngFromDegrees(lat, lng)
} else {
info.LatLng = NaNLatLng()
}

if info.Orientation.SwapsDimensions() {
info.Width, info.Height = info.Height, info.Width
}
Expand Down
22 changes: 21 additions & 1 deletion internal/image/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import (
"fmt"
"image"
"image/color"
"math"
"time"

"github.com/golang/geo/s1"
"github.com/golang/geo/s2"
)

type Size = image.Point
Expand All @@ -14,19 +18,35 @@ type Info struct {
DateTime time.Time
Color uint32
Orientation Orientation
LatLng s2.LatLng
}

const earthRadiusKm = 6371.01

func NaNLatLng() s2.LatLng {
return s2.LatLng{Lat: s1.Angle(math.NaN()), Lng: s1.Angle(math.NaN())}
}

func IsNaNLatLng(latlng s2.LatLng) bool {
return math.IsNaN(float64(latlng.Lat)) || math.IsNaN(float64(latlng.Lng))
}

func AngleToKm(a s1.Angle) float64 {
return a.Radians() * earthRadiusKm
}

func (info *Info) Size() Size {
return Size{X: info.Width, Y: info.Height}
}

func (info *Info) String() string {
return fmt.Sprintf("width: %v, height: %v, date: %v, color: %08x, orientation: %s",
return fmt.Sprintf("width: %v, height: %v, date: %v, color: %08x, orientation: %s, latlng: %s",
info.Width,
info.Height,
info.DateTime.String(),
info.Color,
info.Orientation,
info.LatLng.String(),
)
}

Expand Down
Loading