← Code Recipes
Image & Video

OpenAI Images Free code examples in C#, Python, Java and JavaScript

Image generation and editing, including masked inpainting.

C# Python Java JavaScript

WHAT THIS PAGE COVERS

Editing part of an existing image rather than generating from nothing.

Model gpt-image-2.5-sunburst
Package openai
Checked

Model ids change. If a sample returns a 404 on the model, that is the first thing to check against the official docs.

Install

ImageClient is constructed per model, like AudioClient. One instance per model for the life of the process.

dotnet add package OpenAI

setx OPENAI_API_KEY "sk-your-key"     # Windows, then open a new shell
export OPENAI_API_KEY="sk-your-key"   # macOS / Linux
Generate an image

Ask for Bytes. The default response format is a remote URI that expires in about an hour, which is a broken image in any record you keep longer than lunch.

using OpenAI.Images;

var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY")
    ?? throw new InvalidOperationException("OPENAI_API_KEY is not set.");

ImageClient client = new(model: "gpt-image-2.5-sunburst", apiKey: apiKey);

ImageGenerationOptions options = new()
{
    Size = GeneratedImageSize.W1024xH1024,
    ResponseFormat = GeneratedImageFormat.Bytes,
};

GeneratedImage image = await client.GenerateImageAsync(
    "A studio photograph of a brass microphone on a dark desk",
    options);

await File.WriteAllBytesAsync("microphone.png", image.ImageBytes.ToArray());
Editing part of an image

GenerateImageEditAsync takes the source, the filename, and the mask. The filename argument is not cosmetic — it is how the multipart body declares the type, and the wrong extension is a 400.

await using var source = File.OpenRead("sunlit_lounge.png");
await using var mask = File.OpenRead("mask.png");

ImageEditOptions editOptions = new()
{
    Size = GeneratedImageSize.W1024xH1024,
    ResponseFormat = GeneratedImageFormat.Bytes,
};

GeneratedImage edited = await client.GenerateImageEditAsync(
    image: source,
    imageFilename: "sunlit_lounge.png",
    prompt: "A sunlit indoor lounge area with a pool containing a flamingo",
    mask: mask,
    maskFilename: "mask.png",
    options: editOptions);

await File.WriteAllBytesAsync("edited.png", edited.ImageBytes.ToArray());
Cutting a mask in code

The mask must be the same size as the source, and the editable region must have ALPHA ZERO. ImageSharp makes that a few lines; hand-editing a PNG and hoping is how an afternoon goes.

using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;

using var source = await Image.LoadAsync<Rgba32>("sunlit_lounge.png");

// Opaque black everywhere: opaque means "leave this alone".
using var mask = new Image<Rgba32>(source.Width, source.Height,
    new Rgba32(0, 0, 0, 255));

// Alpha 0 is the only thing the model treats as editable.
mask.Mutate(context => context.Fill(
    Color.Transparent,
    new RectangleF(300, 420, 420, 380)));

await mask.SaveAsPngAsync("mask.png");
Install

The same `openai` package as chat and audio. Images are a namespace on the same client.

pip install openai

export OPENAI_API_KEY="sk-your-key"   # macOS / Linux
setx OPENAI_API_KEY "sk-your-key"     # Windows, then open a new shell
Generate an image

THE RESULT IS BASE64, NOT A URL. data[0].url is None on every GPT image model, and reaching for it is the single most common port of a DALL·E snippet.

import base64
from openai import OpenAI

client = OpenAI()

result = client.images.generate(
    model="gpt-image-2.5-sunburst",
    prompt="A studio photograph of a brass microphone on a dark desk",
    size="1024x1024",
    quality="high",
)

image_bytes = base64.b64decode(result.data[0].b64_json)

with open("microphone.png", "wb") as handle:
    handle.write(image_bytes)
Editing part of an image, not generating a new one

THE MASK IS AN ALPHA CHANNEL AND THE TRANSPARENT PART IS WHAT CHANGES. A black-and-white mask does nothing — the model reads alpha, not luminance, and an opaque PNG produces an image identical to the input with no error.

