ROMAIN GUY讲位图质量

今天记录一篇Romain Guy大佬将位图质量(bitmap quality)、条纹(banding)与抖色(dithering)处理的文章,从中可以看到Android2.3.x以后系统对位图的渲染方式。

早期的Android设备受限于存储器和计算能力没办法提供较高质量的不透明位图渲染,所以只能采用16位D565的surface。这种做法效果还行,但遇到原始bitmap以其他格式编码(如ARGB8888或ARGB4444)时就会出现严重的视觉失真(visual artifacts)。上述两种图像编码格式都含有alpha通道,只是颜色表现的精度不同。其中ARGB8888由于每个像素都需要32位表示,所以需要消耗2倍的内存,它是加载拥有alpha通道位图的默认格式(PNG图片)。如果不是特别需要,请别用ARGB4444,否则后果很严重。

为了演示位图色深对效果的影响,RG自己做了一个apk,包含两个activities:一个是32位,一个是16位的。在任意一个activity中,用户都可以在上述三种格式中自由切换,还测试抖色处理的效果。最终效果如下图:

3种颜色编码格式的效果比较

为了更好的比较,可以看看这三附图左上角的灰度渐变部分,如下图

灰度渐变比较

从上图可以清晰的看出,灰度渐变过程中存在三类失真:条纹、低分辨率以及抖色。需要说明的是,以上三图都是来源于同一幅位图,在加载过程中调用BitmapFactory.Options.inPreferredConfig处理。对于第一张图ARGB8888,可以看出明显的线性条纹(wired bands),同时还能看到这些条纹上有一些偏绿,这是由于8位的色深被压缩到5/6位的结果。第二张ARGB4444的图也有类似的现象,原因是由于将4位色深扩展到5/6位。而且在ARGB4444的图上还能明显看到抖色现象。最后,第三张D565的图上可以看到明显的抖色现象。

不幸的是,这就是Android2.3以前的默认情况。幸运的是一般情况下用户看不出来,除非是在显示精确的色彩渐变或者某些特殊类型的图片。当然也有办法对付这种情况,比如将不透明的D565图片先用高级的PS抖色滤镜处理一下。但这么做会在原始图片中bake noise,破坏原图,使之无法重用,所以不推荐。还有一种办法,就是对32位ARGB8888图像做抖色处理,使之在16位的窗口中表现得更好,如下图:

使用抖色处理的32位图片在16位窗口中的显示情况

这样就基本看不出原有的恶心的条纹了,程序员需要做的仅仅是将dithering flag置位。当然这也并非完美,真正的解决方式还得在32位的surface中绘制32位的图像,这就是Android2.3默认支持的了,效果如下图:

在32位surface上显示32位的位图

下图对比前期在16位surface上绘制抖色处理过的32位图与直接在32位surface上绘制原生32位图的效果对比。

在16位surface上绘制经过抖色处理的32位图片与在32位surface上绘制原生32位图片的对比

由上图可以明显看出抖色效果会产生一些特殊的噪音以迷惑肉眼,使之产生光滑渐变的感觉。而32位直接显示就完全没有任何失真,提供了最优秀的显示效果。这也是Android2.3默认如此显示的原因。

程序员还需要注意的是,选择不同的位图格式还将影响运行性能。比如在32位surface上显示16位的图片需要经过特别的转化,而这需要消耗CPU时间。下图显示了各类转化的开销:

各种格式转化的开销

由上图可以明显看出,采用搭配的显示是最高效的(32位的ARGB8888直接显示在32位的surface上,16位的D565直接显示在16位的surface上)。因此程序员最好能时刻检查代码确认这两者搭配。程序员可以在生成一张位图或者解码一张位图时设置该位图的格式。还可以通过Bitmap.getConfig()获得图片格式的信息。也可以在onCreate时调用getWindow().getAttributes().format来获得窗口格式信息。

最后补充RG的一张PPT和他的说明

关于Android2.3的显示

需要说明的是:

  • 应用可以使用32位的window(比如透明window);
  • 应用可以强行用32位方式加载位图;
  • 应用可以避免条纹失真;
  • 出于兼容性考虑,OpenGL窗口还是采用16位;
  • OpenGL窗口也可以使用32位。
Advertisements

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s