Nano Banana exact pixels: target_pixels, then resize yourself
Nano Banana renders at a native ratio, not your pixels. Sume maps 1080x1350 to 4:5 and records target_pixels on the job; finish with a resize or crop.
Can Nano Banana output an exact pixel size such as 1080x1350 through Sume? Not directly. Nano Banana renders at a native aspect ratio plus a resolution tier, so Sume maps your pixel string to the closest native ratio (4:5 for 1080x1350), generates at that ratio, and stores the size you asked for as target_pixels in the job's request metadata. The final resize is a documented post-step that the caller does.
The Image API docs say this for Nano Banana Pro: it sends aspect_ratio: "4:5" (native roughly 928x1152 at 1K), and exact 1080x1350 is a post-step via the job's target_pixels (Sume Image API docs). The same mapping applies to Nano Banana 2 on origin/main, which this post checked by running the request normalizer.
What the request becomes
Send the pixels in image_size (or in aspect_ratio) as a WIDTHxHEIGHT string, or as a {width, height} object. For Nano Banana 2, a 1080x1350 request is normalised to aspect_ratio: "4:5", and the metadata keeps target_pixels: {width: 1080, height: 1350}. Nothing is resized on Sume's side, which is why the output dimensions are the provider's, not yours.
Do not put the pixels in size: that field is a tier shorthand, and a value like 1024x1024 is rejected with 400 unsupported_parameter. The error text tells you to use a tier (512, 1K, 2K, 4K, 720p, 1080p) or to set image_size or aspect_ratio instead.
| Requested size | Native ratio sent | target_pixels recorded |
|---|---|---|
| 1080x1350 | 4:5 | 1080 x 1350 |
| 1080x1920 | 9:16 | 1080 x 1920 |
| 1200x628 | 16:9 | 1200 x 628 |
| 1500x500 | 21:9 | 1500 x 500 |
Finish the size in your pipeline
When the native ratio equals your target ratio (4:5 to 1080x1350, 9:16 to 1080x1920), a straight resize is enough. When it does not (1200x628 is about 1.91 and the native choice is 16:9, which is 1.78), resize to cover and centre-crop. The code below handles both cases with one function and needs Pillow (pip install pillow).
Choose the tier so the source is at least as large as the target on both edges. At 1K the native 4:5 frame is about 928x1152, so 1080x1350 would be an upscale; request resolution: "2K" when you need a downscale instead.
from PIL import Image, ImageOps
def fit_exact(path: str, width: int, height: int, out: str) -> tuple[int, int]:
"""Resize to cover the target box, then centre-crop to exactly width x height."""
img = Image.open(path).convert("RGB")
fitted = ImageOps.fit(img, (width, height), method=Image.LANCZOS, centering=(0.5, 0.5))
fitted.save(out, "PNG")
return fitted.size
if __name__ == "__main__":
# demo with a synthetic 928x1152 frame, the native 4:5 size at 1K
Image.new("RGB", (928, 1152), "#3a6ea5").save("native.png")
print(fit_exact("native.png", 1080, 1350, "final.png"))Where the pixels live
target_pixels is part of the job request metadata, so it is there when you read the job back through the standard job endpoints (Jobs and results). You can also keep the target in your own code, which is simpler: you already know what size you asked for.
For a story-sized example with a full walkthrough see 9:16 story image from Sume, then resize.
Related posts
More in Developers
- Next.js ImageResponse RCE fix: safe share card from a Sume job
Next.js 16.3.6 patched a critical ImageResponse RCE. After upgrading, build a share-card route that reads the Sume artifact server-side, not from the URL.
- Next.js 16.3.8 dev-server MCP disclosure and where the Sume key lives
Next.js 16.3.8 fixes a low-severity dev-server MCP disclosure and a high-severity image SSRF. How to keep a Sume API key server-side as you upgrade.
- Next.js 16.3.8 fixes ISR cache poisoning: keep job pages dynamic
Next.js v16.3.8 fixes cache poisoning in SSG and ISR and Draft Mode leaks. Why a Sume job status page should stay dynamic and uncached, whatever the version.
- Next.js 16.3.8 route handler: a GET-only Sume job status proxy
A Next.js route handler that proxies only GET /v1/jobs/{id}/status to Sume, validates the id and keeps the key server-side. Written for 16.3.8.
Written by Sume