-
Notifications
You must be signed in to change notification settings - Fork 1.2k
02. Displaying images
This view can display JPG and PNG images of any size. In order to support huge images without running out of memory, a subsampled (low resolution) base layer is loaded, and higher resolution tiles are loaded for the visible area as you zoom in.
Android's BitmapRegionDecoder
is used to load subsampled tiles. When you are displaying an image that is small enough to fit in memory on all devices, you can disable tiling, and the view will instead use BitmapFactory
to decode the full size high resolution image. See below for guidance on when you should use tiling.
The Skia library on which BitmapRegionDecoder
is based had some bugs that will not be fixed in versions of Android prior to Nougat or Oreo. It will still display the vast majority of images properly, but you may see problems displaying CMYK JPGs, and grayscale PNGs, especially on older devices. To reduce the frequency of these problems, the view automatically falls back to BitmapFactory
when the image does not need to be subsampled.
Wherever possible, you should thoroughly test your image on a variety of devices.
If you're displaying an image over 10,000x10,000px it may take a few seconds to load the base layer tiles. If you want gestures to be enabled for most of this period, you can use a low resolution preview image. See the preview images page.
- Images are decoded as RGB_565 bitmaps by default, because this requires half as much memory as ARGB_8888. For most JPGs you won't notice the difference in quality. You can configure the view to use ARGB_8888 if you wish.
- If you are displaying large PNGs with alpha channels, Android will probably decode them as ARGB_8888, and this may cause
OutOfMemoryError
s. If possible, remove the alpha channel from PNGs larger than about 2000x2000. This allows them to be decoded as RGB_565. - When embedding images in your app, it is best to place them in your
assets
directory. Alternatively you can place them indrawable-nodpi
- if you put them in a density-specific drawable directory Android may try to scale the image. - When downloading images for display, you will need to store them on the filesystem. If you can guarantee they are small enough to fit in memory when decoded as a
Bitmap
, you can opt to keep them in memory instead. - If you supply a preloaded
Bitmap
object, the view cannot display it using tiles. If it is larger than the maximum canvas texture size (minimum 2048x2048px), this will cause an error. Images this large will often causeOutOfMemoryError
s on older and lower resolution devices, so instead of preloading large images, you should save them to the file system and allow the view to use tiling to display them. - If you have problems displaying a CMYK JPG or grayscale PNG, consider using a custom decoder.
Tiling is enabled by default. You may wish to disable it under some circumstances.
Enable tiling if:
- You want to zoom into very large images without losing detail.
- You need to display images of unknown size e.g. from the camera or gallery.
- You don't know if the images may be too large to fit in memory on some devices.
- You need to display images larger than 2048px.
Disable tiling if:
- You know the size of the images you're displaying.
- You know the images are small enough to fit in memory on all your target devices.
- Your images are no larger than 2048px, or you are able to scale them down.
Use the tilingDisabled
method of the ImageSource
class when you set the image source.
SubsamplingScaleImageView imageView = (SubsamplingScaleImageView)findViewById(id.imageView);
imageView.setImage(ImageSource.asset("map.png").tilingDisabled());
Image rotation is supported in 90° increments. It's best to save the image in the right orientation when possible but this feature is useful if you want to allow the image to be rotated by the user, and when you are displaying images from the device gallery. Automatic rotation based on EXIF data is supported when you are displaying an image from the device's file system, whether they are from the camera or images you have downloaded and saved to temporary storage.
The desired initial orientation should be set before the image source. If you set it after, the view may waste some time loading the wrong tiles. You can freely change the orientation at any time.
SubsamplingScaleImageView imageView = (SubsamplingScaleImageView)findViewById(id.imageView);
imageView.setOrientation(SubsamplingScaleImageView.ORIENTATION_90);
imageView.setImage(ImageSource.asset("map.png"));
To use automatic EXIF rotation, use SubsamplingScaleImageView.ORIENTATION_USE_EXIF
.
Images stored in resources and assets cannot be rotated based on EXIF, you'll need to do it manually. You probably know the orientation of your own files :-)