2017-02-17 78 views
1

如何在图像画布算面积的透明单位像素,我写了这个功能,但我想有一些像另一种方法帆布只得到不透明像素

ctx = getCanvasImg(); 
for (var x = selection.x2 * zoom; x > selection.x1 * zoom; x--) { 
    for (var y = selection.y2 * zoom; y > selection.y1 * zoom; y--) { 
     var pixel = ctx.getImageData(x, y, 1, 1); 
     var data = pixel.data; 
     var rgba = 'rgba(' + data[0] + ',' + data[1] + ',' + data[2] + ',' + (data[3]/255) + ')'; 
     if (data[0] == 0) { 
      countWhite++; 
     } 
    } 
} 
+0

您的解决方案有问题吗? –

回答

5

只要抓住有需要的地区一次:

var idata = ctx.getImageData(startX, startY, widthOfArea, heightOfArea); 

统计所有不透明像素,可以重复使用,而不是Uint32Array

var data = new Uint32Array(idata.data.buffer); 

// little-endian byte order 
for(var i = 0, len = data.length, count = 0; i < len;) { 
    if (data[i++] >>> 24 === 255) count++; // shifts AABBGGRR to 000000AA, then =255? 
} 

// count = number of opaque pixels 

更新:只是为了澄清意见:这假设little-endian CPU架构。现在大多数主流/消费设备都使用这种CPU架构,这通常不是问题。然而,如果你怀疑你的代码会遇到big-endian系统,你必须事先检查它,并在检查中颠倒字节顺序(对于任何使用类型数组视图的视图都要比8位宽,因为它们将使用本机系统建筑)。

要检查字节序的系统上,你可以这样做:

function isLittleEndian() { 
    return new Uint16Array(new Uint8Array([255,0]).buffer)[0] === 255 
} 

如果大端,检查这种方式,而不是使用and面具,而不是位移位:

// big-endian byte order 
for(var i = 0, len = data.length, count = 0; i < len;) { 
    if (data[i++] & 0xff === 255) count++; // masks RRGGBBAA to 000000AA, then =255? 
} 

您始终可以使用DataView s并指定endianess,但在这种情况下,由于存在轻微的开销,这是没有好处的。