Skip to content

Commit

Permalink
exif: Improve performance
Browse files Browse the repository at this point in the history
Also, do not return an error when input format isn't supported. Just return `nil` exif.

Using the stream API and avoid creating the Ifd mapping and tag index every time makes it faster:

```
name           old time/op    new time/op    delta
DecodeExif-16    3.42ms ± 0%    0.65ms ± 0%  -81.12%  (p=0.029 n=4+4)

name           old alloc/op   new alloc/op   delta
DecodeExif-16    1.51MB ± 0%    0.59MB ± 0%  -60.77%  (p=0.029 n=4+4)

name           old allocs/op  new allocs/op  delta
DecodeExif-16     12.9k ± 0%      1.9k ± 0%  -85.48%  (p=0.029 n=4+4)
```

It's still slower than what we had, though, but correctness comes at a cost:

```

name           old time/op    new time/op    delta
DecodeExif-16     186µs ± 0%     648µs ± 1%  +249.21%  (p=0.029 n=4+4)

name           old alloc/op   new alloc/op   delta
DecodeExif-16     184kB ± 0%     593kB ± 0%  +222.38%  (p=0.029 n=4+4)

name           old allocs/op  new allocs/op  delta
DecodeExif-16     1.20k ± 0%     1.88k ± 0%   +55.99%  (p=0.029 n=4+4)
```

See #8586
  • Loading branch information
bep committed Jul 18, 2021
1 parent 0bb01ba commit 9a00eef
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 22 deletions.
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,6 @@ require (
)

go 1.16


replace github.com/dsoprea/go-exif/v3 => /Users/bep/dev/go/dump/go-exif/v3
31 changes: 11 additions & 20 deletions resources/images/exif/exif.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@
package exif

import (
"fmt"
"io"
"io/ioutil"
"math/big"
"regexp"
"strings"
Expand All @@ -26,7 +24,6 @@ import (

_exif "github.com/dsoprea/go-exif/v3"
exifcommon "github.com/dsoprea/go-exif/v3/common"
png "github.com/dsoprea/go-png-image-structure"
)

const (
Expand All @@ -47,6 +44,9 @@ type Decoder struct {
excludeFieldsrRe *regexp.Regexp
noDate bool
noLatLong bool

idfm *exifcommon.IfdMapping
ti *_exif.TagIndex
}

func IncludeFields(expression string) func(*Decoder) error {
Expand Down Expand Up @@ -99,7 +99,12 @@ func compileRegexp(expression string) (*regexp.Regexp, error) {
}

func NewDecoder(options ...func(*Decoder) error) (*Decoder, error) {
d := &Decoder{}
im, err := exifcommon.NewIfdMappingWithStandard()
if err != nil {
return nil, err
}
ti := _exif.NewTagIndex()
d := &Decoder{idfm: im, ti: ti}
for _, opt := range options {
if err := opt(d); err != nil {
return nil, err
Expand All @@ -110,28 +115,14 @@ func NewDecoder(options ...func(*Decoder) error) (*Decoder, error) {
}

func (d *Decoder) Decode(r io.Reader) (*Exif, error) {
rawBytes, err := ioutil.ReadAll(r)
if err != nil {
return nil, err
}
rawExif, err := _exif.SearchAndExtractExif(rawBytes)
rawExif, err := _exif.SearchAndExtractExifWithReader(r)

if err != nil {
parsed := png.NewPngMediaParser()
if parsed.LooksLikeFormat(rawBytes) {
return nil, fmt.Errorf("type not supported")
}
// No Exif data
return nil, nil
}

im, err := exifcommon.NewIfdMappingWithStandard()
if err != nil {
return nil, err
}
ti := _exif.NewTagIndex()

_, index, err := _exif.Collect(im, ti, rawExif)
_, index, err := _exif.Collect(d.idfm, d.ti, rawExif)
if err != nil {
return nil, err
}
Expand Down
44 changes: 42 additions & 2 deletions resources/images/exif/exif_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,16 @@
package exif

import (
"context"
"encoding/json"
"errors"
"math/big"
"os"
"path/filepath"
"testing"
"time"

"github.com/gohugoio/hugo/common/para"
"github.com/gohugoio/hugo/htesting/hqt"
"github.com/google/go-cmp/cmp"

Expand Down Expand Up @@ -62,6 +65,42 @@ func TestExif(t *testing.T) {
c.Assert(x2, eq, x)
}

func TestExifParallel(t *testing.T) {
c := qt.New(t)

d, err := NewDecoder(IncludeFields("Lens|Date"))
c.Assert(err, qt.IsNil)

p := para.New(4)
r, _ := p.Start(context.Background())

for i := 0; i < 20; i++ {
r.Run(func() error {
f, err := os.Open(filepath.FromSlash("../../testdata/sunset.jpg"))
if err != nil {
return err
}
defer f.Close()

x, err := d.Decode(f)
if err != nil {
return err
}

if x.Date.Format("2006-01-02") != "2017-10-27" {
return errors.New("invalid date")
}

return nil

})

}

c.Assert(r.Wait(), qt.IsNil)

}

func TestImageWithoutExifData(t *testing.T) {
c := qt.New(t)
f, err := os.Open(filepath.FromSlash("../../testdata/sunset_without_exif.jpg"))
Expand Down Expand Up @@ -143,8 +182,9 @@ func TestExifPNG(t *testing.T) {

d, err := NewDecoder()
c.Assert(err, qt.IsNil)
_, err = d.Decode(f)
c.Assert(err, qt.Not(qt.IsNil))
x, err := d.Decode(f)
c.Assert(err, qt.IsNil)
c.Assert(x, qt.IsNil)
}

func TestIssue8079(t *testing.T) {
Expand Down

0 comments on commit 9a00eef

Please sign in to comment.