API de generación de imágenes de OpenAI en Python: ejemplo paso a paso

Envía un prompt desde Python, recibe una imagen en base64 y guárdala en disco. Este tutorial usa los modelos GPT Image actuales y muestra cómo el tamaño, la calidad y el formato cambian el resultado; después añade ediciones con máscaras, vistas previas en streaming, lotes asíncronos y un registro de costos.

API de generación de imágenes de OpenAI en Python: ejemplo paso a paso
Cristian Da Conceicao
Fundador de Picasso IA

La mayoría de los tutoriales sobre el endpoint de imágenes de OpenAI se quedan en "aquí tienes una URL". Eso funcionaba con DALL-E. No funciona con los modelos GPT Image, que devuelven datos en base64 y nada más, así que el script que la gente copia primero suele fallar en result.data[0].url. Este tutorial parte de un script que sí funciona y lo amplía con tamaños, niveles de calidad, ediciones basadas en máscaras, vistas previas en streaming, lotes asíncronos y un pequeño control de costos.

Los parámetros, los nombres de los modelos y los precios que aparecen aquí provienen de la documentación actual de generación de imágenes de OpenAI y de su página de precios, consultadas el 2026-10-06. Cuando una cifra puede cambiar, el texto lo indica.

Antes de escribir código

Antes de que la primera solicitud funcione, necesitas tres cosas: un nombre de modelo, el SDK instalado y una organización de OpenAI verificada. Esta última es la que más problemas da a las cuentas nuevas, porque los modelos GPT Image devuelven un error de acceso hasta que se completa la verificación en la configuración de la consola para desarrolladores.

Manos de un desarrollador escribiendo en un equipo portátil sobre una mesa de roble con luz suave de la mañana

Elige un modelo

Estos son los modelos GPT Image que OpenAI tiene hoy en su lista de precios. Los cinco también funcionan en PicassoIA, lo que resulta útil para probar un prompt antes de escribir código.

ModeloIdeal paraPrecio de salida de imagen (por 1M de tokens)
gpt-image-2.5-flareGeneración cotidiana rápida y de alta calidad$30.00
gpt-image-2.5-sunburstEdiciones precisas e inpainting$30.00
gpt-image-2Versión anterior, mismas tarifas de tokens$30.00
gpt-image-1Modelo GPT Image original$40.00
gpt-image-1-miniEl costo más bajo$8.00

En PicassoIA puedes probar GPT Image 2.5 Flare, GPT Image 2.5 Sunburst, GPT Image 2, GPT Image 1 y GPT Image 1 Mini uno al lado del otro. Un valor por defecto razonable: Flare para generar, Sunburst cuando el trabajo sea una edición.

Instala y autentica

Instala el SDK oficial:

pip install --upgrade openai pillow

Crea un secreto de proyecto en el panel de OpenAI y expórtalo como variable de entorno. El SDK lo lee automáticamente, así que el secreto nunca aparece en tu archivo de código.

# macOS / Linux
export OPENAI_API_KEY="sk-..."

# Windows PowerShell
$env:OPENAI_API_KEY = "sk-..."

💡 Consejo: mantén el secreto fuera de los cuadernos que vayas a compartir y fuera del historial de git. Si se filtra, revócalo en el panel y crea uno nuevo.

Tu primera imagen en Python

El script mínimo

Este es el script completo. Ejecútalo y aparecerá un PNG junto al script.

import base64
from pathlib import Path
from openai import OpenAI

client = OpenAI()

result = client.images.generate(
    model="gpt-image-2.5-flare",
    prompt="A ceramic bowl of ripe peaches on a linen cloth, soft window light, 50mm photograph",
    size="1536x1024",
    quality="medium",
)

image_bytes = base64.b64decode(result.data[0].b64_json)
Path("peaches.png").write_bytes(image_bytes)

Cuatro argumentos hacen todo el trabajo. model elige el motor, prompt describe la imagen, size fija las dimensiones en píxeles y quality equilibra velocidad y costo frente a detalle. Todo lo demás tiene un valor por defecto razonable, y el formato de salida es PNG salvo que pidas otra cosa.

Desarrollador revisando un primer script de Python en un equipo portátil al atardecer

Escribe prompts que aguanten

Un prompt que funciona en una demostración puede desmoronarse en un bucle de cincuenta imágenes. Cuatro hábitos mantienen los resultados constantes:

  • Empieza por el sujeto, luego el escenario, la luz y el objetivo. "Un cuenco de cerámica con melocotones maduros sobre un paño de lino, luz suave de ventana desde la izquierda, fotografía de 50 mm" funciona mejor que una lista de adjetivos.
  • Entrecomilla cualquier texto que deba aparecer en la imagen, y que sean una o dos palabras.
  • Di lo que quieres evitar en términos positivos. "Pared blanca lisa" funciona mejor que "nada de desorden".
  • Cambia una sola cosa por ejecución. Si alteras el sujeto, la luz y el tamaño a la vez, no podrás saber qué cambio ayudó.

