Холст: замаскировать изображение и сохранить его альфа-канал? - PullRequest
11 голосов
/ 27 января 2012

Вот что я пытаюсь сделать:

  1. Получите изображение A и изображение B. Изображение B представляет собой черно-белое изображение маски.
  2. Заменить альфа-канал изображения A красным каналом изображения B.
  3. Нарисуйте изображение С. на холсте.
  4. Нарисуйте изображение A поверх изображения C.

Все выглядит нормально до шага 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);

Ответы [ 2 ]

17 голосов
/ 27 января 2012

Саймон прав: метод putImageData не обращает никакого внимания на композитинг;он просто копирует значения пикселей.Чтобы получить композитинг, нам нужно использовать операции рисования.

Нам нужно связываться с каналами (превратить красный в альфа-канал) с данными пикселей, поместить эти измененные данные пикселей в изображение и затем используйте составную операцию для получения желаемой маскировки.

Kinda lame

//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();
};

jsfiddle пример

Рисунок спример:

Kinda lame about the same

2 голосов
/ 27 января 2012

Потому что на шаге 4 вы используете putImageData, который отлично заменяет пиксели.Вы хотите нарисовать изображение A поверх изображения C, поэтому вы не можете этого сделать.Вместо этого вы захотите использовать 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...