Saltar al contenido principal

GPT Image 2.6 markup por API: cómo editar con marcas paso a paso

Markup es un PNG transparente del tamaño exacto de la foto que va en /v1/images/edits. Un 200 no prueba que se haya leído: dos rutas por llamada lo ignoraron.

LaoZhang AI TeamPublicado13 min de lectura
En esta página
Esquema de una edición con markup en GPT Image 2.6: la foto, una capa transparente con un círculo rojo y el prompt van a /v1/images/edits

Para editar con marcas en GPT Image 2.6 por API envías dos archivos a POST /v1/images/edits: la foto original como primera imagen y, en el campo markup, un PNG transparente del mismo ancho y alto en el que solo has dibujado el círculo, la flecha o el trazo. Esa capa de anotación indica dónde; qué cambiar lo sigue diciendo el prompt («cambia a amarillo la silla dentro del círculo rojo y borra el círculo»). Funciona con gpt-image-2.6-flare y gpt-image-2.6-sunburst, que OpenAI lanzó el 4 de noviembre de 2026, y no se combina con mask ni con prompt_rewriter.

Antes de pagar una llamada, comprueba la capa en local: mismo tamaño que la foto después de aplicar la orientación EXIF, píxeles realmente transparentes, como mucho 16.777.216 píxeles y 50 MB. Más abajo tienes un script de Python que la dibuja y la valida.

La ruta por la que llamas cambia el resultado. Con la API de OpenAI, su propia guía muestra la edición funcionando. A través de un intermediario, una respuesta 200 no demuestra nada: el 5 de noviembre de 2026, dos rutas de pago por llamada aceptaron la capa y editaron otra silla, con capa y sin ella. Envía markup solo por una ruta que reenvíe la petición intacta a OpenAI y pruébala primero con una foto en la que el texto por sí solo no baste para encontrar el objetivo.

Qué hace markup: la capa dice dónde y el prompt dice qué

markup es una capa de anotación transparente que el modelo superpone a la primera imagen de entrada para saber en qué zona actuar. Según la guía de generación de imágenes de OpenAI, apartado «Guide an edit with markup», se usa con el endpoint POST /v1/images/edits de la Image API y con los modelos GPT Image 2.5 y 2.6; si trabajas con la Responses API, las ediciones por zonas van con máscara. La capa no lleva instrucciones: el texto del cambio y lo que debe conservarse siguen yendo en prompt.

Tres reglas de la misma guía condicionan cómo montas la petición. La capa solo se aplica a la primera imagen; si mandas más imágenes, el resto sirven de referencia. markup no se puede combinar con mask ni con prompt_rewriter, así que si tu código ya envía alguno de los dos, quítalo en esta llamada. Y en ediciones con GPT Image 2.6, la guía de prompts de imágenes de OpenAI pide omitir input_fidelity y recuerda que 2.6 no admite reasoning.summary.

El parámetro que más influye en una edición puntual es complexity. El anuncio de Images 2.6 recomienda low para la mayoría de las ediciones, por velocidad, y medium o high en escenas con muchos elementos o restricciones; la guía de prompts añade que, si cambias un solo detalle, empieces por low y compruebes que el entorno sigue intacto. OpenAI también dice que Sunburst mantiene mejor la coherencia entre ediciones con quality en medium o high.

Marcas, máscara o solo texto: cuál necesita tu edición

Si el prompt puede nombrar el objetivo sin ambigüedad («el jarrón de rayas», «el cartel de la entrada»), no necesitas capa: el texto basta y te ahorras un archivo. La capa de anotación tiene sentido cuando hay varios objetos parecidos o el objetivo no tiene un nombre claro, como una de cuatro sillas blancas idénticas. La máscara es otra herramienta, con otras reglas, y es la vía de OpenAI para editar zonas desde la Responses API.

