Skip to content

Instantly share code, notes, and snippets.

@greggman
Created December 23, 2025 10:29
Show Gist options
  • Select an option

  • Save greggman/2359aec968f72ec4b24f69c712753d59 to your computer and use it in GitHub Desktop.

Select an option

Save greggman/2359aec968f72ec4b24f69c712753d59 to your computer and use it in GitHub Desktop.
Load Image with Alpha (via Image)
:root {
color-scheme: dark light;
}
canvas {
background-color: #404040;
background-image:
linear-gradient(45deg, #808080 25%, transparent 25%),
linear-gradient(-45deg, #808080 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, #808080 75%),
linear-gradient(-45deg, transparent 75%, #808080 75%);
background-size: 32px 32px;
background-position: 0 0, 0 16px, 16px -16px, -16px 0px;
}
/*bug-in-github-api-content-can-not-be-empty*/
async function readPNG_RGBA(url) {
// 1. Init WebGPU
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
// 2. Fetch + decode PNG (NO color conversion, NO premultiply)
const bmp = new Image();
bmp.crossOrigin = '';
bmp.src = url;
await bmp.decode();
const w = bmp.width;
const h = bmp.height;
// 3. Create texture
const texture = device.createTexture({
size: [w, h],
format: "rgba8unorm-srgb",
usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT
});
// 4. Upload bitmap to texture
device.queue.copyExternalImageToTexture(
{ source: bmp },
{ texture },
[w, h]
);
// 5. Create readback buffer
const bytesPerRow = ((w * 4 + 255) & ~255); // WebGPU row alignment
const buffer = device.createBuffer({
size: bytesPerRow * h,
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
});
// 6. Copy texture → buffer
const encoder = device.createCommandEncoder();
encoder.copyTextureToBuffer(
{ texture },
{ buffer, bytesPerRow },
[w, h]
);
device.queue.submit([encoder.finish()]);
// 7. Map + read data
await buffer.mapAsync(GPUMapMode.READ);
const mapped = new Uint8Array(buffer.getMappedRange());
console.log("Top-left RGBA:", mapped[0], mapped[1], mapped[2], mapped[3]);
// draw it to a canvas
const canvas = document.createElement('canvas');
const context = canvas.getContext('webgpu');
context.configure({
device,
format: 'rgba8unorm',
usage: GPUTextureUsage.COPY_DST,
alphaMode: 'premultiplied',
});
canvas.width = w;
canvas.height = w;
document.body.appendChild(canvas);
{
const canvasTexture = context.getCurrentTexture();
const encoder = device.createCommandEncoder();
encoder.copyTextureToTexture(
{ texture },
{ texture: canvasTexture },
[w, h],
);
device.queue.submit([encoder.finish()]);
}
}
readPNG_RGBA("https://greggman.github.io/doodles/images/FurBaseColorAlpha.png");
{"name":"Load Image with Alpha (via Image)","settings":{},"filenames":["index.html","index.css","index.js"]}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment