diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2019-08-26 19:12:41 +0200 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2019-08-28 15:59:54 +0200 |
commit | 823f53c861bb49aecc6104e0add39fc3b0729025 (patch) | |
tree | 64a55d1c41de09b67305ad69a3600f3091d4f1fc | |
parent | f9978ed16476ca6d233a89669c62c798cdf9db9d (diff) |
Add a set of image filters
With this you can do variants of this:
```
{{ $img := resources.Get "images/misc/3-jenny.jpg" }}
{{ $img := $img.Resize "300x" }}
{{ $g1 := $img.Filter images.Grayscale }}
{{ $g2 := $img | images.Filter (images.Saturate 30) (images.GaussianBlur 3) }}
```
Fixes #6255
89 files changed, 791 insertions, 139 deletions
@@ -12,7 +12,7 @@ require ( github.com/bep/debounce v1.2.0 github.com/bep/gitmap v1.1.0 github.com/bep/go-tocss v0.6.0 - github.com/disintegration/imaging v1.6.0 + github.com/disintegration/gift v1.2.1 github.com/dustin/go-humanize v1.0.0 github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 github.com/fortytw2/leaktest v1.3.0 @@ -88,8 +88,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= -github.com/disintegration/imaging v1.6.0 h1:nVPXRUUQ36Z7MNf0O77UzgnOb1mkMMor7lmJMJXc/mA= -github.com/disintegration/imaging v1.6.0/go.mod h1:xuIt+sRxDFrHS0drzXUlCJthkJ8k7lkkUojDSR247MQ= +github.com/disintegration/gift v1.2.1 h1:Y005a1X4Z7Uc+0gLpSAsKhWi4qLtsdEcMIbbdvdZ6pc= +github.com/disintegration/gift v1.2.1/go.mod h1:Jh2i7f7Q2BM7Ezno3PhfezbR1xpUg9dUg3/RlKGr4HI= github.com/dlclark/regexp2 v1.1.6 h1:CqB4MjHw0MFCDj+PHHjiESmHX+N7t0tJzKvC6M97BRg= github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= @@ -338,8 +338,6 @@ golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81 h1:00VmoueYNlNz/aHIilyyQz/MHSqGoWJzpFv/HW8xpzI= -golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190523035834-f03afa92d3ff h1:+2zgJKVDVAz/BWSsuniCmU1kLCjL88Z8/kv39xCI9NQ= golang.org/x/image v0.0.0-20190523035834-f03afa92d3ff/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= diff --git a/resources/image.go b/resources/image.go index e1a816942..7113284f7 100644 --- a/resources/image.go +++ b/resources/image.go @@ -16,18 +16,19 @@ package resources import ( "fmt" "image" - "image/color" "image/draw" _ "image/gif" _ "image/png" "os" "strings" + "github.com/gohugoio/hugo/resources/internal" + "github.com/gohugoio/hugo/resources/resource" _errors "github.com/pkg/errors" - "github.com/disintegration/imaging" + "github.com/disintegration/gift" "github.com/gohugoio/hugo/helpers" "github.com/gohugoio/hugo/resources/images" @@ -82,16 +83,26 @@ func (i *imageResource) cloneWithUpdates(u *transformationUpdate) (baseResource, // filter and returns the transformed image. If one of width or height is 0, the image aspect // ratio is preserved. func (i *imageResource) Resize(spec string) (resource.Image, error) { - return i.doWithImageConfig("resize", spec, func(src image.Image, conf images.ImageConfig) (image.Image, error) { - return i.Proc.Resize(src, conf) + conf, err := i.decodeImageConfig("resize", spec) + if err != nil { + return nil, err + } + + return i.doWithImageConfig(conf, func(src image.Image) (image.Image, error) { + return i.Proc.ApplyFiltersFromConfig(src, conf) }) } // Fit scales down the image using the specified resample filter to fit the specified // maximum width and height. func (i *imageResource) Fit(spec string) (resource.Image, error) { - return i.doWithImageConfig("fit", spec, func(src image.Image, conf images.ImageConfig) (image.Image, error) { - return i.Proc.Fit(src, conf) + conf, err := i.decodeImageConfig("fit", spec) + if err != nil { + return nil, err + } + + return i.doWithImageConfig(conf, func(src image.Image) (image.Image, error) { + return i.Proc.ApplyFiltersFromConfig(src, conf) }) } @@ -99,8 +110,22 @@ func (i *imageResource) Fit(spec string) (resource.Image, error) { // crops the resized image to the specified dimensions using the given anchor point. // Space delimited config: 200x300 TopLeft func (i *imageResource) Fill(spec string) (resource.Image, error) { - return i.doWithImageConfig("fill", spec, func(src image.Image, conf images.ImageConfig) (image.Image, error) { - return i.Proc.Fill(src, conf) + conf, err := i.decodeImageConfig("fill", spec) + if err != nil { + return nil, err + } + + return i.doWithImageConfig(conf, func(src image.Image) (image.Image, error) { + return i.Proc.ApplyFiltersFromConfig(src, conf) + }) +} + +func (i *imageResource) Filter(filters ...gift.Filter) (resource.Image, error) { + conf := i.Proc.GetDefaultImageConfig("filter") + conf.Key = internal.HashString(filters) + + return i.doWithImageConfig(conf, func(src image.Image) (image.Image, error) { + return i.Proc.Filter(src, filters...) }) } @@ -118,19 +143,14 @@ const imageProcWorkers = 1 var imageProcSem = make(chan bool, imageProcWorkers) -func (i *imageResource) doWithImageConfig(action, spec string, f func(src image.Image, conf images.ImageConfig) (image.Image, error)) (resource.Image, error) { - conf, err := i.decodeImageConfig(action, spec) - if err != nil { - return nil, err - } - +func (i *imageResource) doWithImageConfig(conf images.ImageConfig, f func(src image.Image) (image.Image, error)) (resource.Image, error) { return i.getSpec().imageCache.getOrCreate(i, conf, func() (*imageResource, image.Image, error) { imageProcSem <- true defer func() { <-imageProcSem }() - errOp := action + errOp := conf.Action errPath := i.getSourceFilename() src, err := i.decodeSource() @@ -138,17 +158,12 @@ func (i *imageResource) doWithImageConfig(action, spec string, f func(src image. return nil, nil, &os.PathError{Op: errOp, Path: errPath, Err: err} } - if conf.Rotate != 0 { - // Rotate it before any scaling to get the dimensions correct. - src = imaging.Rotate(src, float64(conf.Rotate), color.Transparent) - } - - converted, err := f(src, conf) + converted, err := f(src) if err != nil { return nil, nil, &os.PathError{Op: errOp, Path: errPath, Err: err} } - if i.Format == imaging.PNG { + if i.Format == images.PNG { // Apply the colour palette from the source if paletted, ok := src.(*image.Paletted); ok { tmp := image.NewPaletted(converted.Bounds(), paletted.Palette) @@ -222,7 +237,7 @@ func (i *imageResource) re |