Assert an edited image has the source's pixel size: Python check
A short Python check that downloads the source and the edited file and fails if the pixel size differs. Needed on Sume whenever you send an aspect_ratio.
Download both files and compare Image.size. If the edited file is not the same width and height as the source, stop the pipeline before it replaces a catalogue image. The check takes a dozen lines of Pillow and catches the case that matters most on Sume: you sent an aspect_ratio or resolution on an edit, and the model gave you a new shape.
When the size is expected to match
On Ideogram 4.5, an edit with no aspect_ratio and no image_size is sent with image_size: auto, so the shape of the source is kept (Image API docs). Ideogram's own reference says the output resolution matches the input exactly (read 2026-10-05). On GPT Image 2.5 you have to ask for the match with aspect_ratio: "auto", because leaving it out is not the same.
When you do send a shape, the size will differ by design. For example, aspect_ratio: "16:9" at 1K on an Ideogram 4.5 edit is 1536x864, and a resolution: "2K" with no ratio is ignored.
| Model | Request | Size equals source? |
|---|---|---|
| Ideogram 4.5 | no aspect_ratio, no size | yes |
| Ideogram 4.5 | resolution 2K only | yes, 2K is ignored |
| Ideogram 4.5 | aspect_ratio 16:9 | no, 1536x864 at 1K |
| GPT Image 2.5 | aspect_ratio auto | matches the reference |
| GPT Image 2.5 | aspect_ratio omitted | not guaranteed |
The check
Run it after every edit in a batch, with the source URL and the result URL. It exits with code 1 on a mismatch, so a CI step or a shell loop stops.
import io, sys, requests
from PIL import Image
def size_of(url):
r = requests.get(url, timeout=60)
r.raise_for_status()
return Image.open(io.BytesIO(r.content)).size
src_url, out_url = sys.argv[1], sys.argv[2]
src, out = size_of(src_url), size_of(out_url)
if src != out:
print(f"size changed: {src} -> {out}")
sys.exit(1)
print("ok", out)What a mismatch should do
Do not resize the edit back to the source size. Stretching changes the shape of the product, and a crop can cut it off. Log the mismatch with the request body and, if you did not mean to send a shape, remove the field and run again. If you did mean it, run the crop step on purpose.
What this check does not prove
Matching size says nothing about whether pixels outside the edit stayed the same. For that, diff the two files, as in the Pillow diff post. A resized and a different-content image can both be the right size.
Where to put the check
Put it right after the download, before any upload or CMS write. A pipeline that checks only at the end can overwrite a good file with a bad one and leave you looking for the original.
In a batch, collect the mismatches in a list and print them at the end instead of stopping at the first one. You will usually find that all of them share one cause, such as a shape field added by a wrapper.
Sources
Related posts
More in Media tools
- Audio detach range without end: take the rest of a track
In Sume audio detach, range.end is optional: a start-only range runs to the end of the track. How it meets the 900 s output cap and 1800 s source cap.
- audio_source_in_requires_single_spine: source_in needs one voice file
audio.source_in only works with one audio.url. With audio.parts, set source_in on each part instead; the Sume hint is use_part_source_in.
- Avatar clip frame rate: Griffin 25 fps vs Fabric vs H3 Max
Tavus says Griffin streams 8-frame latents at 25 fps. Sume's docs say Fabric is 25 fps and H3 Max must be measured. Probe a clip with video-inspect.
- Baby shower video music: a gentle 90-second slideshow bed
Pick a gentle instrumental for a 90-second baby shower photo slideshow: one generation and a two-minute render, $0.325 on Sume.
Written by Sume