Responsive srcset widths from one Sume master image with Pillow

Generate one high-resolution image, then resize it into several widths and print the srcset and sizes attributes. Python script for a Sume image result.

5 min readSume
All posts

To serve one AI image at several sizes, generate a single large master with Sume, resize it to a list of widths with Pillow, save each as WebP and print an srcset string that lists each file with its width descriptor. Generating each width separately costs one billed image per size, while resizing locally costs nothing after the first generation.

Pick the master from the resolution tiers the model lists (512, 1K, 2K, 4K where supported). Resize only downward, since upscaling a small master adds file weight and no detail.

Which widths are common?

The right set depends on your layout. A starting point for a full-width hero:

Example width set for a hero image, read 2026-10-04
WidthTypical useCondition
480Small phonesOnly if the master is at least 480 wide
768Large phones and small tabletsMaster at least 768 wide
1280LaptopsMaster at least 1280 wide
1920Large desktopsMaster at least 1920 wide

What is the script?

It skips any width larger than the master and prints a ready-to-paste img tag.

import sys
from PIL import Image

WIDTHS = [480, 768, 1280, 1920]

def build(path, stem, alt):
    img = Image.open(path).convert("RGB")
    w, h = img.size
    parts = []
    for tw in WIDTHS:
        if tw > w:
            continue
        out = f"{stem}-{tw}.webp"
        img.resize((tw, round(h * tw / w)), Image.LANCZOS).save(out, quality=82)
        parts.append(f"{out} {tw}w")
    return (
        f'<img src="{stem}-{WIDTHS[0]}.webp" alt="{alt}" '
        f'srcset="{", ".join(parts)}" '
        f'sizes="(min-width: 1024px) 1024px, 100vw" '
        f'width="{w}" height="{h}" loading="lazy">'
    )

if __name__ == "__main__":
    print(build(sys.argv[1], "hero", "Product on a table"))

Where do the width and height attributes come from?

Set them from the master so the browser reserves space and the page does not shift while the image loads. If you also publish the master for social cards, see the OG image tags post for the metadata side.

What about the Sume result URL?

Download the file you need and host it yourself. Do not hotlink the data[].url Sume returns in a production page, because it is a delivery URL for the result, not a promise of permanent hosting; the docs describe results as retrievable through the job, so store the master in your own bucket on arrival.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume