Hello, in Kotlin/JS, a code works fine: `Int8Array...
# compose-web
n
Hello, in Kotlin/JS, a code works fine:
Int8Array(arrayBuffer) as ByteArray
, while in Kotlin/WASM, it crashes:
kotlin.ClassCastException: Cannot cast instance of Int8Array to kotlin.ByteArray: incompatible types
. Any idea how? Code in thread.
Copy code
suspend fun ByteArray.resizeAndCompress(
    width: Int,
    height: Int,
): ByteArray {
    val arrayBuffer = decodeResizeCompressImageBytes(this, width, height)

    return Int8Array(arrayBuffer) as ByteArray
}

private suspend fun decodeResizeCompressImageBytes(
    bytes: ByteArray,
    width: Int,
    height: Int,
): ArrayBuffer
I'm trying to do the same as Coil did (offload image transformation to a Web Worker to avoid UI freeze during heavy computation), but I clearly have no JS / WASM skills and the documentation about this topic is lacking and / or obnoxious for someone without prior JS knowledge.
a
Unfortunately, it's by design. In the JS target we compile number arrays to native JS number arrays, while in Wasm it's usage of the arrays from the GC proposal. So, when you crossing the Wasm/JS border you need to copy one to another. As far as I see, Coil uses kotlinx.browser library and this library contains extension methods to convert in between those array types: • For JS: https://github.com/Kotlin/kotlinx-browser/blob/master/src/jsMain/kotlin/arrayCopy.js.kt • For Wasm: https://github.com/Kotlin/kotlinx-browser/blob/master/src/wasmJsMain/kotlin/arrayCopy.wasm.kt So, assuming that you're using kotlinx.browser as well, your function would look like this:
Copy code
suspend fun ByteArray.resizeAndCompress(
    width: Int,
    height: Int,
): ByteArray {
    val arrayBuffer = decodeResizeCompressImageBytes(this, width, height)
    return Int8Array(arrayBuffer).toByteArray() // On the JS - just cast, on Wasm - copy
}
thank you color 1
n
Ok it works, thank you very much, I was lost on this! So, if I understand correctly, from our "image bytes" (ByteArray on Kotlin): 1/ we copy them (no transfer) to go in the "JS / WASM" world (example, source code for WASM), 2/ then we can directly pass the data to the Web Worker without copying it thanks to some "transferable data techniques" in JS (example), 3/ then we're using some JS / Web Worker magic to transform those bytes as we like 4/ Same technique using "transferable data" from the Web Worker to JS (example) 5/ Then we're re-copying those transformed bytes into a
Int8Array
with
Int8Array(arrayBuffer)
(or is it a simple wrapper?) 6/ And we're re-recopying in Kotlin/WASM with
.toByteArray()
So if I understand correctly, we're copying once on the way to the Web Worker, and twice from the Web Worker (on WASM, only once on JS). That's 4x memory footprint, right? Am I correct? This is a very difficult topic and I try to understand it better because it seems I will have to use it a lot, I want my Compose Web app to be performant and today the only way to offload work on Compose Web is through Web Worker only it seems.