2013/04/09

画像の切り抜き(トリミング)なら BitmapRegionDecoder が超便利

Android で画像を読み込むのは結構厄介。一つの ImageView に読み込むならそんなに悩まないけど、 ListView やら GridView やらで画像を扱うとすぐ OutOfMemory って怒られる。限られた資源、守りたいですね。

基本は BitmapFactory.Options.inJustDecodeBounds = true にして、画像の情報だけを とって BitmapFactory.Options.inSampleSize を適切にしてあげて全体を無難に読み込む。そうじゃなくて、大きな画像の一部を切り抜いてもいいんじゃないかと。そんな画像切り抜き BitmapRegionDecoder クラスというのがあります。


とりあえず

サンプルは Github に上げた。

読み込み

画像の読み込みはバックグラウンドで行うのが基本。AsyncTaskLoader で行なっている。

例では assets にある画像ファイルを読み込んで表示しようとしています。読み込んだ画像よりも Rect のサイズが大きいと例外になると思いきや、はみ出した部分は真っ黒で塗りつぶされた画像が出来上がる。綺麗にやろうとしたらちゃんとサイズを見たほうがいいと思う。

そもそも画像をくり抜こうとしたら Bitmap  作って そこから Canvas 作って Rect 作ってと・・・意外にめんどい。しかも メモリ節約のために小さく切り抜くのにあたらに Bitmap 作るなんて本末転倒。そこはさくっと BitmapRegionDecoder で仕上げるのが吉。

ただし、BitmapRegionDecoder は API Level 10 以上。Froyo[1] Gingerbread (API Level 9,  < Android OS 2.3.3) には対応していません。Android OS 1.6, 2.2 以上がターゲットのアプリには使えないことになります。 まあ、今なら Gingerbread (API Level 10,  >= Android OS 2.3.3)もしくは ICS 以降をターゲットにするでしょうから、全く問題ない範囲だと思います。

無駄にハマったこと

BitmapFactory.Options.inJustDecodeBounds = true で必要な InputStream と BitmapFactory.Options.inJustDecodeBounds = false で実際に読み込む時の InputStream。同じ物を使いまわすとデコードできません。BitmapRegionDecoder#decodeRegion() の場合は
java.io.IOException: Image format not supported
の IOException が出ます。IOException でそのメッセージですか、そうですか・・・。InputStream は別個に作成しましょう。


修正

[1] API Level 9 は初期 Gingerbread でした。G+ にてご指摘頂きまして、ありがとうございます。