Repository: JetBrains/compose-multiplatform
File: components/resources/library/src/commonMain/kotlin/org/jetbrains/compose/resources/ImageResources.kt (Kotlin)

Code before:

private val emptySvgPainter: Painter by lazy { BitmapPainter(emptyImageBitmap) }

@Composable
private fun svgPainter(resource: DrawableResource): Painter {
    val resourceReader = LocalResourceReader.current
    val density = LocalDensity.current
    val svgPainter by rememberResourceState(resource, resourceReader, density, { emptySvgPainter }) { env ->
        val path = resource.getResourceItemByEnvironment(env).path
        val cached = loadImage(path, resourceReader) {
            ImageCache.Svg(it.toSvgElement().toSvgPainter(density))
        } as ImageCache.Svg
        cached.painter
    }
    return svgPainter
}

/**
 * Retrieves an ByteArray using the specified drawable resource.
 *
 * @param resource The drawable resource to be used.
 * @return The ByteArray loaded from the resource.
 */
@ExperimentalResourceApi
@Composable
fun getDrawableResourceBytes(resource: DrawableResource): ByteArray {
    val resourceReader = LocalResourceReader.current
    val bytes by rememberResourceState(resource, resourceReader, { ByteArray(0) }) { env ->
        val item = resource.getResourceItemByEnvironment(env)
        resourceReader.read(item.path)
    }
    return bytes
}

internal expect fun ByteArray.toImageBitmap(): ImageBitmap
internal expect fun ByteArray.toXmlElement(): Element
internal expect fun ByteArray.toSvgElement(): SvgElement

private sealed interface ImageCache {
    class Bitmap(val bitmap: ImageBitmap) : ImageCache
    class Vector(val vector: ImageVector) : ImageCache
    class Svg(val painter: Painter) : ImageCache
}

private val imageCacheMutex = Mutex()
private val imageCache = mutableMapOf<String, Deferred<ImageCache>>()

//@TestOnly
internal fun dropImageCache() {
    imageCache.clear()
}

Review comment (suggestion):
```suggestion
fun getDrawableResourceBytes(resource: DrawableResource): ByteArray? {
```
zero-bytes resource is not a valid resource (I checked, 0-bytes jpg throws `IllegalArgumentException`). We should force users to handle the case when the data isn't loaded yet, otherwise we can hide an error (desktop - works, web - doesn't).

Let's do the same with `getFontResourceBytes`, and describe what `null` means in the KDoc.

Code after:

private val emptySvgPainter: Painter by lazy { BitmapPainter(emptyImageBitmap) }

@Composable
private fun svgPainter(resource: DrawableResource): Painter {
    val resourceReader = LocalResourceReader.current
    val density = LocalDensity.current
    val svgPainter by rememberResourceState(resource, resourceReader, density, { emptySvgPainter }) { env ->
        val path = resource.getResourceItemByEnvironment(env).path
        val cached = loadImage(path, resourceReader) {
            ImageCache.Svg(it.toSvgElement().toSvgPainter(density))
        } as ImageCache.Svg
        cached.painter
    }
    return svgPainter
}

/**
 * Retrieves the byte array of the drawable resource.
 *
 * @param environment The resource environment, which can be obtained from [rememberResourceEnvironment] or [getSystemResourceEnvironment].
 * @param resource The drawable resource.
 * @return The byte array representing the drawable resource.
 */
@ExperimentalResourceApi
suspend fun getDrawableResourceBytes(
    environment: ResourceEnvironment,
    resource: DrawableResource
): ByteArray {
    val resourceItem = resource.getResourceItemByEnvironment(environment)
    return DefaultResourceReader.read(resourceItem.path)
}

internal expect fun ByteArray.toImageBitmap(): ImageBitmap
internal expect fun ByteArray.toXmlElement(): Element
internal expect fun ByteArray.toSvgElement(): SvgElement

private sealed interface ImageCache {
    class Bitmap(val bitmap: ImageBitmap) : ImageCache
    class Vector(val vector: ImageVector) : ImageCache
    class Svg(val painter: Painter) : ImageCache
}

private val imageCacheMutex = Mutex()
private val imageCache = mutableMapOf<String, Deferred<ImageCache>>()

//@TestOnly
internal fun dropImageCache() {
    imageCache.clear()
}