Invert alpha value of a canvas image

What is the best way to invert the alpha channel of a canvas’ content?

I have seen solutions such as this one where you can go through pixel-by-pixel and re-map the alpha value, but this is an expensive operation, and I was hoping that there might be something more performant (or better practice) method, such as a way of using context.filter or something similar to do this.

As a simplified example, given this image, where all pixels have the same RGB channel (black) values but varying alpha channel values:

enter image description here

I would like to produce this image where the RGB channels are unchanged:

enter image description here

Note that there are a range of alpha values in the original and final images.

Answer

We can use globalCompositeOperation to invert the color with alpha.

  1. Source image with radial gradient.

  2. Result image with inverted alpha.

  3. Checking the result: drawing result image on top of yellow background

const src_canvas = document.querySelector('canvas#source');
const src_ctx = src_canvas.getContext('2d');

const result_canvas = document.querySelector('canvas#result');
const result_ctx = result_canvas.getContext('2d');

const check_canvas = document.querySelector('canvas#check');
const check_ctx = check_canvas.getContext('2d');

const w = src_canvas.width = result_canvas.width = check_canvas.width = 180;
const h = src_canvas.height = result_canvas.height = check_canvas.height = 180;

const gradient = src_ctx.createRadialGradient(w/2,h/2,0, w/2,h/2,w/3);
gradient.addColorStop(0, 'rgba(0,0,0,1)');
gradient.addColorStop(1, 'rgba(0,0,0,0)');

src_ctx.fillStyle = gradient;
src_ctx.fillRect(0,0,w,h);

result_ctx.drawImage(src_canvas,0,0);
result_ctx.globalCompositeOperation = 'source-out';
result_ctx.fillRect(0,0,w,h); // uses default fillStyle = 'black'

check_ctx.fillStyle = 'yellow'; // to check if the figure isn't fully opaque
check_ctx.fillRect(0,0,w,h);

check_ctx.drawImage(result_canvas,0,0);
<canvas id="source"></canvas>
<canvas id="result"></canvas>
<canvas id="check"></canvas>

It works only if the base color of gradient (your transparent image) and the color for fillStyle after applying globalCompositeOperation="source-out" is the same. If you have different colors in your transparent image – it wouldn’t work.

I have black as base color of transparent image rgba(0,0,0,...) and black color as default for filling when result_ctx.fillRect(0,0,w,h). If, for example, base color of source image would be red ('rgba(255,0,0,...)') then we had to explicitly define it before fillRect() -> result_ctx.fillStyle = 'red' ('rgb(255,0,0)');