diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2019-08-18 11:21:27 +0200 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2019-08-26 15:00:44 +0200 |
commit | f9978ed16476ca6d233a89669c62c798cdf9db9d (patch) | |
tree | 02edb31008b997a3e77055060a34971fe9e8c5a4 /resources/image_test.go | |
parent | 58d4c0a8be8beefbd7437b17bf7a9a381164d09b (diff) |
Image resource refactor
This commit pulls most of the image related logic into its own package, to make it easier to reason about and extend.
This is also a rewrite of the transformation logic used in Hugo Pipes, mostly to allow constructs like the one below:
{{ ($myimg | fingerprint ).Width }}
Fixes #5903
Fixes #6234
Fixes #6266
Diffstat (limited to 'resources/image_test.go')
-rw-r--r-- | resources/image_test.go | 189 |
1 files changed, 57 insertions, 132 deletions
diff --git a/resources/image_test.go b/resources/image_test.go index 96a66d999..31169444d 100644 --- a/resources/image_test.go +++ b/resources/image_test.go @@ -18,121 +18,101 @@ import ( "math/rand" "path/filepath" "strconv" + "sync" "testing" - "github.com/gohugoio/hugo/htesting/hqt" + "github.com/gohugoio/hugo/media" + "github.com/gohugoio/hugo/resources/resource" - "github.com/disintegration/imaging" + "github.com/google/go-cmp/cmp" - "sync" + "github.com/gohugoio/hugo/htesting/hqt" qt "github.com/frankban/quicktest" ) -func TestParseImageConfig(t *testing.T) { - for i, this := range []struct { - in string - expect interface{} - }{ - {"300x400", newImageConfig(300, 400, 0, 0, "", "")}, - {"100x200 bottomRight", newImageConfig(100, 200, 0, 0, "", "BottomRight")}, - {"10x20 topleft Lanczos", newImageConfig(10, 20, 0, 0, "Lanczos", "topleft")}, - {"linear left 10x r180", newImageConfig(10, 0, 0, 180, "linear", "left")}, - {"x20 riGht Cosine q95", newImageConfig(0, 20, 95, 0, "cosine", "right")}, - - {"", false}, - {"foo", false}, - } { - result, err := parseImageConfig(this.in) - if b, ok := this.expect.(bool); ok && !b { - if err == nil { - t.Errorf("[%d] parseImageConfig didn't return an expected error", i) - } - } else { - if err != nil { - t.Fatalf("[%d] err: %s", i, err) - } - if fmt.Sprint(result) != fmt.Sprint(this.expect) { - t.Fatalf("[%d] got\n%v\n but expected\n%v", i, result, this.expect) - } - } - } -} +var eq = qt.CmpEquals( + cmp.Comparer(func(p1, p2 *resourceAdapter) bool { + return p1.resourceAdapterInner == p2.resourceAdapterInner + }), + cmp.Comparer(func(p1, p2 *genericResource) bool { return p1 == p2 }), + cmp.Comparer(func(m1, m2 media.Type) bool { + return m1.Type() == m2.Type() + }), +) func TestImageTransformBasic(t *testing.T) { - c := qt.New(t) image := fetchSunset(c) - fileCache := image.spec.FileCaches.ImageCache().Fs + + fileCache := image.(specProvider).getSpec().FileCaches.ImageCache().Fs + + assertWidthHeight := func(img resource.Image, w, h int) { + c.Helper() + c.Assert(img, qt.Not(qt.IsNil)) + c.Assert(img.Width(), qt.Equals, w) + c.Assert(img.Height(), qt.Equals, h) + } c.Assert(image.RelPermalink(), qt.Equals, "/a/sunset.jpg") c.Assert(image.ResourceType(), qt.Equals, "image") + assertWidthHeight(image, 900, 562) resized, err := image.Resize("300x200") c.Assert(err, qt.IsNil) c.Assert(image != resized, qt.Equals, true) - c.Assert(image.genericResource != resized.genericResource, qt.Equals, true) - c.Assert(image.sourceFilename != resized.sourceFilename, qt.Equals, true) + c.Assert(image, qt.Not(eq), resized) + assertWidthHeight(resized, 300, 200) + assertWidthHeight(image, 900, 562) resized0x, err := image.Resize("x200") c.Assert(err, qt.IsNil) - c.Assert(resized0x.Width(), qt.Equals, 320) - c.Assert(resized0x.Height(), qt.Equals, 200) - + assertWidthHeight(resized0x, 320, 200) assertFileCache(c, fileCache, resized0x.RelPermalink(), 320, 200) resizedx0, err := image.Resize("200x") c.Assert(err, qt.IsNil) - c.Assert(resizedx0.Width(), qt.Equals, 200) - c.Assert(resizedx0.Height(), qt.Equals, 125) + assertWidthHeight(resizedx0, 200, 125) assertFileCache(c, fileCache, resizedx0.RelPermalink(), 200, 125) resizedAndRotated, err := image.Resize("x200 r90") c.Assert(err, qt.IsNil) - c.Assert(resizedAndRotated.Width(), qt.Equals, 125) - c.Assert(resizedAndRotated.Height(), qt.Equals, 200) + assertWidthHeight(resizedAndRotated, 125, 200) assertFileCache(c, fileCache, resizedAndRotated.RelPermalink(), 125, 200) + assertWidthHeight(resized, 300, 200) c.Assert(resized.RelPermalink(), qt.Equals, "/a/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_300x200_resize_q68_linear.jpg") - c.Assert(resized.Width(), qt.Equals, 300) - c.Assert(resized.Height(), qt.Equals, 200) fitted, err := resized.Fit("50x50") c.Assert(err, qt.IsNil) c.Assert(fitted.RelPermalink(), qt.Equals, "/a/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_625708021e2bb281c9f1002f88e4753f.jpg") - c.Assert(fitted.Width(), qt.Equals, 50) - c.Assert(fitted.Height(), qt.Equals, 33) + 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_hu59e56ffff1bc1d8d122b1403d34e039f_90587_3f65ba24dc2b7fba0f56d7f104519157.jpg") - c.Assert(fittedAgain.Width(), qt.Equals, 10) - c.Assert(fittedAgain.Height(), qt.Equals, 6) + assertWidthHeight(fittedAgain, 10, 6) filled, err := image.Fill("200x100 bottomLeft") c.Assert(err, qt.IsNil) c.Assert(filled.RelPermalink(), qt.Equals, "/a/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_200x100_fill_q68_linear_bottomleft.jpg") - c.Assert(filled.Width(), qt.Equals, 200) - c.Assert(filled.Height(), qt.Equals, 100) + assertWidthHeight(filled, 200, 100) assertFileCache(c, fileCache, filled.RelPermalink(), 200, 100) smart, err := image.Fill("200x100 smart") c.Assert(err, qt.IsNil) - c.Assert(smart.RelPermalink(), qt.Equals, fmt.Sprintf("/a/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_200x100_fill_q68_linear_smart%d.jpg", smartCropVersionNumber)) - c.Assert(smart.Width(), qt.Equals, 200) - c.Assert(smart.Height(), qt.Equals, 100) + c.Assert(smart.RelPermalink(), qt.Equals, fmt.Sprintf("/a/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_200x100_fill_q68_linear_smart%d.jpg", 1)) + assertWidthHeight(smart, 200, 100) assertFileCache(c, fileCache, smart.RelPermalink(), 200, 100) // Check cache filledAgain, err := image.Fill("200x100 bottomLeft") c.Assert(err, qt.IsNil) - c.Assert(filled == filledAgain, qt.Equals, true) - c.Assert(filled.sourceFilename == filledAgain.sourceFilename, qt.Equals, true) + c.Assert(filled, eq, filledAgain) assertFileCache(c, fileCache, filledAgain.RelPermalink(), 200, 100) - } // https://github.com/gohugoio/hugo/issues/4261 @@ -158,6 +138,7 @@ func TestImageTransformLongFilename(t *testing.T) { func TestImageTransformUppercaseExt(t *testing.T) { c := qt.New(t) image := fetchImage(c, "sunrise.JPG") + resized, err := image.Resize("200x") c.Assert(err, qt.IsNil) c.Assert(resized, qt.Not(qt.IsNil)) @@ -173,17 +154,16 @@ func TestImagePermalinkPublishOrder(t *testing.T) { } t.Run(name, func(t *testing.T) { - c := qt.New(t) spec := newTestResourceOsFs(c) - check1 := func(img *Image) { + check1 := func(img resource.Image) { resizedLink := "/a/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_100x50_resize_q75_box.jpg" c.Assert(img.RelPermalink(), qt.Equals, resizedLink) assertImageFile(c, spec.PublishFs, resizedLink, 100, 50) } - check2 := func(img *Image) { + check2 := func(img resource.Image) { c.Assert(img.RelPermalink(), qt.Equals, "/a/sunset.jpg") assertImageFile(c, spec.PublishFs, "a/sunset.jpg", 900, 562) } @@ -198,18 +178,16 @@ func TestImagePermalinkPublishOrder(t *testing.T) { resized, err := orignal.Resize("100x50") c.Assert(err, qt.IsNil) - check1(resized) + check1(resized.(resource.Image)) if !checkOriginalFirst { check2(orignal) } }) } - } func TestImageTransformConcurrent(t *testing.T) { - var wg sync.WaitGroup c := qt.New(t) @@ -239,12 +217,7 @@ func TestImageTransformConcurrent(t *testing.T) { t.Error(err) } - _, err = r2.decodeSource() - if err != nil { - t.Error("Err decode:", err) - } - - img = r1 + img = r2 } } }(i + 20) @@ -253,58 +226,12 @@ func TestImageTransformConcurrent(t *testing.T) { wg.Wait() } -func TestDecodeImaging(t *testing.T) { - c := qt.New(t) - m := map[string]interface{}{ - "quality": 42, - "resampleFilter": "NearestNeighbor", - "anchor": "topLeft", - } - - imaging, err := decodeImaging(m) - - c.Assert(err, qt.IsNil) - c.Assert(imaging.Quality, qt.Equals, 42) - c.Assert(imaging.ResampleFilter, qt.Equals, "nearestneighbor") - c.Assert(imaging.Anchor, qt.Equals, "topleft") - - m = map[string]interface{}{} - - imaging, err = decodeImaging(m) - c.Assert(err, qt.IsNil) - c.Assert(imaging.Quality, qt.Equals, defaultJPEGQuality) - c.Assert(imaging.ResampleFilter, qt.Equals, "box") - c.Assert(imaging.Anchor, qt.Equals, "smart") - - _, err = decodeImaging(map[string]interface{}{ - "quality": 123, - }) - c.Assert(err, qt.Not(qt.IsNil)) - - _, err = decodeImaging(map[string]interface{}{ - "resampleFilter": "asdf", - }) - c.Assert(err, qt.Not(qt.IsNil)) - - _, err = decodeImaging(map[string]interface{}{ - "anchor": "asdf", - }) - c.Assert(err, qt.Not(qt.IsNil)) - - imaging, err = decodeImaging(map[string]interface{}{ - "anchor": "Smart", - }) - c.Assert(err, qt.IsNil) - c.Assert(imaging.Anchor, qt.Equals, "smart") - -} - func TestImageWithMetadata(t *testing.T) { c := qt.New(t) image := fetchSunset(c) - var meta = []map[string]interface{}{ + meta := []map[string]interface{}{ { "title": "My Sunset", "name": "Sunset #:counter", @@ -318,71 +245,69 @@ func TestImageWithMetadata(t *testing.T) { resized, err := image.Resize("200x") c.Assert(err, qt.IsNil) c.Assert(resized.Name(), qt.Equals, "Sunset #1") - } func TestImageResize8BitPNG(t *testing.T) { - c := qt.New(t) image := fetchImage(c, "gohugoio.png") - c.Assert(image.format, qt.Equals, imaging.PNG) + c.Assert(image.MediaType().Type(), qt.Equals, "image/png") c.Assert(image.RelPermalink(), qt.Equals, "/a/gohugoio.png") c.Assert(image.ResourceType(), qt.Equals, "image") resized, err := image.Resize("800x") c.Assert(err, qt.IsNil) - c.Assert(resized.format, qt.Equals, imaging.PNG) + c.Assert(resized.MediaType().Type(), qt.Equals, "image/png") c.Assert(resized.RelPermalink(), qt.Equals, "/a/gohugoio_hu0e1b9e4a4be4d6f86c7b37b9ccce3fbc_73886_800x0_resize_linear_2.png") c.Assert(resized.Width(), qt.Equals, 800) - } func TestImageResizeInSubPath(t *testing.T) { - c := qt.New(t) image := fetchImage(c, "sub/gohugoio2.png") - fileCache := image.spec.FileCaches.ImageCache().Fs + fileCache := image.(specProvider).getSpec().FileCaches.ImageCache().Fs - c.Assert(image.format, qt.Equals, imaging.PNG) + c.Assert(image.MediaType(), eq, media.PNGType) c.Assert(image.RelPermalink(), qt.Equals, "/a/sub/gohugoio2.png") c.Assert(image.ResourceType(), qt.Equals, "image") resized, err := image.Resize("101x101") c.Assert(err, qt.IsNil) - c.Assert(resized.format, qt.Equals, imaging.PNG) + c.Assert(resized.MediaType().Type(), qt.Equals, "image/png") c.Assert(resized.RelPermalink(), qt.Equals, "/a/sub/gohugoio2_hu0e1b9e4a4be4d6f86c7b37b9ccce3fbc_73886_101x101_resize_linear_2.png") c.Assert(resized.Width(), qt.Equals, 101) assertFileCache(c, fileCache, resized.RelPermalink(), 101, 101) publishedImageFilename := filepath.Clean(resized.RelPermalink()) - assertImageFile(c, image.spec.BaseFs.PublishFs, publishedImageFilename, 101, 101) - c.Assert(image.spec.BaseFs.PublishFs.Remove(publishedImageFilename), qt.IsNil) + + spec := image.(specProvider).getSpec() + + assertImageFile(c, spec.BaseFs.PublishFs, publishedImageFilename, 101, 101) + c.Assert(spec.BaseFs.PublishFs.Remove(publishedImageFilename), qt.IsNil) // Cleare mem cache to simulate reading from the file cache. - resized.spec.imageCache.clear() + spec.imageCache.clear() resizedAgain, err := image.Resize("101x101") c.Assert(err, qt.IsNil) c.Assert(resizedAgain.RelPermalink(), qt.Equals, "/a/sub/gohugoio2_hu0e1b9e4a4be4d6f86c7b37b9ccce3fbc_73886_101x101_resize_linear_2.png") c.Assert(resizedAgain.Width(), qt.Equals, 101) assertFileCache(c, fileCache, resizedAgain.RelPermalink(), 101, 101) - assertImageFile(c, image.spec.BaseFs.PublishFs, publishedImageFilename, 101, 101) - + assertImageFile(c, image.(specProvider).getSpec().BaseFs.PublishFs, publishedImageFilename, 101, 101) } func TestSVGImage(t *testing.T) { c := qt.New(t) - spec := newTestResourceSpec(c) + spec := newTestResourceSpec(specDescriptor{c: c}) svg := fetchResourceForSpec(spec, c, "circle.svg") c.Assert(svg, qt.Not(qt.IsNil)) } func TestSVGImageContent(t *testing.T) { c := qt.New(t) - spec := newTestResourceSpec(c) + spec := newTestResourceSpec(specDescriptor{c: c}) svg := fetchResourceForSpec(spec, c, "circle.svg") c.Assert(svg, qt.Not(qt.IsNil)) |