阅读 783

彻底解决第三方分享icon过大的问题

很多第三方分享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[]数组没有必然的关系。