panpf / zoomimage

ZoomImage is a library designed for Compose Multiplatform and Android View for gesture zoom viewing of images, supported scale, pan, locate, rotation, and super-large image subsampling.
Apache License 2.0
234 stars 12 forks source link
android compose compose-multiplatform huge image locate multiplatform pan positioning rotate rotation scale scaling subsampling super-large translation view zoom

logo_image ZoomImage

Platform Platform2 API License version_icon

Translations: 简体中文

ZoomImage is a library designed for Compose Multiplatform and Android View for gesture scale viewing of images. It has the following features and functions:

https://github.com/panpf/zoomimage/assets/3250512/f067bed9-24e4-4ab8-a839-0731e155f4ef

Multiplatform support

Function/Platform Android iOS Desktop Web
Zoom
Subsampling
Exif Orientation
Integrated Sketch
Integrated Coil
Integrated Glide
Integrated Picasso

Download

Published to mavenCentral

${LAST_VERSION}: Download (Not included 'v')

Compose multiplatform:

// Provides the SketchZoomAsyncImage component adapted to the Sketch v4+ image loader (recommended)
implementation("io.github.panpf.zoomimage:zoomimage-compose-sketch:${LAST_VERSION}")

// Provides SketchZoomAsyncImage component adapted to the old Sketch v3 image loader
implementation("io.github.panpf.zoomimage:zoomimage-compose-sketch3:${LAST_VERSION}")

// Provides the CoilZoomAsyncImage component adapted to the Coil v3+ image loader
implementation("io.github.panpf.zoomimage:zoomimage-compose-coil:${LAST_VERSION}")

// Provides CoilZoomAsyncImage component adapted to the old Coil v2 image loader
implementation("io.github.panpf.zoomimage:zoomimage-compose-coil2:${LAST_VERSION}")

// Provides basic ZoomImage component, additional work needs to be done to support subsampling, and 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}")

[!TIP] Just choose one according to the image loader you use or your needs.

Only android compose:

// Provides the GlideZoomAsyncImage component adapted to the Glide image loader
implementation("io.github.panpf.zoomimage:zoomimage-compose-glide:${LAST_VERSION}")

[!TIP] Why is there no picasso version of the compose ZoomImage component? Because Picasso has officially stated that it will not provide support for compose (Original post here)

Android view:

// Provides the SketchZoomImageView component adapted to the Sketch v4+ image loader (recommended)
implementation("io.github.panpf.zoomimage:zoomimage-view-sketch:${LAST_VERSION}")

// Provides SketchZoomImageView component adapted to the old Sketch v3 image loader
implementation("io.github.panpf.zoomimage:zoomimage-view-sketch3:${LAST_VERSION}")

// Provides the CoilZoomImageView component adapted to the Coil v3+ image loader
implementation("io.github.panpf.zoomimage:zoomimage-view-coil:${LAST_VERSION}")

// Provides CoilZoomImageView component adapted to the old Coil v2 image loader
implementation("io.github.panpf.zoomimage:zoomimage-view-coil2:${LAST_VERSION}")

// Provides the GlideZoomImageView component adapted to the Glide image loader
implementation("io.github.panpf.zoomimage:zoomimage-view-glide:${LAST_VERSION}")

// Provides the PicassoZoomImageView component adapted to the Picasso image loader
implementation("io.github.panpf.zoomimage:zoomimage-view-picasso:${LAST_VERSION}")

// Provides the most basic ZoomImageView component. Additional work needs to be done to support subsampling. Network images are not supported.
implementation("io.github.panpf.zoomimage:zoomimage-view:${LAST_VERSION}")

[!TIP] Just choose one according to the image loader you use or your needs.

R8 / Proguard

ZoomImage's own obfuscation is already included in aar, but you may also need to add obfuscation configuration for other libraries that depend indirectly

Quickly Started

Compose multiplatform:

