]> git.maquefel.me Git - brevno-suite/hugo/commitdiff
Move from github.com/disintegration/gift to github.com/gohugoio/gift
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Mon, 19 Jan 2026 10:50:06 +0000 (11:50 +0100)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Mon, 19 Jan 2026 21:18:45 +0000 (22:18 +0100)
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

17 files changed:
go.mod
go.sum
resources/image.go
resources/images/auto_orient.go
resources/images/config.go
resources/images/dither.go
resources/images/filters.go
resources/images/image.go
resources/images/images_integration_test.go
resources/images/imagetesting/testing.go
resources/images/mask.go
resources/images/opacity.go
resources/images/overlay.go
resources/images/padding.go
resources/images/process.go
resources/images/smartcrop.go
resources/images/text.go

diff --git a/go.mod b/go.mod
index 3b94de1700a8f0c4bd31155f00b0ab0d22102248..3c971354621c53cf79f312deb817ceb4045d1bbd 100644 (file)
--- a/go.mod
+++ b/go.mod
@@ -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
diff --git a/go.sum b/go.sum
index 1769cf08a0763c00e7b81b1980eef1aaefe9598f..ef96f149e7168b4570e7ed936569c5f4d5d0feb8 100644 (file)
--- a/go.sum
+++ b/go.sum
@@ -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=
index 573c22c9d197196585533cf059b574443df965eb..0707275671ca75f4e42bcc035a240524a5a267c4 100644 (file)
@@ -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"
index ca4911e816e36b47f708e07bb6ce119ea60c3042..a57987c7850f2860a39eb30c8656cac0c895836d 100644 (file)
@@ -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")
 }
 
index 3277d2a24698153b6861fb70f187da916fc425bb..9475096aca72aed84c9e7b7093970b29ab4d8059 100644 (file)
@@ -28,7 +28,7 @@ import (
        "github.com/gohugoio/hugo/media"
        "github.com/mitchellh/mapstructure"
 
-       "github.com/disintegration/gift"
+       "github.com/gohugoio/gift"
 )
 
 const (
index 19d7e088d60b24c8b4fe5ffced1fec8042a16ac2..825b06e87a1437ce1990f7fa8d17aebbd773b4ac 100644 (file)
@@ -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 {
index 5fb5dae1f400aa9773d6fb8d44a4349ceb366ab4..1bf88645a014876b205e9fb7c60329ef1b023ffa 100644 (file)
@@ -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"
 )
 
index 89b15a4f985298da6c7e0680765ca074a9311ef4..1e78e8bbeddfde8e6db0f026e72fb0ff8d7c0760 100644 (file)
@@ -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"
index d66fa23665402879acff9f27be9ec19e7a1557f7..fade5ae3eed38ef1c397c481bf50bee3992229ce 100644 (file)
@@ -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()
+       }
+}
index 979ca2fc542fb2cf9f37c9c6f6311187662103bc..418c21685a852b14a421d5d3c1274067a18b35e4 100644 (file)
@@ -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"
index 5ce7c5d43e379ff945af1c6f785d0570497b1dce..b3688ef90187068c0aa661e64db5ff950f5b3f98 100644 (file)
@@ -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.
index 482476c5b206d314dfc121e40cd2d570fce139cd..b2eaf5f1218053ad5355a040c055861878ddb0ef 100644 (file)
@@ -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 {
index 780e28fd1ad922e40551b79321cb7e6dfe451e44..91934ddb92d078eab1496f6f6242216bf213bba1 100644 (file)
@@ -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 {
index 4399312f8df2a36ce89c6b877c67aee8f5f1c125..73341b89ef1969c34d808a16b1a44f898c060a55 100644 (file)
@@ -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 {
index fb2e995ce59c86640e0cf96ea14484e8c0c7d481..ed21fce5f17e7d84bf303f91e7de709c06acbf56 100644 (file)
@@ -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")
 }
 
index 4f706df679a9dc2f57c57ee2a38939d4a31dad67..817df738abb330413bc6465278580f23ca7c1c7f 100644 (file)
@@ -17,7 +17,7 @@ import (
        "image"
        "math"
 
-       "github.com/disintegration/gift"
+       "github.com/gohugoio/gift"
 
        "github.com/muesli/smartcrop"
 )
index 11c6eac41f6ebd02082d7a85919e96d3ca2dd691..ae2831638ae5f8bd7156d95b0d3b8b119ad60ae3 100644 (file)
@@ -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 {