HTML、Javascript Canvas 图像并使用 alpha 蒙版图像使其透明

HTML, Javascript Canvas image and make transparent with alpha mask image

我是 html 中 canvas 的新手,我有两张图片,第一张是普通的 jpeg 图片,第二张是用 alpha(黑白)编辑过的,所以问题是我想应用第二张图片的 alpha 蒙版使第一张透明。

图片https://i.stack.imgur.com/fj5mB.jpg

Alpha 蒙版 https://i.stack.imgur.com/5lDgg.png

这是我找到并尝试修改但不起作用的代码。

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

var image = new Image();
image.onload = function() {
    ctx.drawImage(image, 0, 0);
};
image.src = 'image.jpg';

var maskCanvas = document.createElement('canvas');
maskCanvas.width = canvas.width;
maskCanvas.height = canvas.height;
var maskCtx = maskCanvas.getContext('2d');

var mask = new Image();
mask.onload = function() {
    maskCtx.drawImage(mask, 0, 0);
};
mask.src = 'mask.png';

var idata = maskCtx.getImageData(0, 0, maskCanvas.width, maskCanvas.height);
var data32 = new Uint32Array(idata.data.buffer);
var i = 0, len = data32.length;

while(i < len) {
    data32[i] = data32[i++] << 8;
}
ctx.putImageData(idata, 0, 0);

问题的第一部分是图片加载不是同步过程。这意味着如果 javascript 解释器到达您的代码的这一部分:

ctx.putImageData(idata, 0, 0);

所需的两个图像可能尚未加载,因此两个 canvases 只是空的。 您可以通过在 onload 函数中并在代码的最后一行之前插入一些 console.log() 语句来简单地验证这一点。

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

var image = new Image();
image.onload = function() {
  ctx.drawImage(image, 0, 0);
  console.log("image loaded");
};
image.src = 'https://i.stack.imgur.com/fj5mB.jpg';

var maskCanvas = document.createElement('canvas');
maskCanvas.width = canvas.width;
maskCanvas.height = canvas.height;
var maskCtx = maskCanvas.getContext('2d');

var mask = new Image();
mask.onload = function() {
  maskCtx.drawImage(mask, 0, 0);
  console.log("mask loaded");
};
mask.src = 'https://i.stack.imgur.com/5lDgg.png';

var idata = maskCtx.getImageData(0, 0, maskCanvas.width, maskCanvas.height);
var data32 = new Uint32Array(idata.data.buffer);
var i = 0,
  len = data32.length;

while (i < len) {
  data32[i] = data32[i++] << 8;
}
console.log("drawing");
ctx.putImageData(idata, 0, 0);
<canvas id="canvas" width="400" height="400"></canvas>

这将记录

drawing
image loaded
mask loaded

到控制台并清楚地显示它正在绘制,然后才能绘制任何东西。 一种可能的补救措施是使用全局计数器,它会随着每个图像的加载而递增。一到2就调用绘图操作。

问题的第二部分是您的代码根本不完整。这只是两步过程中的第一步 - 将遮罩图像变成实际的 alpha 遮罩,因为它只是一个具有完全不透明 alpha 通道数据的黑白图像。第二步涉及使用蒙版隐藏部分原始图像。这可以通过将上下文的 globalCompositeOperation 更改为 destination-in 并将蒙版绘制到图像的 canvas.

上来完成

完整示例如下:

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

var image = new Image();
image.crossOrigin = "Anonymous";

var imagesLoaded = 0;

image.onload = function() {
  imagesLoaded++;
  ctx.drawImage(image, 0, 0);
  if (imagesLoaded == 2) {
    process();
  }
};
image.src = 'https://api.codetabs.com/v1/proxy?quest=https://i.stack.imgur.com/fj5mB.jpg';

var maskCanvas = document.createElement('canvas');
maskCanvas.width = canvas.width;
maskCanvas.height = canvas.height;
var maskCtx = maskCanvas.getContext('2d');

var mask = new Image();
mask.crossOrigin = "Anonymous";
mask.onload = function() {
  imagesLoaded++;
  maskCtx.drawImage(mask, 0, 0);
  if (imagesLoaded == 2) {
    process();
  }
};
mask.src = 'https://api.codetabs.com/v1/proxy?quest=https://i.stack.imgur.com/5lDgg.png';

function process() {
  var idata = maskCtx.getImageData(0, 0, maskCanvas.width, maskCanvas.height);
  var data32 = new Uint32Array(idata.data.buffer);
  var i = 0,
    len = data32.length;

  while (i < len) {

    data32[i] = data32[i++] << 8;
  }
  maskCtx.putImageData(idata, 0, 0);
  ctx.globalCompositeOperation = "destination-in";
  ctx.drawImage(maskCanvas, 0, 0);
}
<canvas id="canvas" width="400" height="400"></canvas>