Por qué la respuesta es base64

Los modelos GPT Image siempre devuelven base64. La opción response_format="url" que aceptaba DALL-E no es compatible, así que result.data[0].url no existe y la imagen llega dentro de b64_json. De ahí se derivan tres hábitos:

  • Decodifica una vez y guarda en disco. base64.b64decode te da los bytes en bruto para guardar, subir o pasar a Pillow.
  • Aloja el archivo tú mismo. Si un blog o una app necesita un enlace público, sube los bytes a tu propio almacenamiento (S3, R2, un CDN) y guarda esa URL.
  • Omite el disco para vistas previas rápidas. Construye un data URI con f"data:image/png;base64,{b64}" y colócalo en una etiqueta <img>.

💡 ¿Migras código antiguo? Buscar en tu proyecto .url y response_format encuentra casi todas las líneas que hay que cambiar.

Fotografías impresas desplegadas en abanico sobre un escritorio de nogal

Tamaño, calidad y formato de salida

Estos parámetros deciden lo que recibes y lo que cuesta. Esta es la lista completa que publica la documentación:

ParámetroValores aceptadosNotas
size1024x1024, 1536x1024, 1024x1536, o WIDTHxHEIGHT personalizadoLos lados personalizados deben ser múltiplos de 16, la proporción entre 1:3 y 3:1, el lado más largo hasta 3840 px y el total de píxeles entre 655.360 y 8.294.400
qualitylow, medium, high, autoLos modelos 2.5 también admiten xhigh y max
output_formatpng (por defecto), jpeg, webpElige webp o jpeg para archivos más ligeros
output_compression0 a 100Solo JPEG y WebP
backgroundtransparent, opaque, autoLa transparencia necesita un formato con canal alfa, así que usa PNG o WebP
nEnteroVarias imágenes en una misma solicitud
moderationauto (por defecto), lowlow aplica un filtrado más ligero
stream, partial_imagesBooleano, de 0 a 3Fotogramas de vista previa mientras se renderiza la imagen final

Algunas reglas prácticas:

  • Horizontal y vertical. 1536x1024 y 1024x1536 sirven para la mayoría de formatos de blog y redes sociales. Para un 16:9 real, pide 2048x1152: ambos lados son múltiplos de 16 y el número de píxeles queda bien dentro del rango permitido.
  • Itera barato, termina con calidad. Redacta los prompts en quality="low" y vuelve a generar el ganador en high. Pagas por los tokens de salida, y una calidad más alta produce más de ellos.
  • Elige el formato según el destino. Mantén PNG para editar y para la transparencia, y cambia a webp con output_compression=85 para páginas que deban cargar rápido.

Tres láminas enmarcadas en formatos cuadrado, horizontal y vertical sobre una pared de ladrillo

Edita imágenes existentes con máscaras

Edita una imagen

images.edit recibe un archivo de origen y un prompt que describa el cambio. Pasa una lista de archivos cuando quieras combinar varias referencias.

with open("living-room.png", "rb") as photo:
    edited = client.images.edit(
        model="gpt-image-2.5-sunburst",
        image=photo,
        prompt="Swap the grey sofa for a green velvet armchair, keep the window light unchanged",
    )

Path("living-room-edit.png").write_bytes(base64.b64decode(edited.data[0].b64_json))

Describe con la misma claridad lo que debe seguir igual que lo que debe cambiar. Los modelos se desvían cuando el prompt solo nombra el elemento nuevo.

Añade una máscara

Una máscara limita la edición a una región. Es un PNG con canal alfa y las mismas dimensiones que el original. Los píxeles totalmente transparentes marcan la zona a repintar; todo lo opaco queda protegido. Pillow crea una en pocas líneas:

from PIL import Image, ImageDraw

base = Image.open("living-room.png").convert("RGBA")
mask = Image.new("RGBA", base.size, (0, 0, 0, 255))          # opaque: keep
ImageDraw.Draw(mask).rectangle((620, 380, 1180, 900), fill=(0, 0, 0, 0))  # transparent: repaint
mask.save("mask.png")

with open("living-room.png", "rb") as photo, open("mask.png", "rb") as hole:
    edited = client.images.edit(
        model="gpt-image-2.5-sunburst",
        image=photo,
        mask=hole,
        prompt="A green velvet armchair with a wooden side table, matching the room's light",
    )

