前言
有时会看到别人使用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也可能无效,比如将图片换成下面这个
总结
由于ARGB_4444已废除,而ALPHA_8需要在特殊条件下使用,一般用来做特殊需求的,所以我们大多数是用的还是ARGB_8888和RGB_565。
RGB_565能够在保证图片质量的情况下大大减少内存的开销,是解决oom的一种方法。但是一定要注意RGB_565是没有透明度的,如果图片本身需要保留透明度,那么就不能使用RGB_565。
同时也要注意,inPreferredConfig设置的模式并不一定会生效。