Home About
android, svg

SVGコマンドを android.graphics.Path に変換

以前に書いた Kotlin による簡易SVG parser の実装実験 を使って自前のAndroidアプリのアイコン描画などを行っていたのだが、 そんなの標準に提供されているライブラリで対処できるだろう、と思って調べたところ対処できたのでメモしておきます。

やりたいことは、SVGコマンドを android.graphics.Path に変換して、たとえば、 android.graphics.CanvasdrawPath() して、カスタムViewなどで表示させることです。 結論だけを先に書くと androidx.core.graphics.PathParser.createPathFromPathData() を使えばよい。

Material Design のサイトで提供されている icon を Path に変換

SVGコマンドの用意

https://developer.mozilla.org/ja/docs/Web/SVG/Tutorial/Paths を参考に自分でコマンドを書いてもよいのですが、ここでは既存のSVGコマンドを利用してみます。 さまざまなSVGアイコンが用意されているマテリアルデザインのサイト: https://material.io/resources/icons/ から zoom_in-24px.svg をダウンロードします。

中身を見てみると:

<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/><path d="M12 10h-2v2H9v-2H7V9h2V7h1v2h2v1z"/></svg>

縦横 24ピクセル の正方形のアイコンです。

SVGコマンドは path d="(SVGコマンド...)" の部分に記述されています。

SVGコマンドを Path に変換

androidx.core.graphics.PathParser.createPathFromPathData("SVGコマンド") を使えば Path に変換できる。

具体的には以下のようにカスタム View を書く( kotlin ):

class SvgView: View {
    constructor(ctx: Context) : super(ctx) {}
    constructor(ctx: Context, attributeSet: AttributeSet) : super(ctx, attributeSet) {}

    private companion object {
        const val svgCmd =
            "M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"

        val svgPath: Path = PathParser.createPathFromPathData(svgCmd)
    }

    private val paint = Paint()
    init {
        paint.isAntiAlias = true
        paint.style = Paint.Style.FILL
        paint.color = Color.BLUE
    }

    override fun draw(canvas: Canvas?) {
        super.draw(canvas)

        canvas?.drawPath(svgPath, paint)
    }
}

結果:

zoom-in-24px

ちっさ。

実行するデバイスにもよりますが、24px サイズでは小さすぎます。 これを例えば 5倍に拡大してみます。 path.transform(matrix) を使って変形(拡大)します。

init に 5倍にパスを拡大するコードを追加:

init {
    paint.isAntiAlias = true
    paint.style = Paint.Style.FILL
    paint.color = Color.BLUE

    //
    // svgPath を 5倍に拡大
    //
    val matrix = Matrix()
    matrix.setValues(floatArrayOf(
        5f, 0f, 0f,
        0f, 5f, 0f,
        0f, 0f, 1f
    ))

    svgPath.transform(matrix)
}

結果:

zoom-in-24px-5times

まとめ

Androidでは、XML定義経由でSVGコマンドをアイコン等で利用するだけでなく、 プログラム的にSVGコマンドをPathに変換するのも簡単にできる。