Image Composable that supports Zooming/Panning and Dynamic Image Loading/Unloading with SubSampling
Built for Jetpack Compose 🚀 with Kotlin and ❤️
Possible replacement for davemorrissey/subsampling-scale-image-view
- Dynamic partial image loading/unloading based on the tile visibility (Supports wide/large image)
- Zooming and panning out of the box
- Supports all image types supported by BigmapRegionDecoder
- Currently supports ByteArray and InputStream & custom imagesources
- Supports automatic height adjustment based on the content
- Supports animated image zooming/panning
Add MavenCentral Snapshot repository and add dependency
repositories {
maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") }
}
dependencies {
implementation("xyz.quaver:subsampledimage:0.0.1-alpha17-SNAPSHOT")
}
...
Add following line to your Composable
SubSampledImage(modifier = modifier, imageSource = imageSource)
Currently supports ByteArray and InputStream
for ByteArray Images:
rememberByteArrayImageSource(image)
for InputStream Images:
rememberInputStreamImageSource(inputStream)
It is safe to close the stream after calling this function.
... Or Implement your own ImageSource
interface ImageSource {
val imageSize: Size
fun decodeRegion(region: Rect, sampleSize: Int): ImageBitmap
}
To change Reset behavior, Image position, Zoom level or to get information about the state of the composable, use SubSampledImageState
val subSampledImageState = rememberSubSampledImageState(scaleType, bound)
SubSampledImage(modifier = modifier, image = image, state = state)
The position of the displayed image is determined based on three rectangles, canvasSize
, imageRect
, imageSize
Image is projected onto imageRect
, and the portion that overlaps canvasSize
gets shown in the Composable
The size and number of the tiles dynamically change as the zoom level changes
and the tiles automatically loads and unloads Image based on whether or not it overlaps the canvasSize to save memory use
typealias ScaleType = (canvasSize: Size, imageSize: Size) -> Rect
ScaleType
determins imageRect
when the Composable is first initialized or reset.
Predefined ScaleType
can be found in object ScaleTypes
Available ScaleTypes:
Open Issues/Pull Requests for more ScaleTypes or Implement your own function
typealias Bound = (imageRect: Rect, canvasSize: Size) -> Rect
Bound
limits zoom level / position of imageRect
Predefined Bound
can be found in object Bounds
Available Bounds:
Bound | Description |
---|---|
NO_BOUND | No Bound |
FORCE_OVERLAP | Forces imageRect to always overlap with canvasSize . a.k.a. No Whitespace |
FORCE_OVERLAP_OR_CENTER | Forces imageRect to overlap with canvasSize , center if not possible. Do not allow images to go smaller than canvasSize |
SubSampledImage supports automatic height based on loaded image
call Modifier.wrapContentHeight(state: SubSampledImageState, defaultHeight: Dp)
the height is fixed to supplied defaultHeight
until the image loads and changes height based on the aspect ratio of the image
ScaleTypes.FIT_WIDTH
as a scaleType
Open an issue if you want this feature with the width
set state.isGestureEnabled
to true to enable this feature
default value is false
call one of the following to enable double tap zoom
Modifier.doubleClickCycleZoom(state, scale)
Modifier.doubleClickContinuousZoom(state, scale)
Modifier.doubleClickCycleZoom(state, scale)
cycles between scale
and original scale
Modifier.doubleClickContinuousZoom(state, scale)
continues to zoom in
call state.setImageRectWithBound(Rect, animationSpec)
to animate panning and zooming.
see chapter Three Important Rectangles
and double tap zoom source code to learn more
davemorrissey for screen test card images
Copyright 2021 tom5079
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.