Getting Started

June 3, 2026 · View on GitHub

Translations: 简体中文

Load Image

Loading images with Sketch is very simple, as follows:

Compose Multiplatform:

// val imageUri = "/Users/my/Downloads/image.jpg"
// val imageUri = file:///compose_resource/composeResources/com.github.panpf.sketch.sample.resources/files/sample.png
val imageUri = "https://example.com/image.jpg"

AsyncImage(
    uri = imageUri,
    contentDescription = "photo"
)

AsyncImage(
    uri = imageUri,
    state = rememberAsyncImageState(ComposableImageOptions {
        placeholder(Res.drawable.placeholder)
        error(Res.drawable.error)
        crossfade()
        // There is a lot more...
    }),
    contentDescription = "photo"
)

AsyncImage(
    rqeuest = ComposableImageRequest(imageUri) {
        placeholder(Res.drawable.placeholder)
        error(Res.drawable.error)
        crossfade()
        // There is a lot more...
    },
    contentDescription = "photo"
)

Image(
    painter = rememberAsyncImagePainter(
        request = ComposableImageRequest(imageUri) {
            placeholder(Res.drawable.placeholder)
            error(Res.drawable.error)
            crossfade()
            // There is a lot more...
        }
    ),
    contentDescription = "photo"
)

Tip

  1. On Compose Multiplatform you can use AsyncImage directly Components can also use Image + AsyncImagePainter to load the image.
  2. But it is more recommended to use the AsyncImage component because AsyncImage is slightly faster.
  3. This is because Sketch relies on the exact size of the component to start loading images, AsyncImage The size of the component can be obtained during the layout stage, while Image + AsyncImagePainter cannot obtain the component size until the drawing stage.
  4. placeholder(Res.drawable.placeholder) needs to import the sketch-compose-resources module

Android View:

// val imageUri = "/sdcard/download/image.jpg"
// val imageUri = "file:///android_asset/image.jpg"
// val imageUri = "content://media/external/images/media/88484"
val imageUri = "https://example.com/image.jpg"

imageView.loadImage(imageUri)

imageView.loadImage(imageUri) {
    placeholder(R.drawable.placeholder)
    error(R.drawable.error)
    crossfade()
    // There is a lot more...
}

val request = ImageRequest(context, imageUri) {
    placeholder(R.drawable.placeholder)
    error(R.drawable.error)
    crossfade()
    target(imageView)
    // There is a lot more...
}
context.sketch.enqueue(request)

Sketch will automatically adjust the size of the image according to the size of the component to prevent the size of the image loaded into the memory from exceeding the size of the component itself and cause memory waste. It will also automatically cancel the request when the component is destroyed.

Supported Image Formats

Sketch supports a variety of static and dynamic image types, as follows:

FormatDependent Modules
jpeg_
png_
bmp_
webp_
heif_,sketch-avif-awxkee
avif_,sketch-avif-awxkee
svgsketch-svg
gifsketch-animated-gif
sketch-animated-gif-koral
Animated webpsketch-animated-webp
Animated heifsketch-animated-heif
Video framessketch-video
sketch-video-ffmpeg
Apk iconsketch-extensions-apkicon

Each image type has a corresponding Decoder support for it, Learn more about Decoder

Supported URIs

Sketch supports loading images from different data sources such as the network, local machine, and resources, as follows:

URIDescribeCreate FunctionDependent Modules
http://, https://File in network_sketch-http-hurl
sketch-http-okhttp
sketch-http-ktor2
sketch-http-ktor3
file://, /, D:\, \\File in SDCardnewFileUri()_
content://Android Content Resolver__
android.resource://Android ResourcenewResourceUri()_
file:///android_asset/Android AssetnewAssetUri()_
file:///compose_resource/Compose ResourcenewComposeResourceUri()sketch-compose-resources
file:///kotlin_resource/Kotlin ResourcenewKotlinResourceUri()_
file:///photos_asset/ios Photos LibrarynewPhotosAssetUri()_
data:image/, data:img/Base64newBase64Uri()_
blurhash://BlurHashnewBlurHashUri()sketch-blurhash
app.icon://Android App IconnewAppIconUri()sketch-extensions-appicon

Each URI has its own Fetcher to support it, Learn more about Fetcher

Platform differences

Due to limitations of platform characteristics, the functions on different platforms are also different, as follows:

FeatureAndroidiOSDesktopWeb
jpeg
png
webp
bmp
heif✅ (API 24)
avif✅ (API 24)
svg
(Not Support CSS)

(Not Support CSS)

