]> git.maquefel.me Git - brevno-suite/hugo/commitdiff
Fix "image: unknown format" error
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Mon, 22 Dec 2025 10:27:06 +0000 (11:27 +0100)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Mon, 22 Dec 2025 16:49:44 +0000 (17:49 +0100)
Fixes #14295

17 files changed:
hugolib/hugo_sites_multihost_test.go
hugolib/integrationtest_builder.go
hugolib/pagesfromdata/pagesfromgotmpl_integration_test.go
internal/warpc/webp_integration_test.go
resources/image_test.go
resources/images/config.go
resources/images/config_test.go
resources/images/image.go
resources/images/imagetesting/testing.go
resources/images/testdata/images_golden/webp/animation/giphy_hu_87010e943ffb23b4.gif [deleted file]
resources/images/testdata/images_golden/webp/animation/giphy_hu_bb052284cc220165.webp [new file with mode: 0644]
resources/images/testdata/images_golden/webp/animation/giphy_hu_c6b8060edf0363b1.gif [new file with mode: 0644]
resources/images/testdata/images_golden/webp/animation/giphy_hu_e4a5984f8835d617.webp [deleted file]
resources/resources_integration_test.go
resources/transform_test.go
tpl/images/images_integration_test.go
tpl/resources/resources_integration_test.go

index e090e03cc81fb1c8e685681186fd1ead0c988bdd..875fcfd5a002c19dff74c281ab5705c3eaa752d1 100644 (file)
@@ -207,9 +207,9 @@ title: mybundle-en
        b.AssertFileExists("public/de/mybundle/pixel.png", true)
        b.AssertFileExists("public/en/mybundle/pixel.png", true)
 
-       b.AssertFileExists("public/de/mybundle/pixel_hu_58204cbc58507d74.png", true)
+       b.AssertFileExists("public/de/mybundle/pixel_hu_c8522c65d73a0421.png", true)
        // failing test below
