Compose for Desktopで選択画像を表示する

Compose for Desktopで画像を表示するには、Imageコンポーザブル関数を使用します。

@Composable
fun Image(
    bitmap: ImageBitmap,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    alignment: Alignment = Alignment.Center,
    contentScale: ContentScale = ContentScale.Fit,
    alpha: Float = DefaultAlpha,
    colorFilter: ColorFilter? = null,
    filterQuality: FilterQuality = DefaultFilterQuality
)

FileオブジェクトからImageBitmapを取得するには、org.jetbrains.skia.ImageのmakeFromEncoded()とtoComposeImageBitmap()を使用します。

表示画像のスケーリングは、contentScaleで指定します。
ContentScale.Fitは表示領域に合わせて画像が拡大縮小されます。
ContentScale.Insideは表示領域に収まるように画像が縮小されます。

Image(
    bitmap = Image.makeFromEncoded(imageFile!!.readBytes()).toComposeImageBitmap(),
    contentDescription = null,
    modifier = androidx.compose.ui.Modifier.fillMaxSize(),
    contentScale = ContentScale.Inside
)

次のサンプルプログラムは、ファイル選択ダイアログで選択した画像を表示します。

@Composable
@Preview
fun App() {
    var isOpenFileDialog by remember { mutableStateOf(false) }
    var imageFile by remember { mutableStateOf<File?>(null) }

    MaterialTheme {
        Column {
            Button(onClick = { isOpenFileDialog = true }) { Text("Choose a file") }
            if (imageFile != null) {
                Image(
                    bitmap = Image.makeFromEncoded(imageFile!!.readBytes()).toComposeImageBitmap(),
                    contentDescription = null,
                    modifier = androidx.compose.ui.Modifier.fillMaxSize(),
                    contentScale = ContentScale.Inside
                )
            }
        }
        if (isOpenFileDialog) {
            FileDialog(mode = FileDialog.LOAD,
                filenameFilter = { _, name -> name?.matches(Regex("(.+\\.jpg)|(.+\\.png)|(.+\\.gif)")) ?: false },
                onCloseRequest = { directory, file ->
                    isOpenFileDialog = false
                    if (directory != null && file != null) {
                        println(File(directory, file).absolutePath)
                        imageFile = File(directory, file)
                    }
                })
        }
    }
}

@Composable
private fun FileDialog(
    parent: Frame? = null,
    title: String = "Choose a file",
    mode: Int = FileDialog.LOAD,
    filenameFilter: FilenameFilter? = null,
    onCloseRequest: (directory: String?, result: String?) -> Unit
) = AwtWindow(
    create = {
        object : FileDialog(parent, title, mode) {
            init {
                filenameFilter?.let { setFilenameFilter(filenameFilter) }
            }

            override fun setVisible(value: Boolean) {
                super.setVisible(value)
                if (value) {
                    onCloseRequest(directory, file)
                }
            }
        }
    }, dispose = FileDialog::dispose
)

fun main() = application {
    Window(onCloseRequest = ::exitApplication) {
        App()
    }
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください