Add images.Process filter

This allows for constructs like:

```
{{ $filters := slice (images.GaussianBlur 8) (images.Grayscale) (images.Process "jpg q30 resize 200x") }}
{{ $img = $img | images.Filter $filters }}
```

Note that the `action` option in `images.Process` is optional (`resize` in the example above), so you can use the above to just set the target format, e.g.:

```
{{ $filters := slice (images.GaussianBlur 8) (images.Grayscale) (images.Process "jpg") }}
{{ $img = $img | images.Filter $filters }}
```

Fixes #8439
This commit is contained in:
Bjørn Erik Pedersen
2023-09-23 11:45:17 +02:00
parent ef0e7149d6
commit 6a246d1152
6 changed files with 204 additions and 16 deletions

View File

@@ -30,6 +30,15 @@ const filterAPIVersion = 0
type Filters struct{}
func (*Filters) Process(spec any) gift.Filter {
return filter{
Options: newFilterOpts(spec),
Filter: processFilter{
spec: cast.ToString(spec),
},
}
}
// Overlay creates a filter that overlays src at position x y.
func (*Filters) Overlay(src ImageSource, x, y any) gift.Filter {
return filter{

View File

@@ -201,7 +201,7 @@ func (p *ImageProcessor) DecodeExif(r io.Reader) (*exif.ExifInfo, error) {
return p.exifDecoder.Decode(r)
}
func (p *ImageProcessor) ApplyFiltersFromConfig(src image.Image, conf ImageConfig) (image.Image, error) {
func (p *ImageProcessor) FiltersFromConfig(src image.Image, conf ImageConfig) ([]gift.Filter, error) {
var filters []gift.Filter
if conf.Rotate != 0 {
@@ -246,6 +246,14 @@ func (p *ImageProcessor) ApplyFiltersFromConfig(src image.Image, conf ImageConfi
default:
}
return filters, nil
}
func (p *ImageProcessor) ApplyFiltersFromConfig(src image.Image, conf ImageConfig) (image.Image, error) {
filters, err := p.FiltersFromConfig(src, conf)
if err != nil {
return nil, err
}
if len(filters) == 0 {
return p.resolveSrc(src, conf.TargetFormat), nil
@@ -396,6 +404,15 @@ func imageConfigFromImage(img image.Image) image.Config {
return image.Config{Width: b.Max.X, Height: b.Max.Y}
}
// UnwrapFilter unwraps the given filter if it is a filter wrapper.
func UnwrapFilter(in gift.Filter) gift.Filter {
if f, ok := in.(filter); ok {
return f.Filter
}
return in
}
// ToFilters converts the given input to a slice of gift.Filter.
func ToFilters(in any) []gift.Filter {
switch v := in.(type) {
case []gift.Filter:

View File

@@ -0,0 +1,43 @@
// Copyright 2023 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 _ ImageProcessSpecProvider = (*processFilter)(nil)
type ImageProcessSpecProvider interface {
ImageProcessSpec() string
}
type processFilter struct {
spec string
}
func (f processFilter) Draw(dst draw.Image, src image.Image, options *gift.Options) {
panic("not supported")
}
func (f processFilter) Bounds(srcBounds image.Rectangle) image.Rectangle {
panic("not supported")
}
func (f processFilter) ImageProcessSpec() string {
return f.spec
}