Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is Bitmap.Options.inSampleSize supposed to work?

An initial code was official doc: Loading Large Bitmaps Efficiently.

I've started poking around and found that images don't resize as described in a documentation:

If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory. The sample size is the number of pixels in either dimension that correspond to a single pixel in the decoded bitmap. For example, inSampleSize == 4 returns an image that is 1/4 the width/height of the original, and 1/16 the number of pixels. Any value <= 1 is treated the same as 1. Note: the decoder uses a final value based on powers of 2, any other value will be rounded down to the nearest power of 2.

When I've run a code:

    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);
    Log.e(LOG_TAG, "orig img size " + options.outWidth + "x" + 
          options.outHeight);

    // Calculate inSampleSize
    // options.inJustDecodeBounds = false;  // version 2
    for (int i = 2; i<20; i*=2) {
        options.inSampleSize = i;
        Log.d(LOG_TAG, "inSampleSize: " + options.inSampleSize);
        Bitmap b = BitmapFactory.decodeResource(res, resId, options);
        Log.e(LOG_TAG, "img size "+options.outWidth+"x"+options.outHeight);
        if (b != null) {
            Log.e(LOG_TAG, "real img size " + b.getWidth() + "x" +
                  b.getHeight() + " byte count " + b.getByteCount());
            b.recycle();
        }
    }

Logs from running the code (Nexus 5, Android 6.0):

E/t: view size 1080x1776
E/t: orig img size 2448x3264
D/t: inSampleSize: 2
E/t: img size 1224x1632
D/t: inSampleSize: 4
E/t: img size 612x816
D/t: inSampleSize: 8
E/t: img size 306x408
D/t: inSampleSize: 16
E/t: img size 153x204
D/t: inSampleSize: 32
E/t: img size 228x306
E/t: real img size 228x306 byte count 279072

That's good, and now with a real load of files (inJustDecodeBounds=false):

E/t: view size 1080x1776
E/t: orig img size 2448x3264
D/t: inSampleSize: 2
W/art: Throwing OutOfMemoryError "Failed to allocate a 71912460 byte allocation with 1048576 free bytes and 62MB until OOM"
D/t: inSampleSize: 4
E/t: img size 1836x2448
E/t: real img size 1836x2448 byte count 17978112
D/t: inSampleSize: 8
E/t: img size 918x1224
E/t: real img size 918x1224 byte count 4494528
D/t: inSampleSize: 16
E/t: img size 459x612
E/t: real img size 459x612 byte count 1123632
D/t: inSampleSize: 32
E/t: img size 228x306
E/t: real img size 228x306 byte count 279072

I'm completely puzzled. If you look at byte count numbers, you may notice, that

like image 213
Paweł Szczur Avatar asked Nov 15 '15 00:11

Paweł Szczur


People also ask

How do you handle bitmap in Android as it takes too much memory?

If you're displaying large amounts of bitmap data in your app, you're likely to run into OutOfMemoryError errors. The recycle() method allows an app to reclaim memory as soon as possible. Caution: You should use recycle() only when you are sure that the bitmap is no longer being used.

What is a bitmap Android?

A bitmap is simply a rectangle of pixels. Each pixel can be set to a given color but exactly what color depends on the type of the pixel. The first two parameters give the width and the height in pixels. The third parameter specifies the type of pixel you want to use.


1 Answers

I am sure that there is a vision behind why BitmapFactory has a decodeResource() method. I have not yet quite figured out what that vision is.

Regardless, using decodeResource() does not eliminate the density conversion of any density-specific resources that you have. So, if you are on an -hdpi device, and the best-match edition of your drawable is in res/drawable-mdpi/, inSampleSize and the density conversion will both occur. And, frankly, I haven't spent the time to try to figure out exactly how those combine.

IMHO, if you are going to use decodeResource(), it should be for something that is not tied to a specific density: put it in res/drawable-nodpi/. But, that's just me.

Where should I look to learn about the magic behind the density?

In general? There is the documentation and the other documentation.

Specifically with respect to BitmapFactory? I am not aware of anything written about that.

Why does it give different sizes depending on inJustDecodeBounds?

No clue, sorry.

like image 166
CommonsWare Avatar answered Oct 15 '22 06:10

CommonsWare