Skip to content

Commit

Permalink
Merge pull request #15 from PatilShreyas/fix-wasmjs-imagepick
Browse files Browse the repository at this point in the history
Use type-safe API for image picking in Wasm
  • Loading branch information
joreilly authored Jan 26, 2024
2 parents bd6eae0 + df7d746 commit 148aa8a
Showing 1 changed file with 42 additions and 37 deletions.
79 changes: 42 additions & 37 deletions composeApp/src/wasmJsMain/kotlin/actual.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.toComposeImageBitmap
import kotlinx.coroutines.await
import kotlinx.browser.document
import org.jetbrains.skia.Image
import kotlin.io.encoding.Base64
import org.khronos.webgl.ArrayBuffer
import org.khronos.webgl.Uint8Array
import org.khronos.webgl.get
import org.w3c.dom.HTMLInputElement
import org.w3c.files.FileReader
import org.w3c.files.get
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
import kotlin.io.encoding.ExperimentalEncodingApi
import kotlin.js.Promise


actual fun ByteArray.toComposeImageBitmap(): ImageBitmap {
Expand All @@ -31,50 +38,48 @@ actual fun ImagePicker(
LaunchedEffect(show) {
if (show) {
val data = importImageFile()
val rawData = Base64.decode(data.toString())
onImageSelected("", rawData)
onImageSelected("", data)
}
}
}


private suspend fun importImageFile(): String? {
private suspend fun importImageFile(): ByteArray? {
return try {
pickFile().await<JsString>().toString()
pickFile()
} catch (e: Exception) {
e.printStackTrace()
null
}
}

private fun pickFile(): Promise<JsString> = js(
"""
(async () => {
return new Promise((resolve, reject) => {
const input = document.createElement('input');
input.type = 'file';
input.onchange = () => {
const file = input.files[0];
if (file) {
const reader = new FileReader();
reader.onload = () => {
let encoded = reader.result.toString().replace(/^data:(.*,)?/, '');
if ((encoded.length % 4) > 0) {
encoded += '='.repeat(4 - (encoded.length % 4));
}
resolve(encoded);
}
reader.onerror = () => {
reject(reader.error);
resolve("")
}
reader.readAsDataURL(file);
} else {
reject(new Error('No file was selected'));
private suspend fun pickFile(): ByteArray? = suspendCoroutine { cont ->
try {
val input = document.createElement("input").apply {
setAttribute("type", "file")
setAttribute("accept", "image/*")
} as HTMLInputElement

input.onchange = {
val file = input.files?.get(0)
if (file != null) {
val reader = FileReader()
reader.onload = { event ->
val arrayBuffer = (event.target as FileReader).result as ArrayBuffer
val array = Uint8Array(arrayBuffer)

cont.resume(ByteArray(array.length) { array[it] })
}
reader.onerror = {
cont.resumeWithException(Exception(reader.error.toString()))
}
reader.readAsArrayBuffer(file)
} else {
cont.resumeWithException(Exception("No file was selected"))
}
}
};
input.click();
});
})()
""",
)
input.click()
} catch (e: Exception) {
cont.resumeWithException(e)
}
}

0 comments on commit 148aa8a

Please sign in to comment.