Nine portraits in one AI image call: 3x3 grid prompt and slicer

Generate a 3x3 grid in one request and slice it into nine tiles. The pixel math at the 8.29 MP cap, what you give up in resolution, and when nine calls win.

6 min readSume
All posts

One call can give you nine portraits if you ask for a 3x3 grid and slice it, but each tile gets only a ninth of the pixels. On GPT Image 2.5 through Sume, the largest custom size is capped at 8,294,400 pixels, so a square grid at 2880 x 2880 slices into nine 960 x 960 tiles. That is plenty for thumbnails and contact sheets and thin for print.

Per-megapixel pricing is the reason this trick comes up this week: BFL's FLUX 3 Image price list (read 2026-10-03) charges by output size, with a 4K output at $0.607, so a batch idea that packs more subjects into one render looks tempting. Check the maths for your model before relying on it.

The pixel budget

Work backwards from the tile size you need. The grid must be a legal size for the model, and every tile is the grid divided by three on each edge. The table gives a few legal square and wide grids; for the largest legal size per ratio see the size validator.

computed, read 2026-10-03; GPT custom size rules from Sume's docs
Grid sizePixelsTile sizeFits 1080 wide?
2880 x 28808,294,400960 x 960No
2304 x 23045,308,416768 x 768No
1536 x 15362,359,296512 x 512No
3840 x 2160 (3x3 of 16:9)8,294,4001280 x 720Yes

Prompting for a clean grid

Spell out the structure: "a 3 by 3 grid of nine separate portraits, equal square cells, thin white gutters, same lighting in every cell, each cell a different person, no text." Equal cells with visible gutters make slicing reliable. Without gutters the model blends faces across cell edges.

Expect some cells to be weaker than others, and expect the grid not to line up exactly. The script below cuts on exact thirds and trims a small margin from every tile, so a few pixels of gutter never ends up inside a result.

from PIL import Image

def slice_grid(path, rows=3, cols=3, prefix="tile"):
    im = Image.open(path)
    tw, th = im.width // cols, im.height // rows
    out = []
    for r in range(rows):
        for c in range(cols):
            tile = im.crop((c * tw, r * th, (c + 1) * tw, (r + 1) * th))
            name = f"{prefix}_{r}{c}.png"
            tile.save(name)
            out.append((name, tile.size))
    return out

if __name__ == "__main__":
    Image.new("RGB", (2880, 2880), (90, 90, 90)).save("grid.png")
    for name, size in slice_grid("grid.png"):
        print(name, size)

What you give up

Three costs come with the grid. Resolution per tile falls to a ninth. Consistency between tiles is not guaranteed, so a cell may drift in lighting or style even when you ask for the same conditions. And you lose per-image control: one prompt applies to all nine, so you cannot give one portrait a reference photo or a mask.

What you gain is one request, one wait and one bill line. If your model prices by output size, as FLUX 3 Image does on BFL's price page, compare the grid's megapixel cost against nine separate smaller renders before you decide, since a 2K render costs far less per megapixel than a 4K one on that list.

A quality check on the slices

After slicing, review the nine tiles side by side before using any. Three things to look for: a face crossing a gutter, repeated faces between cells, and cells that were drawn at a different scale. If two or more tiles fail, rerun the grid rather than patching, because a grid with a weak seed rarely improves one cell at a time. Name the tiles by row and column so you can map each back to its place in the grid.

For storyboards, put a different scene in each cell and label them in the prompt by position, such as top left, top middle and so on. The model tends to follow position labels better than numbering.

When nine calls win

Use nine calls when you need full-resolution tiles, per-portrait seeds or references, or when a single bad cell should not cost you the other eight. Use one grid call for storyboards, thumbnails, casting sheets and style exploration, where nine small images beat one large one. Sume's sync wait is 30 seconds before a request becomes a 202 job, so a large grid may arrive as a job; poll as described in the jobs docs.

For the related frame-by-frame idea see sprite sheets sliced from a grid.

Sources

Related posts

More in Use cases

All Use cases posts

Written by Sume