魯班圖片壓縮

前言

Luban是圖片壓縮工具,通過參考或者自創壓縮規則推求極致的壓縮效果 目前的版本壓縮效果主要參考微信。因爲微信用戶量最大,如果壓縮後的圖片越接近微信則越被用戶接受。

說明

目前的Luban只是壓縮結果接近微信,自身的算法只是爲了達到這個效果而設計的。與微信並無任何聯繫,也不敢妄稱是微信的算法。

算法步驟

注:下文所說“比例”統一表示:圖片短邊除以長邊爲該圖片比例

第三擋壓縮(參考最新版微信壓縮效果)

  1. 判斷圖片比例值,是否處於以下區間內;
    • [1, 0.5625) 即圖片處於 [1:1 ~ 9:16) 比例範圍內
    • [0.5625, 0.5) 即圖片處於 [9:16 ~ 1:2) 比例範圍內
    • [0.5, 0) 即圖片處於 [1:2 ~ 1:∞) 比例範圍內
  2. 判斷圖片最長邊是否過邊界值;
    • [1, 0.5625) 邊界值爲:1664 * n(n=1), 4990 * n(n=2), 1280 * pow(2, n-1)(n≥3)
    • [0.5625, 0.5) 邊界值爲:1280 * pow(2, n-1)(n≥1)
    • [0.5, 0) 邊界值爲:1280 * pow(2, n-1)(n≥1)
  3. 計算壓縮圖片實際邊長值,以第2步計算結果爲準,超過某個邊界值則:width / pow(2, n-1),height/pow(2, n-1)
  4. 計算壓縮圖片的實際文件大小,以第2、3步結果爲準,圖片比例越大則文件越大。
    size = (newW * newH) / (width * height) * m;
    • [1, 0.5625) 則 width & height 對應 1664,4990,1280 * n(n≥3),m 對應 150,300,300;
    • [0.5625, 0.5) 則 width = 1440,height = 2560, m = 200;
    • [0.5, 0) 則 width = 1280,height = 1280 / scale,m = 500;注:scale爲比例值
  5. 判斷第4步的size是否過小
    • [1, 0.5625) 則最小 size 對應 60,60,100
    • [0.5625, 0.5) 則最小 size 都爲 100
    • [0.5, 0) 則最小 size 都爲 100
  6. 將前面求到的值壓縮圖片 width, height, size 傳入壓縮流程,壓縮圖片直到滿足以上數值

項目描述

目前做App開發總繞不開圖片這個元素。但是隨着手機拍照分辨率的提升,圖片的壓縮成爲一個很重要的問題。單純對圖片進行裁切,壓縮已經有很多文章介紹。但是裁切成多少,壓縮成多少卻很難控制好,裁切過頭圖片太小,質量壓縮過頭則顯示效果太差。

於是自然想到App巨頭“微信”會是怎通過在微信朋友圈發送近100張不同分辨率圖片,對比原圖與微信麼處理,Luban(魯班)就是壓縮後的圖片逆向推算出來的壓縮算法。

因爲有其他語言也想要實現Luban,所以描述了一遍算法步驟

因爲是逆向推算,效果還沒法跟微信一模一樣,但是已經很接近微信朋友圈壓縮後的效果,具體看以下對比!

效果與對比

內容 原圖 Luban Wechat
截屏 720P 720*1280,390k 720*1280,87k 720*1280,56k
截屏 1080P 1080*1920,2.21M 1080*1920,104k 1080*1920,112k
拍照 13M(4:3) 3096*4128,3.12M 1548*2064,141k 1548*2064,147k
拍照 9.6M(16:9) 4128*2322,4.64M 1032*581,97k 1032*581,74k
滾動截屏 1080*6433,1.56M 1080*6433,351k 1080*6433,482k

導入

compile 'io.reactivex:rxandroid:1.2.1'
compile 'io.reactivex:rxjava:1.1.6'

compile 'top.zibin:Luban:1.0.8'

使用

Listener方式

Luban內部採用IO線程進行圖片壓縮,外部調用只需設置好結果監聽即可:

Luban.get(this)
    .load(File)                     //傳人要壓縮的圖片
    .putGear(Luban.THIRD_GEAR)      //設定壓縮檔次,默認三擋
    .setCompressListener(new OnCompressListener() { //設置回調

        @Override
        public void onStart() {
            // TODO 壓縮開始前調用,可以在方法內啓動 loading UI
        }
        @Override
        public void onSuccess(File file) {
            // TODO 壓縮成功後調用,返回壓縮後的圖片文件
        }

        @Override
        public void onError(Throwable e) {
            // TODO 當壓縮過去出現問題時調用
        }
    }).launch();    //啓動壓縮

RxJava方式

RxJava調用方式請自行隨意控制線程:

Luban.get(this)
        .load(file)
        .putGear(Luban.THIRD_GEAR)
        .asObservable()
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .doOnError(new Action1<Throwable>() {
            @Override
            public void call(Throwable throwable) {
                throwable.printStackTrace();
            }
        })
        .onErrorResumeNext(new Func1<Throwable, Observable<? extends File>>() {
            @Override
            public Observable<? extends File> call(Throwable throwable) {
                return Observable.empty();
            }
        })
        .subscribe(new Action1<File>() {
            @Override
            public void call(File file) {
                // TODO 壓縮成功後調用,返回壓縮後的圖片文件
            }
        }).launch();    //啓動壓縮

方法對應表

方法名 功能
load(File file) 傳入要壓縮的文件
setFilename(String filename) 設置壓縮後圖片命名
putGear(int gear) 設置壓縮檔次
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章