diff --git a/api/scanner/exif/exif_parser_external.go b/api/scanner/exif/exif_parser_external.go index b057d1c9..61d958ec 100644 --- a/api/scanner/exif/exif_parser_external.go +++ b/api/scanner/exif/exif_parser_external.go @@ -21,6 +21,7 @@ func (p *externalExifParser) ParseExif(media_path string) (returnExif *models.Me fileInfos := et.ExtractMetadata(media_path) newExif := models.MediaEXIF{} + found_exif := false for _, fileInfo := range fileInfos { if fileInfo.Err != nil { @@ -31,18 +32,21 @@ func (p *externalExifParser) ParseExif(media_path string) (returnExif *models.Me // 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 } @@ -52,6 +56,7 @@ func (p *externalExifParser) ParseExif(media_path string) (returnExif *models.Me layout := "2006:01:02 15:04:05" dateTime, err := time.Parse(layout, date) if err == nil { + found_exif = true newExif.DateShot = &dateTime } } @@ -59,58 +64,71 @@ func (p *externalExifParser) ParseExif(media_path string) (returnExif *models.Me // 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 return } diff --git a/api/scanner/exif/exif_parser_internal.go b/api/scanner/exif/exif_parser_internal.go index b1d30129..5897e6e5 100644 --- a/api/scanner/exif/exif_parser_internal.go +++ b/api/scanner/exif/exif_parser_internal.go @@ -5,6 +5,7 @@ import ( "log" "math/big" "os" + "time" "github.com/photoview/photoview/api/graphql/models" "github.com/pkg/errors" @@ -33,7 +34,8 @@ func (p *internalExifParser) ParseExif(media_path string) (returnExif *models.Me exifTags, err := exif.Decode(photoFile) if err != nil { - return nil, errors.Wrap(err, "Could not decode EXIF") + return nil, nil + // return nil, errors.Wrap(err, "Could not decode EXIF") } newExif := models.MediaEXIF{} @@ -55,7 +57,9 @@ func (p *internalExifParser) ParseExif(media_path string) (returnExif *models.Me date, err := exifTags.DateTime() if err == nil { - newExif.DateShot = &date + _, tz := date.Zone() + date_utc := date.Add(time.Duration(tz) * time.Second).UTC() + newExif.DateShot = &date_utc } exposure, err := exifTags.Get(exif.ExposureTime) diff --git a/api/scanner/exif/exif_test.go b/api/scanner/exif/exif_test.go index 049de693..f125be95 100644 --- a/api/scanner/exif/exif_test.go +++ b/api/scanner/exif/exif_test.go @@ -1,18 +1,20 @@ -// +build integration - package exif import ( + "fmt" + "path" "testing" "time" + "github.com/barasher/go-exiftool" + "github.com/photoview/photoview/api/graphql/models" "github.com/stretchr/testify/assert" ) -const bird_path = "./test_data/bird.jpg" - func TestExifParsers(t *testing.T) { - t.Parallel() + if testing.Short() { + t.Skip("skipping integration test") + } parsers := []struct { name string @@ -28,13 +30,14 @@ func TestExifParsers(t *testing.T) { }, } - for _, p := range parsers { - t.Run(p.name, func(t *testing.T) { - t.Parallel() - - exif, err := p.parser.ParseExif(bird_path) - - if assert.NoError(t, err) { + images := []struct { + path string + assert func(t *testing.T, exif *models.MediaEXIF) + }{ + { + path: "./test_data/bird.jpg", + assert: func(t *testing.T, exif *models.MediaEXIF) { + assert.WithinDuration(t, *exif.DateShot, time.Unix(1336318784, 0).UTC(), time.Minute) assert.EqualValues(t, *exif.Camera, "Canon EOS 600D") assert.EqualValues(t, *exif.Maker, "Canon") assert.WithinDuration(t, *exif.DateShot, time.Unix(1336318784, 0).UTC(), time.Minute) @@ -45,8 +48,34 @@ func TestExifParsers(t *testing.T) { assert.EqualValues(t, *exif.Orientation, 1) assert.InDelta(t, *exif.GPSLatitude, 65.01681388888889, 0.0001) assert.InDelta(t, *exif.GPSLongitude, 25.466863888888888, 0.0001) - } - }) + }, + }, + { + path: "./test_data/stripped.jpg", + assert: func(t *testing.T, exif *models.MediaEXIF) { + assert.Nil(t, exif) + }, + }, + } + + for _, p := range parsers { + for _, img := range images { + t.Run(fmt.Sprintf("%s:%s", p.name, path.Base(img.path)), func(t *testing.T) { + + if p.name == "external" { + _, err := exiftool.NewExiftool() + if err != nil { + t.Skip("failed to get exiftool, skipping test") + } + } + + exif, err := p.parser.ParseExif(img.path) + + if assert.NoError(t, err) { + img.assert(t, exif) + } + }) + } } } diff --git a/api/scanner/exif/test_data/stripped.jpg b/api/scanner/exif/test_data/stripped.jpg new file mode 100644 index 00000000..4a1788e8 Binary files /dev/null and b/api/scanner/exif/test_data/stripped.jpg differ