GithubHelp home page GithubHelp logo

curzibn / luban Goto Github PK

View Code? Open in Web Editor NEW
13.5K 361.0 2.2K 4.91 MB

Luban(鲁班)—Image compression with efficiency very close to WeChat Moments/可能是最接近微信朋友圈的图片压缩算法

License: Apache License 2.0

Java 100.00%
luban android image-compression

luban's Introduction

Luban

Build Status Download

Luban(鲁班) —— Android图片压缩工具,仿微信朋友圈压缩策略。

Luban-turbo —— 鲁班项目的turbo版本,查看trubo分支

写在前面

家境贫寒,工作繁忙。只能不定期更新,还望网友们见谅!

项目描述

目前做App开发总绕不开图片这个元素。但是随着手机拍照分辨率的提升,图片的压缩成为一个很重要的问题。单纯对图片进行裁切,压缩已经有很多文章介绍。但是裁切成多少,压缩成多少却很难控制好,裁切过头图片太小,质量压缩过头则显示效果太差。

于是自然想到App巨头“微信”会是怎么处理,Luban(鲁班)就是通过在微信朋友圈发送近100张不同分辨率图片,对比原图与微信压缩后的图片逆向推算出来的压缩算法。

因为有其他语言也想要实现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

导入

implementation 'top.zibin:Luban:1.1.8'

使用

方法列表

方法 描述
load 传入原图
filter 设置开启压缩条件
ignoreBy 不压缩的阈值,单位为K
setFocusAlpha 设置是否保留透明通道
setTargetDir 缓存压缩图片路径
setCompressListener 压缩回调接口
setRenameListener 压缩前重命名接口

异步调用

Luban内部采用IO线程进行图片压缩,外部调用只需设置好结果监听即可:

Luban.with(this)
        .load(photos)
        .ignoreBy(100)
        .setTargetDir(getPath())
        .filter(new CompressionPredicate() {
          @Override
          public boolean apply(String path) {
            return !(TextUtils.isEmpty(path) || path.toLowerCase().endsWith(".gif"));
          }
        })
        .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调用为例

Flowable.just(photos)
    .observeOn(Schedulers.io())
    .map(new Function<List<String>, List<File>>() {
      @Override public List<File> apply(@NonNull List<String> list) throws Exception {
        // 同步方法直接返回压缩后的文件
        return Luban.with(MainActivity.this).load(list).get();
      }
    })
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe();

RELEASE NOTE

Here

License

Copyright 2016 Zheng Zibin

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

luban's People

Contributors

andyxialm avatar chaoyuelee avatar chenfei0928 avatar curzibn avatar flyilxm avatar oldratlee avatar pineapple2333 avatar xxjy avatar zhangchaoxu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

luban's Issues

优化建议

我们知道一张A压缩过后的结果A_COMPRESS会保存在CACHE结果.

那么下一次我们压缩A的时候,可以直接返回A_COMPRESS.直接跳过压缩流程.
当然也可以设置一个FLAG用来设置是否使用上一次压缩结果.

循环压缩图片 可能会把压缩的图片输出在相同的文件地址导致覆盖

rt,我是这么循环压缩的

