Nearest supported aspect ratio per Sume image model, in Python

A model rejects an aspect ratio it does not list. Read the catalog, pick the closest ratio it accepts, generate, then crop to the exact shape you need.

5 min readSume
All posts

When the ratio you want is not on a model's list, ask for the nearest ratio the model does accept and crop to the exact shape afterwards. On Sume you can do the first half in code: read supported_parameters.aspect_ratio.values for the model from GET /v1/images/models, compare each value to your target, and send the closest one.

The Sume Image API docs list a normalized set of ratios (including 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3, 4:5, 5:4, 2:1, 1:2, 21:9 and 9:21), and say a model accepts only the values its catalog row lists. They also say 4:5 is Instagram portrait at 1080 by 1350 and not 4:3, which is a common mix-up. Different models list different subsets, so a fixed table in your code goes stale; the catalog is the source.

How close is close enough

Compare ratios as numbers, width divided by height, and measure the distance on a log scale so that 2:1 against 3:1 and 1:2 against 1:3 count the same. The table shows how far a few common targets are from nearby catalog values.

Distance between common ratios, read 2026-10-06
TargetCandidateWidth over heightCrop needed
4:5 (0.80)3:4 (0.75)0.75Trim about 6 percent of the height from a 3:4 image
4:5 (0.80)1:1 (1.00)1.00Trim 20 percent of the width from a square
1.91:1 link card16:9 (1.78)1.78Trim about 7 percent of the height
3.8:1 sticker2:1 (2.00)2.00Does not fit; pad instead of crop

The picker

The function converts every catalog value to a number and keeps the one with the smallest log distance. It skips the word auto and any value that is not a ratio.

import math
import os
import requests

H = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
rows = requests.get("https://api.sume.com/v1/images/models", headers=H, timeout=30).json()["data"]
RATIOS = {
    r["id"]: r["supported_parameters"].get("aspect_ratio", {}).get("values", [])
    for r in rows
}

def value(text):
    a, b = text.split(":")
    return int(a) / int(b)

def nearest(model, target):
    options = [v for v in RATIOS.get(model, []) if ":" in v]
    if not options:
        return None
    want = value(target)
    return min(options, key=lambda v: abs(math.log(value(v) / want)))

for model in ("openai/gpt-image-2.5", "ideogram/ideogram-v4.5"):
    print(model, nearest(model, "4:5"))

Crop after you generate

Cropping is a few lines in Pillow: compute the target ratio, then cut equal amounts from the long side. Center the crop unless you know where the subject is. Ask for generous margins in the prompt, such as keep the subject centered with space around it, so the crop does not clip a face or a label.

If a model offers a custom image_size instead, the GPT rules in the docs apply: multiples of 16, maximum edge 3840, ratio at most 3:1. That route gives an exact shape when the numbers fit, with no crop at all.

Rules for the fallback

The nearest ratio is a compromise, so decide in advance what you will do with the gap.

  • Prefer the candidate that needs the smaller crop, so you trim a little and never stretch.
  • Never stretch an image to fit; resize with a fixed ratio and crop the overflow.
  • Keep the subject away from the edges in the prompt so a crop is safe.
  • Log every fallback so you can see which models force a crop.
  • Re-run the choice when the catalog changes.

Putting it in a pipeline

A good place for the picker is the one function that builds your request. The caller passes a target ratio and a model, and gets back the request body plus the crop it will need later. Return the crop as data, such as the target ratio and the ratio actually generated, so the post-processing step does not recompute anything. If you ship to many platforms from one image, generate once at a generous ratio such as 3:2 and crop to each platform's shape instead of paying for a generation per shape. That keeps the look consistent across platforms and the bill low.

A caution on exact pixels

A ratio is not a pixel size. Instagram's 4:5 means 1080 by 1350 in the docs, but some models return a native size close to that and the exact pixel size is a post-step. If a platform checks exact pixels, resize and crop in your own pipeline and verify the final file before upload.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume