回答我自己的问题,我提供了一种将任意图像与黑白图像合并的解决方案。我仍然缺少的是如何为画布的一种颜色设置 Alpha 通道。
我将问题分成几部分并逐个回答。
问题一:如何在不迭代每个像素的情况下将画布转为灰度?
答案:使用混合模式“亮度”将图像绘制到白色画布上
function convertCanvasToGrayscale(canvas){
var tmp = document.createElement('canvas');
tmp.width = canvas.width;
tmp.height = canvas.height;
var tmpctx = tmp.getContext('2d');
// conversion
tmpctx.globalCompositeOperation="source-over"; // default composite value
tmpctx.fillStyle="#FFFFFF";
tmpctx.fillRect(0,0,canvas.width,canvas.height);
tmpctx.globalCompositeOperation="luminosity";
tmpctx.drawImage(canvas,0,0);
// write converted back to canvas
ctx = canvas.getContext('2d');
ctx.globalCompositeOperation="source-over";
ctx.drawImage(tmp, 0, 0);
}
问题2:如何在不迭代每个像素的情况下将灰度画布转换为黑白?
答案:使用颜色#FEFEFE 进行两次颜色减淡混合模式即可完成工作
function convertGrayscaleCanvasToBlackNWhite(canvas){
var ctx = canvas.getContext('2d');
// in case the grayscale conversion is to bulky for ya
// darken the canvas bevore further black'nwhite conversion
//for(var i=0;i<3;i++){
// ctx.globalCompositeOperation = 'multiply';
// ctx.drawImage(canvas, 0, 0);
//}
ctx.globalCompositeOperation = 'color-dodge';
ctx.fillStyle = "rgba(253, 253, 253, 1)";
ctx.beginPath();
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fill();
ctx.globalCompositeOperation = 'color-dodge';
ctx.fillStyle = "rgba(253, 253, 253, 1)";
ctx.beginPath();
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fill();
}
注意:此函数假定您希望黑色区域保持黑色,并且每个非黑色像素都变为白色!因此没有黑色像素的灰度图像将变为全白
我选择这个操作的原因是它在我的情况下效果更好,并且只使用两个混合操作意味着它非常快 - 如果你想让更多的暗像素保持黑色而更多的白色像素变成白色,你可以使用注释的 for 循环变暗事先的图像。因此暗像素会变黑,亮像素会变暗。随着您增加黑色像素的数量,使用颜色减淡将再次完成剩下的工作
问题 3:如何在不迭代每个像素的情况下将黑白画布与另一个画布合并?
答案:使用“乘法”混合模式
function getBlendedImageWithBlackNWhite(canvasimage, canvasbw){
var tmp = document.createElement('canvas');
tmp.width = canvasimage.width;
tmp.height = canvasimage.height;
var tmpctx = tmp.getContext('2d');
tmpctx.globalCompositeOperation = 'source-over';
tmpctx.drawImage(canvasimage, 0, 0);
// multiply means, that every white pixel gets replaced by canvasimage pixel
// and every black pixel will be left black
tmpctx.globalCompositeOperation = 'multiply';
tmpctx.drawImage(canvasbw, 0, 0);
return tmp;
}
问题 4:如何在不迭代每个像素的情况下反转黑白画布?
答案:使用“差异”混合模式
function invertCanvas(canvas){
var ctx = canvas.getContext("2d");
ctx.globalCompositeOperation = 'difference';
ctx.fillStyle = "rgba(255, 255, 255, 1)";
ctx.beginPath();
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fill();
}
现在将canvasimage与canvasmask“合并”
convertCanvasToGrayscale(canvasmask);
convertGrayscaleCanvasToBlackNWhite(canvasmask);
result = getBlendedImageWithBlackNWhite(canvasimage, canvasmask);
关于性能:显然,这些混合模式比修改每个像素要快得多,并且为了更快一点,可以根据需要将所有功能打包到一个功能中并仅回收一个 tmpcanvas - 但这留给读者^^
作为旁注:当您将上面的 getBlendedImageWithBlackNWhite 结果与相同的图像进行比较时,我测试了生成的 png 的大小有何不同,但黑色区域通过迭代每个像素并设置 alpha 通道变得透明
大小上的差异几乎没有,因此如果您真的不需要 alpha 掩码,那么每个黑色像素都应该是透明的信息可能足以进行进一步处理
注意:可以使用 invertCanvas() 函数反转黑白的含义
如果您想了解更多关于我为什么使用这些混合模式或混合模式如何真正起作用的信息
你应该检查它们背后的数学 - 恕我直言,如果你不知道它们是如何工作的,你就无法开发这样的功能:
math behind blend modes
canvas composition standard including a bit math
需要一个例子 - 找出不同之处:http://jsfiddle.net/C3fp4/1/