for(String fileUrl : fileList){
            Luban.get(this).putGear(Luban.THIRD_GEAR)
            .load(new File(fileUrl))
//            .setFilename(getCurrentPhotoFile().getAbsolutePath())
            .setCompressListener(new OnCompressListener() {

                @Override
                public void onSuccess(File file) {
                    DLog.i("完成剪裁:" + file.getAbsolutePath());
                    mCompressList.add(file.getAbsolutePath());
                    if(mCompressList.size() == fileList.size()){
                        uploadFile(mCompressList);
                    }
                }

                @Override
                public void onStart() {
                    DLog.i("开始剪裁");
                }

                @Override
                public void onError(Throwable e) {
                    DLog.i("error:" + e.toString());
                }
            }).launch();

结果发现剪裁完的地址可能会出现相同的结果。

编译报错:不兼容的类型: OnCompressListener 不是函数接口

Error:错误: 不兼容的类型: OnCompressListener 不是函数接口
在 接口 OnCompressListener 中找到多个非覆盖抽象方法
注: 某些输入文件使用或覆盖了已过时的 API。
注: 有关详细信息, 请使用 -Xlint:deprecation 重新编译。
注: 某些输入文件使用了未经检查或不安全的操作。
注: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。
注: 某些消息已经过简化; 请使用 -Xdiags:verbose 重新编译以获得完整输出
1 个错误
FAILURE: Build completed with 2 failures.

1: Task failed with an exception.

  • What went wrong:
    Execution failed for task ':app:compileDebugJavaWithJavac'.

    Compilation failed; see the compiler error output for details.

  • Try:

    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

2: Task failed with an exception.

  • What went wrong:
    Execution failed for task ':app:compileRetrolambdaDebug'.

    Process 'command '/Library/Java/JavaVirtualMachines/jdk1.8.0_40.jdk/Contents/Home/bin/java'' finished with non-zero exit value 1

  • Try:

    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

NullPointerException

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.Bitmap.getWidth()' on a null object reference

关于rxjava

个人是不想用rxjava得,为了一个压缩引用rxjava和rxAndroid 会增大APK大大小,建议分离rxjava,出一个rxjava版本和普通版本。

0.5625、1664等数值的意义

thirdCompress方法中
if (scale <= 1 && scale > 0.5625) {
if (height < 1664) {
size = (width * height) / Math.pow(1664, 2) * 150;
size = size < 60 ? 60 : size;
...
}
为什么要用0.5625、1664等数值进行判断?

建议判断下这个字段是否大于0,错误如下

Process: com.mayi.android_learning, PID: 7575
java.lang.IllegalArgumentException: quality must be 0..100
at android.graphics.Bitmap.compress(Bitmap.java:1017)
at top.zibin.luban.Luban.saveImage(Luban.java:404)
at top.zibin.luban.Luban.compress(Luban.java:363)
at top.zibin.luban.Luban.firstCompress(Luban.java:253)
at top.zibin.luban.Luban.launch(Luban.java:90)
at com.mayi.android_learning.activity.LuBanActivity.handlerImg(LuBanActivity.java:98)
at com.mayi.android_learning.activity.LuBanActivity.onClick(LuBanActivity.java:51)
at com.mayi.android_learning.activity.LuBanActivity$$ViewBinder$1.doClick(LuBanActivity$$ViewBinder.java:24)
at butterknife.internal.DebouncingOnClickListener.onClick(DebouncingOnClickListener.java:22)

讨论帖,新需求与新想法集中营

您这个是图片上传的时候,本地图片压缩吗?
我之前也研究过微信朋友圈的图片压缩,当时得到的结果是:
第一步进行采样率压缩;
第二步进行宽高的等比例压缩(微信对原图和缩略图限制了最大长宽或者最小长宽);
第三步就是对图片的质量进行压缩(一般75或者70);
第四部就是采用webP的格式。
经过这四部的处理,基本上和微信朋友圈的效果一致,包括文件大小和显示效果。
(PS:最近看到微信朋友圈好像换了图片格式,这还有待考证)

常用尺寸和微信压缩比不一致

采用的方式是,从相册选择图片发送朋友圈,等待一时,压缩完成后,保存到相册。
我上传了一张1300w-4:3的图片,luban 是长宽各压缩1/2,微信是的1280*960。
又测试了一张1080P 的截图,luban 尺寸保持1080P,微信是的720P。
因为图片尺寸大了很多,所以在同等大小的情况下,luban 的画质损耗程度完全不可接受。
不知道为什么和作者的测试数据差那么多,是我的测试方法和作者不一致吗?

java.lang.NoClassDefFoundError: Failed resolution of: Lrx/Observable;

public void dealImg(ArrayList fileList){
files.clear();
for (int i = 0; i < fileList.size(); i++) {
File file = fileList.get(i);
Luban.get(this)
.load(file) //传人要压缩的图片
.putGear(Luban.THIRD_GEAR) //设定压缩档次,默认三挡
.setCompressListener(new OnCompressListener() {
@OverRide
public void onStart() {

                    }

                    @Override
                    public void onSuccess(File file) {
                        files.add(file);
                    }

                    public void onError(Throwable e) {

                    }
                }).launch();    //启动压缩
    }
}

java.lang.NoClassDefFoundError: Failed resolution of: Lrx/Observable;
at top.zibin.luban.Luban.launch(Luban.java:113)
at com.xinji.jugongyouyue.workeractivity.WorkerActivityAddProject.dealImg(WorkerActivityAddProject.java:304)
at com.xinji.jugongyouyue.workeractivity.WorkerActivityAddProject.onActivityResult(WorkerActivityAddProject.java:296)
at android.app.Activity.dispatchActivityResult(Activity.java:6378)
at android.app.ActivityThread.deliverResults(ActivityThread.java:3970)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4017)
at android.app.ActivityThread.access$1300(ActivityThread.java:178)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1602)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:192)
at android.app.ActivityThread.main(ActivityThread.java:5784)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1084)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:850)
Caused by: java.lang.ClassNotFoundException: Didn't find class "rx.Observable" on path: DexPathList[[zip file "/data/app/com.xinji.jugongyouyue-1/base.apk"],nativeLibraryDirectories=[/data/app/com.xinji.jugongyouyue-1/lib/arm, /vendor/lib, /system/lib]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
at top.zibin.luban.Luban.launch(Luban.java:113) 
at com.xinji.jugongyouyue.workeractivity.WorkerActivityAddProject.dealImg(WorkerActivityAddProject.java:304) 
at com.xinji.jugongyouyue.workeractivity.WorkerActivityAddProject.onActivityResult(WorkerActivityAddProject.java:296) 
at android.app.Activity.dispatchActivityResult(Activity.java:6378) 
at android.app.ActivityThread.deliverResults(ActivityThread.java:3970) 
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4017) 
at android.app.ActivityThread.access$1300(ActivityThread.java:178) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1602) 
at android.os.Handler.dispatchMessage(Handler.java:111) 
at android.os.Looper.loop(Looper.java:192) 
at android.app.ActivityThread.main(ActivityThread.java:5784) 
at java.lang.reflect.Method.invoke(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:372) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1084) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:850) 
Suppressed: java.lang.ClassNotFoundException: rx.Observable
at java.lang.Class.classForName(Native Method)
at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
... 16 more