La máscara es una guía, no un recorte exacto. Los bordes pueden desbordarse un poco, así que deja un pequeño margen alrededor del objeto que quieres reemplazar.

Mano de un retocador con un lápiz óptico sobre una tableta gráfica junto a un retrato impreso

Vistas previas en streaming y lotes

Imágenes parciales mientras esperas

Los renders de alta calidad pueden tardar un rato. Con stream=True y partial_images, la API envía fotogramas de borrador antes de la imagen final, para que una interfaz pueda mostrar el progreso en lugar de un spinner.

stream = client.images.generate(
    model="gpt-image-2.5-flare",
    prompt="A vintage red bicycle leaning on a brick wall, golden hour, 35mm photograph",
    size="1536x1024",
    quality="high",
    stream=True,
    partial_images=2,
)

for event in stream:
    if event.type == "image_generation.partial_image":
        Path(f"preview-{event.partial_image_index}.png").write_bytes(base64.b64decode(event.b64_json))
    else:
        Path("final.png").write_bytes(base64.b64decode(event.b64_json))

Las vistas previas pueden sumar tokens al conteo, así que compara usage con y sin streaming antes de activarlo en cada solicitud.

Lotes asíncronos sin errores de límite

Para una lista de prompts, AsyncOpenAI junto con un semáforo mantiene bajo control el número de solicitudes en curso:

import asyncio
from openai import AsyncOpenAI

client = AsyncOpenAI(max_retries=4, timeout=180)
gate = asyncio.Semaphore(3)

async def render(index: int, prompt: str) -> Path:
    async with gate:
        result = await client.images.generate(
            model="gpt-image-2.5-flare", prompt=prompt, size="1536x1024", quality="low",
        )
    path = Path(f"batch-{index:02d}.png")
    path.write_bytes(base64.b64decode(result.data[0].b64_json))
    return path

async def main(prompts: list[str]) -> list[Path]:
    return await asyncio.gather(*(render(i, p) for i, p in enumerate(prompts)))

Un semáforo limita la concurrencia, no las imágenes por minuto. En los niveles de uso bajos, el límite por minuto es el que se alcanza primero, así que sube max_retries y deja que el SDK espere antes de reintentar. Cuando nadie espera la salida, estos modelos admiten el endpoint Batch, que cobra los tokens de salida a mitad de precio.

Costos, límites y errores

Tarifas de tokens por modelo

OpenAI cobra estos modelos por tokens, no por imagen, y no publica una tabla de precios por imagen para los actuales. Tarifas por 1M de tokens:

ModeloEntrada de textoEntrada de imagenSalida de imagenSalida de imagen (Batch)
gpt-image-2.5-flare$5.00$8.00$30.00$15.00
gpt-image-2.5-sunburst$5.00$8.00$30.00$15.00
gpt-image-2$5.00$8.00$30.00$15.00
gpt-image-1$5.00$10.00$40.00$20.00
gpt-image-1-mini$2.00$2.50$8.00$4.00

La calidad y el tamaño cambian cuántos tokens de salida usa una imagen, por eso un mismo prompt puede costar cantidades muy distintas en low y en high.

Cuaderno, calculadora y pruebas impresas sobre el escritorio de un freelance

Controla el gasto en código

La respuesta incluye un objeto usage con el conteo de tokens. Conviértelo en dólares después de cada llamada y nunca te llevarás una sorpresa en la factura:

RATES = {"text_in": 5.00, "image_in": 8.00, "image_out": 30.00}  # USD per 1M tokens

def cost_usd(usage) -> float:
    details = usage.input_tokens_details
    return (
        details.text_tokens * RATES["text_in"]
        + details.image_tokens * RATES["image_in"]
        + usage.output_tokens * RATES["image_out"]
    ) / 1_000_000

print(f"Last image: ${cost_usd(result.usage):.4f}")

Los límites de frecuencia dependen de tu nivel de uso. Para gpt-image-2.5-flare, la página del modelo muestra estos límites al escribir esto:

NivelTokens por minutoImágenes por minuto
Nivel 1100K5
Nivel 2250K20
Nivel 3800K50
Nivel 43M150
Nivel 58M250

Errores con los que te encontrarás

Desarrollador frotándose el cuello mientras lee un error en un equipo portátil de noche

