21

When i searched for how to find the size of an image before saving it on the SD card, i found this:

bitmap.getByteCount();

but that method is added in API 12 and i am using API 10. So again i found out this:

getByteCount() is just a convenience method which does exactly what you have placed in the else-block. In other words, if you simply rewrite getSizeInBytes to always return "bitmap.getRowBytes() * bitmap.getHeight()"

here:

Where the heck is Bitmap getByteCount()?

so, by calculating this bitmap.getRowBytes() * bitmap.getHeight() i got the value 120000 (117 KB).

where as the image size on the SD card is 1.6 KB.

What am i missing? or doing wrong?

Thank You

Community
  • 1
  • 1
Archie.bpgc
  • 23,812
  • 38
  • 150
  • 226
  • As noted in a comment below I wonder if this has to do with the (uncompressed) bitmap size in memory vs the (compressed PNG/JPG) size on disk. Thus since this is I think from the `LruCache` example, the 117 KB might be the safer bet. – pjco Mar 29 '13 at 21:10
  • I added more comprehensive answer below, you are calculating it correctly – pjco Mar 29 '13 at 21:54

7 Answers7

33

You are doing it correctly!

A quick way to know for sure if the values are valid, is to log it like this:

int numBytesByRow = bitmap.getRowBytes() * bitmap.getHeight();
int numBytesByCount = bitmap.getByteCount();
Log.v( TAG, "numBytesByRow=" + numBytesByRow ); 
Log.v( TAG, "numBytesByCount=" + numBytesByCount ); 

This gives the result:

03-29 17:31:10.493: V/ImageCache(19704): numBytesByRow=270000
03-29 17:31:10.493: V/ImageCache(19704): numBytesByCount=270000

So both are calculating the same number, which I suspect is the in-memory size of the bitmap. This is different than a JPG or PNG on disk as it is completely uncompressed.


For more info, we can look to AOSP and the source in the example project. This is the file used in the example project BitmapFun in the Android developer docs Caching Bitmaps

AOSP ImageCache.java

/**
 * Get the size in bytes of a bitmap in a BitmapDrawable.
 * @param value
 * @return size in bytes
 */
@TargetApi(12)
public static int getBitmapSize(BitmapDrawable value) {
    Bitmap bitmap = value.getBitmap();

    if (APIUtil.hasHoneycombMR1()) {
        return bitmap.getByteCount();
    }
    // Pre HC-MR1
    return bitmap.getRowBytes() * bitmap.getHeight();
}

As you can see this is the same technique they use

bitmap.getRowBytes() * bitmap.getHeight();

References:

pjco
  • 3,826
  • 25
  • 25
  • +1 Thank you so much for your valuable time for such a Nice answer :) – swiftBoy Sep 30 '13 at 06:35
  • for difference devices it gives different bitmap size...any reason? – Kalpesh Lakhani Jun 21 '14 at 11:33
  • 1
    @KalpeshLakhani different devices use different color modes, and thus take up different amounts of memory for the full, uncompressed image. The 4 modes listed in the Android SDK are `ALPHA_8`, `ARGB_4444`, `ARGB_8888`, and `RGB_565`. See [Bitmap.Config](http://developer.android.com/reference/android/graphics/Bitmap.Config.html) – pjco Jun 25 '14 at 05:28
6

For now i am using this:

ByteArrayOutputStream bao = new ByteArrayOutputStream();
my_bitmap.compress(Bitmap.CompressFormat.PNG, 100, bao);
byte[] ba = bao.toByteArray();
int size = ba.length;

to get total no.of bytes as size. Because the value i get here perfectly matches the size(in bytes) on the image on SD card.

Archie.bpgc
  • 23,812
  • 38
  • 150
  • 226
  • 1
    because the size on disk is not the same as the size in memory. When you have a Bitmap object it represents the full pixel data of the image so that you can display it on screen. When you save the file as information on disk, this information can be compressed by a compression algorithm like JPG or PNG. – Rich Feb 21 '13 at 20:07
  • Don't do this! This works, but is a bad idea for an `LruMemoryCache` (which is what the question comes from). This loads all the data into memory a second time. – pjco Mar 29 '13 at 21:56
  • @pjco Of all the methods listed here, this is the only one which can accurately describe the file size, which I needed for a network traffic indicator. Where `data` is a Bitmap: `data.getByteCount()`, `data.getRowBytes() * data.getHeight()`, and `data.getAllocationByteCount()` all return much higher values than the length of a byte array. – Kyle Falconer Jun 02 '14 at 14:21
  • @netinept, I would think maybe looking at the File() or FileDescriptor() to get the size on disk (I forget off the top of my head which would work) would be better, no? This question was asked in relation to an `LruMemoryCache` which relates to the size in memory. Your use case sounds a bit different. I think it depends on where you get the bitmap and what you are doing with it. If it works for you though that's good, thanks for the comment :) – pjco Jun 04 '14 at 13:56
2

Nothing is missing! Your codesnippet shows exact the implementation from Android-Source:

http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.1.1_r1/android/graphics/Bitmap.java#Bitmap.getByteCount%28%29

I think the differences in size are the result of image-compressing (jpg and so on).

darkNeuron
  • 31
  • 2
  • but i am not compressing it. If i am using JPEG format i am setting quality to 100. Moreover i tried using PNG(lossless) also, where it always gives original quality no matter what i set the value to. – Archie.bpgc Sep 26 '12 at 05:13
  • 1
    Even with quality set to 100, it is still being compressed (http://stackoverflow.com/questions/7982409/is-jpeg-lossless-when-quality-is-set-to-100). The getByteCount method has nothing to do with image formats, it shows you how much memory the image takes up in RAM memory. – junkdog Jan 28 '13 at 10:37
2

Here is an alternative way:

public static int getBitmapByteCount(Bitmap bitmap) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR1)
        return bitmap.getRowBytes() * bitmap.getHeight();
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
        return bitmap.getByteCount();
    return bitmap.getAllocationByteCount();
}

A statement from the IDE for getAllocationByteCount():

This can be larger than the result of getByteCount() if a bitmap is reused to decode other bitmaps of smaller size, or by manual reconfiguration. See reconfigure(int, int, Bitmap.Config), setWidth(int), setHeight(int), setConfig(Bitmap.Config), and BitmapFactory.Options.inBitmap. If a bitmap is not modified in this way, this value will be the same as that returned by getByteCount().

Enzokie
  • 7,365
  • 6
  • 33
  • 39
1

may u can try this code

int pixels = bitmap.getHeight() * bitmap.getWidth();
int bytesPerPixel = 0;
switch(bitmap.getConfig()) {
case ARGB_8888:
bytesPerPixel = 4;
break;
case RGB_565:
bytesPerPixel = 2; 
 break;
case ARGB_4444:
bytesPerPixel = 2; 
 break;
case ALPHA_8 :
 bytesPerPixel = 1; 
 break;
}
 int byteCount = pixels / bytesPerPixel;
steevoo
  • 621
  • 6
  • 18
  • first i thought i might be missing some other factor. but the thing is the value i get using the formula bitmap.getHeight() * bitmap.getWidth(); is 117 K.B(its 120000 if you call it as pixels) where as the image size is just 1.6 k.B on the SD card. so if i have to multiply with bytesPerPixel i will end up getting a still bigger value :( – Archie.bpgc Sep 26 '12 at 06:23
0

the image on the sd card has a different size because it's compressed. on the device it will depend on the width/height

Rafael Sanches
  • 1,823
  • 21
  • 28
0

Why don't you try dividing it between 1024? To get the KB instead of Bytes.

NemesisDoom
  • 596
  • 6
  • 21