result = client.images.edit(
    model="gpt-image-2.5-sunburst",
    image=open("sunlit_lounge.png", "rb"),
    mask=open("mask.png", "rb"),
    prompt="A sunlit indoor lounge area with a pool containing a flamingo",
)

with open("edited.png", "wb") as handle:
    handle.write(base64.b64decode(result.data[0].b64_json))
Making a mask that actually works

The mask must match the source in dimensions, and the region to replace must be genuinely transparent. Pillow can cut one, and doing it in code beats hand-editing a PNG and guessing why nothing changed.

from PIL import Image

source = Image.open("sunlit_lounge.png").convert("RGBA")

# Start fully opaque: opaque means "leave this alone".
mask = Image.new("RGBA", source.size, (0, 0, 0, 255))

# Punch a transparent rectangle where the flamingo should go.
# Alpha 0 is the ONLY thing the model treats as editable.
region = Image.new("RGBA", (420, 380), (0, 0, 0, 0))
mask.paste(region, (300, 420))

mask.save("mask.png")
A background you can composite

background='transparent' gives a real alpha channel, which is what you want for a logo or a sticker. It needs output_format png or webp — asking for jpeg silently gives you a white background instead.

result = client.images.generate(
    model="gpt-image-2.5-sunburst",
    prompt="A flat-illustration blue soundwave icon, no background",
    size="1024x1024",
    background="transparent",
    output_format="png",     # jpeg cannot carry alpha
)

with open("icon.png", "wb") as handle:
    handle.write(base64.b64decode(result.data[0].b64_json))
Install

The official Java SDK. Images sit under client.images(), and the client reads OPENAI_API_KEY from the environment.

# Gradle
implementation("com.openai:openai-java:4.42.0")

export OPENAI_API_KEY="sk-your-key"
Generate an image

DO NOT SET responseFormat. It is only supported on dall-e-2; GPT image models always return base64, and asking for URL is a 400 that reads like a model problem.

import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.images.ImageGenerateParams;
import com.openai.models.images.ImagesResponse;

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;

public class Generate {
    public static void main(String[] args) throws Exception {
        OpenAIClient client = OpenAIOkHttpClient.fromEnv();

        ImageGenerateParams params = ImageGenerateParams.builder()
            .model("gpt-image-2.5-sunburst")
            .prompt("A studio photograph of a brass microphone on a dark desk")
            .size(ImageGenerateParams.Size._1024X1024)
            .build();

        ImagesResponse response = client.images().generate(params);

        String base64 = response.data().orElseThrow()
            .get(0).b64Json().orElseThrow();

        Files.write(Path.of("microphone.png"), Base64.getDecoder().decode(base64));
    }
}
Everything is Optional

data(), b64Json() and url() all come back wrapped. orElseThrow() is fine in a sample and wrong in a service — the empty case is a moderation refusal, which deserves a message rather than a NoSuchElementException.

ImagesResponse response = client.images().generate(params);

byte[] png = response.data()
    .filter(items -> !items.isEmpty())
    .flatMap(items -> items.get(0).b64Json())
    .map(Base64.getDecoder()::decode)
    .orElseThrow(() -> new IllegalStateException(
        "No image returned — usually a moderation refusal rather than an error."));

Files.write(Path.of("microphone.png"), png);
Editing part of an image

ImageEditParams mirrors the generate builder. The mask's TRANSPARENT region is what gets replaced — alpha, not colour, which is the detail that wastes the most time.

import com.openai.models.images.ImageEditParams;

ImageEditParams edit = ImageEditParams.builder()
    .model("gpt-image-2.5-sunburst")
    .image(Files.newInputStream(Path.of("sunlit_lounge.png")))
    .mask(Files.newInputStream(Path.of("mask.png")))
    .prompt("A sunlit indoor lounge area with a pool containing a flamingo")
    .build();

ImagesResponse edited = client.images().edit(edit);

Files.write(
    Path.of("edited.png"),
    Base64.getDecoder().decode(
        edited.data().orElseThrow().get(0).b64Json().orElseThrow()));
Install

Server-side only — an image key in the browser is a public key, and image generation is the most expensive thing to have stolen.

npm install openai

