Bitmap详解(上)

一.简介

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博客

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android中,Bitmap是一种用于表示图像的对象。它由像素点构成,每个像素点包含了图像的颜色信息。\[1\]要创建一个Bitmap对象,可以使用BitmapFactory类的decodeResource()方法来从资源文件中加载图像,或者使用Bitmap的createBitmap()方法来创建一个空白的位图。\[2\]例如,可以使用以下代码创建一个Bitmap对象: ```java Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher); ``` 这段代码将从资源文件中加载名为ic_launcher的图像,并将其存储在bitmap对象中。接下来,你可以对这个bitmap对象进行各种操作,例如旋转、缩放、裁剪等。\[3\]最后,可以将处理后的bitmap对象设置给ImageView来显示图像。 #### 引用[.reference_title] - *1* *2* [Android自定义控件(八)——详解创建bitmap的方式](https://blog.csdn.net/liyuanjinglyj/article/details/103242724)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Bitmap.createBitmap创建的新bitmap可能与原始bitmap是一个对象](https://blog.csdn.net/xuguobiao/article/details/50962877)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值