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:
I would like to produce this image where the RGB channels are unchanged:
Note that there are a range of alpha values in the original and final images.
We can use
globalCompositeOperation to invert the color with alpha.
Source image with radial gradient.
Result image with inverted alpha.
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)');