From cad40cc1581e2f6bc8406aaca1d00e06e4bd0b79 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Sun, 17 Aug 2025 23:05:27 +0200 Subject: [PATCH] feat(icon): minify svg favicons --- internal/reader/icon/finder.go | 16 +++++++++++++++- internal/reader/icon/finder_test.go | 13 +++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/internal/reader/icon/finder.go b/internal/reader/icon/finder.go index 1477d9f9..cfcc9022 100644 --- a/internal/reader/icon/finder.go +++ b/internal/reader/icon/finder.go @@ -26,6 +26,8 @@ import ( "miniflux.app/v2/internal/urllib" "github.com/PuerkitoBio/goquery" + "github.com/tdewolff/minify/v2" + "github.com/tdewolff/minify/v2/svg" "golang.org/x/image/draw" "golang.org/x/image/webp" ) @@ -194,13 +196,25 @@ func (f *iconFinder) downloadIcon(iconURL string) (*model.Icon, error) { } func resizeIcon(icon *model.Icon) *model.Icon { - r := bytes.NewReader(icon.Content) + if icon.MimeType == "image/svg+xml" { + minifier := minify.New() + minifier.AddFunc("image/svg+xml", svg.Minify) + var err error + // minifier.Bytes returns the data unchanged in case of error. + icon.Content, err = minifier.Bytes("image/svg+xml", icon.Content) + if err != nil { + slog.Error("Unable to minimize the svg file", slog.Any("error", err)) + } + return icon + } if !slices.Contains([]string{"image/jpeg", "image/png", "image/gif", "image/webp"}, icon.MimeType) { slog.Info("icon isn't a png/gif/jpeg/webp, can't resize", slog.String("mimetype", icon.MimeType)) return icon } + r := bytes.NewReader(icon.Content) + // Don't resize icons that we can't decode, or that already have the right size. config, _, err := image.DecodeConfig(r) if err != nil { diff --git a/internal/reader/icon/finder_test.go b/internal/reader/icon/finder_test.go index 4ae07174..80991a17 100644 --- a/internal/reader/icon/finder_test.go +++ b/internal/reader/icon/finder_test.go @@ -194,3 +194,16 @@ func TestResizeInvalidImage(t *testing.T) { t.Fatalf("Tried to convert an invalid image") } } +func TestMinifySvg(t *testing.T) { + data := []byte(``) + want := []byte(``) + + icon := model.Icon{ + Content: data, + MimeType: "image/svg+xml", + } + got := resizeIcon(&icon).Content + if !bytes.Equal(want, got) { + t.Fatalf("Didn't correctly minimize the svg: got %s instead of %s", got, want) + } +}