Open Graph image 1200x630 with an AI API: generate 16:9, then crop
Meta recommends og:image at 1200 x 630 and a 1.91:1 ratio. Sume has no 1.91:1 option, so generate 16:9 and crop with 12 lines of Pillow. Steps and limits.

Generate at aspect_ratio: "16:9", then center-crop to 1200 x 630 in code. Meta's sharing guide says to 'use images that are at least 1200 x 630 pixels' and to 'keep your images as close to 1.91:1 aspect ratio as possible' so they show in Feed without cropping, with a file no larger than 8 MB (Meta for Developers, read 2026-10-01). Sume's normalized ratio list has 16:9 (1.78) and 2:1 (2.0) but no 1.91:1, so the final trim is a local step.
16:9 is 1.78 and 1200 x 630 is 1.905, so you lose a thin band at the top and bottom. Tell the prompt to keep the subject and any headline in the middle 80 percent of the frame.
What are the numbers?
Read from each source on the dates shown.
| Item | Value | Source |
|---|---|---|
| Minimum dimension | 200 x 200 px | Meta |
| Recommended | 1200 x 630 px or larger | Meta |
| Smallest acceptable | 600 x 315 px | Meta |
| Target ratio | 1.91:1 | Meta |
| Max file size | 8 MB | Meta |
| Sume ratios nearest 1.91:1 | 16:9 (also 2:1) | Image API |
How do I crop?
Download the result, resize to width 1200, then crop the height to 630 around the center.
import io
import os
import requests
from PIL import Image
H = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
r = requests.post("https://api.sume.com/v1/images", headers=H, timeout=60,
json={"model": "openai/gpt-image-2.5", "aspect_ratio": "16:9",
"prompt": "clean blog header, laptop on a desk, empty centre space"})
r.raise_for_status()
raw = requests.get(r.json()["data"][0]["url"], timeout=60).content
img = Image.open(io.BytesIO(raw)).convert("RGB")
img = img.resize((1200, round(img.height * 1200 / img.width)))
top = (img.height - 630) // 2
img.crop((0, top, 1200, top + 630)).save("og.jpg", quality=90)
print("og.jpg", os.path.getsize("og.jpg"), "bytes")Prompt for a safe crop zone
Because the crop removes about 6 percent of the height, ask for 'subject centered, generous empty margin at top and bottom'. If you add text later, draw it yourself with Pillow on the cropped image, so spelling and position are exact.
Test the result in a link preview tool or by sharing the URL to yourself before announcing a page. Platforms cache preview images, so a wrong first image can stick for a while.
Limits
If the 16:9 result is under 1200 pixels wide, the resize upscales it; pick a higher resolution where the model lists one. Do not ask the model to draw the site name in small type, because crops cut it and text can be misspelled. JPEG at quality 90 keeps most files well under 8 MB, but check the printed byte count.
Sources
Related posts
More in Developers
- OpenAI Agents 0.23 MCP listing page limits and Sume tools_list
Agents SDK 0.23.0 adds configurable MCP listing page limits. For a Sume server: call tools_list once, then tools_schema for the one tool you need.
- OpenAI Agents 0.23 nested agent tools: one Sume key per item
Agents SDK 0.23.0 fixed tool state isolation for nested agents. For paid Sume calls, the idempotency key must still come from your item, not from the agent run.
- OpenAI's DALL-E replacement list names models that retire Dec 1
OpenAI's deprecations page maps dall-e-2 and dall-e-3 to gpt-image models, but gpt-image-1-mini retires Dec 1, 2026. Which ids to pick instead on Sume.
- OpenAI structured outputs: 5000 properties, 10 levels, vs Sume
OpenAI caps strict schemas at 5000 properties and 10 nesting levels. Sume's output_schema uses the same numbers but counts enums and strings differently.
Written by Sume