icns

Easily create .icns files (Mac Icons) with this Go library or the included CLI.
Log | Files | Refs | LICENSE

commit 6b7ce7385c6260292c5f241d189b302439b2aff0
parent d6caefcda1131a84358e50aae17ed893b49fdd9a
Author: Jack Mordaunt <jackmordaunt.dev@gmail.com>
Date:   Fri, 18 Sep 2026 16:09:28 -0400

cmd/shell-extension: resample with x/image/draw

The thumbnail path was the last caller of the archived nfnt/resize, and
matching the library's resampler keeps one filter behaviour across the repo.
It lingers as an indirect dependency because the published v4.0.0 library
still requires it; the next library tag drops it.

Diffstat:
Mcmd/shell-extension/go.mod | 4+++-
Mcmd/shell-extension/go.sum | 2++
Mcmd/shell-extension/internal/provider/provider.go | 27++++++++++++++++++++-------
Mgo.work.sum | 8+++++++-
4 files changed, 32 insertions(+), 9 deletions(-)

diff --git a/cmd/shell-extension/go.mod b/cmd/shell-extension/go.mod @@ -4,6 +4,8 @@ go 1.23.0 require ( github.com/jackmordaunt/icns/v4 v4.0.0 - github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 + golang.org/x/image v0.30.0 golang.org/x/sys v0.25.0 ) + +require github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect diff --git a/cmd/shell-extension/go.sum b/cmd/shell-extension/go.sum @@ -2,5 +2,7 @@ github.com/jackmordaunt/icns/v4 v4.0.0 h1:mAZ+5rI8WEV1k/DxcwQA4FPiWXuLJHjP0MlIuD github.com/jackmordaunt/icns/v4 v4.0.0/go.mod h1:HakgKguVAB9QWZWj7Fb9YZlhIaH/mpKXIhQycPygcRQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= +golang.org/x/image v0.30.0 h1:jD5RhkmVAnjqaCUXfbGBrn3lpxbknfN9w2UhHHU+5B4= +golang.org/x/image v0.30.0/go.mod h1:SAEUTxCCMWSrJcCy/4HwavEsfZZJlYxeHLc6tTiAe/c= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/cmd/shell-extension/internal/provider/provider.go b/cmd/shell-extension/internal/provider/provider.go @@ -9,7 +9,6 @@ import ( "bytes" "fmt" "image" - "image/draw" "io" "log/slog" "runtime" @@ -20,7 +19,7 @@ import ( "github.com/jackmordaunt/icns/cmd/shell-extension/internal/com" "github.com/jackmordaunt/icns/v4" - "github.com/nfnt/resize" + "golang.org/x/image/draw" "golang.org/x/sys/windows" ) @@ -210,13 +209,27 @@ func Thumbnail(r io.Reader, cx int) (*image.RGBA, error) { } chosen = img } + // Normalise to premultiplied RGBA, which is what a GDI ARGB bitmap + // wants, shrinking the icon to fit the cx square on the way if needed. + var ( + b = chosen.Bounds() + w, h = b.Dx(), b.Dy() + ) if side(chosen) > cx { - chosen = resize.Thumbnail(uint(cx), uint(cx), chosen, resize.Lanczos3) + if w >= h { + w, h = cx, max(h*cx/w, 1) + } else { + w, h = max(w*cx/h, 1), cx + } + } + rgba := image.NewRGBA(image.Rect(0, 0, w, h)) + if w == b.Dx() && h == b.Dy() { + draw.Draw(rgba, rgba.Bounds(), chosen, b.Min, draw.Src) + } else { + // CatmullRom is x/image's high quality kernel, and rings less on the + // hard edges typical of icons than a wider Lanczos window. + draw.CatmullRom.Scale(rgba, rgba.Bounds(), chosen, b, draw.Src, nil) } - // Normalise to premultiplied RGBA, which is what a GDI ARGB bitmap wants. - b := chosen.Bounds() - rgba := image.NewRGBA(image.Rect(0, 0, b.Dx(), b.Dy())) - draw.Draw(rgba, rgba.Bounds(), chosen, b.Min, draw.Src) return rgba, nil } diff --git a/go.work.sum b/go.work.sum @@ -1,4 +1,10 @@ -github.com/jackmordaunt/icns/v4 v4.0.0/go.mod h1:HakgKguVAB9QWZWj7Fb9YZlhIaH/mpKXIhQycPygcRQ= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=