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

use*_*521 3 javascript canvas

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

小智 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
}
Run Code Online (Sandbox Code Playgroud)

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

要检查这些情况,你只需要检查alpha通道,你可以简单地修改上面的内容,使用AND掩码过滤掉颜色数据,或者将alpha通道位移过来,将其他位推出 - 我们在非0值之后的情况.

由于这是小端(LSB)格式(如今在大多数主流计算机上),因此组件的顺序为ABGR(0xAABBGGRR),因此我们可以执行以下任一操作:

u32[i] & 0xff000000
Run Code Online (Sandbox Code Playgroud)

或者使用shift(在这种情况下,符号并不重要,但我个人更喜欢使用无符号shift(>>>而不是>>),当我处理无符号数时):

u32[i]>>>24
Run Code Online (Sandbox Code Playgroud)

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

取与

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
}
Run Code Online (Sandbox Code Playgroud)

比特移位

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
}
Run Code Online (Sandbox Code Playgroud)

更新:

加快技巧

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

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

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

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
}
Run Code Online (Sandbox Code Playgroud)