1-Android开发知识安卓工具相关移动开发

一款现代、高效的 Android 图片压缩框架

2019-05-18  本文已影响103人  开发者如是说

本项目主要基于 Android 自带的图片压缩 API 进行实现,提供了开源压缩方案 LubanCompressor 的实现,解决了单一 Fie 类型数据源的问题,并在它们的基础之上进行了功能上的拓展。该项目的主要目的在于:提供一个统一图片压缩框库的实现,集成常用的两种图片压缩算法,让你以更低的成本集成图片压缩功能到自己的项目中。

1、项目背景:开源的图片压缩库

现在 Github 上的图片压缩框架主要有 Luban 和 Compressor 两个。Star 的数量也比较高,一个 9K,另一个 4K. 但是,这两个图片压缩的库有各自的优点和缺点。下面我们通过一个表格总结一下:

框架 优点 缺点
Luban 据说是根据微信图片压缩逆推的算法 1.只适用于一般的图片展示的场景,无法对图片的尺寸进行精准压缩;2.内部封装 AsyncTaks 来进行异步的图片压缩,对于 RxJava 支持不好。3.只支持单一 File 类型数据源和结果类型,应用场景有限。
Compressor 1.可以对图片的尺寸进行精准压缩;2.支持 RxJava。 1.尺寸压缩的场景有限,如果有特别的需求,则需要手动修改源代码;2.图片压缩采样的时候计算有问题,导致采样后的图片尺寸总是小于我们指定的尺寸;3.只支持单一 File 类型数据源和结果类型,应用场景有限。

以上,我们总结了 Github 上面的两款比较受欢迎的开源图片压缩库的优缺点。正如我们上面所说,我们希望能够综合它们的优点,并且解决以上两款开源库设计不好的地方。因此,你可以通过下文来了解我们的库所提供的功能,以及如何在您的项目中接入我们的压缩方案。

2、功能和特性

目前,我们的库已经支持了下面的功能,在后面的介绍中,我们会介绍如何在项目中进行详细配置和使用:

想要进一步了解该库的特性和功能,你还可以使用我们提供的示例 APK

sample_preview.jpg

3、使用

3.1 在 Gradle 中引用我们的库

在项目中接入我们的库是非常简单的。首先,在项目的 Gradle 中加入 jcenter仓库:

repositories {
    jcenter()
}

然后,在项目的依赖中添加该库的依赖:

implementation 'me.shouheng.compressor:compressor:1.3.0'

3.2 使用我们库进行压缩

详细的用法你可以参考我们提供的 Sample 程序,这里我们介绍下使用我们库的几个要点:

首先,你要使用 Compress 类的静态方法获取一个 Compress 实例,这是所有配置的起点。针对不同的数据源,你需要调用它的三个不同的工厂方法:

    // 使用文件 File 获取 Compress 实例
    val compress = Compress.with(this, file)
    // 使用图片的字节数组获取 Compress 实例
    val compress = Compress.with(this, byteArray)
    // 使用图片的 Bitmap 获取 Compress 实例
    val compress = Compress.with(this, bitmap)

然后,你可以调用 Compress 的实例方法来对压缩的参数进行基本的配置:

    compress
        // 指定要求的图片的质量
        .setQuality(60)
        // 指定文件的输出目录(如果返回结果不是 File 的会,无效)
        .setTargetDir(PathUtils.getExternalPicturesPath())
        // 指定压缩结果回调(如哦返回结果不是 File 则不会被回调到)
        .setCompressListener(object : CompressListener {
            override fun onStart() {
                LogUtils.d(Thread.currentThread().toString())
                ToastUtils.showShort("Start [Compressor,File]")
            }
    
            override fun onSuccess(result: File?) {
                LogUtils.d(Thread.currentThread().toString())
                displayResult(result?.absolutePath)
                ToastUtils.showShort("Success [Compressor,File] : $result")
            }
    
            override fun onError(throwable: Throwable?) {
                LogUtils.d(Thread.currentThread().toString())
                ToastUtils.showShort("Error [Compressor,File] : $throwable")
            }
        })

