Skip to content

Commit

Permalink
images: Add images.Overlay filter
Browse files Browse the repository at this point in the history
This allows for constructs ala:

```
{{ $overlay := $img.Filter ($logo | images.Overlay 50 50 )}}
```
Or:

```
{{ $logoFilter := ($logo | images.Overlay 50 50 ) }}
{{ $overlay := $img | images.Filter $logoFilter }}
```

Which will overlay the logo in the top left corner (x=50, y=50) of `$img`.

Fixes gohugoio#8057
  • Loading branch information
bep committed Dec 16, 2020
1 parent a2d146e commit f027dd6
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 2 deletions.
6 changes: 4 additions & 2 deletions resources/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -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}
}
Expand Down Expand Up @@ -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")
Expand Down
15 changes: 15 additions & 0 deletions resources/images/filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package images

import (
"github.com/disintegration/gift"
"github.com/pkg/errors"
"github.com/spf13/cast"
)

Expand All @@ -25,6 +26,20 @@ const filterAPIVersion = 0
type Filters struct {
}

// Overlay creates a filter that overlays an image onto
// another at position x y.
func (*Filters) Overlay(x, y interface{}, id ImageDecoder) (gift.Filter, error) {
src, err := id.DecodeImage()
if err != nil {
return nil, errors.Wrap(err, "failed to decode image")
}

return filter{
Options: newFilterOpts(x, y), // TODO1 src
Filter: &overlayFilter{src: src, x: cast.ToInt(x), y: cast.ToInt(y)},
}, nil
}

// 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 {
Expand Down
5 changes: 5 additions & 0 deletions resources/images/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,3 +325,8 @@ func IsOpaque(img image.Image) bool {

return false
}

// ImageDecoder decodes an image.
type ImageDecoder interface {
DecodeImage() (image.Image, error)
}
37 changes: 37 additions & 0 deletions resources/images/overlay.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// 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 (
"image"
"image/draw"

"github.com/disintegration/gift"
)

var _ gift.Filter = (*overlayFilter)(nil)

type overlayFilter struct {
src image.Image
x, y int
}

func (f *overlayFilter) Draw(dst draw.Image, src image.Image, options *gift.Options) {
gift.New().Draw(dst, src)
gift.New().DrawAt(dst, f.src, 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())
}
5 changes: 5 additions & 0 deletions resources/resource/resourcetypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
package resource

import (
"image"

"github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/langs"
"github.com/gohugoio/hugo/media"
Expand Down Expand Up @@ -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 {
Expand Down
5 changes: 5 additions & 0 deletions resources/transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package resources
import (
"bytes"
"fmt"
"image"
"io"
"path"
"strings"
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit f027dd6

Please sign in to comment.