徹底解決第三方分享icon過大的問題

天之界線2010發表於2018-05-28

很多第三方分享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。

徹底解決第三方分享icon過大的問題

上面三幅圖,圖一是原圖,圖二是用第一種方案得到的,圖三是通過較優方案得到的。可以明顯看到圖三的質量最為接近於原圖。

這裡需要說明的是,圖中的數字是bitmap解析後的bitmap的大小,和傳遞的byte[]陣列沒有必然的關係。

相關文章