# Getting Started
Translations: [简体中文](getting_started.zh.md)
## Load Image
Loading images with [Sketch] is very simple, as follows:
Compose Multiplatform:
```kotlin
// 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:
```kotlin
// 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:
| Format | Dependent Modules |
|:--------------|:-------------------------------------------------|
| jpeg | _ |
| png | _ |
| bmp | _ |
| webp | _ |
| heif | _ |
| avif | _ |
| svg | sketch-svg |
| gif | sketch-animated-gif
sketch-animated-gif-koral |
| Animated webp | sketch-animated-webp |
| Animated heif | sketch-animated-heif |
| Video frames | sketch-video
sketch-video-ffmpeg |
| Apk icon | sketch-extensions-apkicon |
Each image type has a corresponding Decoder support for it, [Learn more about Decoder][decoder]
## Supported URIs
[Sketch] supports loading images from different data sources such as the network, local machine, and
resources, as follows:
| URI | Describe | Create Function | Dependent Modules |
|:--------------------------|:-------------------------|:------------------------|:---------------------------------------------------------------------------------|
| http://, https:// | File in network | _ | sketch-http-hurl
sketch-http-okhttp
sketch-http-ktor2
sketch-http-ktor3 |
| file://, /, D:/ | File in SDCard | newFileUri() | _ |
| content:// | Android Content Resolver | _ | _ |
| file:///android_asset/ | Android Asset | newAssetUri() | _ |
| android.resource:// | Android Resource | newResourceUri() | _ |
| data:image/, data:img/ | Base64 | newBase64Uri() | _ |
| file:///compose_resource/ | Compose Resource | newComposeResourceUri() | sketch-compose-resources |
| file:///kotlin_resource/ | Kotlin Resource | newKotlinResourceUri() | _ |
| blurhash:// | BlurHash | newBlurHashUri() | sketch-blurhash |
| app.icon:// | Android App Icon | newAppIconUri() | sketch-extensions-appicon |
Each URI has its own Fetcher to support it, [Learn more about Fetcher][fetcher]
## Platform differences
Due to limitations of platform characteristics, the functions on different platforms are also
different, as follows:
| Feature | Android | iOS | Desktop | Web |
|:---------------------------------------------------------------------------------------------|:--------------|:------------------------|:------------------------|:------------------------|
| jpeg
png
webp
bmp | ✅ | ✅ | ✅ | ✅ |
| heif | ✅ (API 28) | ❌ | ❌ | ❌ |
| avif | ✅ (API 31) | ❌ | ❌ | ❌ |
| 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/ | ❌ | ✅ | ✅ | ❌ |
| Exif Orientation | ✅ | ✅ | ✅ | ✅ |
| Memory Cache | ✅ | ✅ | ✅ | ✅ |
| Result Cache | ✅ | ✅ | ✅ | ❌ |
| Download Cache | ✅ | ✅ | ✅ | ❌ |
| Default image decoder | BitmapFactory | Skia Image | Skia Image | Skia Image |
| Minimum API | API 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:
```kotlin
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:
```kotlin
// 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:
```kotlin
// 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:
```kotlin
// Initialize koin in the app's entry function or onCreate in the Application
startKoin {
modules(
module {
single {
Sketch.Builder(get()).apply {
logger(level = Logger.Level.Debug)
// There is a lot more...
}.build()
}
})
}
// Get instances anywhere
val sketch = KoinPlatform.getKoin().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)
```
## 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
```kotlin
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:
```kotlin
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:
```kotlin
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)][ImageRequest_ViewExtensions] or
[ImageView.loadImage()][loadImage] extension functions, they will call target() for you, as
follows:
```kotlin
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:
```kotlin
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][ImageRequest_SingletonExtensions].enqueue()
> and [ImageRequest][ImageRequest_SingletonExtensions].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:
```kotlin
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:
```kotlin
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? = imageResult.transformeds
val extras: Map? = 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:
```kotlin
// 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:
```kotlin
// 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()][loadImage] is only available in singleton mode
## Document
Basic functions:
* [Register component][register_component]
* [Compose][compose]
* [Http: Load network images][http]
* [AnimatedImage: GIF、WEBP、HEIF][animated_image]
* [Resize: Modify the image size][resize]
* [Transformation: Transformation image][transformation]
* [Transition: Display images in cool transitions][transition]
* [StateImage: Placeholder and error images][state_image]
* [Listener: Listen for request status and download progress][listener]
* [DownloadCache: Understand download caching to avoid repeated downloads][download_cache]
* [ResultCache: Understand result caching to avoid duplicate conversions][result_cache]
* [MemoryCache: Understand memory caching to avoid repeated loading][memory_cache]
* [Fetcher: Learn about Fetcher and extend new URI types][fetcher]
* [Decoder: Understand the decoding process of Sketch][decoder]
* [Target: Apply the load results to the target][target]
* [SVG: Decode SVG still images][svg]
* [VideoFrames: Decode video frames][video_frame]
* [BlurHash][blurhash]
* [ExifOrientation: Correct the image orientation][exif_orientation]
* [ImageOptions: Manage image configurations in a unified manner][image_options]
* [RequestInterceptor: Intercept ImageRequest][request_interceptor]
* [DecodeInterceptor: Intercept the decoding process][decode_interceptor]
* [Preload images into memory][preload]
* [Download images][download]
* [Lifecycle][lifecycle]
* [Log][log]
* [Migrate][migrate]
Featured functions:
* [SketchImageView: Configure the request through XML attributes][sketch_image_view]
* [Improve the clarity of long images in grid lists][long_image_grid_thumbnails]
* [Displays the download progress][progress_indicator]
* [Displays the image type corner][mime_type_logo]
* [Pause image downloads on cellular data to save data][save_cellular_traffic]
* [The list slides to pause the loading of images][pause_load_when_scrolling]
* [Displays an icon for an apk file or installed app][apk_app_icon]
[comment]: <> (classs)
[AsyncImage]: ../sketch-compose-core/src/commonMain/kotlin/com/github/panpf/sketch/AsyncImage.kt
[AsyncImagePainter]: ../sketch-compose-core/src/commonMain/kotlin/com/github/panpf/sketch/AsyncImagePainter.kt
[AsyncImageState]: ../sketch-compose-core/src/commonMain/kotlin/com/github/panpf/sketch/AsyncImageState.kt
[DiskCache]: ../sketch-core/src/commonMain/kotlin/com/github/panpf/sketch/cache/DiskCache.common.kt
[loadImage]: ../sketch-view/src/main/kotlin/com/github/panpf/sketch/image_view_singleton_extensions.kt
[Disposable]: ../sketch-core/src/commonMain/kotlin/com/github/panpf/sketch/request/Disposable.kt
[Image]: ../sketch-core/src/commonMain/kotlin/com/github/panpf/sketch/Image.kt
[ImageRequest]: ../sketch-core/src/commonMain/kotlin/com/github/panpf/sketch/request/ImageRequest.common.kt
[ImageRequest_SingletonExtensions]: ../sketch-singleton/src/commonMain/kotlin/com/github/panpf/sketch/request/ImageRequest.singleton.kt
[ImageRequest_ViewExtensions]: ../sketch-view-core/src/main/kotlin/com/github/panpf/sketch/request/ImageRequest.view.kt
[ImageResult]: ../sketch-core/src/commonMain/kotlin/com/github/panpf/sketch/request/ImageResult.kt
[SingletonSketch]: ../sketch-singleton/src/commonMain/kotlin/com/github/panpf/sketch/SingletonSketch.common.kt
[Sketch]: ../sketch-core/src/commonMain/kotlin/com/github/panpf/sketch/Sketch.common.kt
[Target]: ../sketch-core/src/commonMain/kotlin/com/github/panpf/sketch/target/Target.kt
[ViewTarget]: ../sketch-view-core/src/main/kotlin/com/github/panpf/sketch/target/ViewTarget.kt
[comment]: <> (wiki)
[animated_image]: animated_image.md
[apk_app_icon]: apk_app_icon.md
[register_component]: register_component.md
[compose]: compose.md
[decoder]: decoder.md
[download_cache]: download_cache.md
[exif_orientation]: exif_orientation.md
[fetcher]: fetcher.md
[getting_started]: getting_started.md
[http]: http.md
[image_options]: image_options.md
[lifecycle]: lifecycle.md
[listener]: listener.md
[log]: log.md
[long_image_grid_thumbnails]: long_image_grid_thumbnails.md
[memory_cache]: memory_cache.md
[mime_type_logo]: mime_type_logo.md
[pause_load_when_scrolling]: pause_load_when_scrolling.md
[preload]: preload.md
[download]: download_image.md
[progress_indicator]: progress_indicator.md
[request_interceptor]: request_interceptor.md
[decode_interceptor]: decode_interceptor.md
[resize]: resize.md
[result_cache]: result_cache.md
[save_cellular_traffic]: save_cellular_traffic.md
[sketch_image_view]: sketch_image_view.md
[state_image]: state_image.md
[svg]: svg.md
[target]: target.md
[transformation]: transformation.md
[transition]: transition.md
[video_frame]: video_frame.md
[migrate]: migrate.md
[blurhash]: blurhash.md