Imagen 4 Fast has no 4:5: generate 3:4 and crop to 1080x1350 in Pillow
Imagen 4 Fast and Grok skip 4:5 on Sume. Request 3:4, then crop to 1080x1350 with ImageOps.fit and a top-biased centering so heads and product tops survive.

Request aspect_ratio: "3:4" from Imagen 4 Fast, then crop the result to 1080x1350 with ImageOps.fit and centering=(0.5, 0.0). 3:4 is 0.75 wide-to-tall and 4:5 is 0.8, so the crop removes about 6 percent of the height, and the top bias takes that sliver from the bottom edge where it usually costs the least.
Why this comes up
Sume's image catalog lists the native aspect ratios of each model rather than a collapsed subset. The Imagen entries are 1:1, 16:9, 9:16, 4:3, and 3:4. There is no 4:5, so request one of the listed ratios. Nano Banana 2 and Seedream do list 4:5, so for those you can ask for the ratio directly.
Imagen 4 Fast is one of the cheaper models: $0.02 list, so $0.025 billed per image. If the cost matters and the ratio does not exist, a small crop is the practical answer.
The crop
ImageOps.fit(image, size, method, bleed, centering) resizes and crops to the exact size. centering is a pair of fractions: (0.5, 0.5) crops evenly, and (0.5, 0.0) keeps the top edge and removes everything from the bottom. Use Image.LANCZOS for the downscale.
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 ImageOps
out = gen(model="google/imagen-4-fast", aspect_ratio="3:4",
prompt="Portrait of a barista holding a latte, cafe window behind, warm light")
img = fetch(out["data"][0]["url"]).convert("RGB")
feed = ImageOps.fit(img, (1080, 1350), Image.LANCZOS, centering=(0.5, 0.0))
feed.save("feed_4x5.jpg", quality=92)
print(img.size, "->", feed.size, "cost", out["usage"]["cost"])What gets cut
The numbers below follow from the ratios. A 3:4 source of 768 by 1024 pixels cropped to 4:5 keeps the full width and trims the height.
| Source | Target ratio | Kept width | Kept height | Removed |
|---|---|---|---|---|
| 768x1024 (3:4) | 4:5 (0.8) | 768 | 960 | 64 px of height, 6.25 percent |
| 1536x2048 (3:4) | 4:5 (0.8) | 1536 | 1920 | 128 px of height, 6.25 percent |
When to prefer another route
- If the subject's feet or a caption sit at the bottom edge, use
centering=(0.5, 0.5)or generate a looser prompt with air at the bottom. - If you need the exact ratio with no crop, pick a model that lists
4:5and read the catalog withGET /v1/images/models. - A 6 percent crop is invisible on a portrait. A 1:1 to 4:5 crop removes 20 percent of the width and is not.
Related steps
The same crop-after-generation idea powers the 4:5 feed image recipe and the 9:16 story resize. To pick a model by its listed ratios in code, use the capability filter. Prompt for headroom above the subject, since the top-biased crop protects the top and spends the bottom.
Sources
Related posts
More in Developers
- Instagram 4:5 feed video from a 3:4 Sume render: the crop fractions
Sume models list 3:4 but not 4:5. Render 3:4, then crop 3.125% off the top and bottom with video-filter. Check the program free before the $0.02 encode.
- Timeline invalid_fit 400: fit must be cover, contain, stretch or blur
invalid_fit means video[].fit is not cover, contain, stretch or blur. Cover is the default, so omit the field if you want it. details.allowed lists values.
- Timeline invalid_fps 400: output.fps must be 24, 25, 30 or 60
invalid_fps rejects any output.fps outside 24, 25, 30 and 60. Omit the field to match the source frame rate; details.allowed lists the accepted values.
- Timeline invalid_transition_type: why xfade is rejected (use fade)
transition.type accepts fade, wipeleft, wiperight, slideup, slidedown and dissolve. xfade is the internal ffmpeg name, so it returns invalid_transition_type.
Written by Sume