很多第三方分享SDK对于分析的icon的bitmap大小做了强制要求,比如32kb,那么我们需要对于即将要通过intent传递的bitmap做一个压缩,保证不会引起异常。
先来对色彩空间做一个了解
ARGB_8888:
32位(4byte),4个byte描述四个不同的参数(alpha,red,green,blue)。BitmapFactory加载时默认参数。
Bitmap.Config.ARGB_8888。
RGB_565:
16位(2byte),3个byte分别描述三个参数(red,green,blue),也就是说不支持透明度。
options.inPreferredConfig = Bitmap.Config.RGB_565;
RGB_565自然比ARGB_8888小,是它的一半,代价是没有透明度。
Bitmap的大小计算公式
大小=(宽×缩放比)×(高×缩放比)×色彩空间
比如在做第三方分享的时候,我们都会用没有透明度的图片,也就是用RGB_565,这里的色彩空间就是2,缩放比为1。
下面是通过最终大小得到缩放后的bitmap的代码:
Bitmap thumbBmp(@DrawableRes int drawableRes, long size) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), drawableRes, options);
int width = (int) Math.sqrt(size / 2); // 用了Bitmap.Config.RGB_565,这里除以2
return Bitmap.createScaledBitmap(bitmap, width, width, true);
}
复制代码
更合理的压缩方案
上述的方案得到的bitamp是完全符合标准的,通过bmp.getByteCount()
可以进行检查。但是我们传递的时候可以选择直接传递byte[],那么就不用考虑色彩空间这种和展示相关的变量了,在参考AdvancedLuban这个库后,我们得到了下面的更优代码:
@Nullable
static byte[] getImageThumbByteArr(@Nullable Bitmap bitmap) {
if (bitmap == null) {
return null;
}
final long size = '耀';
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(bitmap.getWidth() * bitmap.getHeight());
int options = 100;
bitmap.compress(Bitmap.CompressFormat.JPEG, options, outputStream);
while (outputStream.size() > size && options > 6) {
outputStream.reset();
options -= 6;
bitmap.compress(Bitmap.CompressFormat.JPEG, options, outputStream);
}
bitmap.recycle();
return outputStream.toByteArray();
}
复制代码
上面的代码是根据需要输出的byte[]大小进行循环的质量压缩,每次减少6,这样得到最接近于目标size的byte[]。这里的6可以自行修改,size = '耀'
表示最大大小为32768。
上面三幅图,图一是原图,图二是用第一种方案得到的,图三是通过较优方案得到的。可以明显看到图三的质量最为接近于原图。
这里需要说明的是,图中的数字是bitmap解析后的bitmap的大小,和传递的byte[]数组没有必然的关系。