くうと徒然なるままに

モバイルアプリを作りながらバックエンドも作っています。

Jetpack compose for Desktop でLocal に存在する画像を表示する

前置き

Jetpack Compose for Desktop version 0.2.0 での話です。

Jetpack Compose for Desktop での画像表示の現状

Jetpack compose for Desktop のSDK では 画像を表示する関数 Image() が定義されています。
Image() 関数では、 ImageBitmap, Painter, ImageVetor のいずれかの Class のインスタンスを関数呼び出し時に引数として渡します。
どれもが Jetpack Compose for Desktop の SDK 内で定義されたクラスになります。

Painter class のインスタンスを作成するためには ImageBitmap が必要になるため無視します。

また、 ImageVector class も Vector Image を表示するときには使えますが、今回は 普通の .png 等々に絞るため無視します。

ここまでで、 Jetpack Compose for Desktop で画像を表示するために使う関数は Image() を ImageBitmap の引数付きで呼び出す必要があることまでわかりました。

@Composable
inline fun Image(
    bitmap: ImageBitmap,
    // 省略
)

余談ですが、 ImageBitmap を引数に渡して呼び出す関数は ImagePainter を渡すときの関数の Syntax sugar です。

Resource に追加済の Image を表示する

Resource に追加済の画像を表示するためには以下のようにヘルパー関数が用意されているので呼び出すだけで済みます。

Image(imageResource("path/to/resource/image.png"))

Skia の 関数を利用してLocal に存在する画像を読み込めるようにする

imageResource() 関数を呼び出すとThread Context に存在するResourceから画像を読み込もうとします。
しかし、Local の アプリケーション外に存在する画像はResource に登録されてるはずがないので失敗します。

先ほど出てきた imageResource() 関数、Resource から画像ファイルを読み込む場合は、 最終的にByteArray に変換しています。
変換したものを利用し skija(Jetbrains が開発している Skia の Java binding ライブラリ) に存在する、 Image class のインスタンスを作成しています。

fun Image.makeFromEncoded(byteArray)

解決策

画像を読み込みByteArray を作成するところまでを独自で書けば良さそう。 局所的に変更できない・Image から ImageBitmap へのヘルパー関数が使える。

等々を考慮して以下のようなコードになりました。

Image(Image.makeFromEncoded(File(dummyImagePath).readBytes()).asImageBitmap())

実際に使うときにはラッパー関数を用意すると便利そう 例:

    fun imageLocalResource(path: String): ImageBitmap {
        return imageLocalResource(path)
    }

    fun imageLocalResource(path: File): ImageBitmap {
        return makeFromEncoded(path.readBytes()).asImageBitmap()
    }

    // from Resource
    Image(imageResource("path/to/image"))
            
    // from Local
    Image(imageLocalResource("path/to/image"))