关于多图压缩内存问题

看到最新支持了多文件的压缩处理..
那么,当同时进行8个图片的压缩的时候,
势必会出现8个bitmap在内存..8个bitmap同时在进行循环压缩到指定大小...
那么, 很容易就会出现out of memory.
有没有一种方式.扔出8张图片, 以队列的形式每次压缩2张左右.分4次压缩完成.

开始压缩,然后黑屏,然后就一直卡死

public static void compressImage(final String path,final CountDownLatch latch,final int number){
Luban.get(BaseApplication.mContext)
.load(new File(path)) //传人要压缩的图片
.putGear(Luban.THIRD_GEAR) //设定压缩档次,默认三挡
.setCompressListener(new OnCompressListener() { //设置回调

                @Override
                public void onStart() {
                    //TODO 压缩开始前调用,可以在方法内启动 loading UI
                    Logger.e("*********onStart Compress***************");
                }
                @Override
                public void onSuccess(File file) {
                    //TODO 压缩成功后调用,返回压缩后的图片文件
                    Logger.e("*********onSuccess Compress***************");
                    uploadSingleImage(file.getPath(),latch,number);
                }

                @Override
                public void onError(Throwable e) {
                    //TODO 当压缩过去出现问题时调用
                    Logger.e("*********onError Compress***************");
                }
            }).launch();    //启动压缩
}

取消Rxjava

请问能不能出一个版本取消Rajava的,并不是所有的人都偏向于使用Rxjava。

小公告

1、我最近在找工作,Luban 也是这两天突然爆发起来,如果有问题请各位包涵
2、图片压缩是安卓开发的刚需,我希望能靠大家一起讨论完善 Luban
3、如果想把 Luban 用上线上产品的大大请直接用源码,并针对自家产品优化,不要因为 Luban 而对产品造成影响
4、我会不断花时间优化 Luban 项目,希望大家多多支持
5、想加入讨论的大家是希望建Q群,微信群,还是继续在 issues 中讨论,可以在本 issues 下发表意见

- [0.5625, 0.5) 则 width = 1440,height = 2560, m = 200;

代码显示这个地方乘的是400? else if (scale <= 0.5625 && scale > 0.5) {
if (height < 1280 && file.length() / 1024 < 200) return file;

        int multiple = height / 1280 == 0 ? 1 : height / 1280;
        thumbW = width / multiple;
        thumbH = height / multiple;
        size = (thumbW * thumbH) / (1440.0 * 2560.0) * 400;
        size = size < 100 ? 100 : size;

}
作者能解释下,到底是多少不?

鲁班调用报错

Rejecting re-init on previously-failed class java.lang.Class<top.zibin.luban.Luban$3>

个人觉得应该增加onError接口

看了你写的代码,OnCompressListener的onSuccess方法是在try catch里的,既然这样说明可能会有失败,那么加个onError接口应该是极好的

微博很长的截图不能压缩

项目中要上传一张微博长截图,640*11792的尺寸。
while (stream.toByteArray().length / 1024 > size) {
Log.d("Luban","quality options:"+options);
stream.reset();
options -= 6;
bitmap.compress(Bitmap.CompressFormat.JPEG, options, stream);
}
此处循环耗时严重,最后报错:参数quality 在0-100范围。
Caused by: java.lang.IllegalArgumentException: quality must be 0..100

Rxjava线程错误

Luban.get(activity).load(file).putGear(Luban.THIRD_GEAR).asObservable().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
运行压缩后界面会卡主,主线程被阻塞。subscribeOn方法好像无效

示例代码用不了呢。