// Use basic ZoomImage components
val zoomState: ZoomState by rememberZoomState()
LaunchedEffect(zoomState.subsampling) {
    val resUri = Res.getUri("files/huge_world.jpeg")
    val imageSource = ImageSource.fromComposeResource(resUri)
    zoomState.subsampling.setImageSource(imageSource)
}
ZoomImage(
    painter = painterResource(Res.drawable.huge_world_thumbnail),
    contentDescription = "view image",
    modifier = Modifier.fillMaxSize(),
    zoomState = zoomState,
)

// Use SketchZoomAsyncImage component
SketchZoomAsyncImage(
    uri = "https://sample.com/sample.jpeg",
    contentDescription = "view image",
    modifier = Modifier.fillMaxSize(),
)

// Use CoilZoomAsyncImage component
CoilZoomAsyncImage(
    model = "https://sample.com/sample.jpeg",
    contentDescription = "view image",
    modifier = Modifier.fillMaxSize(),
)

[!TIP] The usage of SketchZoomAsyncImage and CoilZoomAsyncImage is the same as their original AsyncImage, except that there is an additional zoomState: ZoomState parameter

Only android compose:

// Use GlideZoomAsyncImage component
GlideZoomAsyncImage(
    model = "https://sample.com/sample.jpeg",
    contentDescription = "view image",
    modifier = Modifier.fillMaxSize(),
)

[!TIP] The usage of GlideZoomAsyncImage is the same as its original GlideImage, except that there is an additional zoomState: ZoomState parameter

Android view:

// Use basis ZoomImageView component
val zoomImageView = ZoomImageView(context)
zoomImageView.setImageResource(R.drawable.huge_world_thumbnail)
zoomImageView.subsampling.setImageSource(ImageSource.resource(R.raw.huge_world))

// Use SketchZoomAsyncImage component
val sketchZoomImageView = SketchZoomImageView(context)
sketchZoomImageView.loadImage("https://sample.com/sample.jpeg")

// Use CoilZoomImageView component
val coilZoomImageView = CoilZoomImageView(context)
sketchZoomImageView.loadImage("https://sample.com/sample.jpeg")

// Use GlideZoomImageView component
val glideZoomImageView = GlideZoomImageView(context)
Glide.with(this@GlideZoomImageViewFragment)
    .load("https://sample.com/sample.jpeg")
    .into(glideZoomImageView)

// Use PicassoZoomImageView component
val picassoZoomImageView = PicassoZoomImageView(context)
picassoZoomImageView.loadImage("https://sample.com/sample.jpeg")

Document

Samples

You can find the sample code in the examples directory, or you can go to release page download App experience

Change Log

Please review the CHANGELOG file

Run Sample App

Prepare the environment:

  1. Android Studio: Koala+ (2024.1.1+)
  2. JDK: 17+
  3. Use kdoctor to check the running environment and follow the prompts to install the required software
  4. Android Studio installs the Kotlin Multiplatform and Compose Multiplatform IDE Supportplugins

Run the sample app:

  1. Clone the project and open it using Android Studio
  2. The running configurations of each platform have been added to the .run directory. After synchronization is completed, directly select the running configuration of the corresponding platform in the running configuration drop-down box at the top of Android Studio and click Run.
  3. The running configuration of the ios platform requires you to manually create it according to the template, as follows:
    1. Copy the .run/iosSample.run.template.xml file and remove the .template suffix. The .ignore file has been configured to ignore iosSample.run.xml
    2. Click Edit Configurations in the run configuration drop-down box at the top, select iosSample and then configure Execute target

Comparison of similar libraries

Function/Library ZoomImage Telephoto PhotoView Subsampling
ScaleImageView
Compose Multiplatform
(Only Android and Desktop)
Android Compose
Android View
Rotate
Locate
Scroll Bar
Read Mode
Subsampling
Subsampling animation
One-finger scale
Mouse wheel scale
Keyboard zoom
Dynamic scale factor
Image Loader
Rich interfaces

My Projects

The following are my other open source projects. If you are interested, you can learn about them:

License

Apache 2.0. See the LICENSE file for details.