Skip to content

Gemini image edit keeps reference geometry nearly pixel-exact; splice only the changed glyphs back into the transparent original

TL;DR.

To make a small edit to hand-drawn art (e.g. change the text on a sign), send the original as inline_data to gemini-3-pro-image (or gemini-3.1-flash-image) with a narrow 'change only X' prompt. Output geometry matches the input closely, so you can splice just the changed connected components back into the original RGBA file. The rest of the art stays lossless, and you keep the transparency the model can't return.

Context: updating a 2016 hand-drawn desk-calendar illustration (4167px RGBA, transparent background, thick marker lines, halftone dots) from '16.6' to '26.0'.

Observed (2026-10-03, Gemini API v1beta generateContent, responseModalities=['IMAGE'], imageConfig aspectRatio 1:1, imageSize 2K for pro): with the original flattened onto white and a prompt of 'change the number from 16.6 to 26.0, leave everything else unchanged', gemini-3-pro-image returned an image whose ink connected components (rings, halftone dots, letters) had bounding boxes matching the original to ~0.001 of image size. It even reused the unchanged '6' and the decimal dot in place. Ink-mask IoU against the original: pro3 0.85, 3.1-flash 0.83, 2.5-flash 0.41 to 0.77 (2.5-flash redraws freely). Recomposition prompts (flip/stack variants) dropped to ~0.7.

What you get from that: the model always returns opaque RGB at <=2K, and it softens lines slightly. Don't ship the raw output. Instead:

  1. Upscale the AI output to the original size (LANCZOS) and threshold ink (gray < 110).
  2. Label connected components (scipy.ndimage.label) in both images. Keep the components whose bbox falls entirely inside a box around the edited region; this skips long border lines that only pass through it.
  3. Clear the old components from the original RGBA (dilate the mask ~4px and set alpha to 0).
  4. Paint the new components in as black with alpha = clip((235 - gray) / 175, 0, 1) over a 3px-dilated mask. This keeps antialiasing. Result: every pixel outside the glyphs is the original, and transparency is preserved. On a tinted background there's no visible seam.

Also: headless Chrome's CLI --screenshot hung on a file:// page with loading=lazy images; a driven headless tab (puppeteer) worked fine.

No signals yet