How to resize image in custom figure shortcode?

Hi!

I started working on a responsive hugo theme and I want to extend Hugo’s figure shortcode and add a functionality for responsive images using the srcset attribute (http://w3c.github.io/html/semantics-embedded-content.html#element-attrdef-img-srcset). This would enable Hugo to generate multiple resized versions of the image and have the browser select the best version for the current view.

Currently the output of the figure shortcode is similar to this:

<figure>
        <img src="example.jpg" alt="" />
</figure>

I want to change it into something similar to this:

<figure>
        <img src="example.jpg" srcset="example-600.jpg 600w, example-900.jpg 900w" alt="" />
</figure>

Here is where I struggle:

The original image filename can be accessed in the figure shortcode using .Get “src” but I can’t really figure out how to resize the image within the figure shortcode.

I tried using something from the image processing examples (https://gohugo.io/content-management/image-processing/) like:

{{ $original := .Page.Resources.GetMatch (printf "*%s*" (.Get "src")) }}

But this does not seem to work in this context. Please point me into the right direction.

Best regards
Tobias

The above is the right direction.

Ok. But I don’t really get how to do the resize. I tried something as simple as:

{{ $original := .Page.Resources.GetMatch (printf "*%s*" (.Get "src")) }}
{{ $image := $original.Resize "600x" }} 
<img src="{{ $image.RelPermalink }}" width="{{ $image.Width }}" height="{{ $image.Height }}" alt="">

This results in an error:

ERROR 2018/09/02 13:45:56 error processing shortcode "shortcodes/figure.html" for page "test.md": template: shortcodes/figure.html:2:22: executing "shortcodes/figure.html" at <$original.Resize>: can't evaluate field Resize in type resource.Resource

Obviously I don’t get the idea. But I can’t really find any proper working examples. :frowning:

Best regards
Tobias

The problem I think you have is that you “match too broadly” and end up trying to resize a text file or something.

Something like this should improve your shortcode:

{{ $original := (.Page.Resources.ByType "image").GetMatch (printf "*%s*" (.Get "src")) }}
{{ with $original }}
{{ $image := .Resize "600x" }} 
<img src="{{ $image.RelPermalink }}" width="{{ $image.Width }}" height="{{ $image.Height }}" alt="">
{{ end }}

If you know that

  1. What you get in src is without extension
  2. You have, say only jpg and png images

Then this would possibly be faster and maybe easier to read:

{{ $original := .Page.Resources.GetMatch (printf "*%s*.{png,jpg}" (.Get "src")) }}

Note that I typed the above directly in here, so there may be mistakes.

2 Likes

This definitively seemed to be the case. However even knowing this, I could only get it to work with a very basic example with only two files (test.jpg and _index.md) in my content directory.

Currently it does not take the srcset/sizes configuration as a parameter and the tag gets really ugly, but I want to put it up for discussion anyway.

This is my _index.md:

---
title: "Test"
---

{{< figure src="test.jpg" alt="Test" >}}

This is my new figure.html:

{{ $srcset := "360|(max-width: 37.5em) 360px,720|(min-width: 75em) 720px,1920|(min-width: 112.5em) 1200px" }}
{{ $srcset := split $srcset "," }}
{{ $original := (.Page.Resources.ByType "image").GetMatch (printf "*%s" (.Get "src")) }}
<!-- image -->
<figure{{ with .Get "class" }} class="{{.}}"{{ end }}>
	<!-- image without srcset -->
    {{ if .Get "link"}}<a href="{{ .Get "link" }}"{{ with .Get "target" }} target="{{ . }}"{{ end }}{{ with .Get "rel" }} rel="{{ . }}"{{ end }}>{{ end }}
        <img src="{{ $original.RelPermalink }}" srcset="{{range $i, $set := $srcset}}{{ $setparams := split $set "|" }}{{$sizecondition := index $setparams 0 }}{{ $image := $original.Resize (print $sizecondition "x") }}{{ if $i }}, {{ end }}{{ (print $image.RelPermalink " " $sizecondition "w") }}{{ end }}" sizes="{{range $i, $set := $srcset}}{{ $setparams := split $set "|" }}{{$mediacondition := index $setparams 1 }}{{ if $i }}, {{ end }}{{ $mediacondition }}{{ end }}" {{ if or (.Get "alt") (.Get "caption") }}alt="{{ with .Get "alt"}}{{.}}{{else}}{{ .Get "caption" }}{{ end }}" {{ end }}{{ with .Get "width" }}width="{{.}}" {{ end }}{{ with .Get "height" }}height="{{.}}" {{ end }}/>
    {{ if .Get "link"}}</a>{{ end }}
    {{ if or (or (.Get "title") (.Get "caption")) (.Get "attr")}}
    <figcaption>{{ if isset .Params "title" }}
        <h4>{{ .Get "title" }}</h4>{{ end }}
        {{ if or (.Get "caption") (.Get "attr")}}<p>
        {{ .Get "caption" }}
        {{ with .Get "attrlink"}}<a href="{{.}}"> {{ end }}
            {{ .Get "attr" }}
        {{ if .Get "attrlink"}}</a> {{ end }}
        </p> {{ end }}
    </figcaption>
    {{ end }}
</figure>
<!-- image -->

The output:

<figure>
	<img src="http://localhost:1313/test.jpg" srcset="http://localhost:1313/test_hu41d132faf56d768d4c312e98f83b7cf9_449843_360x0_resize_q80_lanczos.jpg 360w, http://localhost:1313/test_hu41d132faf56d768d4c312e98f83b7cf9_449843_720x0_resize_q80_lanczos.jpg 720w, http://localhost:1313/test_hu41d132faf56d768d4c312e98f83b7cf9_449843_1920x0_resize_q80_lanczos.jpg 1920w" sizes="(max-width: 37.5em) 360px, (min-width: 75em) 720px, (min-width: 112.5em) 1200px" alt="Test" />   
</figure>

In more complex szenarios it does not work properly due to problems with file matching.

Let me know what you think. I really want to make this work and contribute a responsive figure template to Hugo.

Best regards
Tobias

1 Like

Here’s my version of Tobias’s shortcode with a little more detail:

/layouts/shortcodes/figure.html

{{ $srcset := "360|(max-width: 37.5em) 360px,720|(min-width: 75em) 720px,1920|(min-width: 112.5em) 1200px" }}
{{ $srcset := split $srcset "," }}
{{ $original := (.Page.Resources.ByType "image").GetMatch (printf "*%s" (.Get "src")) }}
<!-- image -->
{{ if $original }}
<figure{{ with .Get "class" }} class="{{.}}"{{ end }}>
	<!-- image without srcset -->
    {{ if .Get "link"}}<a href="{{ .Get "link" }}"{{ with .Get "target" }} target="{{ . }}"{{ end }}{{ with .Get "rel" }} rel="{{ . }}"{{ end }}>{{ end }}
        <img src="{{ $original.RelPermalink }}" srcset="{{range $i, $set := $srcset}}{{ $setparams := split $set "|" }}{{$sizecondition := index $setparams 0 }}{{ $image := $original.Resize (print $sizecondition "x") }}{{ if $i }}, {{ end }}{{ (print $image.RelPermalink " " $sizecondition "w") }}{{ end }}" sizes="{{range $i, $set := $srcset}}{{ $setparams := split $set "|" }}{{$mediacondition := index $setparams 1 }}{{ if $i }}, {{ end }}{{ $mediacondition }}{{ end }}" {{ if or (.Get "alt") (.Get "caption") }}alt="{{ with .Get "alt"}}{{.}}{{else}}{{ .Get "caption" }}{{ end }}" {{ end }}{{ with .Get "width" }}width="{{.}}" {{ end }}{{ with .Get "height" }}height="{{.}}" {{ end }}/>
    {{ if .Get "link"}}</a>{{ end }}
    {{ if or (or (.Get "title") (.Get "caption")) (.Get "attr")}}
    <figcaption>{{ if isset .Params "title" }}
        <h4>{{ .Get "title" }}</h4>{{ end }}
        {{ if or (.Get "caption") (.Get "attr")}}<p>
        {{ .Get "caption" }}
        {{ with .Get "attrlink"}}<a href="{{.}}"> {{ end }}
            {{ .Get "attr" }}
        {{ if .Get "attrlink"}}</a> {{ end }}
        </p> {{ end }}
    </figcaption>
    {{ end }}
</figure>
{{ else }}
    [{{ .Get "src"}} not found]
{{ end }}
<!-- image -->

/content/page/mypage/image.jpg (some image)

/content/page/mypage/index.md

{{< figure src="image.jpg" title="Some Image" >}}

Result:

2 Likes

This topic was automatically closed after 11 hours. New replies are no longer allowed.