in src/webgpu/util/color_space_conversion.ts [197:249]
export function makeInPlaceColorConversion({
srcPremultiplied,
dstPremultiplied,
srcColorSpace = 'srgb',
dstColorSpace = 'srgb',
}: {
srcPremultiplied: boolean;
dstPremultiplied: boolean;
srcColorSpace?: PredefinedColorSpace;
dstColorSpace?: PredefinedColorSpace;
}): InPlaceColorConversion {
const requireColorSpaceConversion = srcColorSpace !== dstColorSpace;
const requireUnpremultiplyAlpha =
srcPremultiplied && (requireColorSpaceConversion || srcPremultiplied !== dstPremultiplied);
const requirePremultiplyAlpha =
dstPremultiplied && (requireColorSpaceConversion || srcPremultiplied !== dstPremultiplied);
return rgba => {
assert(rgba.A >= 0.0 && rgba.A <= 1.0, 'rgba.A out of bounds');
if (requireUnpremultiplyAlpha) {
if (rgba.A !== 0.0) {
rgba.R /= rgba.A;
rgba.G /= rgba.A;
rgba.B /= rgba.A;
} else {
assert(
rgba.R === 0.0 && rgba.G === 0.0 && rgba.B === 0.0 && rgba.A === 0.0,
'Unpremultiply ops with alpha value 0.0 requires all channels equals to 0.0'
);
}
}
// It's possible RGB are now > 1.
// This technically represents colors outside the src gamut, so no clamping yet.
if (requireColorSpaceConversion) {
if (srcColorSpace === 'display-p3' && dstColorSpace === 'srgb') {
Object.assign(rgba, displayP3ToSrgb(rgba));
} else if (srcColorSpace === 'srgb' && dstColorSpace === 'display-p3') {
Object.assign(rgba, srgbToDisplayP3(rgba));
} else {
unreachable();
}
}
// Now RGB may also be negative if the src gamut is larger than the dst gamut.
if (requirePremultiplyAlpha) {
rgba.R *= rgba.A;
rgba.G *= rgba.A;
rgba.B *= rgba.A;
}
};
}