Javascript 画布:遮罩图像并保留其alpha通道?

Javascript 画布:遮罩图像并保留其alpha通道?,javascript,html,canvas,html5-canvas,Javascript,Html,Canvas,Html5 Canvas,以下是我想做的: 获取图像A和图像B。图像B是黑白掩模图像 将图像A的alpha通道替换为图像B的红色通道 在画布上绘制图像C 在图像C的顶部绘制图像A 在第4步之前,一切似乎都正常。图像C根本不可见,而图像A应该是透明的,则为白色 cx.putImageData(imageA, 0, 0); var resultData = cx.getImageData(0, 0, view.width, view.height); for (var h=0; h<resultData.data.l

以下是我想做的:

  • 获取图像A和图像B。图像B是黑白掩模图像
  • 将图像A的alpha通道替换为图像B的红色通道
  • 在画布上绘制图像C
  • 在图像C的顶部绘制图像A
  • 在第4步之前,一切似乎都正常。图像C根本不可见,而图像A应该是透明的,则为白色

    cx.putImageData(imageA, 0, 0);
    var resultData = cx.getImageData(0, 0, view.width, view.height);
    
    for (var h=0; h<resultData.data.length; h+=4) {
        resultData.data[h+3] = imageB.data[h];
    }
    
    cx.putImageData(imageC, 0, 0);
    cx.putImageData(resultData, 0, 0);
    
    cx.putImageData(imageA,0,0);
    var resultData=cx.getImageData(0,0,view.width,view.height);
    
    对于(var h=0;h,因为在步骤4中,您使用的是完全替代像素的
    putImageData
    。您希望在图像C的顶部绘制图像A,因此您不能这样做。相反,您需要使用
    drawImage()

    我们也要这样做:

    cx.putImageData(imageC, 0, 0); // step 3
    // create a new canvas and new context,
    // call that new context ctx2 and canvas can2:
    var can2 = document.createElement('canvas');
    // set can2's width and height, get the context etc...
    ctx2.putImageData(resultData, 0, 0);
    cx.drawImage(can2, 0, 0); // step 4 using drawImage instead of putting image data
    

    Simon是对的:
    putImageData
    方法不注意合成;它只复制像素值。为了得到合成,我们需要使用绘图操作

    我们需要用像素数据处理通道(将红色变成alpha),将更改后的像素数据放入图像,然后使用合成操作获得所需的遮罩

    //copy from one channel to another
    var assignChannel = function(imageData, channelTo, channelFrom) {
      if(channelTo < 0 || channelTo > 3 || channelFrom < 0 || channelFrom > 3) {
        throw new Error("bad channel number");
      }
      if(channelTo == channelFrom)
        return;
      var px = imageData.data;
      for(var i = 0; i < px.length; i += 4) {
        px[i + channelTo] = px[i + channelFrom];
      }
    };
    /**============================================================================ 
      * this function uses 3 or 4 canvases for clarity / pedagogical reasons:
      * redCanvas has our mask image;
      * maskCanvas will be used to store the alpha channel conversion of redCanvas' image;
      * imageCanvas contains the image to be masked;
      * ctx is the context of the canvas to which the masked image will be drawn.
    ============================================================================**/
    var drawOnTopOfRed = function(redCanvas, maskCanvas, imageCanvas, ctx) {
      var redImageData = redCanvas.getContext("2d").getImageData(0, 0, w, h);
    
      //assign the alpha channel
      assignChannel(redImageData, 3, 0);
    
      //write the mask image
      maskCanvas.getContext("2d").putImageData(redImageData, 0, 0);
    
      ctx.save();
    
      //draw the mask
      ctx.globalCompositeOperation = "copy";
      ctx.drawImage(maskCanvas, 0, 0);
    
      //draw the image to be masked, but only where both it
      //and the mask are opaque; see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#compositing for details.
      ctx.globalCompositeOperation = "source-in";
      ctx.drawImage(imageCanvas, 0, 0);
      ctx.restore();
    };
    

    //从一个频道复制到另一个频道
    var assignChannel=函数(imageData、channelTo、channelFrom){
    if(channelTo<0 | | channelTo>3 | | channelFrom<0 | | channelFrom>3){
    抛出新错误(“坏通道号”);
    }
    if(channelTo==channelFrom)
    返回;
    var px=imageData.data;
    对于(变量i=0;i
    一个涂鸦的例子:

    哇,我不知道可以将画布对象作为参数传递给drawImage()。这是可行的,但由于某些原因,drawImage()比putImageData()慢得多,而且因为我需要每隔20-40毫秒绘制一次图像,所以这不是一个完美的解决方案。我做了一些实验,并用两个画布解决了这个问题。putImageData()完全替换像素值,但当我在第一个画布下放置另一个画布时,我可以看到它是透明的。无论如何,感谢您的时间,欣赏它!这很奇怪。使用
    imageData
    几乎总是比使用
    drawImage
    慢得多。这里可能还有其他原因-我可以看到您的完整c吗颂歌?