以上是使用 Compress 进行基本的配置,上面我们给出了一些注释。关于各个方法的含义,后续我们会进行详细的介绍。

根据上述配置,我们就得到了一个 Compress 对象。然后,我们需要指定一个图片压缩策略,并调用压缩策略的方法进行更详细的配置。以 Compressor 为例,我们可以调用 Strategies.compressor() 方法获取它的实例:

val compressor = compress
        .strategy(Strategies.compressor())
        .setConfig(config)
        .setMaxHeight(100f)
        .setMaxWidth(100f)
        .setScaleMode(scaleMode)

按照上述配置,我们就拿到了 Compressor 实例。当然如果你的配置使用比较频繁,为了简化代码,你可以把这些配置过程放在一个工具方法中,而无需每次都进行这些配置。

下面就是触发图片压缩并获取压缩结果的过程了。

上面我们也提到过,针对 File 类型和 Bitmap 类型的返回结果,我们提供了两个方案。默认的返回类型是 File,为了得到 Bitmap 类型的结果,你只需要调用一下 Compressor 实例的 asBitmap() 方法,这样整个流程就‘拐’到了 Bitmap 的构建中去了。

最终触发图片压缩有三种方式,

    // 方式 1:使用 AsyncTask 压缩,此时只能通过之前的回调获取压缩结果
    compressor.launch()
    // 方式 2:将压缩任务转换成 Flowable,使用 RxJava 指定任务的线程和获取结果的线程
    val d = compressor
        .asFlowable()
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe({
            ToastUtils.showShort("Success [Compressor,File,Flowable] $it")
            displayResult(it.absolutePath)
        }, {
            ToastUtils.showShort("Error [Compressor,File,Flowable] : $it")
        })
    // 方式 3:直接在当前线程中获取返回结果(同步,阻塞)
    val resultFile = compressor.get()

对于 Luban 压缩方式的使用与之类似,只需要在指定压缩策略的那一步中将策略替换成 luban 即可。另外,对于自定义图片压缩的方式也是类似的,只需要在指定策略的那一步骤中指定即可。

因此,如果使用的是 RxJava 的方式获取压缩结果,并且输入类型是 File,输出类型是 Bitmap,整个压缩的流程将是下面这样:

    val compressor = Compress.with(this@MainActivity, file)
        .strategy(Strategies.compressor())
        .setConfig(config)
        .setMaxHeight(100f)
        .setMaxWidth(100f)
        .setScaleMode(scaleMode)
        .asBitmap()
        .asFlowable()
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe({
            ToastUtils.showShort("Success [Compressor,Bitmap,Flowable] $it")
            displayResult(it)
        }, {
            ToastUtils.showShort("Error [Compressor,Bitmap,Flowable] : $it")
        })

3.3 你可能需要注意的事项

4、项目资料

如果您对该项目感兴趣并且希望为该项目共享您的代码,那么您可以通过下面的一些资料来了解相关的内容:

  1. 项目整体的架构设计:https://www.processon.com/view/link/5cdfb769e4b00528648784b7
  2. Android 图片压缩 API 的介绍,该项目的简介等:《开源一个 Android 图片压缩框架》
  3. 我们提供的示例 APK:app-debug.apk

更新日志

关于作者

你可以通过访问下面的链接来获取作者的信息:

  1. Twitter: https://twitter.com/shouheng_wang
  2. 微博:https://weibo.com/5401152113/profile?rightmod=1&wvr=6&mod=personinfo
  3. Github: https://github.com/Shouheng88
  4. 掘金:https://juejin.im/user/585555e11b69e6006c907a2a

项目地址:https://github.com/Shouheng88/Compressor

上一篇下一篇

猜你喜欢

热点阅读