I’m trying converting all images to webp format and resizing them to a maximum width of 600px. I would like to keep the original size if the image is already less than 600px wide. Markdown posts still use original images (bundle resources).
Can anyone share a code snippet with me so it can do it automatically, such as an img tag with a webp file and lazy load?
Here’s a variation of the image render template I’ve been using, with some adjustments.
If you’re not using the extended version of Hugo, then images will be resized but not converted to WEBP.
Although it is possible with Hugo, remote resources won’t be resized or converted by the following code. This can be resource heavy and time consuming if not used with caution.
GIF images won’t be converted as the library Hugo uses cannot yet handle animated GIFs. Remove the respective condition if that’s not an issue.
Local SVG images will be embedded within the HTML output, which is opinionated but in my use case permits coloring them with CSS. We’re assuming they contain safe HTML.
<!-- layouts/partials/render-image.html -->
<!-- get image URL from Markdown tag -->
{{- $src := (.Destination | safeURL) -}}
{{ $src = replace $src "./" "" }}
<!-- check .Store.Get "imgwidth" or use default width -->
{{- $imgwidth := .Page.Store.Get "imgwidth" | default 600 -}}
<!-- check if it exists as a page resource -->
{{- with (or ((.Page.Resources.ByType "image").Get $src) ((resources.ByType "image").Get $src)) -}}
<!-- if SVG then output its contents -->
{{- if strings.HasSuffix $src ".svg" -}}
{{ .Content | safeHTML }}
{{- else -}}
{{ $resized := . }}
<!-- resize if wider than "imgwidth" but if GIF file then avoid resizing animations; WebP animations not yet supported; see upstream ticket: https://github.com/golang/go/issues/53364 -->
{{ if and (gt .Width $imgwidth) (ne .MediaType.SubType "gif") }}
{{ if hugo.IsExtended }}
{{- $resized = .Resize (print $imgwidth "x webp") -}}
{{ else }}
{{- $resized = .Resize (print $imgwidth "x") -}}
{{ warnf "Missing Hugo Extended, in partial render-image.html" }}
{{ end }}
{{ end }}
<img src="{{ $resized.RelPermalink }}"
width="{{ $resized.Width }}"
height="{{ $resized.Height }}"
{{ with $.PlainText }} alt="{{ . }}" {{ end }}
{{ with $.Title }} title="{{ . | plainify | htmlEscape }}" {{ end }}
{{- range $k, $v := $.Attributes -}}
{{- if $v -}}
{{- printf " %s=%q" $k ($v | htmlEscape) | safeHTMLAttr -}}
{{- end -}}
{{- end -}}
loading="lazy" decoding="async" />
<!-- closing tag on img intented, for compatibility with XML output -->
{{- end -}}
{{- else -}}
<!-- or otherwise its an external resource so load the URL -->
<img src="{{ .Destination | safeURL }}"
{{ with $.PlainText }} alt="{{ . }}" {{ end }}
{{ with $.Title }} title="{{ . | plainify | htmlEscape }}" {{ end }}
{{- range $k, $v := .Attributes -}}
{{- if $v -}}
{{- printf " %s=%q" $k ($v | htmlEscape) | safeHTMLAttr -}}
{{- end -}}
{{- end -}}
loading="lazy" decoding="async" data-src="external" />
{{- end -}}
I hope that helps. Notes to improve any of the above, welcome!