トップAndroid Java > Canvas#drawBitmapを使いこなそう

Canvas#drawBitmapを使いこなそう

drawBitmapの主な使い方

void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)
指定されたビットマップを描画し、自動的にスケーリング/変換して、宛先の四角形を塗りつぶします。
void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint)
指定されたビットマップを描画し、自動的にスケーリング/変換して、宛先の四角形を塗りつぶします。
void drawBitmap(Bitmap bitmap, float left, float top, Paint paint)
現在のマトリックスによって変換された指定されたペイントを使用して、指定されたビットマップを (x,y) に左上隅で描画します。

地図アプリMapでの使い方

タイル地図画像データの拡大表示

zoom 15の皇居を中心とした地図を下に示す。この地図では、森林と水域(堀、川など)しか描画していない。黒線はタイルの境界線を表す。 全体が表示されているタイルは2枚だけであるが、全体で12タイルの表示が行われている。

タイル画像地図データはパソコン用に作られており、サイズは 256x256画素である。スマホは高精細なため、これを 3x3 倍して 768x768 画素に拡大してスマホ画面に表示している。Rect r256 は 256x256画素であり、Rect rPX は 768x768画素である。

タイル毎にスマホ画面(Canvas canvas)上の位置は異なるため、この位置計算が下のプログラムの主な仕事である。

    void drawBitmap(Canvas canvas, Bitmap bmp, int xoff, int yoff) {
        int xo256 = xoff * 256 / PX;
        int yo256 = yoff * 256 / PX;
        r256.set(xoff < 0 ? -xo256 : 0, yoff < 0 ? -yo256 : 0,
                xoff + PX < W ? 256 : (int)((W-xoff) * 256.0 / PX),
                yoff + PX < H ? 256 : (int)((H-yoff) * 256.0 / PX));
        rPX.set(Math.max(xoff, 0), Math.max(yoff, 0),
                Math.min(xoff + PX, W), Math.min(yoff + PX, H));
        canvas.drawBitmap(bmp, r256, rPX, paintCanvas);
    }

森林、水域等ポリゴンの描画

森林、水域等ポリゴンは Graphics#Path にポリゴンの頂点座標を登録して、 Canvas#drawPath メソッドを使って、塗りつぶす。

同じ Canvas のメソッドではあるが、このページの主題ではいので、詳細はここでは省く。

パターンによる塗りつぶし

森林には葉っぱアイコンを散りばめている。このようなパターンによる塗りつぶしは Canvas#drawPathでは行えない。

ここが PorterDuff演算の出番である。 以前から、PorterDuff演算の存在は知っていたが、ネットに分かりやすい事例がないため、 これまで地図アプリでの見送っていた。

地図アプリを再構築するに当たり、PorterDuff演算を使ってみた。 分かってしまえば、実に簡単である。ネットに分かりやすい事例がないことが最大の問題であった。

256x256画素のパターン Bitmapデータは予め作っておく。 これは PorterDuff演算を使わない自前プログラムのときとほぼ同じである。

    void fillPolygon(Canvas canvas, TileToRender tile, Paint paint, Bitmap pattern) {
        if (!fIntersect) return;
        tile.cvWork.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);    // DST
        fillPolygon(tile.cvWork, tile, paint);                              // polygonをcolorで塗りつぶし
        tile.cvWork.drawBitmap(pattern, rect, rect, tile.pPorterDuffSRC_ATOP);
        canvas.drawBitmap(tile.bmpWork, rect, rect, null);
    }

パターン画像データを下に示す。葉っぱアイコン以外は透明な画像データである。 これを単色で塗りつぶしたポリゴンに重ねるだけである。

実際の地図では、道路や建物など様々なものを書き加える。このため、Canvas に直接、森林を塗りつぶして、 そこにパターン画像を重ね書きすることはできない。

ワーク用Canvas tile.cvWork を使う。ここに 森林ポリゴンを単色(緑に近い色)で塗りつぶす。 塗りつぶされていないところは透明である。ここが重要な点である。

ここにパターン画像を上書きする。ここで PorterDuff.Mode を SRC_ATOP とする。これにより、 単色で塗りつぶされていたポリゴンだけに対して、パターン画像が上書きされる。 new Paint()

リファレンス

[1] Canvas
[2] PorterDuff.Mode