Does anyone have an example of how to use Coil3 for image loading in a native iOS in a KMM project? I have managed to set it up for android, using a common ImageLoader
, but i can't figure out how to set it up for iOS. FYI this is not a Compose Multiplatform project, just shared Kotlin logic and native UI per platform
Googled examples, everything seems to point to compose multiplatform, but I need native implementation, if it exists.
Coil3 documentation says:
On non-Android platforms, Coil uses Skiko to render images. Skiko is a set of Kotlin bindings that wrap the Skia graphics engine developed by Google.
coil3.ImageLoader
returns Deferred<ImageResult>
which in it's order has coil3.Image
field inside. In nonAndroid platforms coil3.Image
interface contains method toBitmap()
to get org.jetbrains.skia.Bitmap
.
So, get images in SwiftUI (get UIImage
object) we have to solve two tasks:
Deferred<ImageResult>
to ImageResult
.
I would recommend to use this plugin:skie = { id = "co.touchlab.skie", version.ref = "skie"}
Read more here: https://skie.touchlab.co/features/suspend
org.jetbrains.skia.Bitmap
to UIImage
Here is example:
import coil3.Image
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.refTo
import org.jetbrains.skia.Bitmap
import org.jetbrains.skia.Image.Companion.makeFromBitmap
import platform.CoreFoundation.CFDataCreate
import platform.CoreGraphics.CGColorRenderingIntent
import platform.CoreGraphics.CGColorSpaceCreateDeviceRGB
import platform.CoreGraphics.CGDataProviderCreateWithCFData
import platform.CoreGraphics.CGImageAlphaInfo
import platform.CoreGraphics.CGImageCreate
import platform.CoreGraphics.kCGBitmapByteOrder32Little
import platform.UIKit.UIImage
@OptIn(ExperimentalForeignApi::class)
fun convertImage(image: Image): UIImage? {
val bitmap: Bitmap = image.toBitmap()
val skikoImage = makeFromBitmap(bitmap)
val skikoImagePixelMap = skikoImage.peekPixels()
if (skikoImagePixelMap != null) {
val cfDataRef = CFDataCreate(
allocator = null,
bytes = skikoImagePixelMap.buffer.bytes.asUByteArray().refTo(0),
length = skikoImagePixelMap.buffer.size.toLong()
)
val cgImageRef = CGImageCreate(
width = skikoImage.width.toULong(),
height = skikoImage.height.toULong(),
bitsPerComponent = 8u,
bitsPerPixel = 32u,
bytesPerRow = (skikoImage.width * 4).toULong(),
space = CGColorSpaceCreateDeviceRGB(),
bitmapInfo = kCGBitmapByteOrder32Little or CGImageAlphaInfo.kCGImageAlphaPremultipliedFirst.value,
provider = CGDataProviderCreateWithCFData(cfDataRef),
decode = null,
shouldInterpolate = true,
intent = CGColorRenderingIntent.kCGRenderingIntentDefault
)
return UIImage(cGImage = cgImageRef)
}
return null
}
It worth to mention few things:
@OptIn(ExperimentalForeignApi::class)
annotation says that API still in experemental mode.Task
)I hope it will help you.