Put the headline on in code: a text-free AI image plus Pillow
When the copy must be exact, ask the model for a text-free image with space for it, then draw the headline in Pillow. The text is then yours, not the model's.

When the words must be exact, do not ask the model to draw them. Request a text-free image with an empty area, then draw the headline in code with your own font. The copy is then exactly what you typed, and a typo fix is a one-line change.
Models are getting better at text: Higgsfield lists FLUX 3 Image with more accurate text (Higgsfield changelog, read 2026-10-02). Even so, a regulated price, a legal line, or a brand name is safer when you set it yourself.
What do I ask the image model for?
Describe the scene and the empty space, and say no text. Use aspect_ratio from the model's catalog list, for example 4:5 for Instagram portrait on models that list it.
| Element | Made by | Why |
|---|---|---|
| Scene, product, light | Image model via POST /v1/images | What models are good at |
| Headline, price, legal line | Your code | Exact characters |
| Logo | Your file | Exact brand |
| Final export | Pillow | Fixed size and format |
How do I draw the text?
Open the downloaded image, load a font file you licence, and draw with a stroke or a scrim so the text reads on any background. Set FONT to a path on your machine.
import os
from PIL import Image, ImageDraw, ImageFont
FONT = os.environ.get("FONT", "DejaVuSans-Bold.ttf")
image = Image.open("scene.png").convert("RGBA")
width, height = image.size
scrim = Image.new("RGBA", image.size, (0, 0, 0, 0))
ImageDraw.Draw(scrim).rectangle(
[0, int(height * 0.72), width, height], fill=(0, 0, 0, 120)
)
image = Image.alpha_composite(image, scrim)
draw = ImageDraw.Draw(image)
font = ImageFont.truetype(FONT, size=width // 12)
draw.text((width // 10, int(height * 0.8)), "Free shipping over 50",
font=font, fill="white")
image.convert("RGB").save("ad.jpg", quality=92)When is model-drawn text still the right call?
When the text is part of the art, such as a hand-lettered poster, the model has to draw it, and then you review every output. For everything else, code wins on exactness. For many markets, loop the same script with a dictionary of strings instead of one edit call per market; see the price-change edit loop for the edit-based route. Request fields for the image call are in the Image API docs.
Sources
Related posts
More in Use cases
- Help-center article from a product video: one still per step
Combine video inspect sentence segments with video frames at[] to get a screenshot at each step start. 24 stills max per call, 300-second clip cap.
- Higgsfield's Seedance outage on Sept 30: slow vs failed jobs on Sume
Higgsfield said Seedance 2.0 failed more and 2.5 ran slow on Sept 30, now fixed. On Sume, a slow job is queued or processing; rerun only after failed.
- Higgsfield's six launches in three days: what to re-test
Higgsfield's changelog lists six items from 2026-09-29 to 10-01. A re-test list for an ad team, with the Sume route to check for each one.
- Check 200 holiday clips before upload with a free probe-only inspect
A video-inspect call with frames false is a probe with no stills and no charge. Use it as a pre-upload audio gate, then pull stills only for clips you doubt.
Written by Sume