Solo textoCapa de anotación (markup)Máscara (mask)
Cómo señalas la zonaDescribiéndola en promptDibujando círculos, flechas o trazos en un PNG transparenteCon un PNG cuyo canal alfa delimita la zona editable
Dónde se usaCualquier ediciónPOST /v1/images/edits (Image API)Image API y Responses API
PrecisiónDepende de que el objetivo sea únicoIndica la ubicación; el alcance del cambio lo decide el promptEs una guía: el modelo «puede no seguir la forma exacta»
Requisitos del archivoNingunoMismo ancho y alto que la primera imagen, píxeles transparentes, ≤50 MBCanal alfa, mismo formato y tamaño que la imagen, menos de 50 MB
Se combina conAmbasNi mask ni prompt_rewriterNo con markup
Úsalo cuandoEl objeto se nombra en una fraseHay objetos repetidos o difíciles de describirLlamas desde la Responses API o ya generas máscaras en tu flujo

La regla práctica sale de las pruebas descritas más abajo. Un jarrón de rayas único en una cocina se encontró solo con texto en todas las ediciones; en cambio, con cuatro sillas blancas idénticas, las cuatro ediciones hechas en rutas que no leían la capa colorearon una silla equivocada. Si dudas, quita la capa y prueba: si el resultado acierta igual, el texto ya era suficiente.

Requisitos del archivo de la capa de anotación

La capa debe ser un PNG aparte, transparente, con exactamente el mismo ancho y alto que la primera imagen una vez aplicada su orientación, y con al menos una parte transparente; OpenAI insiste en no aplanarla sobre la foto. Los límites son 16.777.216 píxeles para la foto y para la capa, cada una, y 50 MB para el archivo de la capa. Así se rompe cada regla en la práctica y así la detecta el script del apartado siguiente:

Regla (guía y referencia de OpenAI)Cómo suele romperseQué comprueba el script
Mismo ancho y alto que la primera imagen tras la orientaciónFoto de móvil guardada en horizontal con etiqueta EXIF de giro; capa exportada a otra escalaCompara el tamaño de la capa con el de la foto pasada por ImageOps.exif_transpose
Contiene píxeles transparentesCapa exportada como JPEG o «acoplada» sobre la foto o sobre blancoQue la capa sea RGBA y que el mínimo del canal alfa sea menor que 255
Como mucho 16.777.216 píxelesFotos de cámara de más de 16 megapíxelesAncho × alto de la capa
Archivo de la capa de 50 MB como máximoPNG enorme sin comprimirPeso del archivo en disco
En JSON, image_url de como mucho 20.971.520 caracteresData URL base64 de un archivo grandeNo lo comprueba; base64 ocupa unos 4/3 del archivo
Solo actúa sobre la primera imagenFoto puesta en segundo lugar tras una imagen de referenciaNo lo comprueba; revisa el orden de images

El límite de 20.971.520 caracteres es el maxLength que la referencia de images.edit de la API de OpenAI indica para image_url. El script verifica las reglas publicadas, no lo que responde la API ante una capa mal hecha: ese error no se ha observado en la API oficial, y una de las rutas por llamada de la prueba descrita más abajo aceptó con 200 y sin aviso una capa de 1000×750 para una foto de 1200×900 y otra totalmente opaca. Validar en local es la única garantía de que el problema no es el archivo.

Crear y validar la capa con un script de Python

make_markup_overlay.py dibuja una elipse roja sobre un lienzo totalmente transparente del tamaño de la foto, después de aplicar la orientación EXIF, y comprueba las cuatro reglas que se pueden medir en el archivo. Solo necesita Pillow. Pasos:

  1. Instala Pillow con pip install pillow.
  2. Abre la foto en cualquier visor que muestre coordenadas y apunta la esquina superior izquierda y la inferior derecha del rectángulo que envuelve el objeto. Usa la foto tal como se ve, ya girada.
  3. Ejecuta el script con la foto, las cuatro coordenadas y el nombre de salida.
  4. Si imprime OK, la capa cumple las reglas; si imprime FAIL, corrige lo que indica antes de llamar a la API.
