diff --git a/resources/images/exif/exif.go b/resources/images/exif/exif.go index 8df348b23..90198eeed 100644 --- a/resources/images/exif/exif.go +++ b/resources/images/exif/exif.go @@ -173,11 +173,12 @@ func decodeTag(x *_exif.Exif, f _exif.FieldName, t *tiff.Tag) (any, error) { case tiff.RatVal: n, d, _ := t.Rat2(i) rat := big.NewRat(n, d) - if n == 1 { - rv = append(rv, rat) - } else { + // if t is int or t > 1, use float64 + if rat.IsInt() || rat.Cmp(big.NewRat(1, 1)) == 1 { f, _ := rat.Float64() rv = append(rv, f) + } else { + rv = append(rv, rat) } case tiff.FloatVal: diff --git a/resources/images/exif/exif_test.go b/resources/images/exif/exif_test.go index cd5961404..821367550 100644 --- a/resources/images/exif/exif_test.go +++ b/resources/images/exif/exif_test.go @@ -133,3 +133,183 @@ var eq = qt.CmpEquals( return v1.Unix() == v2.Unix() }), ) + +func TestIssue10738(t *testing.T) { + + c := qt.New(t) + + testFunc := func(path, include string) any { + f, err := os.Open(filepath.FromSlash(path)) + c.Assert(err, qt.IsNil) + defer f.Close() + + d, err := NewDecoder(IncludeFields(include)) + c.Assert(err, qt.IsNil) + x, err := d.Decode(f) + c.Assert(err, qt.IsNil) + + // Verify that it survives a round-trip to JSON and back. + data, err := json.Marshal(x) + c.Assert(err, qt.IsNil) + x2 := &ExifInfo{} + err = json.Unmarshal(data, x2) + + c.Assert(x2, eq, x) + + v, found := x.Tags["ExposureTime"] + c.Assert(found, qt.Equals, true) + return v + } + + type args struct { + path string // imagePath + include string // includeFields + } + + type want struct { + vN int64 // numerator + vD int64 // denominator + } + + type testCase struct { + name string + args args + want want + } + + tests := []testCase{ + { + "canon_cr2_fraction", args{ + path: "../../testdata/issue10738/canon_cr2_fraction.jpg", + include: "Lens|Date|ExposureTime", + }, want{ + 1, + 500, + }, + }, + { + "canon_cr2_integer", args{ + path: "../../testdata/issue10738/canon_cr2_integer.jpg", + include: "Lens|Date|ExposureTime", + }, want{ + 10, + 0, + }, + }, + { + "dji_dng_fraction", args{ + path: "../../testdata/issue10738/dji_dng_fraction.jpg", + include: "Lens|Date|ExposureTime", + }, want{ + 1, + 4000, + }, + }, + { + "fuji_raf_fraction", args{ + path: "../../testdata/issue10738/fuji_raf_fraction.jpg", + include: "Lens|Date|ExposureTime", + }, want{ + 1, + 250, + }, + }, + { + "fuji_raf_integer", args{ + path: "../../testdata/issue10738/fuji_raf_integer.jpg", + include: "Lens|Date|ExposureTime", + }, want{ + 1, + 0, + }, + }, + { + "leica_dng_fraction", args{ + path: "../../testdata/issue10738/leica_dng_fraction.jpg", + include: "Lens|Date|ExposureTime", + }, want{ + 1, + 100, + }, + }, + { + "lumix_rw2_fraction", args{ + path: "../../testdata/issue10738/lumix_rw2_fraction.jpg", + include: "Lens|Date|ExposureTime", + }, want{ + 1, + 400, + }, + }, + { + "nikon_nef_d5600", args{ + path: "../../testdata/issue10738/nikon_nef_d5600.jpg", + include: "Lens|Date|ExposureTime", + }, want{ + 1, + 1000, + }, + }, + { + "nikon_nef_fraction", args{ + path: "../../testdata/issue10738/nikon_nef_fraction.jpg", + include: "Lens|Date|ExposureTime", + }, want{ + 1, + 640, + }, + }, + { + "nikon_nef_integer", args{ + path: "../../testdata/issue10738/nikon_nef_integer.jpg", + include: "Lens|Date|ExposureTime", + }, want{ + 30, + 0, + }, + }, + { + "nikon_nef_fraction_2", args{ + path: "../../testdata/issue10738/nikon_nef_fraction_2.jpg", + include: "Lens|Date|ExposureTime", + }, want{ + 1, + 6400, + }, + }, + { + "sony_arw_fraction", args{ + path: "../../testdata/issue10738/sony_arw_fraction.jpg", + include: "Lens|Date|ExposureTime", + }, want{ + 1, + 160, + }, + }, + { + "sony_arw_integer", args{ + path: "../../testdata/issue10738/sony_arw_integer.jpg", + include: "Lens|Date|ExposureTime", + }, want{ + 4, + 0, + }, + }, + } + + for _, tt := range tests { + c.Run(tt.name, func(c *qt.C) { + got := testFunc(tt.args.path, tt.args.include) + switch got.(type) { + case float64: + eTime, ok := got.(float64) + c.Assert(ok, qt.Equals, true) + c.Assert(eTime, qt.Equals, float64(tt.want.vN)) + case *big.Rat: + eTime, ok := got.(*big.Rat) + c.Assert(ok, qt.Equals, true) + c.Assert(eTime, eq, big.NewRat(tt.want.vN, tt.want.vD)) + } + }) + } +} diff --git a/resources/testdata/issue10738/canon_cr2_fraction.jpg b/resources/testdata/issue10738/canon_cr2_fraction.jpg new file mode 100644 index 000000000..4ee6a23e9 Binary files /dev/null and b/resources/testdata/issue10738/canon_cr2_fraction.jpg differ diff --git a/resources/testdata/issue10738/canon_cr2_integer.jpg b/resources/testdata/issue10738/canon_cr2_integer.jpg new file mode 100644 index 000000000..145a9935d Binary files /dev/null and b/resources/testdata/issue10738/canon_cr2_integer.jpg differ diff --git a/resources/testdata/issue10738/dji_dng_fraction.jpg b/resources/testdata/issue10738/dji_dng_fraction.jpg new file mode 100644 index 000000000..fdbad4aaf Binary files /dev/null and b/resources/testdata/issue10738/dji_dng_fraction.jpg differ diff --git a/resources/testdata/issue10738/fuji_raf_fraction.jpg b/resources/testdata/issue10738/fuji_raf_fraction.jpg new file mode 100644 index 000000000..1a588229e Binary files /dev/null and b/resources/testdata/issue10738/fuji_raf_fraction.jpg differ diff --git a/resources/testdata/issue10738/fuji_raf_integer.jpg b/resources/testdata/issue10738/fuji_raf_integer.jpg new file mode 100644 index 000000000..3902be379 Binary files /dev/null and b/resources/testdata/issue10738/fuji_raf_integer.jpg differ diff --git a/resources/testdata/issue10738/leica_dng_fraction.jpg b/resources/testdata/issue10738/leica_dng_fraction.jpg new file mode 100644 index 000000000..a1ccf452e Binary files /dev/null and b/resources/testdata/issue10738/leica_dng_fraction.jpg differ diff --git a/resources/testdata/issue10738/lumix_rw2_fraction.jpg b/resources/testdata/issue10738/lumix_rw2_fraction.jpg new file mode 100644 index 000000000..5da5943d6 Binary files /dev/null and b/resources/testdata/issue10738/lumix_rw2_fraction.jpg differ diff --git a/resources/testdata/issue10738/nikon_nef_d5600.jpg b/resources/testdata/issue10738/nikon_nef_d5600.jpg new file mode 100644 index 000000000..26d791f39 Binary files /dev/null and b/resources/testdata/issue10738/nikon_nef_d5600.jpg differ diff --git a/resources/testdata/issue10738/nikon_nef_fraction.jpg b/resources/testdata/issue10738/nikon_nef_fraction.jpg new file mode 100644 index 000000000..535addad1 Binary files /dev/null and b/resources/testdata/issue10738/nikon_nef_fraction.jpg differ diff --git a/resources/testdata/issue10738/nikon_nef_fraction_2.jpg b/resources/testdata/issue10738/nikon_nef_fraction_2.jpg new file mode 100644 index 000000000..15d9bda92 Binary files /dev/null and b/resources/testdata/issue10738/nikon_nef_fraction_2.jpg differ diff --git a/resources/testdata/issue10738/nikon_nef_integer.jpg b/resources/testdata/issue10738/nikon_nef_integer.jpg new file mode 100644 index 000000000..00a880511 Binary files /dev/null and b/resources/testdata/issue10738/nikon_nef_integer.jpg differ diff --git a/resources/testdata/issue10738/sony_arw_fraction.jpg b/resources/testdata/issue10738/sony_arw_fraction.jpg new file mode 100644 index 000000000..6550b5d39 Binary files /dev/null and b/resources/testdata/issue10738/sony_arw_fraction.jpg differ diff --git a/resources/testdata/issue10738/sony_arw_integer.jpg b/resources/testdata/issue10738/sony_arw_integer.jpg new file mode 100644 index 000000000..8548c0a18 Binary files /dev/null and b/resources/testdata/issue10738/sony_arw_integer.jpg differ