BigImageViewer
Big image viewer supporting pan and zoom, with very little memory usage and full featured image loading choices. Powered by Subsampling Scale Image View, Fresco, Glide, and Picasso. Even with gif and webp support! 🍻
Top Related Projects
An image loading and caching library for Android focused on smooth scrolling
A powerful image downloading and caching library for Android
An Android library for managing images and the memory they use.
Powerful and flexible library for loading, caching and displaying images on Android.
Implementation of ImageView for Android that supports zooming, by various touch gestures.
Android library (AAR). Highly configurable, easily extendable deep zoom view for displaying huge images without loss of detail. Perfect for photo galleries, maps, building plans etc.
Quick Overview
BigImageViewer is an Android library for viewing large images efficiently. It supports zooming, panning, and displaying various image formats including JPEG, PNG, GIF, and even long images. The library is designed to handle large images smoothly without causing out-of-memory errors.
Pros
- Efficient memory usage, preventing out-of-memory errors
- Supports multiple image formats, including long images
- Smooth zooming and panning capabilities
- Easy integration with popular image loading libraries like Glide and Fresco
Cons
- Limited to Android platform
- May require additional setup for certain image formats
- Documentation could be more comprehensive
- Some advanced features may require additional configuration
Code Examples
Loading an image with BigImageViewer:
BigImageViewer.initialize(GlideImageLoader.with(context))
val bigImageView = findViewById<BigImageView>(R.id.big_image_view)
bigImageView.showImage(Uri.parse("https://example.com/large_image.jpg"))
Configuring image loading options:
val bigImageView = findViewById<BigImageView>(R.id.big_image_view)
bigImageView.setInitScaleType(ScaleType.CENTER_CROP)
bigImageView.setOptimizeDisplay(true)
bigImageView.showImage(Uri.parse("https://example.com/large_image.jpg"))
Adding a custom progress indicator:
val bigImageView = findViewById<BigImageView>(R.id.big_image_view)
bigImageView.setProgressIndicator(ProgressPieIndicator())
bigImageView.showImage(Uri.parse("https://example.com/large_image.jpg"))
Getting Started
- Add the dependency to your app's
build.gradle
:
dependencies {
implementation 'com.github.piasy:BigImageViewer:1.8.1'
implementation 'com.github.piasy:GlideImageLoader:1.8.1'
}
- Initialize BigImageViewer in your Application class:
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
BigImageViewer.initialize(GlideImageLoader.with(this))
}
}
- Use BigImageView in your layout:
<com.github.piasy.biv.view.BigImageView
android:id="@+id/big_image_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
- Load an image in your Activity or Fragment:
val bigImageView = findViewById<BigImageView>(R.id.big_image_view)
bigImageView.showImage(Uri.parse("https://example.com/large_image.jpg"))
Competitor Comparisons
An image loading and caching library for Android focused on smooth scrolling
Pros of Glide
- More comprehensive image loading library with support for various sources (network, local, etc.)
- Extensive caching mechanisms for improved performance
- Wider adoption and larger community support
Cons of Glide
- Larger library size, which may impact app size
- Steeper learning curve due to more features and configuration options
Code Comparison
BigImageViewer:
BigImageView bigImageView = findViewById(R.id.big_image_view);
bigImageView.showImage(Uri.parse("https://example.com/image.jpg"));
Glide:
ImageView imageView = findViewById(R.id.image_view);
Glide.with(this)
.load("https://example.com/image.jpg")
.into(imageView);
Key Differences
- BigImageViewer focuses specifically on large image viewing and zooming
- Glide is a more general-purpose image loading and caching library
- BigImageViewer uses a custom view (BigImageView) while Glide works with standard ImageViews
- Glide offers more advanced features like transformations and placeholders
Use Cases
- Choose BigImageViewer for apps primarily dealing with large, zoomable images
- Opt for Glide for general image loading needs and apps requiring extensive image manipulation
A powerful image downloading and caching library for Android
Pros of Picasso
- Widely adopted and battle-tested in many production apps
- Extensive caching mechanisms for improved performance
- Supports image transformations and filters out of the box
Cons of Picasso
- Limited support for very large images
- Lacks built-in zooming and panning capabilities
- Memory management can be challenging for extremely large images
Code Comparison
BigImageViewer:
BigImageView bigImageView = findViewById(R.id.bigImageView);
bigImageView.showImage(Uri.parse("https://example.com/large-image.jpg"));
Picasso:
ImageView imageView = findViewById(R.id.imageView);
Picasso.get().load("https://example.com/image.jpg").into(imageView);
Key Differences
- BigImageViewer is specifically designed for handling large images efficiently, while Picasso is a general-purpose image loading library.
- BigImageViewer provides built-in zooming and panning capabilities, which Picasso lacks.
- Picasso offers more extensive image transformation options out of the box.
- BigImageViewer uses a tile-based approach for loading large images, which can be more memory-efficient for very large images compared to Picasso's approach.
Use Cases
- Choose BigImageViewer when working with extremely large images or when zooming and panning are crucial features.
- Opt for Picasso for general image loading tasks, especially when dealing with standard-sized images and when extensive caching and transformation options are needed.
An Android library for managing images and the memory they use.
Pros of Fresco
- More comprehensive image loading library with broader feature set
- Better performance optimization for memory usage and caching
- Larger community and ongoing support from Facebook
Cons of Fresco
- Steeper learning curve due to complexity
- Larger library size, which may impact app size
- More dependencies and potential for conflicts
Code Comparison
BigImageViewer:
BigImageView bigImageView = findViewById(R.id.mBigImage);
bigImageView.showImage(Uri.parse("https://example.com/image.jpg"));
Fresco:
SimpleDraweeView draweeView = findViewById(R.id.my_image_view);
draweeView.setImageURI("https://example.com/image.jpg");
Key Differences
- BigImageViewer focuses specifically on large image viewing, while Fresco is a more general-purpose image loading library
- BigImageViewer has a simpler API for basic use cases, making it easier to implement for large image viewing
- Fresco offers more advanced features like image processing, animated GIF support, and progressive JPEG loading
Use Case Recommendations
- Choose BigImageViewer for projects primarily focused on displaying large images with minimal setup
- Opt for Fresco in larger applications requiring extensive image handling capabilities and willing to invest time in setup and optimization
Powerful and flexible library for loading, caching and displaying images on Android.
Pros of Android-Universal-Image-Loader
- More mature and widely adopted library with extensive documentation
- Supports a broader range of image sources, including file system, assets, and content providers
- Offers more customization options for caching, display, and decoding
Cons of Android-Universal-Image-Loader
- No longer actively maintained, with the last update in 2016
- Lacks support for modern Android features and optimizations
- Heavier library size compared to more focused alternatives
Code Comparison
Android-Universal-Image-Loader:
ImageLoader imageLoader = ImageLoader.getInstance();
imageLoader.displayImage(imageUri, imageView, options);
BigImageViewer:
BigImageView bigImageView = findViewById(R.id.big_image_view);
bigImageView.showImage(Uri.parse(imageUri));
Summary
Android-Universal-Image-Loader is a comprehensive and well-established library with extensive features, but it lacks recent updates and modern optimizations. BigImageViewer, on the other hand, is more focused on handling large images efficiently and supports modern Android features. While Android-Universal-Image-Loader offers more customization options, BigImageViewer provides a simpler API for displaying large images with better performance. The choice between the two depends on specific project requirements, with Android-Universal-Image-Loader being suitable for projects needing broad image handling capabilities, and BigImageViewer excelling in scenarios involving large image display and manipulation.
Implementation of ImageView for Android that supports zooming, by various touch gestures.
Pros of PhotoView
- More mature and widely adopted project with a larger community
- Supports zooming and panning with smooth animations out of the box
- Simpler integration for basic image viewing needs
Cons of PhotoView
- Limited support for very large images, which can lead to out-of-memory errors
- Lacks built-in support for progressive loading or tiling of large images
- Less flexibility for customizing the image loading process
Code Comparison
PhotoView implementation:
PhotoView photoView = findViewById(R.id.photo_view);
Glide.with(this).load(imageUrl).into(photoView);
BigImageViewer implementation:
BigImageView bigImageView = findViewById(R.id.big_image_view);
bigImageView.showImage(Uri.parse(imageUrl));
Both libraries offer simple APIs for basic image viewing, but BigImageViewer provides more advanced features for handling large images efficiently.
Android library (AAR). Highly configurable, easily extendable deep zoom view for displaying huge images without loss of detail. Perfect for photo galleries, maps, building plans etc.
Pros of subsampling-scale-image-view
- Simpler implementation, easier to integrate for basic image viewing needs
- Supports custom tile loading for advanced use cases
- Efficient memory usage through subsampling and tiling
Cons of subsampling-scale-image-view
- Limited file format support compared to BigImageViewer
- Lacks built-in support for GIF animations
- Less actively maintained, with fewer recent updates
Code Comparison
subsampling-scale-image-view:
SubsamplingScaleImageView imageView = new SubsamplingScaleImageView(context);
imageView.setImage(ImageSource.uri("/sdcard/image.jpg"));
BigImageViewer:
BigImageView bigImageView = findViewById(R.id.big_image_view);
bigImageView.showImage(Uri.parse("file:///sdcard/image.jpg"));
Both libraries offer simple APIs for loading and displaying large images, but BigImageViewer provides a more modern and flexible approach with support for multiple image loading engines.
BigImageViewer offers a wider range of features, including support for various image formats (JPEG, PNG, GIF, WebP) and integration with popular image loading libraries like Glide and Fresco. It also provides better performance for large images and animated GIFs.
subsampling-scale-image-view, while more focused in scope, excels in memory efficiency and custom tile loading capabilities. It's a solid choice for projects with specific requirements around large static images.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
BigImageViewer
Big image viewer supporting pan and zoom, with very little memory usage and full featured image loading choices. Powered by Subsampling Scale Image View, Fresco, Glide, and Picasso. Even with gif and webp support!
Demo
pan and zoom | gif support |
---|---|
Getting started
Add the dependencies
Note: please put this download url at the first of your repositories
part, otherwise, gradle may search in wrong place.
allprojects {
repositories {
mavenCentral()
}
}
implementation 'com.github.piasy:BigImageViewer:1.8.1'
// load with fresco
implementation 'com.github.piasy:FrescoImageLoader:1.8.1'
// load with glide
implementation 'com.github.piasy:GlideImageLoader:1.8.1'
// progress pie indicator
implementation 'com.github.piasy:ProgressPieIndicator:1.8.1'
// support thumbnail, gif and webp with Fresco
implementation 'com.github.piasy:FrescoImageViewFactory:1.8.1'
// support thumbnail and gif with Glide
implementation 'com.github.piasy:GlideImageViewFactory:1.8.1'
Initialize
// MUST use app context to avoid memory leak!
// load with fresco
BigImageViewer.initialize(FrescoImageLoader.with(appContext));
// or load with glide
BigImageViewer.initialize(GlideImageLoader.with(appContext));
// or load with glide custom component
BigImageViewer.initialize(GlideCustomImageLoader.with(appContext, CustomComponentModel.class));
Note that if you've already used Fresco in your project, please change
Fresco.initialize
into BigImageViewer.initialize
.
Add the BigImageView to your layout
<com.github.piasy.biv.view.BigImageView
android:id="@+id/mBigImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:failureImage="@drawable/failure_image"
app:failureImageInitScaleType="center"
app:optimizeDisplay="true"
/>
You can disable display optimization using optimizeDisplay
attribute, or
BigImageView.setOptimizeDisplay(false)
, which will disable animation for long
image, and the switch between thumbnail and origin image.
Show the image
BigImageView bigImageView = (BigImageView) findViewById(R.id.mBigImage);
bigImageView.showImage(Uri.parse(url));
Usage
Animated image support
Since 1.5.0, BIV support display animated image, e.g. gif and animated webp, to achieve that,
you need set a custom ImageViewFactory
via biv.setImageViewFactory
:
// FrescoImageViewFactory is a prebuilt factory, which use Fresco's SimpleDraweeView
// to display animated image, both gif and webp are supported.
biv.setImageViewFactory(new FrescoImageViewFactory());
// GlideImageViewFactory is another prebuilt factory, which use ImageView to display gif,
// animated webp is not supported (although it will be displayed with ImageView,
// but it won't animate).
biv.setImageViewFactory(new GlideImageViewFactory());
Node: if the image is not gif or animated webp, then it will be displayed by SSIV, the image type is not determined by its file extension, but by its file header magic code.
Thumbnail support
To show a thumbnail before the big image is loaded, you can call below version of showImage
:
bigImageView.showImage(Uri.parse(thumbnail), Uri.parse(url));
Note: make sure that you have already called setImageViewFactory
.
Shared element transition support (experimental)
Since 1.6.0, BIV has experimental support for shared element transition, but it has following known issues:
- The shared image may flicker during enter transition, or become white after return transition, when using Fresco, see Fresco issue #1445;
- The shared image may flicker after return transition, especially after you zoomed SSIV;
You can play with the demo app to evaluate the shared element transition support.
Download progress indicator
bigImageView.setProgressIndicator(new ProgressPieIndicator());
There is one built-in indicator, ProgressPieIndicator
, you can implement your
own indicator easily, learn by example.
Prefetch
You can prefetch images in advance, so it could be shown immediately when user want to see it.
BigImageViewer.prefetch(uris);
Save image into gallery
bigImageView.setImageSaveCallback(new ImageSaveCallback() {
@Override
public void onSuccess(String uri) {
Toast.makeText(LongImageActivity.this,
"Success",
Toast.LENGTH_SHORT).show();
}
@Override
public void onFail(Throwable t) {
t.printStackTrace();
Toast.makeText(LongImageActivity.this,
"Fail",
Toast.LENGTH_SHORT).show();
}
});
// should be called on worker/IO thread
bigImageView.saveImageIntoGallery();
Get current image file
// only valid when image file is downloaded.
File path = bigImageView.getCurrentImageFile();
Image init scale type
You can set the normal image scale type using initScaleType
attribute, or setInitScaleType
.
mBigImageView.setInitScaleType(BigImageView.INIT_SCALE_TYPE_CENTER_CROP);
value | effect |
---|---|
center | Center the image in the view, but perform no scaling. |
centerCrop | Scale the image uniformly (maintain the image's aspect ratio) so that both dimensions (width and height) of the image will be equal to or larger than the corresponding dimension of the view (minus padding). The image is then centered in the view. |
centerInside | Scale the image uniformly (maintain the image's aspect ratio) so that both dimensions (width and height) of the image will be equal to or less than the corresponding dimension of the view (minus padding). The image is then centered in the view. |
fitCenter | Scales the image so that it fits entirely inside the parent. At least one dimension (width or height) will fit exactly. Aspect ratio is preserved. Image is centered within the parent's bounds. |
fitEnd | Scales the image so that it fits entirely inside the parent. At least one dimension (width or height) will fit exactly. Aspect ratio is preserved. Image is aligned to the bottom-right corner of the parent. |
fitStart | Scales the image so that it fits entirely inside the parent. At least one dimension (width or height) will fit exactly. Aspect ratio is preserved. Image is aligned to the top-left corner of the parent. |
fitXY | Scales width and height independently, so that the image matches the parent exactly. This may change the aspect ratio of the image. |
custom | Scale the image so that both dimensions of the image will be equal to or less than the maxScale and equal to or larger than minScale. The image is then centered in the view. |
start | Scale the image so that both dimensions of the image will be equal to or larger than the corresponding dimension of the view. The top left is shown. |
Note: SSIV only support centerCrop, centerInside, custom and start, other scale types are treated as centerInside, while other scale types may be used by animated image types.
Failure image
You can set a local failure image using failureImage
attribute, or setFailureImage
.
It will displayed using an ImageView
when the image network request fails. If not specified,
nothing is displayed when the request fails.
Failure image init scale type
You can set the failure image scale type using failureImageInitScaleType
attribute,
or setFailureImageInitScaleType
.
Any value of ImageView.ScaleType
is valid. Default value is ImageView.ScaleType.FIT_CENTER
. It will be ignored if there is
no failure image set.
Tap to retry
When failure image is specified, you can tap the failure image then it will retry automatically.
That's the default behavior, you can change it using tapToRetry
attribute, or setTapToRetry
.
Image load callback
You can handle the image load response by creating a new ImageLoader.Callback
and overriding the key callbacks
ImageLoader.Callback myImageLoaderCallback = new ImageLoader.Callback() {
@Override
public void onCacheHit(int imageType, File image) {
// Image was found in the cache
}
@Override
public void onCacheMiss(int imageType, File image) {
// Image was downloaded from the network
}
@Override
public void onStart() {
// Image download has started
}
@Override
public void onProgress(int progress) {
// Image download progress has changed
}
@Override
public void onFinish() {
// Image download has finished
}
@Override
public void onSuccess(File image) {
// Image was retrieved successfully (either from cache or network)
}
@Override
public void onFail(Exception error) {
// Image download failed
}
}
Then setting it as the image load callback
mBigImageView.setImageLoaderCallback(myImageLoaderCallback);
The onSuccess(File image)
is always called after the image was retrieved
successfully whether from the cache or the network.
For an example, see ImageLoaderCallbackActivity.java
Cancel image loading
BIV will cancel image loading automatically when detach from window, you can also call cancel
to cancel it manually.
You can also call BigImageViewer.imageLoader().cancelAll();
in an appropriate time,
e.g. Activity/Fragment's onDestroy
callback, to cancel all flying requests, avoiding memory leak.
Full customization
You can get the SSIV instance through the method below:
public SubsamplingScaleImageView getSSIV() {
return mImageView;
}
Then you can do anything you can imagine about SSIV :)
Note: you should test whether SSIV is null, because the image could be a gif, then it won't be displayed by SSIV.
Custom SSIV support
You can even use your own custom SSIV, by calling biv.setImageViewFactory()
,
passing in a factory that override createStillImageView
, and return your custom SSIV.
Custom Glide components support
You can use your custom Glide's components. If you have customized your Glide's configuration, you are able to apply that configuration to BIV too, to do that you only have to initialize BIV in this way:
BigImageViewer.initialize(GlideCustomImageLoader.with(appContext, CustomComponentModel.class));
Where CustomComponentModel.class
is the Glide's model component. That's it!
For more detailed example, please refer to the example project.
Caveats
-
Handle permission when you want to save image into gallery.
-
When you want load local image file, you can create the Uri via
Uri.fromFile
, but the path will be url encoded, and may cause the image loader fail to load it, consider usingUri.parse("file://" + file.getAbsolutePath())
. -
When using with RecyclerView or ViewPager, the recycled BIV doesn't know it should clear the loaded image or reload the image, so you need manually notify it in some way, see issue 107, and issue 177.
-
Crash on Android 4.x device? You could force gradle to use a specific version of OkHttp (some version earlier than 3.13.0), by adding this block to your module's build.gradle, please note that it should be added at the top level, not inside any other block:
configurations { all { resolutionStrategy { eachDependency { DependencyResolveDetails details -> if (details.requested.group == 'com.squareup.okhttp3' && details.requested.name == 'okhttp') { // OkHttp drops support before 5.0 since 3.13.0 details.useVersion '3.12.6' } } } } }
Why another big image viewer?
There are several big image viewer libraries, PhotoDraweeView, FrescoImageViewer, and Subsampling Scale Image View.
They both support pan and zoom. PhotoDraweeView and FrescoImageViewer both use Fresco to load image, which will cause extremely large memory usage when showing big images. Subsampling Scale Image View uses very little memory, but it can only show local image file.
This library show big image with Subsampling Scale Image View, so it only uses very little memory. And this library support using different image load libraries, so it's full featured!
If you are interested in how does this library work, you can refer to this issue, and Subsampling Scale Image View.
Performance
Memory usage of different libraries:
- | PhotoDraweeView | FrescoImageViewer | BigImageViewer |
---|---|---|---|
4135*5134 | 80MB | 80MB | 2~20 MB |
Todo
- GlideImageLoader
- Save image file to gallery
- Optimize long image showing effect, thanks for razerdp
- Optimize "double tap to zoom" effect, thanks for razerdp
- Loading animation
- Downloading progress
- Thumbnail support
- Component to display image list, with memory optimization
- Fail image
- Retry when fail
- PicassoImageLoader, track this issue
Those features are offered by image load libraries, and they should be easy to implement, but I don't have enough time currently. So your contributions are welcome!
When you submit PR, please conform the code style of this project, which is customized from Square Android style.
Top Related Projects
An image loading and caching library for Android focused on smooth scrolling
A powerful image downloading and caching library for Android
An Android library for managing images and the memory they use.
Powerful and flexible library for loading, caching and displaying images on Android.
Implementation of ImageView for Android that supports zooming, by various touch gestures.
Android library (AAR). Highly configurable, easily extendable deep zoom view for displaying huge images without loss of detail. Perfect for photo galleries, maps, building plans etc.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot