定点数Alpha合成中0xff≠1.0的整数运算问题求解
定点数Alpha合成的整数精度问题解决方案
我正在编写兼容C和C++的代码,采用整数数学(定点数)实现Alpha合成,但遇到了0xff无法完全等价于1.0的棘手问题——这在Alpha通道处理中尤为突出。例如(0xff * 0xff) >> 8的计算结果是0xfe,如果对Alpha为0xff、RGB为0xff的纯白像素做预乘Alpha操作,RGB通道会变成0xfe,不再是纯白。
以下是实现Alpha预乘和带预乘Alpha的Alpha合成的示例函数,二者都存在类似精度问题(暂忽略小端RGBA/BGRA的字节序问题):
uint32_t premultiply_alpha(uint32_t color) { uint32_t alpha = ((color>>24) & 0xff); uint32_t rb = color & 0xff00ffU; uint32_t g = color & 0x00ff00U; rb = (rb * alpha) >> 8; g = (g * alpha) >> 8; return (color & 0xff000000) | (rb & 0xff00ff) | (g & 0x00ff00); }
uint32_t rgb_blend(uint32_t background, uint32_t color) { uint32_t alpha = color>>24; uint32_t rb = background & 0xff00ffU; uint32_t g = background & 0x00ff00U; rb = (color & 0xff00ff) + ((0xff - alpha) * rb >> 8); g = (color & 0x00ff00) + ((0xff - alpha) * g >> 8); uint32_t dest_alpha = background>>24; dest_alpha = alpha + dest_alpha - ((alpha*dest_alpha) >> 8); dest_alpha = dest_alpha < 255 ? dest_alpha : 255; return (dest_alpha << 24) | (rb & 0xff00ff) | (g & 0x00ff00); }
第一个函数存在上述的纯白像素预乘后变色问题,第二个函数里的(0xff - alpha)能正确表示0,但无法准确对应1.0。
请问无需通过浮点数转换,这类问题通常有哪些成熟的处理方案?
补充说明
正如John的评论指出,问题核心在于>>8等价于除以0x100而非0xff,因此把移位操作替换为/0xff可以解决问题。由于除数是常量,编译器会利用《Hacker's Delight》第10章的技巧避免使用div指令(实测GCC即使未开启优化也会这么做)。但实践中发现,这种优化下同时处理r和b寄存器存在安全隐患,我仍想了解是否存在「标准」解决方案或通用处理方式。
内容的提问来源于stack exchange,提问作者Harris M Snyder
相关产品推荐
相关产品推荐

