github.com/graemephi/kahugo@v0.62.3-0.20211121071557-d78c0423784d/hugolib/image_test.go (about)

     1  // Copyright 2019 The Hugo Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package hugolib
    15  
    16  import (
    17  	"io"
    18  	"os"
    19  	"path/filepath"
    20  	"runtime"
    21  	"strings"
    22  	"testing"
    23  
    24  	"github.com/gohugoio/hugo/config"
    25  	"github.com/gohugoio/hugo/htesting"
    26  
    27  	qt "github.com/frankban/quicktest"
    28  	"github.com/gohugoio/hugo/hugofs"
    29  )
    30  
    31  // We have many tests for the different resize operations etc. in the resource package,
    32  // this is an integration test.
    33  func TestImageOps(t *testing.T) {
    34  	c := qt.New(t)
    35  	// Make this a real as possible.
    36  	workDir, clean, err := htesting.CreateTempDir(hugofs.Os, "image-resize")
    37  	c.Assert(err, qt.IsNil)
    38  	defer clean()
    39  
    40  	newBuilder := func(timeout interface{}) *sitesBuilder {
    41  		v := config.New()
    42  		v.Set("workingDir", workDir)
    43  		v.Set("baseURL", "https://example.org")
    44  		v.Set("timeout", timeout)
    45  
    46  		b := newTestSitesBuilder(t).WithWorkingDir(workDir)
    47  		b.Fs = hugofs.NewDefault(v)
    48  		b.WithViper(v)
    49  		b.WithContent("mybundle/index.md", `
    50  ---
    51  title: "My bundle"
    52  ---
    53  
    54  {{< imgproc >}}
    55  
    56  `)
    57  
    58  		b.WithTemplatesAdded(
    59  			"shortcodes/imgproc.html", `
    60  {{ $img := resources.Get "images/sunset.jpg" }}
    61  {{ $r := $img.Resize "129x239" }}
    62  IMG SHORTCODE: {{ $r.RelPermalink }}/{{ $r.Width }}
    63  `,
    64  			"index.html", `
    65  {{ $p := .Site.GetPage "mybundle" }}
    66  {{ $img1 := resources.Get "images/sunset.jpg" }}
    67  {{ $img2 := $p.Resources.GetMatch "sunset.jpg" }}
    68  {{ $img3 := resources.GetMatch "images/*.jpg" }}
    69  {{ $r := $img1.Resize "123x234" }}
    70  {{ $r2 := $r.Resize "12x23" }}
    71  {{ $b := $img2.Resize "345x678" }}
    72  {{ $b2 := $b.Resize "34x67" }}
    73  {{ $c := $img3.Resize "456x789" }}
    74  {{ $fingerprinted := $img1.Resize "350x" | fingerprint }}
    75  
    76  {{ $images := slice $r $r2 $b $b2 $c $fingerprinted }}
    77  
    78  {{ range $i, $r := $images }}
    79  {{ printf "Resized%d:" (add $i  1) }} {{ $r.Name }}|{{ $r.Width }}|{{ $r.Height }}|{{ $r.MediaType }}|{{ $r.RelPermalink }}|
    80  {{ end }}
    81  
    82  {{ $blurryGrayscale1 := $r | images.Filter images.Grayscale (images.GaussianBlur 8) }}
    83  BG1: {{ $blurryGrayscale1.RelPermalink }}/{{ $blurryGrayscale1.Width }}
    84  {{ $blurryGrayscale2 := $r.Filter images.Grayscale (images.GaussianBlur 8) }}
    85  BG2: {{ $blurryGrayscale2.RelPermalink }}/{{ $blurryGrayscale2.Width }}
    86  {{ $blurryGrayscale2_2 := $r.Filter images.Grayscale (images.GaussianBlur 8) }}
    87  BG2_2: {{ $blurryGrayscale2_2.RelPermalink }}/{{ $blurryGrayscale2_2.Width }}
    88  
    89  {{ $filters := slice images.Grayscale (images.GaussianBlur 9) }}
    90  {{ $blurryGrayscale3 := $r | images.Filter $filters }}
    91  BG3: {{ $blurryGrayscale3.RelPermalink }}/{{ $blurryGrayscale3.Width }}
    92  
    93  {{ $blurryGrayscale4 := $r.Filter $filters }}
    94  BG4: {{ $blurryGrayscale4.RelPermalink }}/{{ $blurryGrayscale4.Width }}
    95  
    96  {{ $p.Content }}
    97  
    98  `)
    99  
   100  		return b
   101  	}
   102  
   103  	imageDir := filepath.Join(workDir, "assets", "images")
   104  	bundleDir := filepath.Join(workDir, "content", "mybundle")
   105  
   106  	c.Assert(os.MkdirAll(imageDir, 0777), qt.IsNil)
   107  	c.Assert(os.MkdirAll(bundleDir, 0777), qt.IsNil)
   108  	src, err := os.Open("testdata/sunset.jpg")
   109  	c.Assert(err, qt.IsNil)
   110  	out, err := os.Create(filepath.Join(imageDir, "sunset.jpg"))
   111  	c.Assert(err, qt.IsNil)
   112  	_, err = io.Copy(out, src)
   113  	c.Assert(err, qt.IsNil)
   114  	out.Close()
   115  
   116  	src.Seek(0, 0)
   117  
   118  	out, err = os.Create(filepath.Join(bundleDir, "sunset.jpg"))
   119  	c.Assert(err, qt.IsNil)
   120  	_, err = io.Copy(out, src)
   121  	c.Assert(err, qt.IsNil)
   122  	out.Close()
   123  	src.Close()
   124  
   125  	// First build it with a very short timeout to trigger errors.
   126  	b := newBuilder("10ns")
   127  
   128  	imgExpect := `
   129  Resized1: images/sunset.jpg|123|234|image/jpeg|/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_123x234_resize_q75_box.jpg|
   130  Resized2: images/sunset.jpg|12|23|image/jpeg|/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_ada4bb1a57f77a63306e3bd67286248e.jpg|
   131  Resized3: sunset.jpg|345|678|image/jpeg|/mybundle/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_345x678_resize_q75_box.jpg|
   132  Resized4: sunset.jpg|34|67|image/jpeg|/mybundle/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_44d8c928664d7c5a67377c6ec58425ce.jpg|
   133  Resized5: images/sunset.jpg|456|789|image/jpeg|/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_456x789_resize_q75_box.jpg|
   134  Resized6: images/sunset.jpg|350|219|image/jpeg|/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_350x0_resize_q75_box.a86fe88d894e5db613f6aa8a80538fefc25b20fa24ba0d782c057adcef616f56.jpg|
   135  BG1: /images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_2ae8bb993431ec1aec40fe59927b46b4.jpg/123
   136  BG2: /images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_2ae8bb993431ec1aec40fe59927b46b4.jpg/123
   137  BG3: /images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_ed7740a90b82802261c2fbdb98bc8082.jpg/123
   138  BG4: /images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_ed7740a90b82802261c2fbdb98bc8082.jpg/123
   139  IMG SHORTCODE: /images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_129x239_resize_q75_box.jpg/129
   140  `
   141  
   142  	assertImages := func() {
   143  		b.Helper()
   144  		b.AssertFileContent(filepath.Join(workDir, "public/index.html"), imgExpect)
   145  		b.AssertImage(350, 219, "public/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_350x0_resize_q75_box.a86fe88d894e5db613f6aa8a80538fefc25b20fa24ba0d782c057adcef616f56.jpg")
   146  		b.AssertImage(129, 239, "public/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_129x239_resize_q75_box.jpg")
   147  	}
   148  
   149  	err = b.BuildE(BuildCfg{})
   150  	if runtime.GOOS != "windows" && !strings.Contains(runtime.GOARCH, "arm") && !htesting.IsGitHubAction() {
   151  		// TODO(bep)
   152  		c.Assert(err, qt.Not(qt.IsNil))
   153  	}
   154  
   155  	b = newBuilder(29000)
   156  	b.Build(BuildCfg{})
   157  
   158  	assertImages()
   159  
   160  	// Truncate one image.
   161  	imgInCache := filepath.Join(workDir, "resources/_gen/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_ed7740a90b82802261c2fbdb98bc8082.jpg")
   162  	f, err := os.Create(imgInCache)
   163  	c.Assert(err, qt.IsNil)
   164  	f.Close()
   165  
   166  	// Build it again to make sure we read images from file cache.
   167  	b = newBuilder("30s")
   168  	b.Build(BuildCfg{})
   169  
   170  	assertImages()
   171  }
   172  
   173  func TestImageResizeMultilingual(t *testing.T) {
   174  	b := newTestSitesBuilder(t).WithConfigFile("toml", `
   175  baseURL="https://example.org"
   176  defaultContentLanguage = "en"
   177  
   178  [languages]
   179  [languages.en]
   180  title = "Title in English"
   181  languageName = "English"
   182  weight = 1
   183  [languages.nn]
   184  languageName = "Nynorsk"
   185  weight = 2
   186  title = "Tittel på nynorsk"
   187  [languages.nb]
   188  languageName = "Bokmål"
   189  weight = 3
   190  title = "Tittel på bokmål"
   191  [languages.fr]
   192  languageName = "French"
   193  weight = 4
   194  title = "French Title"
   195  
   196  `)
   197  
   198  	pageContent := `---
   199  title: "Page"
   200  ---
   201  `
   202  
   203  	b.WithContent("bundle/index.md", pageContent)
   204  	b.WithContent("bundle/index.nn.md", pageContent)
   205  	b.WithContent("bundle/index.fr.md", pageContent)
   206  	b.WithSunset("content/bundle/sunset.jpg")
   207  	b.WithSunset("assets/images/sunset.jpg")
   208  	b.WithTemplates("index.html", `
   209  {{ with (.Site.GetPage "bundle" ) }}
   210  {{ $sunset := .Resources.GetMatch "sunset*" }}
   211  {{ if $sunset }}
   212  {{ $resized := $sunset.Resize "200x200" }}
   213  SUNSET FOR: {{ $.Site.Language.Lang }}: {{ $resized.RelPermalink }}/{{ $resized.Width }}/Lat: {{ $resized.Exif.Lat }}
   214  {{ end }}
   215  {{ else }}
   216  No bundle for {{ $.Site.Language.Lang }}
   217  {{ end }}
   218  
   219  {{ $sunset2 := resources.Get "images/sunset.jpg" }}
   220  {{ $resized2 := $sunset2.Resize "123x234" }}
   221  SUNSET2: {{ $resized2.RelPermalink }}/{{ $resized2.Width }}/Lat: {{ $resized2.Exif.Lat }}
   222  
   223  
   224  `)
   225  
   226  	b.Build(BuildCfg{})
   227  
   228  	b.AssertFileContent("public/index.html", "SUNSET FOR: en: /bundle/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_200x200_resize_q75_box.jpg/200/Lat: 36.59744166666667")
   229  	b.AssertFileContent("public/fr/index.html", "SUNSET FOR: fr: /fr/bundle/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_200x200_resize_q75_box.jpg/200/Lat: 36.59744166666667")
   230  	b.AssertFileContent("public/index.html", " SUNSET2: /images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_123x234_resize_q75_box.jpg/123/Lat: 36.59744166666667")
   231  	b.AssertFileContent("public/nn/index.html", " SUNSET2: /images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_123x234_resize_q75_box.jpg/123/Lat: 36.59744166666667")
   232  
   233  	b.AssertImage(200, 200, "public/fr/bundle/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_200x200_resize_q75_box.jpg")
   234  	b.AssertImage(200, 200, "public/bundle/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_200x200_resize_q75_box.jpg")
   235  
   236  	// Check the file cache
   237  	b.AssertImage(200, 200, "resources/_gen/images/bundle/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_200x200_resize_q75_box.jpg")
   238  
   239  	b.AssertFileContent("resources/_gen/images/bundle/sunset_3166614710256882113.json",
   240  		"DateTimeDigitized|time.Time", "PENTAX")
   241  	b.AssertImage(123, 234, "resources/_gen/images/sunset_hu59e56ffff1bc1d8d122b1403d34e039f_90587_123x234_resize_q75_box.jpg")
   242  	b.AssertFileContent("resources/_gen/images/sunset_3166614710256882113.json",
   243  		"DateTimeDigitized|time.Time", "PENTAX")
   244  
   245  	// TODO(bep) add this as a default assertion after Build()?
   246  	b.AssertNoDuplicateWrites()
   247  }