检查Javascript中区域中的所有像素是否都为空?

时间:2015-03-17 02:35:44

标签: javascript canvas

我有2D画布,其中绘制了一些东西,我想知道区域中的所有像素(rect - x,y,w,h)是否都是空的/完全透明的?我知道这可以用getImageData完成,但有更快的方法吗?我正在编写一个简单的java脚本图像打包器,我希望从最终工作表中排除空图像。

1 个答案:

答案 0 :(得分:6)

读取像素的唯一方法是使用getImageData(),但您可以使用与默认Uint8ClampedArray不同的视图加快此类检查,例如允许Uint32Array你每次迭代读取一个像素:

function isEmpty(ctx, x, y, w, h) {

    var idata = ctx.getImageData(x, y, w, h),      // needed as usual ...
        u32 = new Uint32Array(idata.data.buffer),  // reads 1x uint32 instead of 4x uint8
        i = 0, len = u32.length;

    while(i < len) if (u32[i++]) return false;     // if !== 0 return false, not empty
    return true                                    // all empty, all OK
}

但是,这不能用于检查透明度。即使像素是完全透明的,也可能存在其他通道中的颜色数据。例如,这会产生一个不可见的像素:rgba(255,128,0,0)isEmpty()会报告该区域非空,即使该像素不可见。

要检查这些情况,您只需要检查Alpha通道,并且您可以简单地修改上述内容以使用AND掩码过滤掉颜色数据,或者将Alpha通道位移过来,推动另一个位出 - 在任何一种情况下,我们都在非0值之后。

由于这是little-endian(LSB)格式(如今在大多数主流计算机上),组件的顺序为ABGR(0xAABBGGRR),因此我们可以这样做:

u32[i] & 0xff000000

或使用shift(在这种情况下,符号无关紧要,但我个人更喜欢使用无符号移位(&gt;&gt;&gt;而不是&gt;&gt;)当我处理无符号数时):

u32[i]>>>24

性能方面没有什么区别,我猜想如果有的话,ANDing会稍快一点:

<强> AND运算

function isTransparent(ctx, x, y, w, h) {

    var idata = ctx.getImageData(x, y, w, h),       // needed as usual ...
        u32 = new Uint32Array(idata.data.buffer),   // reads 1x uint32 instead of 4x bytes
        i = 0, len = u32.length;

    while(i < len) if (u32[i++] & 0xff000000) return false; // not transparent?
    return true                                     // all transparent, all OK
}

<强>位移

function isTransparent(ctx, x, y, w, h) {

    var idata = ctx.getImageData(x, y, w, h),       // needed as usual ...
        u32 = new Uint32Array(idata.data.buffer),   // reads 1x uint32 instead of 4x bytes
        i = 0, len = u32.length;

    while(i < len) if (u32[i++]>>>24) return false; // not transparent?
    return true                                     // all transparent, all OK
}

<强>更新

加速技巧

如果你知道你检查的数据至少有一些大小,比如2x2像素,你也可以跳过每隔一个像素,甚至每隔一行来提高速度:

while(i < len) if (u32[(i += 2)]>>>24) return false; // skips every 2. pixel

对于行,您需要两个迭代器:

while(i < len) {
    var endLine = i + width, p = i;  // p in case you deal with odd widths
    while(p < endLine) if (u32[(p += 2)]>>>24) return false; // skip every 2. pixel
    i += width * 2;  // skip a line
}