Hugo: process a Sume image with Fill and a WebP output spec

Hugo reads PNG, JPEG and WebP and can write WebP itself. Save a Sume PNG into the page bundle, then use Fill to cut a 1200x630 card and output WebP.

5 min readSume
All posts

Ask Sume for a PNG, save it in the page bundle, and let Hugo make the sizes and the WebP. Hugo's image processing page lists AVIF, BMP, GIF, JPEG, PNG, TIFF and WebP as processable, and names three resize methods: Resize, Fit and Fill, with Fill returning an image that is cropped and resized. A spec such as "300x webp" sets the size and the output format in one string.

So there is no reason to request WebP from the Sume image API in the first place. Keep the lossless PNG as the source, and let the site build produce the smaller files. The one exception is Recraft V4, whose catalog row lists only webp; Hugo reads that as a source too.

Should I fetch the image at build time?

The page shows resources.GetRemote for a remote URL, for example the Hugo logo. For a generated image, I would not use it. A Sume URL is a result of a paid job, and a site build that depends on a remote file can fail, or change, long after the job. Download the file once, commit it next to the content, and let Hugo process the local copy.

A request that works for a social card is a 16:9 image, which Fill can crop to 1200x630 with little loss:

curl -s https://api.sume.com/v1/images \
  -H "Authorization: Bearer $SUME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"openai/gpt-image-2.5","prompt":"calm abstract hero image, soft gradients, no text","aspect_ratio":"16:9","quality":"medium","output_format":"png"}' \
  | jq -r '.data[0].url' | xargs curl -s -o content/posts/launch/hero.png

The template

This follows the pattern on Hugo's page, where .Resources.Get returns an image in a page bundle and a processing method returns a new resource with .RelPermalink, .Width and .Height.

{{ with .Resources.Get "hero.png" }}
  {{ with .Fill "1200x630 webp" }}
    <img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}" alt="">
  {{ end }}
{{ end }}

What can break?

If the first call returns 202 instead of 200, jq finds no data and nothing is downloaded. Slow settings such as 4K or high quality are the ones most likely to miss the 30-second wait; the jobs guide shows how to poll status_url. The usage.cost field on a 200 is the billed USD amount, which is worth noting in the post's front matter so a later edit does not trigger an unplanned regeneration.

Write real alt text for content images. The empty alt above is right for a purely decorative card and wrong for an image that carries meaning.

Sources

Related posts

More in Use cases

All Use cases posts

Written by Sume