加快HTML5 Canvas像素渲染速度

Eva*_*edy 5 javascript html5 canvas color-blending

我正在设计一个在HTML5 Canvas元素上运行的Photoshop风格的Web应用程序.该程序运行良好,速度非常快,直到我将混合模式添加到等式中.我通过将每个画布元素合并为一个并使用从底部画布开始的右混合模式组合每个画布的每个像素来实现混合模式.

for (int i=0; i<width*height*4; i+=4) {
    var base = [layer[0][i],layer[0][i+1],layer[0][i+2],layer[0][i+3]];
    var nextLayerPixel = [layer[1][i],layer[1][i+1],layer[1][i+2],layer[1][i+3]];
    //Apply first blend between first and second layer
    basePixel = blend(base,nextLayerPixel);
    for(int j=0;j+1 != layer.length;j++){
        //Apply subsequent blends here to basePixel
        nextLayerPixel = [layer[j+1][i],layer[j+1][i+1],layer[j+1][i+2],layer[j+1][i+3]];
        basePixel = blend(basePixel,nextLayerPixel);
   }
   pixels[i] = base[0];
   pixels[i+1] = base[1];
   pixels[i+2] = base[2];
   pixels[i+3] = base[3];
}
canvas.getContext('2d').putImageData(imgData,x,y);
Run Code Online (Sandbox Code Playgroud)

随着它调用混合不同的混合模式.我的"普通"混合模式如下:

var blend = function(base,blend) {
    var fgAlpha = blend[3]/255;
    var bgAlpha = (1-blend[3]/255)*base[3]/255;
    blend[0] = (blend[0]*fgAlpha+base[0]*bgAlpha);
    blend[1] = (blend[1]*fgAlpha+base[1]*bgAlpha);
    blend[2] = (blend[2]*fgAlpha+base[2]*bgAlpha);
    blend[3] = ((blend[3]/255+base[3])-(blend[3]/255*base[3]))*255;
    return blend;
}
Run Code Online (Sandbox Code Playgroud)

我的测试结果是Chrome(在测试的浏览器中产生了一些最佳效果)是在画布620x385(238,700像素)上将三层混合在一起的大约400毫秒.

这是一个非常小的实现,因为大多数项目的大小会更大,并且包含更多层,这将使执行时间在此方法下飙升.

我想知道是否有更快的方法将两个画布上下文与混合模式组合而不必遍历每个像素.

Ber*_*rgi 3

不要创建这么多的 4 值数组,使用现有内存时它应该会快得多。另外,您可能想在数组上使用该reduce函数layer,这似乎正是您所需要的。然而,根本不使用任何函数可能会更快——无需创建执行上下文。以下代码将仅针对每个图层调用混合函数,而不是每个像素 * 图层。

var layer = [...]; // an array of CanvasPixelArrays
var base = imgData.data; // the base CanvasPixelArray whose values will be changed
                         // if you don't have one, copy layer[0]
layer.reduce(blend, base); // returns the base, on which all layers are blended
canvas.getContext('2d').putImageData(imgData, x, y);

function blend(base, pixel) {
// blends the pixel array into the base array and returns base
    for (int i=0; i<width*height*4; i+=4) {
        var fgAlpha = pixel[i+3]/255,
            bgAlpha = (1-pixel[i+3]/255)*fgAlpha;
        base[i  ] = (pixel[i  ]*fgAlpha+base[i  ]*bgAlpha);
        base[i+1] = (pixel[i+1]*fgAlpha+base[i+1]*bgAlpha);
        base[i+2] = (pixel[i+2]*fgAlpha+base[i+2]*bgAlpha);
        base[i+3] = ((fgAlpha+base[i+3])-(fgAlpha*base[i+3]))*255;
//                           ^ this seems wrong, but I don't know how to fix it
    }
    return base;
}
Run Code Online (Sandbox Code Playgroud)

替代解决方案:根本不要在 javascript 中将各层混合在一起。只需将画布绝对放置在彼此之上并给它们一个 CSS 即可opacity。这应该会大大加快显示速度。只是我不确定这是否可以与您的其他效果一起使用,如果它们需要应用于多个图层。