-       b.AssertFileExists("public/en/mybundle/pixel_hu_58204cbc58507d74.png", true)
+       b.AssertFileExists("public/en/mybundle/pixel_hu_c8522c65d73a0421.png", true)
 }
 
 func TestMultihostResourceOneBaseURLWithSubPath(t *testing.T) {
index 76271fdbb18e3fcd0a3681943a39c96ac870e7a5..b9aec370509ae3f507af65fccaedd98f02deaec8 100644 (file)
@@ -720,6 +720,16 @@ func (s *IntegrationTestBuilder) EditFileReplaceFunc(filename string, replacemen
        return s
 }
 
+func (s *IntegrationTestBuilder) EditFileAppend(filename, contnt string) *IntegrationTestBuilder {
+       absFilename := s.absFilename(filename)
+       b, err := afero.ReadFile(s.fs.Source, absFilename)
+       s.Assert(err, qt.IsNil)
+       s.changedFiles = append(s.changedFiles, absFilename)
+       oldContent := string(b)
+       s.writeSource(absFilename, oldContent+contnt)
+       return s
+}
+
 func (s *IntegrationTestBuilder) EditFiles(filenameContent ...string) *IntegrationTestBuilder {
        for i := 0; i < len(filenameContent); i += 2 {
                filename, content := filepath.FromSlash(filenameContent[i]), filenameContent[i+1]
index cb42e46f9b90f69d4732c02913834ff572d0c140..6c8c376b0477ee91c9ef04c430607d321d39ed9d 100644 (file)
@@ -122,7 +122,7 @@ docs/p1/sub/mymixcasetext2.txt
                "RelPermalink: /docs/p1/sub/mymixcasetext2.txt|Name: sub/mymixcasetext2.txt|",
                "RelPermalink: /mydata.yaml|Name: sub/data1.yaml|Title: Sub data|Params: map[]|",
                "Featured Image: /a/pixel.png|featured.png|",
-               "Resized Featured Image: /a/pixel_hu_a32b3e361d55df1.png|10|",
+               "Resized Featured Image: /a/pixel_hu_a354833fd576551d.png|10|",
                // Resource from string
                "RelPermalink: /docs/p1/mytext.txt|Name: textresource|Title: My Text Resource|Params: map[param1:param1v]|",
                // Dates
index 8a98541b2fa74553e27082a33f3fd117cd76eac0..544c45e245132d43f954a8ff58de315897e21102 100644 (file)
@@ -60,7 +60,7 @@ Resized RelPermalink: {{ $resized.RelPermalink }}|
 
        b := hugolib.Test(t, files)
 
-       b.ImageHelper("public/gopher_hu_f8d20fe200599f16.webp").AssertFormat("webp")
+       b.ImageHelper("public/gopher_hu_cc98ebaf742cba8e.webp").AssertFormat("webp")
 }
 
 func TestWebPInvalid(t *testing.T) {
@@ -111,9 +111,9 @@ sourcefilename: ../../resources/testdata/giphy.gif
        // Source animated gif:
        // Frame durations in ms.
        giphyFrameDurations := []int{200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200}
-       b.ImageHelper("public/giphy_hu_e4a5984f8835d617.webp").AssertFormat("webp").AssertIsAnimated(true).AssertLoopCount(0).AssertFrameDurations(giphyFrameDurations)
-       b.ImageHelper("public/giphy_hu_87010e943ffb23b4.gif").AssertFormat("gif").AssertIsAnimated(true).AssertLoopCount(0).AssertFrameDurations(giphyFrameDurations)
-       b.ImageHelper("public/giphy_hu_e4a5984f8835d617.webp").AssertFormat("webp").AssertIsAnimated(true).AssertLoopCount(0).AssertFrameDurations(giphyFrameDurations)
+
+       b.ImageHelper("public/giphy_hu_bb052284cc220165.webp").AssertFormat("webp").AssertIsAnimated(true).AssertLoopCount(0).AssertFrameDurations(giphyFrameDurations)
+       b.ImageHelper("public/giphy_hu_c6b8060edf0363b1.gif").AssertFormat("gif").AssertIsAnimated(true).AssertLoopCount(0).AssertFrameDurations(giphyFrameDurations)
 
        // Source animated webp:
        animFrameDurations := []int{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80}
index 19d2f5a8f99d0996b549117fba56ac7b5ed47064..b4153f8341deb6230cd6f2d9764cfe224cbfbd8b 100644 (file)
@@ -113,28 +113,28 @@ func TestImageTransformBasic(t *testing.T) {
        assertWidthHeight(resizedAndRotated, 125, 200)
 
        assertWidthHeight(resized, 300, 200)
-       c.Assert(resized.RelPermalink(), qt.Equals, "/a/sunset_hu_d2115125d9324a79.jpg")
+       c.Assert(resized.RelPermalink(), qt.Equals, "/a/sunset_hu_f4f15cdbaaca3b2d.jpg")
 
        fitted, err := resized.Fit("50x50")
        c.Assert(err, qt.IsNil)
-       c.Assert(fitted.RelPermalink(), qt.Equals, "/a/sunset_hu_c2c98e06123b048e.jpg")
+       c.Assert(fitted.RelPermalink(), qt.Equals, "/a/sunset_hu_c9781e950a09210.jpg")
        assertWidthHeight(fitted, 50, 33)
 
        // Check the MD5 key threshold
        fittedAgain, _ := fitted.Fit("10x20")
        fittedAgain, err = fittedAgain.Fit("10x20")
        c.Assert(err, qt.IsNil)
-       c.Assert(fittedAgain.RelPermalink(), qt.Equals, "/a/sunset_hu_dc9e89c10109de72.jpg")
+       c.Assert(fittedAgain.RelPermalink(), qt.Equals, "/a/sunset_hu_78c1665fdce5ec4d.jpg")
        assertWidthHeight(fittedAgain, 10, 7)
 
        filled, err := image.Fill("200x100 bottomLeft")
        c.Assert(err, qt.IsNil)
-       c.Assert(filled.RelPermalink(), qt.Equals, "/a/sunset_hu_b9f6d350738928fe.jpg")
+       c.Assert(filled.RelPermalink(), qt.Equals, "/a/sunset_hu_b3e01daae854e587.jpg")
        assertWidthHeight(filled, 200, 100)
 
        smart, err := image.Fill("200x100 smart")
        c.Assert(err, qt.IsNil)
-       c.Assert(smart.RelPermalink(), qt.Equals, "/a/sunset_hu_6fd390e7b0d26f0b.jpg")
+       c.Assert(smart.RelPermalink(), qt.Equals, "/a/sunset_hu_622a1375d91d9312.jpg")
        assertWidthHeight(smart, 200, 100)
 
        // Check cache
@@ -144,12 +144,12 @@ func TestImageTransformBasic(t *testing.T) {
 
        cropped, err := image.Crop("300x300 topRight")
        c.Assert(err, qt.IsNil)
-       c.Assert(cropped.RelPermalink(), qt.Equals, "/a/sunset_hu_3df036e11f4ddd43.jpg")
+       c.Assert(cropped.RelPermalink(), qt.Equals, "/a/sunset_hu_9016246670a22728.jpg")
        assertWidthHeight(cropped, 300, 300)
 
        smartcropped, err := image.Crop("200x200 smart")
        c.Assert(err, qt.IsNil)
-       c.Assert(smartcropped.RelPermalink(), qt.Equals, "/a/sunset_hu_12e2d26de89b464b.jpg")
+       c.Assert(smartcropped.RelPermalink(), qt.Equals, "/a/sunset_hu_78e9677f68b821ed.jpg")
        assertWidthHeight(smartcropped, 200, 200)
 
        // Check cache
@@ -216,7 +216,7 @@ func TestImageTransformFormat(t *testing.T) {
 
        imagePng, err := image.Resize("450x png")
        c.Assert(err, qt.IsNil)
-       c.Assert(imagePng.RelPermalink(), qt.Equals, "/a/sunset_hu_e8b9444dcf2e75ef.png")
+       c.Assert(imagePng.RelPermalink(), qt.Equals, "/a/sunset_hu_63ccccb11ff4e285.png")
        c.Assert(imagePng.ResourceType(), qt.Equals, "image")
        assertExtWidthHeight(imagePng, ".png", 450, 281)
        c.Assert(imagePng.Name(), qt.Equals, "sunset.jpg")
@@ -224,7 +224,7 @@ func TestImageTransformFormat(t *testing.T) {
 
        imageGif, err := image.Resize("225x gif")
        c.Assert(err, qt.IsNil)
-       c.Assert(imageGif.RelPermalink(), qt.Equals, "/a/sunset_hu_f80842d4c3789345.gif")
+       c.Assert(imageGif.RelPermalink(), qt.Equals, "/a/sunset_hu_6d1f23c09eddc748.gif")
        c.Assert(imageGif.ResourceType(), qt.Equals, "image")
        assertExtWidthHeight(imageGif, ".gif", 225, 141)
        c.Assert(imageGif.Name(), qt.Equals, "sunset.jpg")
@@ -247,7 +247,7 @@ func TestImagePermalinkPublishOrder(t *testing.T) {
                        }()
 
                        check1 := func(img images.ImageResource) {
-                               resizedLink := "/a/sunset_hu_3910bca82e28c9d6.jpg"
+                               resizedLink := "/a/sunset_hu_3a097ae28aebc166.jpg"
                                c.Assert(img.RelPermalink(), qt.Equals, resizedLink)
                                assertImageFile(c, spec.PublishFs, resizedLink, 100, 50)
                        }
@@ -288,12 +288,12 @@ func TestImageBugs(t *testing.T) {
                c.Assert(err, qt.IsNil)
                c.Assert(resized, qt.Not(qt.IsNil))
                c.Assert(resized.Width(), qt.Equals, 200)
-               c.Assert(resized.RelPermalink(), qt.Equals, "/a/1234567890qwertyuiopasdfghjklzxcvbnm5to6eeeeee7via8eleph_hu_951d3980b18c52a9.jpg")
+               c.Assert(resized.RelPermalink(), qt.Equals, "/a/1234567890qwertyuiopasdfghjklzxcvbnm5to6eeeeee7via8eleph_hu_a6f31c42e1afef07.jpg")
                resized, err = resized.Resize("100x")
                c.Assert(err, qt.IsNil)
                c.Assert(resized, qt.Not(qt.IsNil))
                c.Assert(resized.Width(), qt.Equals, 100)
-               c.Assert(resized.RelPermalink(), qt.Equals, "/a/1234567890qwertyuiopasdfghjklzxcvbnm5to6eeeeee7via8eleph_hu_1daa203572ecd6ec.jpg")
+               c.Assert(resized.RelPermalink(), qt.Equals, "/a/1234567890qwertyuiopasdfghjklzxcvbnm5to6eeeeee7via8eleph_hu_14e106419fe28039.jpg")
        })
 
        // Issue #6137
@@ -391,7 +391,7 @@ func TestImageResize8BitPNG(t *testing.T) {
        resized, err := image.Resize("800x")
        c.Assert(err, qt.IsNil)
        c.Assert(resized.MediaType().Type, qt.Equals, "image/png")
-       c.Assert(resized.RelPermalink(), qt.Equals, "/a/gohugoio_hu_fe2b762e9cac406c.png")
+       c.Assert(resized.RelPermalink(), qt.Equals, "/a/gohugoio_hu_626cfc4db4222bfe.png")
        c.Assert(resized.Width(), qt.Equals, 800)
 }
 
index e2f0d5211e8533096f5a10b21da6a3b8758ae2a2..f098053077a5dcda4fc837301e17d0ffe64c36bb 100644 (file)
@@ -67,17 +67,9 @@ var (
                media.Builtin.WEBPType.SubType: WEBP,
        }
 
-       // Add or increment if changes to an image format's processing requires
-       // re-generation.
-       imageFormatsVersions = map[Format]int{
-               PNG:  0,
-               WEBP: 1, //  Moved to WASM-based WebP encoder and decoder.
-               GIF:  0,
-       }
-
        // Increment to mark all processed images as stale. Only use when absolutely needed.
-       // See the finer grained smartCropVersionNumber and imageFormatsVersions.
-       mainImageVersionNumber = 0
+       // See the finer grained smartCropVersionNumber.
+       mainImageVersionNumber = 1
 )
 
 var anchorPositions = map[string]gift.Anchor{
@@ -328,10 +320,6 @@ func DecodeImageConfig(options []string, defaults *config.ConfigNamespace[Imagin
                options = append(options, strconv.Itoa(mainImageVersionNumber))
        }
 
-       if v, ok := imageFormatsVersions[sourceFormat]; ok && v > 0 {
-               options = append(options, strconv.Itoa(v))
-       }
-
        if smartCropVersionNumber > 0 && c.Anchor == SmartCropAnchor {
                options = append(options, strconv.Itoa(smartCropVersionNumber))
        }
index 09aadeb62c64b3413f0111c5cf819d56ffcddb90..907bb10cb1acdc4cb7a214b5c9348e4ed5e054c5 100644 (file)
@@ -19,7 +19,6 @@ import (
        "testing"
 
        qt "github.com/frankban/quicktest"
-       "github.com/gohugoio/hugo/common/hashing"
 )
 
 func TestDecodeConfig(t *testing.T) {
@@ -118,7 +117,7 @@ func TestDecodeImageConfig(t *testing.T) {
                                t.Fatalf("[%d] err: %s", i, err)
                        }
                        expect := this.expect.(ImageConfig)
-                       expect.Key = hashing.HashStringHex(options)
+                       result.Key = ""
 
                        if fmt.Sprint(result) != fmt.Sprint(expect) {
                                t.Fatalf("[%d] got\n%v\n but expected\n%v", i, result, expect)
index ce9d5f4d5d8c68f8b9328020052ba4626f45123e..4d8f4961c4465f344306b669363ff87e68393415 100644 (file)
@@ -380,6 +380,25 @@ func (f Format) MediaType() media.Type {
        }
 }
 
+func (f Format) String() string {
+       switch f {
+       case JPEG:
+               return "JPEG"
+       case PNG:
+               return "PNG"
+       case GIF:
+               return "GIF"
+       case TIFF:
+               return "TIFF"
+       case BMP:
+               return "BMP"
+       case WEBP:
+               return "WEBP"
+       default:
+               return "Unknown"
+       }
+}
+
 type imageConfig struct {
        config       image.Config
        configInit   sync.Once
index 54365f867de4d7e342e091f0f4d577c6d75bd679..979ca2fc542fb2cf9f37c9c6f6311187662103bc 100644 (file)
@@ -125,7 +125,7 @@ func RunGolden(opts GoldenImageTestOpts) *hugolib.IntegrationTestBuilder {
        shouldSkip := func(d fs.DirEntry) bool {
                if runtime.GOARCH == "arm64" {
                        // TODO(bep) figure out why this fails on arm64. I have inspected the images, and they look identical.
-                       if d.Name() == "giphy_hu_e4a5984f8835d617.webp" {
+                       if d.Name() == "giphy_hu_bb052284cc220165.webp" {
                                c.Logf("skipping %s on %s", d.Name(), runtime.GOARCH)
                                return true
                        }
diff --git a/resources/images/testdata/images_golden/webp/animation/giphy_hu_87010e943ffb23b4.gif b/resources/images/testdata/images_golden/webp/animation/giphy_hu_87010e943ffb23b4.gif
deleted file mode 100644 (file)
index 66a6b73..0000000
Binary files a/resources/images/testdata/images_golden/webp/animation/giphy_hu_87010e943ffb23b4.gif and /dev/null differ
diff --git a/resources/images/testdata/images_golden/webp/animation/giphy_hu_bb052284cc220165.webp b/resources/images/testdata/images_golden/webp/animation/giphy_hu_bb052284cc220165.webp
new file mode 100644 (file)
index 0000000..cc11d24
Binary files /dev/null and b/resources/images/testdata/images_golden/webp/animation/giphy_hu_bb052284cc220165.webp differ
diff --git a/resources/images/testdata/images_golden/webp/animation/giphy_hu_c6b8060edf0363b1.gif b/resources/images/testdata/images_golden/webp/animation/giphy_hu_c6b8060edf0363b1.gif
new file mode 100644 (file)
index 0000000..66a6b73
Binary files /dev/null and b/resources/images/testdata/images_golden/webp/animation/giphy_hu_c6b8060edf0363b1.gif differ
diff --git a/resources/images/testdata/images_golden/webp/animation/giphy_hu_e4a5984f8835d617.webp b/resources/images/testdata/images_golden/webp/animation/giphy_hu_e4a5984f8835d617.webp
deleted file mode 100644 (file)
index cc11d24..0000000
Binary files a/resources/images/testdata/images_golden/webp/animation/giphy_hu_e4a5984f8835d617.webp and /dev/null differ
index 54c6122cbecc89f667e4dfdd68890dbfcc37d024..1cc870f807c0a9d1ca5e47050ae68256311d765e 100644 (file)
@@ -62,9 +62,9 @@ anigif: {{ $anigif.RelPermalink }}|{{ $anigif.Width }}|{{ $anigif.Height }}|{{ $
 
        assertImages := func() {
                b.AssertFileContent("public/index.html", `
- gif: /mybundle/pixel_hu_93429543fc146fce.gif|}|1|2|image/gif|
-bmp: /mybundle/pixel_hu_f9bf2acd6578e2c6.bmp|}|2|3|image/bmp|
-anigif: /mybundle/giphy_hu_652d28653068b48f.gif|4|5|image/gif|
+gif: /mybundle/pixel_hu_d6bad5e71f783c98.gif|}|1|2|image/gif|
+bmp: /mybundle/pixel_hu_a8812c9bf8812b53.bmp|}|2|3|image/bmp|
+anigif: /mybundle/giphy_hu_7f64f85f904209d4.gif|4|5|image/gif|
                `)
        }
 
index eac85ada94c3c1f7776d69b7d0dd1bbcefbd65b1..feae43e4140af83ac8819205871ed8c0a4192912 100644 (file)
@@ -386,15 +386,15 @@ func TestTransform(t *testing.T) {
                resizedPublished1, err := img.Resize("40x40")
                c.Assert(err, qt.IsNil)
                c.Assert(resizedPublished1.Height(), qt.Equals, 40)
-               c.Assert(resizedPublished1.RelPermalink(), qt.Equals, "/gopher.changed_hu_85920388a7ff96fa.png")
-               assertShouldExist(c, spec, "public/gopher.changed_hu_85920388a7ff96fa.png", true)
+               c.Assert(resizedPublished1.RelPermalink(), qt.Equals, "/gopher.changed_hu_6347c67500afc377.png")
+               assertShouldExist(c, spec, "public/gopher.changed_hu_6347c67500afc377.png", true)
 
                // Permalink called.
                resizedPublished2, err := img.Resize("30x30")
                c.Assert(err, qt.IsNil)
                c.Assert(resizedPublished2.Height(), qt.Equals, 30)
-               c.Assert(resizedPublished2.Permalink(), qt.Equals, "https://example.com/gopher.changed_hu_c8d8163c08643a7f.png")
-               assertShouldExist(c, spec, "public/gopher.changed_hu_c8d8163c08643a7f.png", true)
+               c.Assert(resizedPublished2.Permalink(), qt.Equals, "https://example.com/gopher.changed_hu_2d293650135f63d6.png")
+               assertShouldExist(c, spec, "public/gopher.changed_hu_2d293650135f63d6.png", true)
 
                assertNoDuplicateWrites(c, spec)
        })
index b8edb22f3a7c7e6e78f5d4a3e835638b6a22608f..55b541ff12a865f05cf6706c661733396777badc 100644 (file)
@@ -188,3 +188,33 @@ Brightnes method: /qr_hu_d5f06fd7594d0594.webp
 Brightnes func: /qr_hu_d5f06fd7594d0594.webp
 `)
 }
+
+// Note that this test doesn't really reproduce the original issue,
+// but keep it as a regression test for WebP decoding in general.
+// TODO(bep) I fixed the failing site, but I don't really understand why it failed. But now it's Christmas.
+func TestPNGIssue14295(t *testing.T) {
+       t.Parallel()
+
+       files := `
+-- hugo.toml --
+disableLiveReload = true
+-- assets/qr.png --
+sourcefilename: testdata/images_golden/funcs/qr-level-high_scale-6.png
+-- layouts/home.html --
+{{ $img := resources.Get "qr.png" }}
+{{ $img = $img.Resize "200x webp" | images.Filter (images.GaussianBlur 5) }}
+Image: {{ $img.RelPermalink }}
+
+`
+
+       tempDir := t.TempDir()
+
+       for range 2 {
+               b := hugolib.Test(t, files, hugolib.TestOptWithConfig(func(cfg *hugolib.IntegrationTestConfig) {
+                       cfg.NeedsOsFS = true
+                       cfg.WorkingDir = tempDir
+               }))
+               b.AssertFileContent("public/index.html", `Image: /qr_hu_6b5f59be9c4d3b3a.webp`)
+
+       }
+}
index 919afe4997d2780c510b0ef637be505cb43c2127..60889cb077b8f0ec49c3eca5bb0eafd7b7cc5029 100644 (file)
@@ -60,14 +60,13 @@ Copy3: {{ $copy3.RelPermalink}}|{{ $copy3.MediaType }}|{{ $copy3.Content | safeJ
 
        b.AssertFileContent("public/index.html", `
 Image Orig:  /blog/images/pixel.png|image/png|1|1|
-Image Copy1:  /blog/images/copy_hu_1d9addfff177f388.png|image/png|3|4|
-Image Copy2:  /blog/images/copy2.png|image/png|3|4
+Image Copy1:  /blog/images/copy_hu_ef85c36d9b9eff0.png|image/png|3|4|
+Image Copy2:  /blog/images/copy2.png|image/png|3|4|
 Image Copy3:  image/png|3|4|
 Orig: /blog/js/foo.js|text/javascript|let foo;|
 Copy1: /blog/js/copies/bar.js|text/javascript|let foo;|
 Copy2: /blog/js/copies/baz.a677329fc6c4ad947e0c7116d91f37a2.js|text/javascript|let foo;|
 Copy3: /blog/js/copies/moo.a677329fc6c4ad947e0c7116d91f37a2.min.js|text/javascript|let foo|
-
                `)
 
        b.AssertFileExists("public/images/copy2.png", true)