v155 · canvas color spaces

Linear-light gradients

A canvas gradient interpolates in the canvas's own colour space. In the default gamma-encoded sRGB store, the halfway point between red and green is computed on encoded bytes — and comes out dark and muddy, because the encoding is not proportional to light. Give the canvas an srgb-linear backing store and the same two stops blend the way photons do.

Ships in Chrome 155 (--enable-blink-features=ColorSpacePredefinedLinearSpaces on earlier builds). Where the linear backing store is unavailable, the second panel is a clearly-labelled JavaScript reference rendering — the linear-light interpolation computed pixel-by-pixel in script and gamma-encoded for display. It shows the math this feature moves into the browser; it is not the native surface, and the label on the panel says which one you are looking at.

The same two stops, two interpolation domains

Gamma-encoded sRGB store (the default)

native canvas

Linear-light store (colorSpace: "srgb-linear")

checking…

the API

// The only change is the context setting — the drawing code is identical.
const ctx = canvas.getContext("2d", { colorSpace: "srgb-linear" });
const g = ctx.createLinearGradient(0, 0, w, 0);
g.addColorStop(0, "red");
g.addColorStop(1, "rgb(0 200 0)");
ctx.fillStyle = g;
ctx.fillRect(0, 0, w, h);
// Interpolation now happens on linear-light values.
// The browser converts to the display's space when painting the element.

see also