(Not Support CSS)
gif
Animated webp✅ (API 28)
Animated heif✅ (API 30)
Video frames
BlurHash
http://
https://
file://, /
file:///compose_resource/
data:image/jpeg;base64
file:///android_asset/
content://
android.resource://
file:///kotlin_resource/
file:///photos_asset/
Exif Orientation
Memory Cache
Result Cache
Download Cache
Default image decoderBitmapFactorySkia ImageSkia ImageSkia Image
Minimum APIAPI 21-JDK 1.8-

The minimum API is '-' to synchronize with Compose Multiplatform

Sketch

The Sketch class is the core of the entire framework, which is used to execute and manage ImageRequest

The sketch-compose-core and sketch-view-core modules provide components such as ImageRequest, AsyncImage to load images, but they also require you to create Sketch instances and then use it when loading the image, as follows:

val sketch = Sketch(context)

// Compose
AsyncImage(
    uri = "https://www.example.com/image.jpg",
    sketch = sketch,
    moidifier = Modifier.fillMaxSize(),
    contentDescription = "photo",
)

// View
val request = ImageRequest(imageView, uri = "https://www.example.com/image.jpg")
sketch.enqueue(request)

For more convenience, Sketch provides singleton mode and Koin mode, which allows you to directly use the shared Sketch instance when loading pictures.

Singleton mode

You can directly rely on the sketch-compose or sketch-view module to use singleton mode, and also provide more convenient components or loading functions, as follows:

// Android
val sketch = context.sketch
val sketch = SingletonSketch.get(context)

// Non Android
val sketch = SingletonSketch.get()

// Compose
AsyncImage(
    uri = "https://www.example.com/image.jpg",
    moidifier = Modifier.fillMaxSize(),
    contentDescription = "photo",
)

// View
imageView.loadImage(uri = "https://www.example.com/image.jpg")
// or
ImageRequest(imageView, uri = "https://www.example.com/image.jpg").enqueue(request)

When you need to customize Sketch, you can create Sketch and configure it in the following ways:

// Android
class MyApplication : Application(), SingletonSketch.Factory {

    override fun createSketch(): Sketch {
        return Sketch.Builder(context).apply {
            logger(level = Logger.Level.Debug)
            // There is a lot more...
        }.build()
    }
}

// Non Android. Called in the App entry function
SingletonSketch.setSafe {
    Sketch.Builder(PlatformContext.INSTANCE).apply {
        logger(level = Logger.Level.Debug)
        // There is a lot more...
    }.build()
}

Koin mode

If you use Koin as a dependency injection framework, you can rely on the sketch-compose-koin or sketch-view-koin module to use the Koin pattern, which also provides more convenient components or loading functions, as follows:

// Initialize koin in the app's entry function or onCreate in the Application
startKoin {
    modules(
        module {
            single<Sketch> {
                Sketch.Builder(get()).apply {
                    logger(level = Logger.Level.Debug)
                    // There is a lot more...
                }.build()
            }
        })
}

// Get instances anywhere
val sketch = KoinPlatform.getKoin().get<Sketch>()

// Compose
AsyncImage(
    uri = "https://www.example.com/image.jpg",
    moidifier = Modifier.fillMaxSize(),
    contentDescription = "photo",
)

// View
imageView.loadImage(uri = "https://www.example.com/image.jpg")
// or
ImageRequest(imageView, uri = "https://www.example.com/image.jpg").enqueue(request)

ImageRequest

ImageRequest is used to describe an image loading request, which includes the uri of the image and placeholder image, transform, transition, new size, Target, Listener and other configurations

Create ImageRequest

Create a simple ImageRequest that limits the maximum number of pixels of the image to 300x300

val request = ImageRequest(context, "https://www.example.com/image.jpg") {
    size(300, 300)
    // There is a lot more...
}

Tip

For more configuration of ImageRequest, please refer to the ImageRequest.Builder class

Configure Target

To load the results directly into the component, you also need to configure Target

On Compose Target is configured by AsyncImage and AsyncImagePainter's cornerstone AsyncImageState, you just need to Just pass ImageRequest to AsyncImage or AsyncImagePainter, as follows:

val request = ImageRequest(context, "https://www.example.com/image.jpg") {
    size(300, 300)
    // There is a lot more...
}

AsyncImage(
    request = request,
    contentDescription = "photo"
)

Image(
    painter = rememberAsyncImagePainter(request),
    contentDescription = "photo"
)

Caution

You cannot call the target() function in AsyncImage and AsyncImagePainter, which will cause the app to crash

