mirror of
https://github.com/gohugoio/hugo.git
synced 2026-08-24 15:28:54 +00:00
Move from github.com/disintegration/gift to github.com/gohugoio/gift
With some performance improvements upstream, there's improvements in memory usage. Note that the benchmark below is full site builds with image processing:
```
goos: darwin
goarch: arm64
pkg: github.com/gohugoio/hugo/resources/images
cpu: Apple M1 Pro
│ benchcmp.bench │ feat-forkgift-14397.bench │
│ sec/op │ sec/op vs base │
ImageResize-10 74.60m ± 4% 73.75m ± 4% ~ (p=0.093 n=6)
│ benchcmp.bench │ feat-forkgift-14397.bench │
│ B/op │ B/op vs base │
ImageResize-10 32.38Mi ± 1% 29.31Mi ± 1% -9.49% (p=0.002 n=6)
│ benchcmp.bench │ feat-forkgift-14397.bench │
│ allocs/op │ allocs/op vs base │
ImageResize-10 12.53k ± 1% 12.05k ± 1% -3.82% (p=0.002 n=6)
```
Closes #14397
This commit is contained in:
@@ -25,7 +25,6 @@ require (
|
||||
github.com/bits-and-blooms/bitset v1.24.4
|
||||
github.com/cespare/xxhash/v2 v2.3.0
|
||||
github.com/clbanning/mxj/v2 v2.7.0
|
||||
github.com/disintegration/gift v1.2.1
|
||||
github.com/dustin/go-humanize v1.0.1
|
||||
github.com/evanw/esbuild v0.27.2
|
||||
github.com/fatih/color v1.18.0
|
||||
@@ -36,6 +35,7 @@ require (
|
||||
github.com/gobuffalo/flect v1.0.3
|
||||
github.com/gobwas/glob v0.2.3
|
||||
github.com/goccy/go-yaml v1.19.2
|
||||
github.com/gohugoio/gift v0.1.0
|
||||
github.com/gohugoio/go-i18n/v2 v2.1.3-0.20251018145728-cfcc22d823c6
|
||||
github.com/gohugoio/go-radix v1.2.0
|
||||
github.com/gohugoio/hashstructure v0.6.0
|
||||
|
||||
@@ -209,8 +209,6 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
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.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
|
||||
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
@@ -270,6 +268,8 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
|
||||
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/gohugoio/gift v0.1.0 h1:KDx+OBrSn/sXmnMdMLYocOLn35MrBpnVhgQghHxd7g8=
|
||||
github.com/gohugoio/gift v0.1.0/go.mod h1:1Mrm5CjF33KpD749Dwj+UAjWZ3LC6cBXGuTMa5XwoP4=
|
||||
github.com/gohugoio/go-i18n/v2 v2.1.3-0.20251018145728-cfcc22d823c6 h1:pxlAea9eRwuAnt/zKbGqlFO2ZszpIe24YpOVLf+N+4I=
|
||||
github.com/gohugoio/go-i18n/v2 v2.1.3-0.20251018145728-cfcc22d823c6/go.mod h1:m5hu1im5Qc7LDycVLvee6MPobJiRLBYHklypFJR0/aE=
|
||||
github.com/gohugoio/go-radix v1.2.0 h1:D5GTk8jIoeXirBSc2P4E4NdHKDrenk9k9N0ctU5Yrhg=
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ import (
|
||||
"github.com/gohugoio/hugo/common/hugo"
|
||||
"github.com/gohugoio/hugo/common/paths"
|
||||
|
||||
"github.com/disintegration/gift"
|
||||
"github.com/gohugoio/gift"
|
||||
|
||||
"github.com/gohugoio/hugo/resources/images/meta"
|
||||
"github.com/gohugoio/hugo/resources/internal"
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
"image"
|
||||
"image/draw"
|
||||
|
||||
"github.com/disintegration/gift"
|
||||
"github.com/gohugoio/gift"
|
||||
)
|
||||
|
||||
var _ gift.Filter = (*autoOrientFilter)(nil)
|
||||
@@ -38,7 +38,7 @@ type ImageFilterFromOrientationProvider interface {
|
||||
AutoOrient(orientation int) gift.Filter
|
||||
}
|
||||
|
||||
func (f autoOrientFilter) Draw(dst draw.Image, src image.Image, options *gift.Options) {
|
||||
func (f autoOrientFilter) Draw(dst draw.Image, src image.Image, options *gift.Options) error {
|
||||
panic("not supported")
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ import (
|
||||
"github.com/gohugoio/hugo/media"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
|
||||
"github.com/disintegration/gift"
|
||||
"github.com/gohugoio/gift"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
"image"
|
||||
"image/draw"
|
||||
|
||||
"github.com/disintegration/gift"
|
||||
"github.com/gohugoio/gift"
|
||||
"github.com/makeworld-the-better-one/dither/v2"
|
||||
)
|
||||
|
||||
@@ -62,8 +62,8 @@ var ditherMethodsOrdered = map[string]dither.OrderedDitherMatrix{
|
||||
"vertical5x3": dither.Vertical5x3,
|
||||
}
|
||||
|
||||
func (f ditherFilter) Draw(dst draw.Image, src image.Image, options *gift.Options) {
|
||||
gift.New().Draw(dst, f.ditherer.Dither(src))
|
||||
func (f ditherFilter) Draw(dst draw.Image, src image.Image, options *gift.Options) error {
|
||||
return gift.New().Draw(dst, f.ditherer.Dither(src))
|
||||
}
|
||||
|
||||
func (f ditherFilter) Bounds(srcBounds image.Rectangle) image.Rectangle {
|
||||
|
||||
@@ -25,7 +25,7 @@ import (
|
||||
"github.com/makeworld-the-better-one/dither/v2"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
|
||||
"github.com/disintegration/gift"
|
||||
"github.com/gohugoio/gift"
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ import (
|
||||
"github.com/gohugoio/hugo/media"
|
||||
"github.com/gohugoio/hugo/resources/images/meta"
|
||||
|
||||
"github.com/disintegration/gift"
|
||||
"github.com/gohugoio/gift"
|
||||
|
||||
"github.com/gohugoio/hugo/common/himage"
|
||||
"github.com/gohugoio/hugo/common/hugio"
|
||||
|
||||
@@ -50,3 +50,57 @@ Orientation: {{ $orientation }}|eq 6: {{ eq $orientation 6 }}|Type: {{ printf "%
|
||||
b := hugolib.Test(t, files)
|
||||
b.AssertFileContent("public/index.html", "Orientation: 6|eq 6: true|")
|
||||
}
|
||||
|
||||
func BenchmarkImageResize(b *testing.B) {
|
||||
files := `
|
||||
-- content/p1/sunrise.jpg --
|
||||
sourcefilename: ../../resources/testdata/sunrise.jpg
|
||||
-- content/p1/index.md --
|
||||
-- content/p2/sunrise.jpg --
|
||||
sourcefilename: ../../resources/testdata/sunrise.jpg
|
||||
-- content/p2/index.md --
|
||||
-- content/p3/sunrise.jpg --
|
||||
sourcefilename: ../../resources/testdata/sunrise.jpg
|
||||
-- content/p3/index.md --
|
||||
-- content/p4/sunrise.jpg --
|
||||
sourcefilename: ../../resources/testdata/sunrise.jpg
|
||||
-- content/p4/index.md --
|
||||
-- content/p5/sunrise.jpg --
|
||||
sourcefilename: ../../resources/testdata/sunrise.jpg
|
||||
-- content/p5/index.md --
|
||||
-- content/p6/sunrise.jpg --
|
||||
sourcefilename: ../../resources/testdata/sunrise.jpg
|
||||
-- content/p6/index.md --
|
||||
-- content/p7/sunrise.jpg --
|
||||
sourcefilename: ../../resources/testdata/sunrise.jpg
|
||||
-- content/p7/index.md --
|
||||
-- content/p8/sunrise.jpg --
|
||||
sourcefilename: ../../resources/testdata/sunrise.jpg
|
||||
-- content/p8/index.md --
|
||||
-- content/p9/sunrise.jpg --
|
||||
sourcefilename: ../../resources/testdata/sunrise.jpg
|
||||
-- content/p9/index.md --
|
||||
-- content/p10/sunrise.jpg --
|
||||
sourcefilename: ../../resources/testdata/sunrise.jpg
|
||||
-- content/p10/index.md --
|
||||
-- layouts/home.html --
|
||||
Home.
|
||||
-- layouts/page.html --
|
||||
Page.
|
||||
{{ $image := .Resources.Get "sunrise.jpg" }}
|
||||
{{ ($image.Process "resize 200x200").Publish }}
|
||||
|
||||
`
|
||||
|
||||
cfg := hugolib.IntegrationTestConfig{
|
||||
T: b,
|
||||
TxtarString: files,
|
||||
}
|
||||
|
||||
for b.Loop() {
|
||||
b.StopTimer()
|
||||
builder := hugolib.NewIntegrationTestBuilder(cfg).Init()
|
||||
b.StartTimer()
|
||||
builder.Build()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
qt "github.com/frankban/quicktest"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"github.com/disintegration/gift"
|
||||
"github.com/gohugoio/gift"
|
||||
"github.com/gohugoio/hugo/common/hashing"
|
||||
"github.com/gohugoio/hugo/common/himage"
|
||||
"github.com/gohugoio/hugo/common/hugio"
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"image/color"
|
||||
"image/draw"
|
||||
|
||||
"github.com/disintegration/gift"
|
||||
"github.com/gohugoio/gift"
|
||||
)
|
||||
|
||||
// maskFilter applies a mask image to a base image.
|
||||
@@ -15,10 +15,10 @@ type maskFilter struct {
|
||||
}
|
||||
|
||||
// Draw applies the mask to the base image.
|
||||
func (f maskFilter) Draw(dst draw.Image, baseImage image.Image, options *gift.Options) {
|
||||
func (f maskFilter) Draw(dst draw.Image, baseImage image.Image, options *gift.Options) error {
|
||||
maskImage, err := f.mask.DecodeImage()
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to decode image: %s", err))
|
||||
return fmt.Errorf("failed to decode image: %s", err)
|
||||
}
|
||||
|
||||
// Ensure the mask is the same size as the base image
|
||||
@@ -54,7 +54,11 @@ func (f maskFilter) Draw(dst draw.Image, baseImage image.Image, options *gift.Op
|
||||
draw.DrawMask(outputImage, baseBounds, baseImage, image.Point{}, alphaMask, image.Point{}, draw.Over)
|
||||
|
||||
// Copy the result to the destination
|
||||
gift.New().Draw(dst, outputImage)
|
||||
if err := gift.New().Draw(dst, outputImage); err != nil {
|
||||
return fmt.Errorf("failed to draw masked image: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Bounds returns the bounds of the resulting image.
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"image/color"
|
||||
"image/draw"
|
||||
|
||||
"github.com/disintegration/gift"
|
||||
"github.com/gohugoio/gift"
|
||||
)
|
||||
|
||||
var _ gift.Filter = (*opacityFilter)(nil)
|
||||
@@ -27,11 +27,12 @@ type opacityFilter struct {
|
||||
opacity float32
|
||||
}
|
||||
|
||||
func (f opacityFilter) Draw(dst draw.Image, src image.Image, options *gift.Options) {
|
||||
func (f opacityFilter) Draw(dst draw.Image, src image.Image, options *gift.Options) error {
|
||||
// 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)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f opacityFilter) Bounds(srcBounds image.Rectangle) image.Rectangle {
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"image"
|
||||
"image/draw"
|
||||
|
||||
"github.com/disintegration/gift"
|
||||
"github.com/gohugoio/gift"
|
||||
)
|
||||
|
||||
var _ gift.Filter = (*overlayFilter)(nil)
|
||||
@@ -28,14 +28,15 @@ type overlayFilter struct {
|
||||
x, y int
|
||||
}
|
||||
|
||||
func (f overlayFilter) Draw(dst draw.Image, src image.Image, options *gift.Options) {
|
||||
func (f overlayFilter) Draw(dst draw.Image, src image.Image, options *gift.Options) error {
|
||||
overlaySrc, err := f.src.DecodeImage()
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to decode image: %s", err))
|
||||
return fmt.Errorf("failed to decode image: %s", err)
|
||||
}
|
||||
|
||||
gift.New().Draw(dst, src)
|
||||
gift.New().DrawAt(dst, overlaySrc, image.Pt(f.x, f.y), gift.OverOperator)
|
||||
if err := gift.New().Draw(dst, src); err != nil {
|
||||
return err
|
||||
}
|
||||
return gift.New().DrawAt(dst, overlaySrc, image.Pt(f.x, f.y), gift.OverOperator)
|
||||
}
|
||||
|
||||
func (f overlayFilter) Bounds(srcBounds image.Rectangle) image.Rectangle {
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"image/color"
|
||||
"image/draw"
|
||||
|
||||
"github.com/disintegration/gift"
|
||||
"github.com/gohugoio/gift"
|
||||
)
|
||||
|
||||
var _ gift.Filter = (*paddingFilter)(nil)
|
||||
@@ -28,7 +28,7 @@ type paddingFilter struct {
|
||||
ccolor color.Color // canvas color
|
||||
}
|
||||
|
||||
func (f paddingFilter) Draw(dst draw.Image, src image.Image, options *gift.Options) {
|
||||
func (f paddingFilter) Draw(dst draw.Image, src image.Image, options *gift.Options) error {
|
||||
w := src.Bounds().Dx() + f.left + f.right
|
||||
h := src.Bounds().Dy() + f.top + f.bottom
|
||||
|
||||
@@ -41,8 +41,10 @@ func (f paddingFilter) Draw(dst draw.Image, src image.Image, options *gift.Optio
|
||||
|
||||
i := image.NewRGBA(image.Rect(0, 0, w, h))
|
||||
draw.Draw(i, i.Bounds(), image.NewUniform(f.ccolor), image.Point{}, draw.Src)
|
||||
gift.New().Draw(dst, i)
|
||||
gift.New().DrawAt(dst, src, image.Pt(f.left, f.top), gift.OverOperator)
|
||||
if err := gift.New().Draw(dst, i); err != nil {
|
||||
return err
|
||||
}
|
||||
return gift.New().DrawAt(dst, src, image.Pt(f.left, f.top), gift.OverOperator)
|
||||
}
|
||||
|
||||
func (f paddingFilter) Bounds(srcBounds image.Rectangle) image.Rectangle {
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
"image"
|
||||
"image/draw"
|
||||
|
||||
"github.com/disintegration/gift"
|
||||
"github.com/gohugoio/gift"
|
||||
)
|
||||
|
||||
var _ ImageProcessSpecProvider = (*processFilter)(nil)
|
||||
@@ -30,7 +30,7 @@ type processFilter struct {
|
||||
spec string
|
||||
}
|
||||
|
||||
func (f processFilter) Draw(dst draw.Image, src image.Image, options *gift.Options) {
|
||||
func (f processFilter) Draw(dst draw.Image, src image.Image, options *gift.Options) error {
|
||||
panic("not supported")
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
"image"
|
||||
"math"
|
||||
|
||||
"github.com/disintegration/gift"
|
||||
"github.com/gohugoio/gift"
|
||||
|
||||
"github.com/muesli/smartcrop"
|
||||
)
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/disintegration/gift"
|
||||
"github.com/gohugoio/gift"
|
||||
"github.com/gohugoio/hugo/common/hugio"
|
||||
|
||||
"golang.org/x/image/font"
|
||||
@@ -42,7 +42,7 @@ type textFilter struct {
|
||||
fontSource hugio.ReadSeekCloserProvider
|
||||
}
|
||||
|
||||
func (f textFilter) Draw(dst draw.Image, src image.Image, options *gift.Options) {
|
||||
func (f textFilter) Draw(dst draw.Image, src image.Image, options *gift.Options) error {
|
||||
// Load and parse font
|
||||
ttf := goregular.TTF
|
||||
if f.fontSource != nil {
|
||||
@@ -143,6 +143,7 @@ func (f textFilter) Draw(dst draw.Image, src image.Image, options *gift.Options)
|
||||
d.DrawString(line)
|
||||
y = y + fontHeight + f.linespacing
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f textFilter) Bounds(srcBounds image.Rectangle) image.Rectangle {
|
||||
|
||||
Reference in New Issue
Block a user