HUGO

Has anyone a webp shortcode?

Has anyone a webp shortcode? One that serves webp if the browser supports it, and jpg if not. I have both variants in assets.

The 10 or so I tried so far all not working. I am using 0.88.1ext

layouts/shortcodes/picture.html
{{- $path := .Get "path" -}}
{{- $alt := .Get "alt" -}}
{{- $width := .Get "width" -}}
{{- $height := .Get "height " -}}

{{- $msg1 := "The %q shortcode requires a parameter named %q. See %s" -}}
{{- $msg2 := "The resource %q passed to the %q shortcode is not an image. See %s" -}}
{{- $msg3 := "The resource %q passed to the %q shortcode could not be found. See %s" -}}

{{ if not $path }}
  {{ errorf $msg1 .Name "path" .Position }}
{{ end }}

{{- with $i := resources.Get $path -}}
  {{- if eq $i.MediaType.MainType "image" -}}
    {{- if not $width -}}
      {{- $width = $i.Width -}}
    {{- end -}}
    {{- if not $height -}}
      {{- $height = $i.Height -}}
    {{- end -}}

    {{- $j := "" -}}
    {{- $w := "" -}}

    {{- if eq $i.MediaType "image/webp" -}}
      {{- $fitOptions := printf "%vx%v jpg" $width $height -}}
      {{- $j = $i.Fit $fitOptions -}}
      {{- $w = $i -}}
    {{- else if eq $i.MediaType "image/jpeg" -}}
      {{- $fitOptions := printf "%vx%v webp" $width $height -}}
      {{- $w = $i.Fit $fitOptions -}}
      {{- $j = $i -}}
    {{- else -}}
      {{- $fitOptions := printf "%vx%v jpg" $width $height -}}
      {{- $j = $i.Fit $fitOptions -}}
      {{- $fitOptions = printf "%vx%v webp" $width $height -}}
      {{- $w = $i.Fit $fitOptions -}}
    {{- end -}}

    <picture>
      <source srcset="{{ $w.RelPermalink }}" type="image/webp">
      <source srcset="{{ $j.RelPermalink }}" type="image/jpeg">
      <img src="{{ $j.RelPermalink }}" alt="{{ $alt }}" width="{{ $j.Width }}" height="{{ $j.Height }}">
    </picture>
  {{- else -}}
    {{- errorf $msg2 $path $.Name $.Position -}}
  {{- end -}}
{{- else -}}
  {{- errorf $msg3 $path .Name .Position -}}
{{- end -}}
{{- /* chomp */ -}}

Place one format (JPEG, PNG, WEBP, or GIF) of an image in the assets/ directory, then call the shortcode like this:

{{< picture path="a.png" >}}
{{< picture path="a.png" alt="My image" width="300" height="150" >}}
  • The alt, width, and height parameters are optional.
  • The image size will be adjusted to fit (aspect ratio is maintained) the provided dimensions.
  • If you provide neither width nor height, the image size will not change.
  • If you provide either width or height, the missing value will be determined by the original image.

This is rendered something like:

<picture>
  <source srcset="/a_hu1c281d6ad96666827d571a3c8f40b864_327575_533x400_fit_q75_h2_box_3.webp" type="image/webp">
  <source srcset="/a_hu1c281d6ad96666827d571a3c8f40b864_327575_533x400_fit_q75_bgffffff_box_3.jpg" type="image/jpeg">
  <img src="/a_hu1c281d6ad96666827d571a3c8f40b864_327575_533x400_fit_q75_bgffffff_box_3.jpg" alt="" width="533" height="400">
</picture>
<picture>
  <source srcset="/a_hu1c281d6ad96666827d571a3c8f40b864_327575_300x400_fit_q75_h2_box_3.webp" type="image/webp">
  <source srcset="/a_hu1c281d6ad96666827d571a3c8f40b864_327575_300x400_fit_q75_bgffffff_box_3.jpg" type="image/jpeg">
  <img src="/a_hu1c281d6ad96666827d571a3c8f40b864_327575_300x400_fit_q75_bgffffff_box_3.jpg" alt="My image" width="300" height="225">