In the Android View system, you need to actively call the target() function and pass in the ImageView, as follows:

val request = ImageRequest(context, "https://www.example.com/image.jpg") {
    size(300, 300)
    target(imageView)
    // There is a lot more...
}
context.sketch.enqueue(request)

You can also use ImageRequest(ImageView, String) or ImageView.loadImage() extension functions, they will call target() for you, as follows:

val request = ImageRequest(imageView, "https://www.example.com/image.jpg") {
    size(300, 300)
    // There is a lot more...
}
context.sketch.enqueue(request)

imageView.loadImage() {
    size(300, 300)
    // There is a lot more...
}

Execute ImageRequest

After ImageRequest is created, it is handed over to Sketch for execution. Sketch supports asynchronous and synchronous execution of ImageRequest, as follows:

val request = ImageRequest(context, "https://www.example.com/image.jpg")

// Asynchronous execution of ImageRequest does not block the current thread or suspend the current coroutine.
val disposable: Disposable = sketch.enqueue(request)

// Synchronously execute ImageRequest and suspend the current coroutine until the result is returned.
coroutineScope.launch(Dispatchers.Main) {
    val imageResult: ImageResult = sketch.execute(request)
    val image: Image = imageResult.image
}

Note

The singleton mode provides ImageRequest.enqueue() and ImageRequest.execute() extension functions for ImageRequest to facilitate sequential writing.

Get Result

When Target is configured, Sketch will hand over the results to Target for display, but sometimes you need to do something with the results or when Target is not configured, you need to actively obtain the results, as follows:

val request = ImageRequest(context, "https://www.example.com/image.jpg")

// When using the enqueue() method to asynchronously execute a request, you can obtain the result through the returned Disposable.job
val disposable = sketch.enqueue(request)
coroutineScope.launch(Dispatchers.Main) {
    val imageResult: ImageResult = disposable.job.await()
}

// You can directly obtain the results when executing a request synchronously using the execute() method.
coroutineScope.launch(Dispatchers.Main) {
    val imageResult: ImageResult = sketch.execute(request)
}

ImageResult contains a lot of useful information, as follows:

val imageResult: ImageResult = ...
val request: ImageRequest = imageResult.request
val image: Image = imageResult.image
when (image) {
    is BitmapImage -> {
        val bitmap: Bitmap = image.bitmap
    }
    is DrawableImage -> {
        val drawable: Drawable = image.drawable
    }
    is PainterImage -> {
        val painter: Painter = image.painter
    }
    is AnimatedImage -> {
        val codec: Codec = image.codec
    }
}
if (imageResult is ImageResult.Success) {
    val memoryCacheKey: String = imageResult.memoryCacheKey
    val resultCacheKey: String = imageResult.resultCacheKey
    val downloadCacheKey: String = imageResult.downloadCacheKey
    val imageInfo: ImageInfo = imageResult.imageInfo
    val dataFrom: DataFrom = imageResult.dataFrom
    val resize: Resize = imageResult.resize
    val transformeds: List<String>? = imageResult.transformeds
    val extras: Map<String, String>? = imageResult.extras
} else if (imageResult is ImageResult.Error) {
    val throwable: Throwable = imageResult.throwable
}

Cancel request

When Target is configured, ImageRequest will automatically cancel the request under the following circumstances:

  • AsyncImage or AsyncImagePainter component forgotten
  • ImageView's onViewDetachedFromWindow() method is executed
  • Lifecycle changes to DESTROYED state

When Target is not configured or when active cancellation is required, it can be canceled through Disposable or Job, as follows:

// When using the enqueue() method to asynchronously execute a request, a Disposable will be returned, which can be used to cancel the request when needed.
val request = ImageRequest(context, "https://www.example.com/image.jpg")
val disposable = sketch.enqueue(request)
disposable.dispose()

// When using the execute() method to execute a request synchronously, you can cancel the request through its coroutine's Job when needed.
val job = coroutineScope.launch(Dispatchers.Main) {
    val request = ImageRequest(context, "https://www.example.com/image.jpg")
    val imageResult: ImageResult = sketch.execute(request)
}
job.cancel()

ImageView extensions

Sketch provides a series of extensions for ImageView, as follows:

// load
imageView.loadImage("https://www.example.com/image.jpg") {
    placeholder(R.drawable.placeholder)
    error(R.drawable.error)
    crossfade(true)
}

// cancel
imageView.disposeLoad()

// result
val imageResult: ImageResult? = imageView.imageResult

loadImage() is only available in singleton mode

Document

Basic functions:

Featured functions: