Rounded-corner tile from an AI image with an alpha mask in Pillow
Round the corners of a Sume image with a supersampled ImageDraw mask and putalpha. A radius-to-size table, a smooth edge, and a PNG you can drop on any page.

Draw a white rounded rectangle on a black mode L mask with ImageDraw.rounded_rectangle, at 4 times the size, shrink the mask with LANCZOS for smooth edges, and set it as the image's alpha with putalpha. Save as PNG. A radius of about 22 percent of the side gives the familiar phone-icon look.
Why supersample the mask
Pillow draws shapes without anti-aliasing. A mask drawn at the final size has jagged corners. Draw at 4 times the size and shrink, and the corner pixels get intermediate alpha values, which looks smooth.
A rounded tile needs a transparent corner, so the output has to be PNG or WebP. JPEG has no alpha and fills the corners with black.
The code
Start from a square result. Sume models list 1:1, so request it and you avoid cropping. If you start from another ratio, crop to a square with ImageOps.fit first.
import os, io, requests
from PIL import Image
H = {"Authorization": "Bearer " + os.environ["SUME_API_KEY"]}
def gen(**body):
r = requests.post("https://api.sume.com/v1/images", json=body, headers=H, timeout=60)
r.raise_for_status()
if r.status_code == 202:
raise SystemExit("queued, read /v1/jobs/{id}/result: " + r.text)
return r.json()
def fetch(u):
return Image.open(io.BytesIO(requests.get(u, timeout=60).content))
from PIL import ImageDraw, ImageOps
out = gen(model="google/nano-banana-2", aspect_ratio="1:1",
prompt="Minimal app tile illustration of a paper plane over a blue gradient")
size = 512
img = ImageOps.fit(fetch(out["data"][0]["url"]).convert("RGBA"), (size, size), Image.LANCZOS)
radius = round(size * 0.22)
big = Image.new("L", (size * 4, size * 4), 0)
ImageDraw.Draw(big).rounded_rectangle((0, 0, size * 4 - 1, size * 4 - 1), radius * 4, fill=255)
mask = big.resize((size, size), Image.LANCZOS)
img.putalpha(mask)
img.save("tile_rounded.png")
print(img.mode, img.size, "radius", radius, "cost", out["usage"]["cost"])Radius by tile size
Corner radius as a share of the side sets the style. Smaller shares look like cards, and larger shares look like icons or pills.
| Style | Share of side | Radius at 512 px | Radius at 1024 px |
|---|---|---|---|
| Card | 8 percent | 41 | 82 |
| App icon | 22 percent | 113 | 225 |
| Pill-like | 50 percent | 256 | 512 |
Gotchas
- A radius of 50 percent makes a circle for a square image. Use it for avatars.
- Do not blur or resize the PNG with JPEG tools afterward, since the corners will fill with black.
- If the page applies
border-radiusin CSS, you do not need the mask. Use it when the file itself must carry the shape, such as in an email or a store listing. - Supersampling 4 times on a 4096 pixel tile uses 16,384 pixels per side. Cap the final size first.
Where it fits
For icon sets, start from the app icon recipe, which covers the sizes a store asks for, then round the corners last. Derive the other widths from one master with the srcset recipe, and keep PNG all the way, see PNG between passes.
Sources
Related posts
More in Media tools
- Add a "save this" end card to a Short with caption cues
After the July 2026 Save button, burn a short on-screen ask into the last 3 seconds with video-captions cues: start, end, text. No speech needed.
- Seamless loop with Wan 3.0: the same image as first and last frame
Send one image as both start and end frame to ask Wan 3.0 for a loop on Sume, keep it 4 to 6 seconds, and check the join with stills before it repeats.
- Serum label close-up: three crop punch-ins from one clip for $0.06
Cut three label and dropper close-ups from one serum clip with video-filter crop fractions: $0.02 each, no re-shoot, no efficacy claims added to the frame.
- Shopify video limits: 120 fps and WebM allowed, so Sume MP4s fit
Shopify takes video up to 1 GB, 10 min, 120 fps and 4096 px per side. Sume's 24, 25, 30 or 60 fps MP4 at up to 2160 px sits inside all of those limits.
Written by Sume