Background and Format

Background, Transparency and Output Format

background: 'transparent' returns an alpha channel, so it needs output_format: 'png' or 'webp'. In the clear run, 76% of the icon's pixels came back fully transparent, with anti-aliased edges that sit cleanly on any background. opaque forces a filled background and auto lets the model choose (the JPEG run got white). Transparency is in preview on gpt-image-2 86 . Each response echoes the size, quality, background and output_format actually used: log those, not what you asked for.

background: 'transparent' needs PNG or WebP: an icon's alpha channel over three backgrounds, and JPEG's white fillHTMLLive
<!doctype html>
<style>
  body { margin: 0; padding: 8px; background: #fafaf7; font: 12px system-ui, sans-serif; color: #263238; }
  canvas { display: block; max-width: 100%; }
</style>
<p>output_format: <label><input type="radio" name="f" value="png" checked> png</label>
  <label><input type="radio" name="f" value="webp"> webp</label> <label><input type="radio" name="f" value="jpeg"> jpeg</label>
  <span id="out"></span></p>
<canvas id="c" width="600" height="220"></canvas>
<script>
  // The "returned" icon: an open book with a small bird, drawn with transparent surroundings
  const S = 180, icon = document.createElement('canvas');
  icon.width = icon.height = S;
  const g = icon.getContext('2d');
  g.fillStyle = '#1f5f8b';
  g.beginPath();  g.moveTo(20, 120);  g.quadraticCurveTo(55, 100, 90, 120);  g.lineTo(90, 150);
  g.quadraticCurveTo(55, 130, 20, 150);  g.closePath();  g.fill();
  g.beginPath();  g.moveTo(160, 120);  g.quadraticCurveTo(125, 100, 90, 120);  g.lineTo(90, 150);
  g.quadraticCurveTo(125, 130, 160, 150);  g.closePath();  g.fill();
  g.fillStyle = '#e09a10';  g.beginPath();  g.ellipse(95, 88, 26, 20, 0, 0, 7);  g.fill();       // bird
  g.beginPath();  g.arc(115, 70, 12, 0, 7);  g.fill();
  g.fillStyle = '#263238';  g.beginPath();  g.arc(119, 67, 2.5, 0, 7);  g.fill();
  g.fillStyle = '#b5452f';  g.beginPath();  g.moveTo(126, 70);  g.lineTo(136, 73);  g.lineTo(126, 76);  g.fill();

  // Count fully transparent pixels, as the chapter did for the clear run
  const alpha = g.getImageData(0, 0, S, S).data;
  let clear = 0;
  for (let i = 3; i < alpha.length; i += 4) if (alpha[i] === 0) clear++;

  const ctx = document.getElementById('c').getContext('2d');
  function checker(x, y) {
    for (let r = 0; r < S / 12; r++) for (let q = 0; q < S / 12; q++) {
      ctx.fillStyle = (r + q) % 2 ? '#ddd' : '#fff';  ctx.fillRect(x + q * 12, y + r * 12, 12, 12);
    }
  }
  function draw(format) {
    ctx.clearRect(0, 0, 600, 220);
    const backs = [['checkerboard', null], ['cream #fff3e0', '#fff3e0'], ['ink #263238', '#263238']];
    backs.forEach(([name, color], k) => {
      const x = 10 + k * 196, y = 10;
      if (color) { ctx.fillStyle = color;  ctx.fillRect(x, y, S, S); } else checker(x, y);
      // JPEG has no alpha channel: the transparent area arrives filled (white, in the chapter's run)
      if (format === 'jpeg') { ctx.fillStyle = '#ffffff';  ctx.fillRect(x, y, S, S); }
      ctx.drawImage(icon, x, y);
      ctx.fillStyle = '#263238';  ctx.fillText(name, x, 208);
    });
    document.getElementById('out').textContent = format === 'jpeg'
      ? '→ JPEG cannot carry alpha: request background "opaque" (or auto) with it.'
      : `→ ${Math.round(clear / (S * S) * 100)}% of the pixels are fully transparent; edges are anti-aliased.`;
  }
  document.querySelectorAll('input[name=f]').forEach(r => r.onchange = () => draw(r.value));
  draw('png');
</script>