Superdry Memorandom :-p

旧「superdry memorandum :-D」です

Bitmap quality, banding and dithering

Romain Guyさんが自身のブログで、Android 2.3 (Gingerbread)のBitmap表示品質向上対応について語っている。適当に訳してみた。

AndroidのBitmapエンコード形式には以下の3つが用意されています。

  • RGB_565…昔のAndroidのBitmapエンコード形式。透過できない。16ビット。
  • ARGB_4444…透過できる。16ビット。でも表示が美しくない。
  • ARGB_8888…透過できる。32ビット。美しいけどメモリくう。

しかし、16ビット領域でARGB_8888を表示した場合など、最適なエンコードで表示されないと画像が汚くなります。32ビットの画像は32ビット領域で、16ビットの画像は16ビット領域で、横方向に帯が入ります。

対処法として、例えばRGB_565をPhotoshopなどで事前にディザ加工してきれいに表示する方法があります。しかしこの方法はおすすめしません。ノイズを焼き込んだり、再利用がむずかしいからです。

そこで今までは、Paint.setDither(boolean)とかDrawable.setDither(boolean)とかで、見かけ上きれいな表示を実現してました。

2.3からはすべてのwindowで32ビット表示となります。

  • RGBX_8888…透過しない。32ビット。
  • RGBA_8888…透過できる。32ビット。

画像もすべて32ビット表示。

  • ARGB_8888

適切なビットマップ形式を選択すると実行時のパフォーマンスも向上します。以下は表示実行時間。

16bits 16bits by dither 32bits
ARGB_8888 19ms 10ms 11ms
ARGB_4444 15ms 15ms 14ms
RGB_565 10ms 10ms 13ms

RGB_565が一番互換性に富んでいるのがわかるよね。

空のBitmap作成時とBitmaFactory.Optionsで画像をデコードするとき画像のエンコード形式を選べる。Bitmap.getConfig()で存在するBitmapのエンコード形式もとれる。windowのエンコード形式が知りたければonCreate()でgetWindow().getAttributes().formatを呼べば取得できるので、これらをつかって最適なエンコード形式で最適なパフォーマンスを実現してください。

今回使ったソースコードこちら

今回の記事には関係ないけど、OpenGL Surfaceはその互換性のために16bitsのままらしい…