Luban.get(this)
.load(file) //传人要压缩的图片
.putGear(Luban.THIRD_GEAR) //设定压缩档次,默认三挡
.setCompressListener(new OnCompressListener() {
@OverRide
public void onStart() {
}

                    @Override
                    public void onSuccess(File file) {
                    }

                    @Override
                    public void onError(Throwable e) {

                    }
                }).launch();    //启动压缩

我这里提示onStart跟onError不能用@OverRide

N985st 4.4 机型 miui oom( 手机拍照的图片, 大小1.37MB , 3120 * 4208)

必现, 或许和图片选择库有一定的关系, 滑到最底部, 选择那张图片, 点完成, 会oom;

08-04 12:05:12.904 32005-32005/top.zibin.luban.example E/dalvikvm-heap: Out of memory on a 13128976-byte allocation.
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm: "main" prio=5 tid=1 RUNNABLE
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:   | group="main" sCount=0 dsCount=0 obj=0x4161ee58 self=0x4153b518
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:   | sysTid=32005 nice=0 sched=0/0 cgrp=apps handle=1074413908
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:   | state=R schedstat=( 6918152497 1493630453 7279 ) utm=644 stm=47 core=2
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:     at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:     at android.graphics.BitmapFactory.decodeStreamInternal(BitmapFactory.java:627)
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:603)
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:     at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:378)
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:     at top.zibin.luban.Luban.compress(Luban.java:317)
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:     at top.zibin.luban.Luban.compress(Luban.java:359)
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:     at top.zibin.luban.Luban.thirdCompress(Luban.java:213)
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:     at top.zibin.luban.Luban.asObservable(Luban.java:158)
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:     at top.zibin.luban.example.MainActivity.compressWithRx(MainActivity.java:96)
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:     at top.zibin.luban.example.MainActivity.onActivityResult(MainActivity.java:134)
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:     at android.app.Activity.dispatchActivityResult(Activity.java:5434)
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:     at android.app.ActivityThread.deliverResults(ActivityThread.java:3363)
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:     at android.app.ActivityThread.handleSendResult(ActivityThread.java:3410)
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:     at android.app.ActivityThread.access$1300(ActivityThread.java:141)
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1260)
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:     at android.os.Handler.dispatchMessage(Handler.java:102)
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:     at android.os.Looper.loop(Looper.java:136)
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:     at android.app.ActivityThread.main(ActivityThread.java:5113)
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:     at java.lang.reflect.Method.invokeNative(Native Method)
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:     at java.lang.reflect.Method.invoke(Method.java:515)
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:609)
08-04 12:05:12.904 32005-32005/top.zibin.luban.example I/dalvikvm:     at dalvik.system.NativeStart.main(Native Method)
08-04 12:05:12.904 32005-32005/top.zibin.luban.example D/skia: --- decoder->decode returned false
08-04 12:05:12.904 32005-32005/top.zibin.luban.example D/AndroidRuntime: Shutting down VM
08-04 12:05:12.904 32005-32005/top.zibin.luban.example W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0x4161dd58)

压缩图片报错

java.lang.OutOfMemoryError
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
at android.graphics.BitmapFactory.decodeStreamInternal(BitmapFactory.java:639)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:615)
at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:391)
at top.zibin.luban.Luban.compress(Luban.java:344)//问题在这
at top.zibin.luban.Luban.compress(Luban.java:386)
at top.zibin.luban.Luban.thirdCompress(Luban.java:240)
at top.zibin.luban.Luban.access$200(Luban.java:24)
at top.zibin.luban.Luban$10.call(Luban.java:178)
at top.zibin.luban.Luban$10.call(Luban.java:175)
at rx.internal.operators.OperatorMap$1.onNext(OperatorMap.java:54)
at rx.internal.util.ScalarSynchronousObservable$1.call(ScalarSynchronousObservable.java:46)
at rx.internal.util.ScalarSynchronousObservable$1.call(ScalarSynchronousObservable.java:35)
at rx.Observable$2.call(Observable.java:162)
at rx.Observable$2.call(Observable.java:154)
at rx.Observable$2.call(Observable.java:162)
at rx.Observable$2.call(Observable.java:154)
at rx.Observable.unsafeSubscribe(Observable.java:8098)
at rx.internal.operators.OperatorSubscribeOn$1$1.call(OperatorSubscribeOn.java:62)
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)

增加内部多线程处理

新版添加多图片同时处理功能,方法名如下
public Luban load(List<File> files){ //TODO compress image list }

java.lang.ArithmeticException: divide by zero

thirdCompress

else if (c <= 0.5625 && c > 0.5) { int multiple = j / 1280; k = i / multiple; l = j / multiple; s = (k * l) / (1440.0 * 2560.0) * 200; s = s < 100 ? 100 : s;
multiple有可能为 0

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.