Ktor HttpClientで画像をアップロードする

Ktor HttpClientで画像をアップロードするコードを紹介する。

使用したプログラミング言語とライブラリのバージョン

  • Kotlin 1.6.10
  • Jetpack Compose 1.1.1
  • Ktor 2.0.0

Ktor HttpClientで画像をアップロードする

build.gradleの編集

build.gradle (:app) に以下の行を追加する。

implementation "io.ktor:ktor-client-core:2.0.0"
implementation "io.ktor:ktor-client-android:2.0.0"

画像をアップロードする

関数storeは、引数にアップロードするBitmapと、レスポンスを返す関数をとる。

画像はJPEGに変換してアップロードする。

val jpg = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, jpg)

HttpClientはデフォルトのエンジンを使用する。
後で、レスポンスをJSONに変換するコードを追加する。

val client = HttpClient()

HttpClientのsubmitFormWithBinaryData()メソッドを使用して画像をアップロードする。

val response = client.submitFormWithBinaryData(
    url = "http://192.168.10.114/upload.php",
    formData = formData {
        appendInput(key = "file", headers = Headers.build {
            append(HttpHeaders.ContentType, "image/jpg")
            append(HttpHeaders.ContentDisposition, "filename=image.jpg")
        }) {
            buildPacket {
                writeFully(jpg.toByteArray())
            }
        }
    }
)

全体のコードは次のようになる。

object ImageRepository {
    suspend fun store(bitmap: Bitmap, onResult: (String?) -> Unit) {
        val jpg = ByteArrayOutputStream()
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, jpg)

        val client = HttpClient()
        val response = client.submitFormWithBinaryData(
            url = "http://192.168.10.114/upload.php",
            formData = formData {
                appendInput(key = "file", headers = Headers.build {
                    append(HttpHeaders.ContentType, "image/jpg")
                    append(HttpHeaders.ContentDisposition, "filename=image.jpg")
                }) {
                    buildPacket {
                        writeFully(jpg.toByteArray())
                    }
                }
            }
        )
        onResult(response.bodyAsText())
    }
}

JSONのレスポンスを受け取る

レスポンスのJSONをパースして、オブジェクトを返す。

build.gradleの編集

build.gradle (:app) に以下の行を追加する。

plugins {
    id 'org.jetbrains.kotlin.plugin.serialization' version '1.6.10' // 追加
}
dependencies {
    implementation 'io.ktor:ktor-serialization-kotlinx-json:2.0.0' // 追加
    implementation 'io.ktor:ktor-client-content-negotiation:2.0.0' // 追加
    implementation 'org.jetbrains.kotlin:kotlin-serialization:1.6.21' // 追加
}

JSONのレスポンスを受け取る

パースするJSONの形式に合わせてクラスを作成する。

@Serializable
data class StoreResponse(
    val success: String? = null,
    val error: String? = null,
    val filename: String? = null
)

HttpClientがJSONを扱えるように設定する。

val client = HttpClient {
    install(ContentNegotiation) {
        json(json = Json, contentType = ContentType.Application.Json)
    }
}

そうすると、自動的にクラスに合わせてパースしてくれる。

val response: StoreResponse = client.submitFormWithBinaryData(
    // 省略
).body()

全体のコードは次のようになる。

object ImageRepository {
    suspend fun upload(bitmap: Bitmap, onResult: (StoreResponse?) -> Unit) {
        val jpg = ByteArrayOutputStream()
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, jpg)

        val client = HttpClient {
            install(ContentNegotiation) {
                json(json = Json, contentType = ContentType.Application.Json)
            }
        }

        val response: StoreResponse = client.submitFormWithBinaryData(
            url = "http://192.168.10.114/upload.php",
            formData = formData {
                appendInput(key = "file", headers = Headers.build {
                    append(HttpHeaders.ContentType, "image/jpg")
                    append(HttpHeaders.ContentDisposition, "filename=image.jpg")
                }) {
                    buildPacket {
                        writeFully(jpg.toByteArray())
                    }
                }
            }
        ).body()
        onResult(response)
    }
}

@Serializable
data class StoreResponse(
    val success: String? = null,
    val error: String? = null,
    val filename: String? = null
)

コメントを残す

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

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