详解Bitmap之ARGB_8888/RGB_565/ALPHA_8/ARGB_4444

简介: 有时会看到别人使用bitmap是用到ARGB_8888/RGB_565这类参数,那么这些参数是什么?对bitmap有什么影响?

前言


有时会看到别人使用bitmap是用到ARGB_8888/RGB_565这类参数,那么这些参数是什么?对bitmap有什么影响?


Bitmap.Config


他们是Bitmap.Config的四种枚举类型。ARGB分别是alpha透明度和red、green、blue三色

  • ARGB_8888:分别用8位来记录4个值,所以每个像素会占用32位。
  • ARGB_4444:分别用4位来记录4个值,所以每个像素会占用16位。
  • RGB_565:分别用5位、6位和5位来记录RGB三色值,所以每个像素会占用16位。
  • ALPHA_8:根据注释应该是不保存颜色值,只保存透明度(8位),每个像素会占用8位。

内存大小


那么对bitmap有何影响?

这里都以ARGB_8888为基准来进行对比。

  • ARGB_4444:内存占用减少一半,但是每个值图片失真度很严重,这个参数本身已经不推荐使用了。
  • RGB_565:内存占用减少一半,舍弃了透明度,同时三色值也有部分损失,但是图片失真度很小。
  • ALPHA_8:内存占用减少3/4,没有颜色,只有透明度,即黑白。


测试代码
try {
    URL url = new URL("http://h.hiphotos.baidu.com/image/pic/item/b21c8701a18b87d6b025e513040828381f30fd53.jpg");
    HttpURLConnection connection = (HttpURLConnection)url.openConnection();
    InputStream in = connection.getInputStream();
    ByteArrayOutputStream content = new ByteArrayOutputStream();
    byte[] buffer = new byte[10 * 1024];
    int count;
    while((count = in.read(buffer)) > 0){
        content.write(buffer, 0, count);
    }
    byte[] data = content.toByteArray();
    BitmapFactory.Options options1 = new BitmapFactory.Options();
    options1.inPreferredConfig = Bitmap.Config.ARGB_8888;
    Bitmap bitmap1 = BitmapFactory.decodeByteArray(data, 0 , data.length, options1);
    //System.out.println("bitmap ARGB_8888 length " + bitmap1.getByteCount());
    System.out.println("bitmap ARGB_8888 length " + bitmap1.getRowBytes() * bitmap1.getHeight());
    BitmapFactory.Options options2 = new BitmapFactory.Options();
    options2.inPreferredConfig = Bitmap.Config.RGB_565;
    Bitmap bitmap2 = BitmapFactory.decodeByteArray(data, 0 , data.length, options2);
    //System.out.println("bitmap RGB_565 length " + bitmap2.getByteCount());
    System.out.println("bitmap RGB_565 length " + bitmap2.getRowBytes() * bitmap2.getHeight());
    BitmapFactory.Options options3 = new BitmapFactory.Options();
    options3.inPreferredConfig = Bitmap.Config.ALPHA_8;
    Bitmap bitmap3 = BitmapFactory.decodeByteArray(data, 0 , data.length, options3);
    //System.out.println("bitmap ALPHA_8 length " + bitmap3.getByteCount());
    System.out.println("bitmap ALPHA_8 length " + bitmap3.getRowBytes() * bitmap3.getHeight());
    BitmapFactory.Options options4 = new BitmapFactory.Options();
    options4.inPreferredConfig = Bitmap.Config.ARGB_4444;
    Bitmap bitmap4 = BitmapFactory.decodeByteArray(data, 0 , data.length, options4);
    //System.out.println("bitmap ARGB_4444 length " + bitmap4.getByteCount());
    System.out.println("bitmap ARGB_4444 length " + bitmap4.getRowBytes() * bitmap4.getHeight());
} catch (Exception e) {
    e.printStackTrace();
}
复制代码

但是实际测试中发现内存的大小与预期并不一样,那么是为什么?


ARGB_4444


首先,使用ARGB_4444发现内存没有变化,看看官方的解释

/** Each pixel is stored on 2 bytes. The three RGB color channels and the 
alpha channel (translucency) are stored with a 4 bits precision (16 possible 
values.) This configuration is mostly useful if the application needs to store 
translucency information but also needs to save memory. It is recommended to 
use ARGB_8888 instead of this configuration. Note: as of 
Build.VERSION_CODES.KITKAT, any bitmap created with this configuration will be 
created using ARGB_8888 instead.
Deprecated
Because of the poor quality of this configuration, it is advised to use 
ARGB_8888 instead. **/
@Deprecated
ARGB_4444   (4),
复制代码


原来在KITKAT,即Android 19之后,这个参数就彻底无效了,只用这个参数会被默认替换为ARGB_8888,所以内存大小没有变化。


ALPHA_8


测试的时候,发现ALPHA_8也无效,不仅内存大小没变化,图片也还是原图,没有失去色彩。

我们来看看官方对inPreferredConfig的注释:


/* If this is non-null, the decoder will try to decode into this internal
configuration. If it is null, or the request cannot be met, the decoder will 
try to pick the best matching config based on the system's screen depth, and 
characteristics of the original image such as if it has per-pixel alpha 
(requiring a config that also does). Image are loaded with the 
Bitmap.Config.ARGB_8888 config by default. */
public Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888;
复制代码


翻译过来就是如果inPreferredConfig不为null,那么解码器回尝试使用此参数指定的颜色模式来对图片进行解码,如果解码时发现不能满足这个模式,那么解码器回根据原图的特征及当前设备的屏幕位深,自动选择合适的颜色模式来解码。

简单说就是inPreferredConfig只是一个建议选项,最终使用的模式不一定是它指定的,这个要跟原图特征和当前设备的屏幕位深有关。

这就是当我么使用ALPHA_8无线的原因。另外根据上面的描述,RGB_565也可能无效,比如将图片换成下面这个


pngimg.com/uploads/coc…



总结


由于ARGB_4444已废除,而ALPHA_8需要在特殊条件下使用,一般用来做特殊需求的,所以我们大多数是用的还是ARGB_8888和RGB_565。

RGB_565能够在保证图片质量的情况下大大减少内存的开销,是解决oom的一种方法。但是一定要注意RGB_565是没有透明度的,如果图片本身需要保留透明度,那么就不能使用RGB_565。

同时也要注意,inPreferredConfig设置的模式并不一定会生效。


目录
相关文章
|
6月前
|
存储 计算机视觉 Python
BGR与RGB
BGR与RGB
1733 1
|
15天前
|
存储 编解码 监控
RGB 和 YUV 区别
【10月更文挑战第26天】RGB和YUV在色彩表示原理、数据存储方式、应用场景以及转换关系等方面都存在着明显的区别,它们各自在不同的领域发挥着重要的作用。
|
存储 编解码 Android开发
NV21、NV12、YV12、RGB、YUV、RGBA、RGBX8888等图像色彩编码格式区别
NV21、NV12、YV12、RGB、YUV、RGBA、RGBX8888都是常见的图像颜色编码格式,它们之间的主要区别在于色彩空间和数据排列方式。
212 0
|
编解码 芯片