Posted at

Canvasを使ってあるBitmapから正円のBitmapを作成する処理を書いた話


やりたいこと

ある画像から、サムネイルのアイコンを作って表示する処理が必要になったので、Canvasを使って実装してみました。



例えばこういうネクタイの画像があったとすると、欲しいのは以下のようなアイコンになります。



拡大縮小はせず、中心部分をうまく丸く切り取る処理をする場合、以下のような実装になります。


実際のソースコード

    private fun getCroppedBitmap(bitmap: Bitmap): Bitmap {

val size = Math.min(bitmap.width, bitmap.height)
val output = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)
val canvas = Canvas(output)

val paint = Paint()

paint.isAntiAlias = true
canvas.drawARGB(0, 0, 0, 0)
canvas.drawCircle(size / 2f, size / 2f, size / 2f, paint)
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
val max = Math.max(bitmap.width, bitmap.height)
val start = (size - max) / 2
val left = if (bitmap.width < bitmap.height) 0 else start
val top = if (bitmap.height < bitmap.width) 0 else start
val rect = Rect(left, top, bitmap.width + left, bitmap.height + top)
canvas.drawBitmap(bitmap, Rect(0, 0, bitmap.width, bitmap.height), rect, paint)
return output
}


解説

やっていることはそんなに難しくはありません。

まず、出力先のBitmapをsize指定で作成します。この時、sizeは元画像の幅/高さのうち小さい方を指定します。

次にCanvasとPaintを用意します。

今回は円形に画像を切り抜くので、Paintにはジャギーが目立たなくなるようにisAntiAliasをtrueに設定します(詳細はアンチエイリアスを参照のこと)。

canvasは透明で塗りつぶしてから、drawCircle(中心点のx座標,中心点のy座標,半径,paint)でsizeの半分の半径でちょうど中央に円を描きます。

paint.xfermodeを設定する前のdrawCircleがDST、その後のdrawBitmapがSRCなので、画像が丸の中に入るようにするにはPorterDuffXfermode(PorterDuff.Mode.SRC_IN)paint.xfermodeに設定します。

最後に切り抜くrectを決めてdrawBitmapすることで、描画処理は完了です。