python
"""Crea y valida una capa de anotación para ediciones con markup de GPT Image 2.6 / 2.5.
Dibuja una elipse roja sobre un lienzo totalmente transparente del tamaño de la foto
(tras aplicar la orientación EXIF) y comprueba las reglas publicadas por OpenAI:
mismo ancho y alto que la primera imagen, píxeles transparentes,
como mucho 16.777.216 píxeles y como mucho 50 MB.
Uso: python3 make_markup_overlay.py foto.jpg x0 y0 x1 y1 [salida.png]"""
import os, sys
from PIL import Image, ImageDraw, ImageOps

MAX_PIXELS = 16_777_216
MAX_BYTES = 50 * 1024 * 1024


def build(photo, box, out):
    img = ImageOps.exif_transpose(Image.open(photo))  # la API compara tamaños tras la orientación
    overlay = Image.new("RGBA", img.size, (0, 0, 0, 0))
    ImageDraw.Draw(overlay).ellipse(box, outline=(230, 20, 20, 255), width=max(4, img.width // 150))
    overlay.save(out)
    return img.size


def check(photo, out):
    img = ImageOps.exif_transpose(Image.open(photo))
    ov = Image.open(out)
    problems = []
    if ov.size != img.size:
        problems.append(f"size {ov.size} != photo {img.size}")
    if ov.mode != "RGBA" or ov.getchannel("A").getextrema()[0] == 255:
        problems.append("no transparent pixels (flattened overlay)")
    if ov.width * ov.height > MAX_PIXELS:
        problems.append("overlay over 16,777,216 pixels")
    if os.path.getsize(out) > MAX_BYTES:
        problems.append("overlay over 50 MB")
    return problems


if __name__ == "__main__":
    photo, *nums = sys.argv[1:6]
    out = sys.argv[6] if len(sys.argv) > 6 else "markup.png"
    size = build(photo, [int(n) for n in nums], out)
    issues = check(photo, out)
    print(f"photo {size[0]}x{size[1]} -> {out} ({os.path.getsize(out)} bytes)")
    print("OK" if not issues else "FAIL: " + "; ".join(issues))

El 5 de noviembre de 2026, con la foto de la cocina que publica OpenAI en su guía (1200×900, convertida a PNG) y la silla delantera izquierda como objetivo, python3 make_markup_overlay.py kitchen.png 235 610 465 785 markup.png imprimió photo 1200x900 -> markup.png (5645 bytes) y OK. Para revisar una capa que ya tienes, importa la función: python3 -c "from make_markup_overlay import check; print(check('kitchen.png', 'otra-capa.png'))". Ese mismo día, una capa de 1000×750 devolvió size (1000, 750) != photo (1200, 900), una capa acoplada sobre blanco devolvió no transparent pixels (flattened overlay) y la capa del ejemplo oficial de OpenAI pasó sin problemas.

Si prefieres dibujar a mano en un editor de imágenes, exporta solo la capa de los trazos en PNG con transparencia, sin la foto debajo, y pásala por check antes de enviarla.

Enviar markup a /v1/images/edits en multipart o en JSON

En una petición multipart, la capa va como archivo en el campo markup, igual que la foto va en image. En una petición JSON, las imágenes de entrada van en el array images y la capa en un objeto markup con exactamente uno de estos dos campos: image_url (URL HTTPS o data URL en base64) o file_id (un archivo subido antes a la Files API). En ambos casos el modelo es gpt-image-2.6-flare o gpt-image-2.6-sunburst y el texto del cambio va en prompt.

La versión multipart sigue el ejemplo oficial de la guía de OpenAI, con la capa y el prompt de la silla. Necesita openai 3.46.0 o posterior: el argumento markup existe desde la 3.42.0 y complexity desde la 3.46.0, según el contenido de los paquetes publicados en PyPI a 5 de noviembre de 2026; con una versión anterior, pasa los campos que falten en extra_body. El SDK lee OPENAI_API_KEY y, si llamas a través de un intermediario, OPENAI_BASE_URL:

python
import base64
from pathlib import Path

from openai import OpenAI

client = OpenAI()
PROMPT = (
    "Recolor the chair inside the red circle to bright mustard-yellow leather. Keep its shape. "
    "Keep the other chairs white and keep the rest of the kitchen unchanged. "
    "Remove the red circle from the finished photo."
)

with open("kitchen.png", "rb") as image, open("markup.png", "rb") as markup:
    result = client.images.edit(
        model="gpt-image-2.6-sunburst",
        image=("kitchen.png", image, "image/png"),
        markup=("markup.png", markup, "image/png"),
        quality="medium",
        complexity="low",
        size="auto",
        prompt=PROMPT,
    )

Path("sillas.png").write_bytes(base64.b64decode(result.data[0].b64_json))

La versión JSON no depende del SDK: monta el cuerpo según la referencia de images.edit, con la foto y la capa como data URL, y sirve para cualquier lenguaje que hable HTTP:

python
import base64, os
from pathlib import Path

import requests

def data_url(path):
    return "data:image/png;base64," + base64.b64encode(Path(path).read_bytes()).decode()

body = {
    "model": "gpt-image-2.6-sunburst",
    "prompt": "Recolor the chair inside the red circle to bright mustard-yellow leather. "
              "Keep its shape. Keep the other chairs white and keep the rest of the kitchen "
              "unchanged. Remove the red circle from the finished photo.",
    "images": [{"image_url": data_url("kitchen.png")}],
    "markup": {"image_url": data_url("markup.png")},
    "quality": "medium",
    "complexity": "low",
    "size": "auto",
}
base = os.environ.get("OPENAI_BASE_URL", "https://api.openai.com/v1")
r = requests.post(f"{base}/images/edits", json=body, timeout=300,
                  headers={"Authorization": f"Bearer {os.environ['OPENAI_API_KEY']}"})
r.raise_for_status()
Path("sillas.png").write_bytes(base64.b64decode(r.json()["data"][0]["b64_json"]))

Con size="auto", la API de OpenAI conservó la proporción 4:3 en su propio ejemplo y devolvió 1448×1086 a partir de 1200×900. Si necesitas un tamaño fijo, la guía de prompts de GPT Image 2.6 de OpenAI pide múltiplos de 16 en ancho y alto y una proporción entre 1:3 y 3:1; para una foto 4:3, 1536x1152 cumple. Cómo redactar el cambio y lo que debe conservarse lo cubre la guía de prompts de GPT Image 2.6 probada en texto, ediciones y GIF.

Markup en LaoZhang API: las rutas por llamada ignoraron la capa

En LaoZhang API, las rutas de pago por llamada gpt-image-2.6-web y gpt-image-2.6-sunburst-vip aceptaron markup el 5 de noviembre de 2026 pero no lo tuvieron en cuenta. La prueba usó la cocina de OpenAI con cuatro sillas blancas idénticas y una capa que rodeaba solo la delantera izquierda; el prompt la nombraba únicamente como «la silla dentro del círculo rojo». Se lanzó la misma petición con capa y sin ella en cada ruta, una vez por combinación:

Aviso: laozhang.ai es un servicio propio. Sus precios son nuestra tarifa, no una comparación independiente.

RutaCapa de anotaciónTamaño devueltoSilla que se volvió amarilla
gpt-image-2.6-webSí1448×1086La delantera derecha
gpt-image-2.6-webNo1448×1086Las del lado derecho
gpt-image-2.6-sunburst-vip, size: "1536x1152"Sí1536×1152La delantera derecha
gpt-image-2.6-sunburst-vip, size: "1536x1152"No1536×1152La delantera derecha

Cuadrícula de cuatro pruebas en LaoZhang API: con capa y sin capa, en la ruta web y en la VIP, la silla rodeada sigue blanca y se vuelve amarilla otra silla

La silla rodeada siguió blanca en los cuatro casos y el círculo rojo no apareció en ninguna salida, así que la capa no produjo ninguna diferencia visible. Cada edición tardó 24 segundos en la ruta web y 38 en la VIP. Es una ejecución por celda y no dice nada de la API de OpenAI ni del reenvío oficial. Se eligieron las sillas porque una primera ronda con el jarrón de rayas no permitía sacar conclusiones: el jarrón salió azul en todas las ediciones, también sin capa, porque el texto basta para encontrarlo; esa misma ronda es la que aceptó las capas de tamaño equivocado y opaca.

La misma ronda dejó un efecto secundario que conviene conocer: sin size, la ruta VIP devolvió 2048×2048 a partir de la foto de 1200×900 y recompuso la cocina en un cuadrado; con size: "1536x1152" mantuvo el 4:3, mientras que la ruta web devolvió 1448×1086. Si una edición te llega cuadrada y con otro encuadre, la causa más probable es la falta de size en una ruta así.

Para usar markup en LaoZhang API, la ruta que corresponde es el reenvío oficial: gpt-image-2.6-flare o gpt-image-2.6-sunburst con una clave del grupo OpenAI Official (o OpenAI Official Enterprise, con un recargo del 20 %), facturada por tokens a las tarifas de OpenAI y con los endpoints /v1/images/generations y /v1/images/edits. Según la documentación de GPT Image 2.5 y 2.6 de LaoZhang API (en inglés), el cuerpo de la petición es el mismo que en OpenAI y solo cambia model; el grupo va en la clave, nunca en la petición. Esa documentación no menciona markup y markup aún no se ha ejecutado por esa ruta, así que antes de llevarlo a producción repite la prueba de las sillas. Las rutas por llamada cuestan USD 0,03 por imagen y siguen siendo útiles para ediciones guiadas solo por texto, no para markup.

Comprobar que la edición no cambió nada fuera del círculo

La guía de OpenAI cierra su ejemplo pidiendo comparar el resto de la imagen con el original, y esa comparación se puede medir: reescala el resultado al tamaño de la foto, rellena la elipse de la capa y calcula cuánto cambió cada píxel dentro y fuera de ella. El 5 de noviembre de 2026, aplicado a los dos resultados que OpenAI publica para el jarrón (entrada de 1200×900, salidas de 1448×1086), el cambio medio dentro del círculo fue del 12,1 % en Sunburst y del 11,2 % en Flare; fuera, del 4,3 % en Sunburst y del 8,4 % en Flare. En ese ejemplo, Flare alteró el resto de la foto unas dos veces más que Sunburst. Es un solo ejemplo. El reescalado añade por sí mismo una diferencia de base pequeña: ampliar la foto original a 1448×1086 y devolverla a 1200×900 con LANCZOS cambia la zona exterior en torno a un 0,29 %, así que casi todo el 4,3 % y el 8,4 % es cambio real del modelo.

Barras del cambio medio dentro y fuera del círculo en el ejemplo oficial: Sunburst 12,1 % y 4,3 %, Flare 11,2 % y 8,4 %, frente al 0,29 % de solo reescalar

Para medir tus propias ediciones:

  1. Guarda la foto original, la capa y el resultado en la misma carpeta.
  2. Instala numpy y Pillow, y ejecuta el script con los tres archivos.
  3. Si avisa de que la proporción cambió, no compares cifras: la escena se recompuso y tienes que repetir la edición con un size de la misma proporción.
  4. Compara el cambio de fuera con el de dentro. Un valor bajo fuera y claramente mayor dentro indica una edición local; si fuera se acerca a lo de dentro, se ha retocado toda la foto.
python
"""Compara una edición con la foto original, dentro y fuera de la zona marcada.
Uso: python3 comparar_edicion.py foto.png capa.png editada.png"""
import sys

import numpy as np
from PIL import Image, ImageDraw, ImageOps

foto, capa, editada = sys.argv[1:4]
orig = ImageOps.exif_transpose(Image.open(foto)).convert("RGB")
ed = Image.open(editada).convert("RGB")
print(f"original {orig.size[0]}x{orig.size[1]}  editada {ed.size[0]}x{ed.size[1]}")
if abs(ed.width / ed.height - orig.width / orig.height) > 0.01:
    print("AVISO: otra proporción; la escena se recompuso y la comparación no es fiable")

# Zona = elipse rellena que envuelve todo lo que dibujaste en la capa
alfa = np.array(Image.open(capa).convert("RGBA"))[:, :, 3]
ys, xs = np.nonzero(alfa > 0)
zona = Image.new("L", orig.size, 0)
ImageDraw.Draw(zona).ellipse([xs.min(), ys.min(), xs.max(), ys.max()], fill=255)
dentro = np.array(zona) > 0

O = np.asarray(orig, dtype=float)
E = np.asarray(ed.resize(orig.size, Image.LANCZOS), dtype=float)
cambio = np.abs(E - O).mean(axis=2) / 255 * 100
print(f"cambio medio dentro: {cambio[dentro].mean():.1f} %   fuera: {cambio[~dentro].mean():.1f} %")

Con la capa y las dos salidas del ejemplo oficial, este script da exactamente las cifras de arriba. No hay un umbral universal: depende de cuánto ocupe la zona y de cuánto deba cambiar. Úsalo para comparar dos ajustes sobre la misma foto, por ejemplo Flare frente a Sunburst o complexity en low frente a high, y revisa siempre la imagen a simple vista.

Cuánto cuesta una edición con markup: sin recargo

Markup no cuesta nada extra. La guía de OpenAI dice que las ediciones guiadas con una capa usan las mismas tarifas por token que cualquier otra edición, y la página de precios de la API de OpenAI fija para GPT Image 2.6 USD 8 por millón de tokens de entrada de imagen, USD 30 por millón de tokens de salida de imagen y USD 5 por millón de tokens de entrada de texto.

Como referencia, una edición de Sunburst en low enviada por el reenvío oficial descrito en el apartado anterior, a las tarifas de OpenAI, costó USD 0,03301 en total, entrada y salida incluidas. Para estimar la parte de salida, una imagen fija de 1024 genera 824 tokens en low, 1.449 en medium y 1.756 en high; a USD 30 por millón son USD 0,02472, 0,04347 y 0,05268 (por ejemplo, 824 × 30 / 1.000.000). A eso se suma la entrada de imagen y de texto, que crece con el tamaño de la foto. Si dudas entre 2.5 y 2.6 por coste o por calidad, la comparación completa está en GPT Image 2.6 vs 2.5: diferencias y cuándo cuesta 4 veces más.

Preguntas frecuentes sobre markup en GPT Image 2.6

¿Markup funciona también con GPT Image 2.5?

Según la guía de generación de imágenes de OpenAI, sí: la sección de markup habla de «GPT Image 2.5 and 2.6». A 5 de noviembre de 2026, la referencia de images.edit describe el campo markup con la frase «Supports GPT Image 2.5», sin mencionar 2.6, mientras que el anuncio del 4 de noviembre y las fichas de gpt-image-2.6-flare y gpt-image-2.6-sunburst incluyen las ediciones con markup. En 2.5 las dos fuentes coinciden; en 2.6, la guía y el anuncio son las declaraciones más recientes sobre el modelo.

¿Por qué algunas páginas dicen que GPT Image 2.6 no tiene ID de modelo?

Porque se escribieron antes del lanzamiento. El campo markup apareció en la especificación de la API a finales de octubre de 2026 y varias páginas lo cubrieron cuando 2.6 aún no tenía ID; desde el 4 de noviembre de 2026 los modelos son gpt-image-2.6-flare y gpt-image-2.6-sunburst.

¿Puedo marcar la zona en la app de ChatGPT en lugar de usar la API?

Sí, la app tiene su propia herramienta de marcas en el editor de imágenes, pero funciona distinto: sus botones vuelven a generar la imagen. Cómo usarla sin perder el resto de la foto está en Editor de fotos de ChatGPT: cómo editar sin que cambie todo.

Fuentes4

Páginas externas que cita esta guía, en el orden en que aparecen. Última actualización: 5 nov 2026.

  1. 1.guía de generación de imágenes de OpenAI, apartado «Guide an edit with markup»developers.openai.com/api/docs/guides/image-generation
  2. 2.guía de prompts de imágenes de OpenAIdevelopers.openai.com/api/docs/guides/image-prompting
  3. 3.referencia de images.edit de la API de OpenAIdevelopers.openai.com/api/reference/resources/images/methods/edit
  4. 4.página de precios de la API de OpenAIdevelopers.openai.com/api/docs/pricing