export function makeInPlaceColorConversion()

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;
    }
  };
}