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.

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:
| Width | Typical use | Condition |
|---|---|---|
| 480 | Small phones | Only if the master is at least 480 wide |
| 768 | Large phones and small tablets | Master at least 768 wide |
| 1280 | Laptops | Master at least 1280 wide |
| 1920 | Large desktops | Master 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
- AI music longer or shorter than the video: prompt, loop, trim or join
A generated track rarely matches the video length. Four ways on Sume: put the length in the prompt, loop the soundtrack, set an in-point, or join takes.
- AI video API: seed and size return 400 on Sume; what to send instead
No Sume video model accepts seed, and size returns 400 unsupported_parameter. Use resolution and aspect_ratio, and keep the prompt and frames to redo a take.
- Vendors swap GPUs; keep one video job shape
Luma said on Jul 23, 2026 it runs video-to-video inference on AMD and Tensorwave. Your client should not care: one Sume job shape covers every model.
- Profit per SKU across channels: add AI media cost from Sume
Amazon lists cross-channel profitability as upcoming. Add what your product images and clips cost per SKU by reading Sume's usage ledger by job id.
Written by Sume