一.简介
Bitmap 即位图,也叫做点阵图。点指的是像素点,阵指的是阵列。点阵图,就是以像素为最小单位构成的图,缩放会失真。每个像素实则都是一个非常小的正方形,并被分配不同的颜色,然后通过不同的排列来构成像素阵列,最终呈现出完整的图像。
如上图,Bitmap源码可知,Bitmap其实就是一个 实现了Parcelable接口的常量类。
二.图片格式
Android目前常用的图片格式有png,jpeg和webp。
<1> png:无损压缩图片格式,支持Alpha通道,不会损失图片质量,解压后能还原出完整的原始图像数据,但也因此压缩比小,压缩后的体积仍然很大。
<2> jpeg:有损压缩图片格式,不支持背景透明,压缩比大,压缩后的体积比较小,但其高压缩率是通过去除冗余的图像数据进行的,因此解压后无法还原出完整的原始图像数据。
<3> webp:是一种同时提供了有损压缩和无损压缩的图片格式,派生自视频编码格式VP8,从谷歌官网来看,无损webp平均比png小26%,有损的webp平均比jpeg小25%~34%,无损webp支持Alpha通道,有损webp在一定的条件下同样支持,有损webp在Android4.0(API 14)之后支持,无损和透明在Android4.3(API18)之后支持。采用webp能够在保持图片清晰度的情况下,可以有效减小图片所占有的磁盘空间大小。
压缩格式文件的大小:图片大小。
图片占用内存的大小:解压缩后显示在设备屏幕上的原始图像数据所占用的内存大小。
三.相关名称解释
<1> 色深
又叫色彩深度 (Color Depth)。假设色深的数值为 n,代表每个像素会采用 n 个二进制位来存储颜色信息,也即 2 的 n 次方,表示的是每个像素能显示 2^n 种颜色。
比如色深值为8 表示每个像素显示 2^8=256 种的颜色。典型的如GIF图像的色深就为8。
显然,色深会影响图片的整体质量,色深越大,能表示的颜色越丰富,图片也就越清晰,颜色过渡就越平滑。但相对的,图片的体积也会增加,因为每个像素必须存储更多的颜色信息。
<2> 分辨率
这里的分辨率指的是图片的分辨率,不是手机屏幕的分辨率。
图片的分辨率决定位图图像细节的精细程度。图像的分辨率越高,所包含的像素就越多,图像也就越清晰,同样的,它也会相应增加图片的体积。
通常,我们用每一个方向上的像素数量来表示分辨率,也即水平像素数×垂直像素数,比如 320×240等。
一张分辨率为 640x480 的图片,其像素数量就达到了 307,200,也就是我们常说的 30万像素。
四.Bitmap相关知识
1.Bitmap.Config
由以上源码截图可知,Config是Bitmap类中的枚举。用来确定Bitmap的色深。
枚举举例
枚举值:RGB_565
源码注释:Each pixel is stored on 2 bytes。
说明:RGB_565值的色深 每个像素在内存中占据2个字节。
******************************************************************
枚举值:ARGB_4444
源码注释:Each pixel is stored on 2 bytes。
说明:ARGB_4444值的色深 每个像素在内存中占据2个字节。
******************************************************************
枚举值:ARGB_8888
源码注释:Each pixel is stored on 4 bytes。
说明:ARGB_8888值的色深 每个像素在内存中占据4个字节。
******************************************************************
枚举值:RGBA_F16
源码注释:Each pixels is stored on 8 bytes。
说明:RGBA_F16值的色深 每个像素在内存中占据8个字节。
2.getByteCount()方法
<1> 源码
/**
* Returns the minimum number of bytes that can be used to store this bitmap's pixels.
*
* <p>As of {@link android.os.Build.VERSION_CODES#KITKAT}, the result of this method can
* no longer be used to determine memory usage of a bitmap. See {@link
* #getAllocationByteCount()}.</p>
*/
public final int getByteCount() {
if (mRecycled) {
Log.w(TAG, "Called getByteCount() on a recycle()'d bitmap! "
+ "This is undefined behavior!");
return 0;
}
// int result permits bitmaps up to 46,340 x 46,340
return getRowBytes() * getHeight();
}
<2> 方法作用
源码:Returns the minimum number of bytes that can be used to store this bitmap's pixels.
翻译:返回可用于存储此位图像素的最小字节数。
说明:此方法是API12加入的,API19开始使用getAllocationByteCount()方法代替
<3> 说明
由上述源码可知,getByteCount()方法返回的是 位图像素中行之间的字节数 * 高度 即
getRowBytes() * getHeight()
int result permits bitmaps up to 46,340 x 46,340。
Int结果允许位图最大为46,340 x 46,340。
<4> 计算位图像素中行之间的字节数
/**
* Return the number of bytes between rows in the bitmap's pixels. Note that
* this refers to the pixels as stored natively by the bitmap. If you call
* getPixels() or setPixels(), then the pixels are uniformly treated as
* 32bit values, packed according to the Color class.
*
* <p>As of {@link android.os.Build.VERSION_CODES#KITKAT}, this method
* should not be used to calculate the memory usage of the bitmap. Instead,
* see {@link #getAllocationByteCount()}.
*
* @return number of bytes between rows of the native bitmap pixels.
*/
public final int getRowBytes() {
if (mRecycled) {
Log.w(TAG, "Called getRowBytes() on a recycle()'d bitmap! This is undefined behavior!");
}
return nativeRowBytes(mNativePtr);
}
return nativeRowBytes(mNativePtr);
private static native int nativeRowBytes(long nativeBitmap);
源码所示,getRowBytes方法,底层调用的是native方法。
SkImageInfo.h类
static int SkColorTypeBytesPerPixel(SkColorType ct) {
static const uint8_t gSize[] = {
0, // Unknown
1, // Alpha_8
2, // RGB_565
2, // ARGB_4444
4, // RGBA_8888
4, // BGRA_8888
1, // kIndex_8
};
SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gSize) == (size_t)(kLastEnum_SkColorType + 1),
size_mismatch_with_SkColorType_enum);
SkASSERT((size_t)ct < SK_ARRAY_COUNT(gSize));
return gSize[ct];
}
static inline size_t SkColorTypeMinRowBytes(SkColorType ct, int width) {
return width * SkColorTypeBytesPerPixel(ct);
}
SkColorTypeMinRowBytes方法中 返回的是
width * SkColorTypeBytesPerPixel(ct):宽度*SkColorTypeBytesPerPixel(ct)。
SkColorTypeBytesPerPixel(ct):字面解释:根据颜色类型获取每个像素对应的字节数。
<5> 总结
有上述源码分析可知
getByteCount()方法
作用:返回可用于存储此位图像素的最小字节数。
源码:根据颜色类型获取每个像素对应的字节数 * Bitmap的宽度 *Bitmap的高度。
3.getAllocationByteCount()方法
<1> 源码
/**
* Returns the size of the allocated memory used to store this bitmap's pixels.
*
* <p>This can be larger than the result of {@link #getByteCount()} if a bitmap is reused to
* decode other bitmaps of smaller size, or by manual reconfiguration. See {@link
* #reconfigure(int, int, Config)}, {@link #setWidth(int)}, {@link #setHeight(int)}, {@link
* #setConfig(Bitmap.Config)}, and {@link BitmapFactory.Options#inBitmap
* BitmapFactory.Options.inBitmap}. If a bitmap is not modified in this way, this value will be
* the same as that returned by {@link #getByteCount()}.</p>
*
* <p>This value will not change over the lifetime of a Bitmap.</p>
*
* @see #reconfigure(int, int, Config)
*/
public final int getAllocationByteCount() {
if (mRecycled) {
Log.w(TAG, "Called getAllocationByteCount() on a recycle()'d bitmap! "
+ "This is undefined behavior!");
return 0;
}
return nativeGetAllocationByteCount(mNativePtr);
}
<2> 方法作用
源码:Returns the size of the allocated memory used to store this bitmap's pixels.
翻译:返回用于存储此位图像素的已分配内存的大小。
*************************************************************************************
源码:This can be larger than the result of {@link #getByteCount()} if a bitmap is reused to decode other bitmaps of smaller size, or by manual reconfiguration
翻译:如果一个位图被重用来解码其他较小大小的位图,或者通过手动重新配置,这个值可能大于{@link #getByteCount()}的结果。
*************************************************************************************
源码:If a bitmap is not modified in this way, this value will be the same as that returned by {@link #getByteCount()}
翻译:如果不以这种方式修改位图,则该值将与{@link #getByteCount()}返回的值相同。
<3> 说明
return nativeGetAllocationByteCount(mNativePtr);
private static native int nativeGetAllocationByteCount(long nativeBitmap);
即此方法底层调用native的nativeGetAllocationByteCount方法。
4.总结
getAllocationByteCount()方法返回的是 用于存储此位图像素的已分配内存的大小。如果我们通过手动重新配置Bitmap,比如 BitmapFactory.Options.inBitmap 属性设为 true 以支持其他更小的 Bitmap 复用其内存时,这个值可能大于getByteCount()的结果。否则和getByteCount()的结果一致。
Bitmap其他详解 Bitmap详解(下)_jianning-wu的博客-CSDN博客