Android:API版本低于12时bitmap.getByteCount()的用法

21

当我搜索如何在将图像保存到SD卡之前找到其大小时,我发现了这个:

bitmap.getByteCount();
但是这种方法在API 12中添加,并且我正在使用API 10。 所以我再次发现了这个:

getByteCount()只是一个方便的方法,它恰好执行您放置在else块中的操作。 换句话说,如果您只是将getSizeInBytes重写为始终返回“ bitmap.getRowBytes()* bitmap.getHeight()”

在这里:

Bitmap getByteCount在哪里?

因此,通过计算此bitmap.getRowBytes()* bitmap.getHeight(),我获得了值120000(117 KB)

而在SD卡上的图像大小为1.6 KB

我错过了什么? 还是我做错了什么?

谢谢你


正如下面的评论所述,我想知道这是否与内存中的(未压缩的)位图大小相比磁盘上的(压缩的PNG/JPG)大小有关。因此,由于我认为这是来自“LruCache”示例,117 KB可能是更安全的选择。 - pjco
我在下面添加了更全面的答案,你计算得很正确。 - pjco
7个回答

33

你做得很正确!

确保数值有效的快捷方法是像这样记录日志:

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

这将产生结果:

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

所以两者都在计算相同的数字,我怀疑这个数字是位图的内存大小。这与磁盘上的 JPGPNG 不同,因为它完全未经压缩。


要了解更多信息,我们可以查看AOSP和示例项目中的源代码。这是示例项目 BitmapFun 中使用的文件,位于Android开发者文档中的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();
}

正如您所看到的,这是他们使用的相同技术

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

参考资料:


+1 非常感谢您宝贵的时间提供这个出色的答案 :) - swiftBoy
不同设备给出不同的位图大小...有什么原因吗? - Kalpesh Lakhani
1
@KalpeshLakhani 不同的设备使用不同的颜色模式,因此对于完整的未压缩图像占用不同数量的内存。Android SDK中列出的4种模式是ALPHA_8ARGB_4444ARGB_8888RGB_565。请参见Bitmap.Config - pjco

6

目前我正在使用这个:

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

要获取总字节数作为大小。因为我在这里得到的值完全与SD卡上图像的大小(以字节为单位)相匹配。


1
因为磁盘上的大小与内存中的大小不同。当您拥有一个 Bitmap 对象时,它表示图像的完整像素数据,因此您可以在屏幕上显示它。当您将文件保存为磁盘上的信息时,这些信息可以通过像 JPG 或 PNG 这样的压缩算法进行压缩。 - Rich
不要这样做!虽然这个方法可以运行,但对于“LruMemoryCache”(这是问题的来源)来说并不是一个好主意。这会导致所有数据在内存中再次加载一遍。 - pjco
在这里列出的所有方法中,只有这个方法可以准确描述文件大小,我需要用它作为网络流量指示器。其中 data 是位图:data.getByteCount()data.getRowBytes() * data.getHeight()data.getAllocationByteCount() 返回的值都比字节数组的长度高得多。 - Kyle Falconer
@netinept,我认为也许看一下File()或FileDescriptor()来获取磁盘上的大小(我忘记了哪个会起作用)可能更好,不是吗?这个问题是在关于LruMemoryCache中的大小内存的。您的用例听起来有点不同。我认为这取决于您从哪里获取位图以及您对其进行什么操作。如果它适合您,那很好,感谢您的评论 :) - pjco

2

但我没有压缩它。如果我使用JPEG格式,我将质量设置为100。此外,我尝试过使用PNG(无损),它总是以原始质量输出,无论我将值设置为多少。 - Archie.bpgc
1
即使将质量设置为100,它仍然被压缩了(https://dev59.com/uGsz5IYBdhLWcg3wTmCr)。getByteCount方法与图像格式无关,它显示图像在RAM内存中占用多少内存。 - junkdog

2

这里有一种替代方法:

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();
}

IDE中关于getAllocationByteCount()的声明:

如果一个位图被重用以解码较小尺寸的其他位图,或通过手动重新配置,那么此值可以大于getByteCount()的结果。请参见reconfigure(int, int, Bitmap.Config)、setWidth(int)、setHeight(int)、setConfig(Bitmap.Config)和BitmapFactory.Options.inBitmap。如果一个位图没有以这种方式被修改,那么这个值将与getByteCount()返回的值相同。


1

你可以尝试这段代码

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;

起初我以为可能缺少其他因素。但事实上,使用公式bitmap.getHeight() * bitmap.getWidth()得到的值是117 K.B(如果将其称为像素,则为120000),而图像大小仅为1.6 k.B在SD卡上。因此,如果我必须乘以bytesPerPixel,我最终会得到一个更大的值:( - Archie.bpgc

0

为什么不尝试将它除以1024?这样可以得到KB而不是Bytes。


0

SD卡上的图像大小不同,因为它被压缩了。在设备上,它将取决于宽度/高度。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接