</picture>

Note that the width and height in the rendered <img> element may not match the width and height parameters in the shortcode call. That’s expected: the .Fit method maintains aspect ratio.

4 Likes

I’ve recently published the module lazyimg for that, with support for lazy-loading and responsive images (related post here).

From a shortcode, you can call it like:

{{< lazyimg img="images/alps.jpg" renderer="webp" >}}

<!-- More extensively, with support for a blur-up LQIP -->
{{< lazyimg img="images/alps.jpg" renderer="lqip-webp" resizer="responsive" maxSize="640x" alt="mountains" >}}

Due to its flexible architecture, you can independently exchange resizers and renderers.
README and example site give more insights on all available configuration options/defaults which can be easily overriden.

The module is currently being battle-tested in my theme, and I plan to release its first stable version, soon. Feedback appreciated!

1 Like

Thanks, it works nearly perfectly. Only the images in assets didn’t work for me. But just leaving them in static and it worked right out of the box.

Looks very ambitious, but didn’t work for me. Can’t start the server and get a long strings of errors. The solution I was looking for was like one partial and a one-liner in the md.

That doesn’t sound right to me, unless you have changed how static/ is mounted in your site configuration.

I am not aware that I changed anything, certainly not intentionally :wink: I just tried a quick “build” and it worked too, although I get sort of fingerprinted image file names in the root /public/.

For my understanding, putting width and height is pointless since the aspect ratio is kept anyway, right? So using either one would be fine. Yes?

I really like your solution!

Well, something is different. Because unless you have somehow mapped static/ to assets/, this shortcode will fail.

If you don’t want the images in the root of public/, place them in assets/images/, then call with:

{{< picture path="images/a.png" >}}
{{< picture path="images/a.png" alt="My image" width="300" height="150" >}}

No, it is not. When you fit an image, you are telling Hugo to shrink or enlarge the image to fit within a bounding box (width x height) while maintaining its aspect ratio.

Let’s say your original image is 200x400 (portrait). Then you do this:

{{< picture path="a.png" width="600" >}}

Because you did not explicitly set the height, the height of the original image will be used to define the bounding box. You are telling Hugo to scale your 200x400 image to fit into a 600x400 bounding box while maintaining its aspect ratio. The result? No change. Your image will be 200x400.

{{< picture path="a.png" height="800" >}}

Because you did not explicitly set the width, the width of the original image will be used to define the bounding box. You are telling Hugo to scale your 200x400 image to fit into a 200x800 bounding box while maintaining its aspect ratio. The result? No change. Your image will be 200x400.

With the shortcode’s current logic, you cannot not enlarge an image unless you provide both width and height.

{{< picture path="a.png" width="100" >}}

Because you did not explicitly set the height, the height of the original image will be used to define the bounding box. You are telling Hugo to scale your 200x400 image to fit into a 100x400 bounding box while maintaining its aspect ratio. The result? Your image will be 100x200.

Finally, if you would prefer, modify the logic to use .Resize when only one dimension is provided and .Fill when both dimensions are provided.

I am unclear what happened earlier. Now I put them assets/images/ and they do land in public/images/ as they should.

Thanks for the code and support.

(IMHO this site should have a ‘snipped’ page, a bit like the wordpress plugin page, would make searching/finding/sharing code samples much easier. A bit like the “Themes” page, but with added comments)

I wonder about this error:

<img src="view-source:http://localhost:1313/images/to-mexico_hu4884240ad1f341604cb24c8fd834bb0f_7761_300x98_fit_q75_h2_box.webp" alt="The image “view-source:http://localhost:1313/images/to-mexico_hu4884240ad1f341604cb24c8fd834bb0f_7761_300x98_fit_q75_h2_box.webp” cannot be displayed because it contains errors.">

Most images work, but sometimes it does not.

Please share a link to the public repository for your project. I need to reproduce the problem locally. Thanks.

Looks like just the *.webp is effected. When I look at the fingerprinted image it looks fine, means I can view it with Chrome and FF.
I just put it on a live server for a moment and all images show fine.
Let me do more testing.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.