diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2020-12-16 15:52:47 +0300 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2020-12-17 11:14:18 +0300 |
commit | 3ba147e702a5ae0af6e8b3b0296d256c3246a546 (patch) | |
tree | be78ef8f1a2106bf8816f0a8c4f7872169353691 /resources | |
parent | a2d146ec32a26ccca9ffa68d3c840ec5b08cca96 (diff) |
images: Add images.Overlay filter
This allows for constructs ala:
```
{{ $overlay := $img.Filter (images.Overlay $logo 50 50 )}}
```
Or:
```
{{ $logoFilter := (images.Overlay $logo 50 50 ) }}
{{ $overlay := $img | images.Filter $logoFilter }}
```
Which will overlay the logo in the top left corner (x=50, y=50) of `$img`.
Fixes #8057
Fixes #4595
Updates #6731
Diffstat (limited to 'resources')
-rw-r--r-- | resources/image.go | 6 | ||||
-rw-r--r-- | resources/image_test.go | 6 | ||||
-rw-r--r-- | resources/images/filters.go | 8 | ||||
-rw-r--r-- | resources/images/image.go | 6 | ||||
-rw-r--r-- | resources/images/overlay.go | 43 | ||||
-rw-r--r-- | resources/resource/resourcetypes.go | 5 | ||||
-rw-r--r-- | resources/testdata/golden/gohugoio24_huc57dd738f4724f4b341121e66fd85555_267952_3ad578dd67cd055b4382e4062918d0a2.png | bin | 0 -> 61498 bytes | |||
-rw-r--r-- | resources/testdata/golden/gohugoio8_hu7f72c00afdf7634587afaa5eff2a25b2_73538_b4afd8d32218a87ed1f7e351368501c3.png | bin | 0 -> 26664 bytes | |||
-rw-r--r-- | resources/testdata/golden/gopher-hero8_huaa0cd7d2cfc14ff32a57f171896f2285_13327_30x0_resize_box_2.png | bin | 0 -> 1314 bytes | |||
-rw-r--r-- | resources/testdata/golden/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_da536a2a5436e387d0d482675e08ad48.jpg | bin | 0 -> 6848 bytes | |||
-rw-r--r-- | resources/transform.go | 5 |
11 files changed, 77 insertions, 2 deletions
diff --git a/resources/image.go b/resources/image.go index ed303613f..0396c2208 100644 --- a/resources/image.go +++ b/resources/image.go @@ -242,7 +242,7 @@ func (i *imageResource) doWithImageConfig(conf images.ImageConfig, f func(src im errOp := conf.Action errPath := i.getSourceFilename() - src, err := i.decodeSource() + src, err := i.DecodeImage() if err != nil { return nil, nil, &os.PathError{Op: errOp, Path: errPath, Err: err} } @@ -324,7 +324,9 @@ func (i *imageResource) decodeImageConfig(action, spec string) (images.ImageConf return conf, nil } -func (i *imageResource) decodeSource() (image.Image, error) { +// DecodeImage decodes the image source into an Image. +// This an internal method and may change. +func (i *imageResource) DecodeImage() (image.Image, error) { f, err := i.ReadSeekCloser() if err != nil { return nil, _errors.Wrap(err, "failed to open image for decode") diff --git a/resources/image_test.go b/resources/image_test.go index 9c1861960..8c69591cf 100644 --- a/resources/image_test.go +++ b/resources/image_test.go @@ -533,6 +533,11 @@ func TestImageOperationsGolden(t *testing.T) { fmt.Println(workDir) } + gopher := fetchImageForSpec(spec, c, "gopher-hero8.png") + var err error + gopher, err = gopher.Resize("30x") + c.Assert(err, qt.IsNil) + // Test PNGs with alpha channel. for _, img := range []string{"gopher-hero8.png", "gradient-circle.png"} { orig := fetchImageForSpec(spec, c, img) @@ -589,6 +594,7 @@ func TestImageOperationsGolden(t *testing.T) { f.Invert(), f.Hue(22), f.Contrast(32.5), + f.Overlay(gopher.(images.ImageSource), 20, 30), } resized, err := orig.Fill("400x200 center") diff --git a/resources/images/filters.go b/resources/images/filters.go index dd7b58345..74c50363e 100644 --- a/resources/images/filters.go +++ b/resources/images/filters.go @@ -25,6 +25,14 @@ const filterAPIVersion = 0 type Filters struct { } +// Overlay creates a filter that overlays src at position x y. +func (*Filters) Overlay(src ImageSource, x, y interface{}) gift.Filter { + return filter{ + Options: newFilterOpts(src.Key(), x, y), + Filter: overlayFilter{src: src, x: cast.ToInt(x), y: cast.ToInt(y)}, + } +} + // Brightness creates a filter that changes the brightness of an image. // The percentage parameter must be in range (-100, 100). func (*Filters) Brightness(percentage interface{}) gift.Filter { diff --git a/resources/images/image.go b/resources/images/image.go index 88eed2f7e..3d28263c0 100644 --- a/resources/images/image.go +++ b/resources/images/image.go @@ -325,3 +325,9 @@ func IsOpaque(img image.Image) bool { return false } + +// ImageSource identifies and decodes an image. +type ImageSource interface { + DecodeImage() (image.Image, error) + Key() string +} diff --git a/resources/images/overlay.go b/resources/images/overlay.go new file mode 100644 index 000000000..780e28fd1 --- /dev/null +++ b/resources/images/overlay.go @@ -0,0 +1,43 @@ +// Copyright 2020 The Hugo Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package images + +import ( + "fmt" + "image" + "image/draw" + + "github.com/disintegration/gift" +) + +var _ gift.Filter = (*overlayFilter)(nil) + +type overlayFilter struct { + src ImageSource + x, y int +} + +func (f overlayFilter) Draw(dst draw.Image, src image.Image, options *gift.Options) { + overlaySrc, err := f.src.DecodeImage() + if err != nil { + panic(fmt.Sprintf("failed to decode image: %s", err)) + } + + gift.New().Draw(dst, src) + gift.New().DrawAt(dst, overlaySrc, image.Pt(f.x, f.y), gift.OverOperator) +} + +func (f overlayFilter) Bounds(srcBounds image.Rectangle) image.Rectangle { + return image.Rect(0, 0, srcBounds.Dx(), srcBounds.Dy()) +} diff --git a/resources/resource/resourcetypes.go b/resources/resource/resourcetypes.go index f42372fa3..206ce8de8 100644 --- a/resources/resource/resourcetypes.go +++ b/resources/resource/resourcetypes.go @@ -14,6 +14,8 @@ package resource import ( + "image" + "github.com/gohugoio/hugo/common/maps" "github.com/gohugoio/hugo/langs" "github.com/gohugoio/hugo/media" @@ -59,6 +61,9 @@ type ImageOps interface { Resize(spec string) (Image, error) Filter(filters ...interface{}) (Image, error) Exif() *exif.Exif + + // Internal + DecodeImage() (image.Image, error) } type ResourceTypeProvider interface { diff --git a/resources/testdata/golden/gohugoio24_huc57dd738f4724f4b341121e66fd85555_267952_3ad578dd67cd055b4382e4062918d0a2.png b/resources/testdata/golden/gohugoio24_huc57dd738f4724f4b341121e66fd85555_267952_3ad578dd67cd055b4382e4062918d0a2.png Binary files differnew file mode 100644 index 000000000..3a267fbdb --- /dev/null +++ b/resources/testdata/golden/gohugoio24_huc57dd738f4724f4b341121e66fd85555_267952_3ad578dd67cd055b4382e4062918d0a2.png diff --git a/resources/testdata/golden/gohugoio8_hu7f72c00afdf7634587afaa5eff2a25b2_73538_b4afd8d32218a87ed1f7e351368501c3.png b/resources/testdata/golden/gohugoio8_hu7f72c00afdf7634587afaa5eff2a25b2_73538_b4afd8d32218a87ed1f7e351368501c3.png Binary files differnew file mode 100644 index 000000000..86896ef01 --- /dev/null +++ b/resources/testdata/golden/gohugoio8_hu7f72c00afdf7634587afaa5eff2a25b2_73538_b4afd8d32218a87ed1f7e351368501c3.png diff --git a/resources/testdata/golden/gopher-hero8_huaa0cd7d2cfc14ff32a57f171896f2285_13327_30x0_resize_box_2.png b/resources/testdata/golden/gopher-hero8_huaa0cd7d2cfc14ff32a57f171896f2285_13327_30x0_resize_box_2.png Binary files differnew file mode 100644 index 000000000..5b8748351 --- /dev/null +++ b/resources/testdata/golden/gopher-hero8_huaa0cd7d2cfc14ff32a57f171896f2285_13327_30x0_resize_box_2.png diff --git a/resources/testdata/golden/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_da536a2a5436e387d0d482675e08ad48.jpg b/resources/testdata/golden/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_da536a2a5436e387d0d482675e08ad48.jpg Binary files differnew file mode 100644 index 000000000..15f2ef1c5 --- /dev/null +++ b/resources/testdata/golden/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_da536a2a5436e387d0d482675e08ad48.jpg diff --git a/resources/transform.go b/resources/transform.go index a9ec84671..9007ead18 100644 --- a/resources/transform.go +++ b/resources/transform.go @@ -16,6 +16,7 @@ package resources import ( "bytes" "fmt" + "image" "io" "path" "strings" @@ -264,6 +265,10 @@ func (r *resourceAdapter) Width() int { return r.getImageOps().Width() } +func (r *resourceAdapter) DecodeImage() (image.Image, error) { + return r.getImageOps().DecodeImage() +} + func (r *resourceAdapter) getImageOps() resource.ImageOps { img, ok := r.target.(resource.ImageOps) if !ok { |