簡體   English   中英

將畫布圖像和畫布alpha蒙版合並到dataurl生成的png中

[英]Merge canvas image and canvas alpha mask into dataurl generated png

給定兩個具有相同像素大小的畫布,其中canvas1包含任意圖像(jpg,png等),canvas2包含黑色和非黑色像素。

我想要實現的目標:使用第三個canvas3我想克隆canvas1並且每個黑色canvas2像素(可能包括黑度閾值)在canvas3中是透明的

我已經有了這樣一個有效的解決方案:

canvas3context.drawImage(canvas1,0,0);
var c3img = canvas3context.getImageData(0,0,canvas3.width,canvas3.height);
var c2img = canvas2context.getImageData(0,0,canvas2.width,canvas2.height);
loop(){
    if(c2img i-th,i+1-th,i+2-th pixel is lower than threshold)
      set c3img.data[i]=c3img.data[i+1]=c3img.data[i+2]=c3img.data[i+3]=0
}

上面(偽)代碼的問題是,它很慢所以我的問題是:任何人都可以分享一個想法如何顯着提高速度? 我想到了webgl,但我從來沒有使用它 - 所以我不知道着色器或這需要的工具或術語。 另一個想法是,也許我可以非常快速地將canvas2轉換為黑白(不僅僅是像上面那樣修改循環中的每個像素)並使用混合模式來生成透明像素

任何幫助都非常感謝

回答我自己的問題,我提供了一個解決方案,將任意圖像與黑白圖像合並。 我還缺少的是如何為一種顏色的畫布設置alpha通道。

我將這個問題分成幾部分並分別回答。

問題1:如何在不迭代每個像素的情況下將畫布轉換為灰度?

答案:將圖像繪制到具有混合模式“光度”的白色畫布上

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

注意:此功能假設您希望黑色區域變黑並且每個非黑色像素變為白色! 因此,沒有黑色像素的灰度圖像將變為完全白色我選擇此操作的原因是它在我的情況下工作得更好並且僅使用兩個混合操作意味着它非常快 - 如果你想要更暗的像素被留下黑色等等白色像素變為白色,您可以使用注釋的循環預先使圖像變暗。 因此,暗像素將變為黑色,更亮的像素變得更暗。 當您使用顏色減少增加黑色像素的數量時,將再次執行剩余的工作

問題3:如何在不迭代每個像素的情況下將黑白畫布與另一個畫布合並?

答案:使用'multiply'混合模式

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-mask,每個黑色像素都是透明的信息可能足以進一步處理

注意:可以使用invertCanvas()函數反轉黑白的含義

如果你想了解更多為什么我使用這些混合模式或混合模式如何真正起作用你應該檢查它們背后的數學 - 如果你不知道它們是如何工作的話,你就無法開發這樣的函數: 數學背后混合模式 畫布組成標准包括一點數學

需要一個例子 - 發現差異: http//jsfiddle.net/C3fp4/1/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM