mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-28 23:12:14 -05:00
parent
11fcda971c
commit
f9b3c0f486
8 changed files with 76 additions and 14 deletions
|
@ -34,6 +34,19 @@ A shorter version of the above, if you only need to apply the filter once:
|
||||||
|
|
||||||
The above will overlay `$logo` in the upper left corner of `$img` (at position `x=50, y=50`).
|
The above will overlay `$logo` in the upper left corner of `$img` (at position `x=50, y=50`).
|
||||||
|
|
||||||
|
## Opacity
|
||||||
|
|
||||||
|
{{% funcsig %}}
|
||||||
|
images.Opacity SRC OPACITY
|
||||||
|
{{% /funcsig %}}
|
||||||
|
|
||||||
|
Opacity creates a filter that changes the opacity of an image.
|
||||||
|
The OPACITY parameter must be in range (0, 1).
|
||||||
|
|
||||||
|
```go-html-template
|
||||||
|
{{ $img := $img.Filter (images.Opacity 0.5 )}}
|
||||||
|
```
|
||||||
|
|
||||||
## Text
|
## Text
|
||||||
|
|
||||||
Using the `Text` filter, you can add text to an image.
|
Using the `Text` filter, you can add text to an image.
|
||||||
|
|
|
@ -63,7 +63,7 @@ var eq = qt.CmpEquals(
|
||||||
}
|
}
|
||||||
return p1.Name() == p2.Name() && p1.Size() == p2.Size() && p1.IsDir() == p2.IsDir()
|
return p1.Name() == p2.Name() && p1.Size() == p2.Size() && p1.IsDir() == p2.IsDir()
|
||||||
}),
|
}),
|
||||||
//cmp.Comparer(func(p1, p2 *genericResource) bool { return p1 == p2 }),
|
// cmp.Comparer(func(p1, p2 *genericResource) bool { return p1 == p2 }),
|
||||||
cmp.Comparer(func(m1, m2 media.Type) bool {
|
cmp.Comparer(func(m1, m2 media.Type) bool {
|
||||||
return m1.Type == m2.Type
|
return m1.Type == m2.Type
|
||||||
}),
|
}),
|
||||||
|
@ -162,7 +162,6 @@ func TestImageTransformBasic(t *testing.T) {
|
||||||
croppedAgain, err := image.Crop("300x300 topRight")
|
croppedAgain, err := image.Crop("300x300 topRight")
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
c.Assert(cropped, qt.Equals, croppedAgain)
|
c.Assert(cropped, qt.Equals, croppedAgain)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestImageTransformFormat(t *testing.T) {
|
func TestImageTransformFormat(t *testing.T) {
|
||||||
|
@ -267,7 +266,6 @@ func TestImageBugs(t *testing.T) {
|
||||||
c.Assert(resized, qt.Not(qt.IsNil))
|
c.Assert(resized, qt.Not(qt.IsNil))
|
||||||
c.Assert(resized.Width(), qt.Equals, 100)
|
c.Assert(resized.Width(), qt.Equals, 100)
|
||||||
c.Assert(resized.RelPermalink(), qt.Equals, "/a/_hu59e56ffff1bc1d8d122b1403d34e039f_90587_c876768085288f41211f768147ba2647.jpg")
|
c.Assert(resized.RelPermalink(), qt.Equals, "/a/_hu59e56ffff1bc1d8d122b1403d34e039f_90587_c876768085288f41211f768147ba2647.jpg")
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Issue #6137
|
// Issue #6137
|
||||||
|
@ -278,7 +276,6 @@ func TestImageBugs(t *testing.T) {
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
c.Assert(resized, qt.Not(qt.IsNil))
|
c.Assert(resized, qt.Not(qt.IsNil))
|
||||||
c.Assert(resized.Width(), qt.Equals, 200)
|
c.Assert(resized.Width(), qt.Equals, 200)
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Issue #7955
|
// Issue #7955
|
||||||
|
@ -307,9 +304,7 @@ func TestImageBugs(t *testing.T) {
|
||||||
c.Assert(resized.Width(), qt.Equals, test.targetWH)
|
c.Assert(resized.Width(), qt.Equals, test.targetWH)
|
||||||
c.Assert(resized.Height(), qt.Equals, test.targetWH)
|
c.Assert(resized.Height(), qt.Equals, test.targetWH)
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -613,7 +608,6 @@ func TestImageOperationsGoldenWebp(t *testing.T) {
|
||||||
dir2 := filepath.FromSlash("testdata/golden_webp")
|
dir2 := filepath.FromSlash("testdata/golden_webp")
|
||||||
|
|
||||||
assetGoldenDirs(c, dir1, dir2)
|
assetGoldenDirs(c, dir1, dir2)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestImageOperationsGolden(t *testing.T) {
|
func TestImageOperationsGolden(t *testing.T) {
|
||||||
|
@ -621,7 +615,7 @@ func TestImageOperationsGolden(t *testing.T) {
|
||||||
c.Parallel()
|
c.Parallel()
|
||||||
|
|
||||||
// Note, if you're enabling this on a MacOS M1 (ARM) you need to run the test with GOARCH=amd64.
|
// Note, if you're enabling this on a MacOS M1 (ARM) you need to run the test with GOARCH=amd64.
|
||||||
// GOARCH=amd64 go test -timeout 30s -run "^TestImageOperationsGolden$" ./resources -v
|
// GOARCH=amd64 go test -count 1 -timeout 30s -run "^TestImageOperationsGolden$" ./resources -v
|
||||||
// The above will print out a folder.
|
// The above will print out a folder.
|
||||||
// Replace testdata/golden with resources/_gen/images in that folder.
|
// Replace testdata/golden with resources/_gen/images in that folder.
|
||||||
devMode := false
|
devMode := false
|
||||||
|
@ -644,6 +638,10 @@ func TestImageOperationsGolden(t *testing.T) {
|
||||||
gopher, err = gopher.Resize("30x")
|
gopher, err = gopher.Resize("30x")
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
|
|
||||||
|
f := &images.Filters{}
|
||||||
|
|
||||||
|
sunset := fetchImageForSpec(spec, c, "sunset.jpg")
|
||||||
|
|
||||||
// Test PNGs with alpha channel.
|
// Test PNGs with alpha channel.
|
||||||
for _, img := range []string{"gopher-hero8.png", "gradient-circle.png"} {
|
for _, img := range []string{"gopher-hero8.png", "gradient-circle.png"} {
|
||||||
orig := fetchImageForSpec(spec, c, img)
|
orig := fetchImageForSpec(spec, c, img)
|
||||||
|
@ -653,7 +651,15 @@ func TestImageOperationsGolden(t *testing.T) {
|
||||||
rel := resized.RelPermalink()
|
rel := resized.RelPermalink()
|
||||||
|
|
||||||
c.Assert(rel, qt.Not(qt.Equals), "")
|
c.Assert(rel, qt.Not(qt.Equals), "")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check the Opacity filter.
|
||||||
|
opacity30, err := orig.Filter(f.Opacity(30))
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
overlay, err := sunset.Filter(f.Overlay(opacity30.(images.ImageSource), 20, 20))
|
||||||
|
rel := overlay.RelPermalink()
|
||||||
|
c.Assert(rel, qt.Not(qt.Equals), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// A simple Gif file (no animation).
|
// A simple Gif file (no animation).
|
||||||
|
@ -699,8 +705,6 @@ func TestImageOperationsGolden(t *testing.T) {
|
||||||
c.Assert(rel, qt.Not(qt.Equals), "")
|
c.Assert(rel, qt.Not(qt.Equals), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
f := &images.Filters{}
|
|
||||||
|
|
||||||
filters := []gift.Filter{
|
filters := []gift.Filter{
|
||||||
f.Grayscale(),
|
f.Grayscale(),
|
||||||
f.GaussianBlur(6),
|
f.GaussianBlur(6),
|
||||||
|
@ -746,11 +750,9 @@ func TestImageOperationsGolden(t *testing.T) {
|
||||||
dir2 := filepath.FromSlash("testdata/golden")
|
dir2 := filepath.FromSlash("testdata/golden")
|
||||||
|
|
||||||
assetGoldenDirs(c, dir1, dir2)
|
assetGoldenDirs(c, dir1, dir2)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func assetGoldenDirs(c *qt.C, dir1, dir2 string) {
|
func assetGoldenDirs(c *qt.C, dir1, dir2 string) {
|
||||||
|
|
||||||
// The two dirs above should now be the same.
|
// The two dirs above should now be the same.
|
||||||
dirinfos1, err := os.ReadDir(dir1)
|
dirinfos1, err := os.ReadDir(dir1)
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
|
|
|
@ -28,8 +28,7 @@ import (
|
||||||
// Increment for re-generation of images using these filters.
|
// Increment for re-generation of images using these filters.
|
||||||
const filterAPIVersion = 0
|
const filterAPIVersion = 0
|
||||||
|
|
||||||
type Filters struct {
|
type Filters struct{}
|
||||||
}
|
|
||||||
|
|
||||||
// Overlay creates a filter that overlays src at position x y.
|
// Overlay creates a filter that overlays src at position x y.
|
||||||
func (*Filters) Overlay(src ImageSource, x, y any) gift.Filter {
|
func (*Filters) Overlay(src ImageSource, x, y any) gift.Filter {
|
||||||
|
@ -39,6 +38,15 @@ func (*Filters) Overlay(src ImageSource, x, y any) gift.Filter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Opacity creates a filter that changes the opacity of an image.
|
||||||
|
// The opacity parameter must be in range (0, 1).
|
||||||
|
func (*Filters) Opacity(opacity any) gift.Filter {
|
||||||
|
return filter{
|
||||||
|
Options: newFilterOpts(opacity),
|
||||||
|
Filter: opacityFilter{opacity: cast.ToFloat32(opacity)},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Text creates a filter that draws text with the given options.
|
// Text creates a filter that draws text with the given options.
|
||||||
func (*Filters) Text(text string, options ...any) gift.Filter {
|
func (*Filters) Text(text string, options ...any) gift.Filter {
|
||||||
tf := textFilter{
|
tf := textFilter{
|
||||||
|
|
39
resources/images/opacity.go
Normal file
39
resources/images/opacity.go
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
// 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/color"
|
||||||
|
"image/draw"
|
||||||
|
|
||||||
|
"github.com/disintegration/gift"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ gift.Filter = (*opacityFilter)(nil)
|
||||||
|
|
||||||
|
type opacityFilter struct {
|
||||||
|
opacity float32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f opacityFilter) Draw(dst draw.Image, src image.Image, options *gift.Options) {
|
||||||
|
// 0 is fully transparent and 255 is opaque.
|
||||||
|
alpha := uint8(f.opacity * 255)
|
||||||
|
mask := image.NewUniform(color.Alpha{alpha})
|
||||||
|
draw.DrawMask(dst, dst.Bounds(), src, image.Point{}, mask, image.Point{}, draw.Over)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f opacityFilter) Bounds(srcBounds image.Rectangle) image.Rectangle {
|
||||||
|
return image.Rect(0, 0, srcBounds.Dx(), srcBounds.Dy())
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
Binary file not shown.
After Width: | Height: | Size: 56 KiB |
Binary file not shown.
After Width: | Height: | Size: 45 KiB |
Loading…
Reference in a new issue