前言
Luban
是圖片壓縮工具,通過參考或者自創壓縮規則推求極致的壓縮效果
目前的版本壓縮效果主要參考微信。因爲微信用戶量最大,如果壓縮後的圖片越接近微信則越被用戶接受。
說明
目前的Luban
只是壓縮結果接近微信,自身的算法只是爲了達到這個效果而設計的。與微信並無任何聯繫,也不敢妄稱是微信的算法。
算法步驟
注:下文所說“比例”統一表示:圖片短邊除以長邊爲該圖片比例
第三擋壓縮(參考最新版微信壓縮效果)
-
判斷圖片比例值,是否處於以下區間內;
- [1, 0.5625) 即圖片處於 [1:1 ~ 9:16) 比例範圍內
- [0.5625, 0.5) 即圖片處於 [9:16 ~ 1:2) 比例範圍內
- [0.5, 0) 即圖片處於 [1:2 ~ 1:∞) 比例範圍內
-
判斷圖片最長邊是否過邊界值;
- [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)
- 計算壓縮圖片實際邊長值,以第2步計算結果爲準,超過某個邊界值則:width / pow(2, n-1),height/pow(2, n-1)
-
計算壓縮圖片的實際文件大小,以第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爲比例值
-
判斷第4步的size是否過小
- [1, 0.5625) 則最小 size 對應 60,60,100
- [0.5625, 0.5) 則最小 size 都爲 100
- [0.5, 0) 則最小 size 都爲 100
- 將前面求到的值壓縮圖片 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) |
設置壓縮檔次 |