Home » Android » Is there a way to load and draw partially a bitmap from file in Android?

Is there a way to load and draw partially a bitmap from file in Android?

Posted by: admin June 15, 2020 Leave a comment

Questions:

Say I have a somewhat large (i.e. not fit in most phones’ memory) bitmap on disk. I want to draw only parts of it on the screen in a way that isn’t scaled (i.e. inSampleSize == 1)

Is there a way to load/draw just the part I want given a Rect specifying the area without loading the entire bitmap content?

How to&Answers:

I’m quite confident this is possible since you can load a really large bitmap file into an ImageView without problems so there must be some sort of a built-in way to handle large bitmaps… and after a few attempts, I’ve found a solution:

Instead of loading the entire bitmap and manually draw it yourself, load it as a Drawable instead:

InputStream mapInput = getResources().openRawResource(
        R.drawable.transit_map);
_map = Drawable.createFromStream(mapInput, "transit_map");

_map.setBounds(0, 0, _mapDimension.width(), _mapDimension.height());

I’m using a resource file but since you can use Drawable.createFromStream to load image from any InputStream, it should works with arbitrary bitmap.

Then, use the Drawable.draw method to draw it onto the desired canvas like so:

int left = -(int) contentOffset.x;
int top = -(int) contentOffset.y;
int right = (int) (zoom * _mapDimension.width() - contentOffset.x);
int bottom = (int) (zoom * _mapDimension.height() - contentOffset.y);

_map.setBounds(left, top, right, bottom);
_map.draw(canvas);

As in the above case, You can also scale and translate the bitmap as well by manipulating the drawable’s bounds and only the relevant parts of the bitmap will be loaded and drawn onto the Canvas.

The result is a pinch-zoomable view from just one single 200KB bitmap file. I’ve also tested this with a 22MB PNG file and it still works without any OutOfMemoryError including when screen orientation changes.

Answer:

Now it’s very relevant: BitmapRegionDecoder.

Note: available since Android SDK 10

Answer:

It can easily be done by using RapidDecoder.

import rapid.decoder.BitmapDecoder;

Rect bounds = new Rect(10, 20, 30, 40);
Bitmap bitmap = BitmapDecoder.from("your-file.png")
                             .region(bounds)
                             .decode();
imageView.setImageBitmap(bitmap);

It supports down to Android 2.2 (API Level 8).

Answer:

Generally speaking, that isn’t possible, particularly since most image formats are compressed, so you don’t even know which bytes to read until you’ve extracted the uncompressed form.

Break your image up into small tiles and load just the tiles you need to cover the region you want to display at runtime. To avoid jittery scrolling, you might also want to preload tiles that are just out of sight (the ones that border the visible tiles) on a background thread.