export OPENAI_API_KEY="sk-your-key"
Generate an image

b64_json, always. There is no url field to read on a GPT image model, and the snippet you are porting from DALL·E will read one.

import { writeFile } from "node:fs/promises";
import OpenAI from "openai";

const openai = new OpenAI();

const result = await openai.images.generate({
  model: "gpt-image-2.5-sunburst",
  prompt: "A studio photograph of a brass microphone on a dark desk",
  size: "1024x1024",
  quality: "high",
});

await writeFile(
  "microphone.png",
  Buffer.from(result.data[0].b64_json, "base64"),
);
Editing part of an image

toFile() is not optional — the SDK needs a filename and MIME type to build the multipart body, and a bare ReadStream throws an error that does not say so.

import fs from "node:fs";
import OpenAI, { toFile } from "openai";

const result = await openai.images.edit({
  model: "gpt-image-2.5-sunburst",
  image: await toFile(
    fs.createReadStream("sunlit_lounge.png"),
    "sunlit_lounge.png",
    { type: "image/png" },
  ),
  mask: await toFile(
    fs.createReadStream("mask.png"),
    "mask.png",
    { type: "image/png" },
  ),
  prompt: "A sunlit indoor lounge area with a pool containing a flamingo",
});

await writeFile("edited.png", Buffer.from(result.data[0].b64_json, "base64"));
What the mask actually means

TRANSPARENT MEANS EDIT THIS. The model reads the alpha channel, so a black-and-white mask is ignored entirely and returns something close to the original — no error, just no change.

import sharp from "sharp";

const { width, height } = await sharp("sunlit_lounge.png").metadata();

// Opaque everywhere = "leave it all alone".
const base = sharp({
  create: { width, height, channels: 4, background: { r: 0, g: 0, b: 0, alpha: 1 } },
});

// A fully transparent rectangle is the editable region.
const hole = await sharp({
  create: { width: 420, height: 380, channels: 4,
            background: { r: 0, g: 0, b: 0, alpha: 0 } },
}).png().toBuffer();

await base
  .composite([{ input: hole, left: 300, top: 420, blend: "dest-out" }])
  .png()
  .toFile("mask.png");
Keeping the cost visible

Quality is the price dial and it is easy to leave on max in a loop. Log it with the prompt, because the bill arrives a month after the code was written.

async function generate(prompt, quality = "medium") {
  const started = Date.now();

  const result = await openai.images.generate({
    model: "gpt-image-2.5-sunburst",
    prompt,
    size: "1024x1024",
    quality,           // low | medium | high | xhigh | max | auto
  });

  console.log(
    JSON.stringify({
      quality,
      ms: Date.now() - started,
      // usage is per-image token counts; it is what the invoice is built from.
      usage: result.usage,
      prompt: prompt.slice(0, 60),
    }),
  );

  return Buffer.from(result.data[0].b64_json, "base64");
}

QUESTIONS

Which languages are the OpenAI Images examples in?

C#, Python, Java and JavaScript. Every sample runs as pasted and reads its credentials from an environment variable — no key is ever written into the code.

Which package do I install for OpenAI Images?

The samples use openai. The install step on each language tab gives the exact command.

Which OpenAI Images model do these examples use?

gpt-image-2.5-sunburst, checked against the official documentation on 26 September 2026. Model ids change often; if a call returns a model-not-found error, check the current list in the official docs.

Where is the official OpenAI Images documentation?

https://platform.openai.com/docs/guides/image-generation — it is linked at the bottom of this page, and it is the authority whenever it disagrees with a sample here.

ALSO IN IMAGE & VIDEO

The authority

Official OpenAI Images documentation

Model names, pricing and rate limits change faster than any page here can. When this page and the official docs disagree, the official docs are right.

Read the docs ↗

https://platform.openai.com/docs/guides/image-generation

New drops, every week

Free tools & Claude templates, landing regularly.

We keep shipping new free tools, code recipes and Claude Code templates. Follow @freeyantra on Instagram or join the newsletter so you never miss one.

Follow @freeyantra

or get them by email

Double opt-in. Unsubscribe any time. Privacy