解析BitmapData.getPixel32()返回值因何不准确

事情发展的起因是这样的:BitmapData.getPixel32()返回值不准确,为什么? 网友Norris很热心,他把他的观点写得井井有条:http://www.norris2u4.com/?p=370 。在继续往后阅读前,先看看我的总结,造成 getPixel32() 返回值存在偏差的根本原因是:BitmapData 存储的像素数据并不是各通道(ARGB)的原始数据,而是 RGB 跟 Alpha 通道相乘后的数据。在调用 BitmapData.getPixel32() 方法时,Flash Player 虽然返回的是未经相乘的 ARGB 数据,但这个数据是还原后的 ARGB ,而不是原始 ARGB 。以下例子说明了这一点:

var bmd:BitmapData = new BitmapData(100, 100, true, 0);
bmd.setPixel32(0, 0, 0×44536435); // 把坐标为(0, 0)的点设置颜色值 0×44536435
trace(bmd.getPixel32(0, 0).toString(16)); // 输出 44526534 ,明显有偏差

原始的 ARGB 数据 0×44536435(十六进制):

Alpha = 0×44;(透明通道)
Red_原始 = 0×53;(红通道)
Green_原始 = 0×64;(绿通道)
Blue_原始 = 0×35;(蓝通道)
还原的 ARGB 数据 0×44526534 (十六进制):

Alpha = 0×44;
Red_还原 = 0×52;
Green_还原 = 0×65;
Blue_还原 = 0×34;
可以看得出,只有 Alpha 通道是准确的(始终不变),其余通道都有偏差。这是因为 还原的 ARGB 数据 是从 经过相乘后的 ARGB 数据 中还原过来的:

相乘过程:

原始的 ARGB 数据(0×44536435)在被 BitmapData 存储前都经过相乘,就是 RGB 跟 Alpha 通道相乘(把 Alpha 值转为一个百分比进行计算,这个百分比等于:Alpha/0xFF):

Alpha = 0×44;
Red_相乘 = Red * ( Alpha / 0xFF ) = 0×53 * ( 0×44 / 0xFF ) = 0×16;
Green_相乘 = Green * ( Alpha / 0xFF ) = 0×64 * ( 0×44 / 0xFF ) = 0×1A;
Blue_相乘 = Blue * ( Alpha / 0xFF ) = 0×35 * ( 0×44 / 0xFF ) = 0×0E;
还原过程:

还原过程就相乘过程的逆过程,就是把 RGB 除以 Alpha 通道(同样地,把 Alpha 值转为一个百分比进行计算,这个百分比等于:Alpha/0xFF):

Alpha = 0×44;
Red_还原 = Red_相乘 / ( Alpha / 0xFF ) = 0×16 / ( 0×44 / 0xFF ) = 0×52;
Green_还原 = Green_相乘 / ( Alpha / 0xFF ) = 0×1A / ( 0×44 / 0xFF ) = 0×61;
Blue_还原 = Blue_相乘 / ( Alpha / 0xFF ) = 0×0E / ( 0×44 / 0xFF ) = 0×34;
整个流程:原始数据 -> 相乘数据 -> 还原数据。分别对比 实验数据 和 理论分析数据 :

实验数据:

实际上,调用 getPixel32() 方法后得到:0×44526534
理论分析数据:

按理论分析,调用 getPixel32() 方法后应用得到:0×44526134
分析到现在,还是很郁闷。理论值跟实际值不同(其中红色文字的 Blue 通道不同)。按道理,让 getPixel32() 返回值产生偏差的原因就是以上所述,但,经过痛苦的分析后却又发现 让 getPixel32() 返回值产生偏差的原因不完全是以上所述。

总结:

 一切都是 Adobe Flash Player 的错,而不完全是 Adobe 的错。总之在开发过程中,一定要牢记:别指望 BitmapData 能准确存储每点像素的原始颜色值。最后奉上官方语言参考上的解说:

BitmapData 对象中的所有像素都作为预乘颜色值进行存储。预乘图像像素具有已经与 Alpha 数据相乘的红色、绿色和蓝色通道值。例如,如果 Alpha 值为 0,则 RGB 通道的值也为 0,与它们未经过相乘的值无关。这种丢失数据的情况可能会在执行操作时导致一些问题。所有 BitmapData 方法都采用并返回未经过相乘的值。内部像素表示形式在其作为值返回之前从经过预乘的形式转换为未经过相乘的形式。在设置操作过程中,设置原始图像像素之前,像素值是经过预乘的。

你可能感兴趣的:(bitmap)