ZoomImage gives Compose and Android View a gesture zoom image viewer
Image zoom library specially designed for Compose Multiplatform and Android View. Supported scale, pan, locate, rotation, and super-large image subsampling.
At a glance
- What is it?
- ZoomImage is a Kotlin library for gesture zooming of images, built for Compose Multiplatform and for the classic Android View, with subsampling for very large images, locate anywhere, rotation, Exif orientation handling, read mode, and integrations for Sketch, Coil, Glide and Picasso. It is Apache-2.0 licensed and published to Maven Central.
- Who is it for?
- ZoomImage suits a Kotlin team that has to display a photograph at full resolution and wants pinch, double-click, drag, rotation and locate to behave the same on Android, iOS, desktop and web, since the same library covers the Compose Multiplatform targets and the View target.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 25 days ago.
- What is it written in?
- Mainly Kotlin, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the library covers, and for which toolkits
ZoomImage is a gesture zoom viewing of images library, and the README is precise about the scope: it is specially designed for Compose Multiplatform and Android View.
So there are two front ends over a shared core. The Compose side targets Compose Multiplatform on Android, iOS, macOS Native, JVM desktop and web, and the View side is the classic Android View system. The core directory, zoomimage-core/, holds the gesture and layout logic, and every other top level directory is a thin integration on top of it.
The feature list is what makes it more than a pinch-zoom modifier. Basic interaction covers double-click scale, two-finger scale, single-finger scale, mouse wheel scale, keyboard scale, single-finger drag, inertial sliding and keyboard drag. On top of that there is locate, which lets the user find a point anywhere in the image and keeps it centred, and rotation at 0, 90, 180, 270 and 360 degrees.
The piece that distinguishes it from a typical zoomable image composable is subsampling, which supports subsampling of very large images to avoid OOM, with tile support animation and sharpness gradients. That is the difference between a library that scales a bitmap and a library that can open a photo whose decoded size would not fit in memory.
The rest of the list is polish that matters in a real image viewer. A dynamic scale factor automatically calculates the most appropriate double-click scaling factor based on the image size and the container size. Scaling damping gives a rubber band effect when the scale is pushed beyond the maximum or minimum. A scroll bar shows the current scroll position. Read mode fills the screen on a long image so the user can start reading without a double-click first. Exif orientation is read and the image is rotated accordingly. And the image loader is pluggable, with support for Sketch, Coil, Glide and Picasso, and the ability to customise further.
The licence is Apache-2.0, the primary language is Kotlin, the homepage is panpf.github.io/zoomimage, and there is a Chinese translation of the README.
The platform matrix, and the two rows that stop at Android
The multiplatform support table is worth reading closely, because it shows that the platform support is not uniform across the features.
Zoom, Subsampling, Exif Orientation, and the Sketch and Coil integrations are all supported on Android, iOS, macOS Native, JVM and Web. The two exceptions are the Glide and the Picasso integrations, which are supported on Android only.
That asymmetry has a clear reason. Glide and Picasso are Android libraries with no iOS, desktop or web implementation, so an integration that wraps them cannot exist on those targets. Sketch and Coil, by contrast, are multiplatform themselves, so their integrations can follow the platform matrix.
The same reasoning explains a note elsewhere in the README, which asks why there is no Picasso version of the compose ZoomImage component and answers that Picasso has officially stated that it will not provide support for Compose, with a link to the original post.
So if your project is Compose Multiplatform and you use an image loader that is itself multiplatform, you get the whole feature set. If you are on Android View with Glide or Picasso, you get the Android feature set, which is all of it. The only configuration where you lose something is Compose on a non-Android target with an Android-only loader, and in that case the library tells you the fix is to move loaders rather than to wait.
The samples directory matches the matrix, with samples/androidApp, samples/iosApp, samples/jsApp, samples/jvmApp, samples/macosApp, samples/shared and samples/wasmJsApp, and the web example is hosted at panpf.github.io/zoomimage/app. For Android, iOS, jvm, macOS and web deployable packages the README points at the Releases page.
Choosing the artifact, and the two naming schemes
Everything is published to Maven Central, and the artifact naming is systematic enough that picking the wrong one is the main install mistake to avoid.
For Compose Multiplatform there are eleven coordinates in the README, and they differ along two axes: the UI toolkit and the image loader. The Sketch line has sketch4, sketch4-koin, sketch4-core, sketch3 and sketch3-core. The Coil line has coil3, coil3-core, coil2 and coil2-core. Then there is the plain zoomimage-compose, which provides the basic ZoomImage component and does not support network images, and zoomimage-compose-resources, which supports loading images from the composeResources folder.
The core variants are worth distinguishing. The singleton mode integration gives you a ready component such as SketchZoomAsyncImage, the koin variant does the same for projects using Koin for dependency injection, and the core variant is the lower level piece you wire up yourself.
The Android View side follows the same scheme with a view- prefix: zoomimage-view-sketch4, zoomimage-view-sketch4-koin, zoomimage-view-sketch4-core, then the sketch3, coil3, coil2 and glide and picasso variants. The Glide one provides a GlideZoomImageView component and the Picasso one a PicassoZoomImageView.
The README's tip is to just choose one according to the image loader you use or your needs, and the sample below shows the pattern:
// Provides basic ZoomImage component, does not support network images.
implementation("io.github.panpf.zoomimage:zoomimage-compose:${LAST_VERSION}")
// Support loading images from composeResources folder
implementation("io.github.panpf.zoomimage:zoomimage-compose-resources:${LAST_VERSION}")The version placeholder is written as ${LAST_VERSION} in the README, with a note that the v prefix is not included in the published version.
Installing the Compose and View artifacts
The Compose Multiplatform coordinates are given with a comment above each line explaining what the artifact provides, and the first three are marked as recommended.
// Integrate Sketch v4+ singleton mode, provides SketchZoomAsyncImage component. (Recommended)
implementation("io.github.panpf.zoomimage:zoomimage-compose-sketch4:${LAST_VERSION}")
// Integrate Sketch v4+ core, provides SketchZoomAsyncImage component. (Recommended)
implementation("io.github.panpf.zoomimage:zoomimage-compose-sketch4-core:${LAST_VERSION}")
// Integrate Coil v3+ singleton mode, provides CoilZoomAsyncImage component.
implementation("io.github.panpf.zoomimage:zoomimage-compose-coil3:${LAST_VERSION}")If you are on Android only and use Glide, the Compose artifact is a single line:
// Integrate Glide, provides GlideZoomAsyncImage component.
implementation("io.github.panpf.zoomimage:zoomimage-compose-glide:${LAST_VERSION}")And the View artifacts are listed in the same way, with the Sketch and Coil lines first and the Glide and Picasso ones at the end:
// Integrate Sketch v4+ singleton mode, provides SketchZoomAsyncImage component. (Recommended)
implementation("io.github.panpf.zoomimage:zoomimage-view-sketch4:${LAST_VERSION}")
// Integrate Glide, provides GlideZoomImageView component.
implementation("io.github.panpf.zoomimage:zoomimage-view-glide:${LAST_VERSION}")The repository layout mirrors the artifact list exactly, with a directory per published coordinate, from zoomimage-compose-coil2 through zoomimage-compose-sketch4 and zoomimage-view-sketch4-koin down to the shared zoomimage-core. So if you are unsure which module a coordinate corresponds to, the directory names answer that. The build itself is a Gradle project with buildSrc, a libs.versions.toml for the version catalog, and a mkdocs.yml with a build_docs.sh for the documentation site.
Where ZoomImage fits, and where it stops
The comparison worth making is with what you would otherwise write, and with the other zoom libraries in the same ecosystem.
Writing it yourself means implementing the gesture arbitration, which is the part that is genuinely hard. Pinch zoom, double-click zoom and drag all compete for the same pointer events, and each has to win or lose in a defined order or the interaction feels broken. On top of that sits the subsampling, which needs a tile source, a tile cache and the animation from the low-resolution preview to the full-resolution tiles. Doing that well is a project.
Against a general purpose image loader, the difference is that a loader such as Coil or Glide is about getting bytes and decoding them, while this is about the viewing interaction. The integrations here are thin: they supply the bitmap and the loader, and ZoomImage supplies the gesture handling, the tile pipeline and the layout.
The limits are structural. This is a viewer, not a gallery, so there is no picker, no thumbnail grid and no paging. The feature set is desktop and mobile oriented, with keyboard scale and keyboard drag on the list, which is unusual for an Android library and reflects the multiplatform ambition, but it also means there is no specific support for things like pinch-to-zoom on a trackpad or the system-level zoom accessibility behaviours that a platform's own image viewer would provide. And the artifact selection is a real decision: there are more than twenty published coordinates, and picking the wrong one means either no network image support or a missing feature.
There is also a version to think about. The release history shows 1.7.0 on 2026-09-28, preceded by 1.7.0-beta01 on 2026-09-21 and 1.7.0-alpha01 on 2026-08-06, so the project is working through a release with the usual alpha and beta steps, and the last push was on 2026-09-28.
One documentation gap is worth flagging. The README covers the features, the platform matrix and the artifacts in detail, and the documentation site is at panpf.github.io/zoomimage, but the README as given here does not document the API surface, the gesture configuration options or the custom image loader contract. For a library this configurable, that documentation is where you would want to look before committing to it, and the SECURITY.md, CHANGELOG.md and CHANGELOG.zh.md at the repository root are the other places to check.
Editorial conclusion
ZoomImage suits a Kotlin team that has to display a photograph at full resolution and wants pinch, double-click, drag, rotation and locate to behave the same on Android, iOS, desktop and web, since the same library covers the Compose Multiplatform targets and the View target. It is the wrong tool if you need a photo picker or a gallery, because the library is a viewer rather than a browser, and it is the wrong tool if you need Picasso in Compose, which the README explains is because Picasso has stated it will not support Compose. Before adopting it, pick the artifact that matches your image loader and your UI toolkit from the download list, and check the platform table, because Glide and Picasso integrations are Android only.
Frequently asked questions
How do I add ZoomImage to a Compose Multiplatform project?
Add the coordinate that matches your image loader from the download list, for example implementation("io.github.panpf.zoomimage:zoomimage-compose-sketch4:${LAST_VERSION}") for Sketch v4 in singleton mode. The plain zoomimage-compose artifact provides the basic component but does not support network images, and zoomimage-compose-resources loads from the composeResources folder.
Which platforms does ZoomImage support?
Zoom, Subsampling, Exif Orientation and the Sketch and Coil integrations are supported on Android, iOS, macOS Native, JVM and Web. The Glide and Picasso integrations are Android only, because those two loaders are themselves Android only.
Does ZoomImage support very large images?
Yes. It supports subsampling of very large images to avoid OOM, with tile support animation and sharpness gradients, so an image whose decoded size would not fit in memory can still be viewed.
Why is there no Picasso version of the Compose ZoomImage component?
The README explains that Picasso has officially stated that it will not provide support for Compose, with a link to the original post. The Picasso integration therefore exists only for the Android View target.
What does ZoomImage do about rotation and Exif?
It supports 0, 90, 180, 270 and 360 degree rotation of pictures, and it reads the Exif Orientation information and automatically rotates images accordingly, with Exif Orientation listed as supported on all five platforms.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/panpf-zoomimage)Was this useful?