SíntomaCausa probableSolución
Error de acceso en la primera llamadaOrganización no verificadaCompleta la verificación en la consola para desarrolladores
AttributeError en .urlLos modelos GPT Image devuelven solo base64Lee b64_json en su lugar
Bad request que menciona moderaciónEl prompt o la imagen de entrada activó un filtro de seguridadReformula el prompt y evita temas sensibles
Bad request en sizeUn lado no es múltiplo de 16, la proporción supera 3:1 o el número de píxeles está fuera de rangoAjusta las dimensiones
Límite de frecuencia de 429Se alcanzó el límite del nivelReduce la concurrencia, sube max_retries o usa Batch
TimeoutLa alta calidad puede tardar muchoAumenta timeout en el cliente

Estos son los tres que más importan en producción:

import openai

try:
    result = client.images.generate(model="gpt-image-2.5-flare", prompt=prompt, size="1536x1024")
except openai.BadRequestError as err:
    print("Rejected:", err.message)
except openai.RateLimitError:
    print("Image limit reached, slow down")
except openai.APIConnectionError:
    print("Network problem, retry later")

Cómo usar GPT Image 2 en PicassoIA

Antes de gastar presupuesto de API en experimentos de prompts, ejecútalos en el navegador. GPT Image 2 en PicassoIA renderiza texto legible dentro de las imágenes, admite fondos transparentes, acepta imágenes de referencia y genera hasta 10 variaciones por ejecución.

Prueba prompts sin código

  1. Abre la página del modelo y escribe tu prompt. Pon entre comillas cualquier texto que deba aparecer dentro de la imagen.
  2. Fija la calidad en low para los borradores. Cambia a high para el render final.
  3. Elige una relación de aspecto: 3:2 o 2:3 reflejan 1536x1024 y 1024x1536, y 16:9 da un encuadre panorámico.
  4. Elige el formato de salida. WebP es el valor por defecto; PNG mantiene limpia la transparencia.
  5. Fija el número de imágenes entre 1 y 10, y genera.
  6. Sube imágenes de referencia si quieres editar en lugar de crear desde cero.

Los campos del formulario se corresponden con la llamada en Python, así que una receta que funciona en el navegador se traslada directamente al código:

Campo de PicassoIAArgumento de Python
aspect_ratiosize
qualityquality
output_formatoutput_format
output_compressionoutput_compression
backgroundbackground
moderationmoderation
number_of_imagesn
input_imagesimage (en images.edit)

Un campo opcional acepta tu propia credencial de OpenAI; déjalo vacío y el proxy de PicassoIA gestiona la solicitud.

Diseñadora pasando una fotografía de retrato en una tableta en un estudio luminoso

Dos hábitos más dan buenos resultados. Primero, redacta el prompt con un modelo de lenguaje: pega una idea aproximada en GPT 5 o Claude Sonnet 4.6 y pide tres variantes fotográficas con objetivo, luz y encuadre. Segundo, pasa el mismo prompt por PicassoIA Image y Seedream 4.5 para ver qué estilo encaja con tu proyecto. Para ediciones que no necesitan código, PicassoIA Image Editor Pro gestiona los cambios de foto directamente en el navegador.

La API para desarrolladores de PicassoIA

Si tu flujo de trabajo necesita otro proveedor, PicassoIA tiene su propia API para desarrolladores con una forma similar a la de Replicate:

  • URL base: https://api.picassoia.com/v1
  • Autenticación: un token Bearer que empieza por pia_sk_
  • Flujo: crea una predicción con POST /v1/models/{owner}/{name}/predictions, consulta GET /v1/predictions/{id} y luego lee el resultado
  • Límite: 5 predicciones simultáneas por cuenta

Los trabajos son asíncronos, así que el bucle de crear y consultar sustituye a la llamada bloqueante única que escribiste arriba. Revisa los requisitos del plan en la página de la API de PicassoIA antes de construir sobre ella.

Crea tus propias imágenes hoy

Ya tienes un flujo de trabajo funcional: instala el SDK, verifica la organización, pide una imagen, decodifica el base64, ajusta size y quality, edita con una máscara, muestra vistas previas en streaming, procesa en lotes con límites y registra el gasto. La forma más rápida de mejorar los resultados es el volumen. Escribe diez prompts, ejecútalos en low, quédate con los dos mejores y vuelve a renderizar esos en high.

Profesional creativo frente a una pared de estudio llena de fotografías impresas

Si quieres probar prompts antes de tocar la API, abre GPT Image 2 en PicassoIA, genera algunas variaciones y compáralas con otros modelos en la biblioteca de modelos de PicassoIA. Cuando tengas imágenes fijas que te gusten, la colección de efectos de PicassoIA puede añadir movimiento y estilo sobre ellas. Elige un tema que te importe, escribe un prompt detallado y mira qué sale.

Compartir este artículo

Elige tu idioma