Luban 2:简洁高效的Android图片压缩库

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

📑 目录

  • [📖 项目描述](#📖 项目描述 "#-%E9%A1%B9%E7%9B%AE%E6%8F%8F%E8%BF%B0")
  • [📊 效果与对比](#📊 效果与对比 "#-%E6%95%88%E6%9E%9C%E4%B8%8E%E5%AF%B9%E6%AF%94")
    • [🔬 核心算法特性](#🔬 核心算法特性 "#-%E6%A0%B8%E5%BF%83%E7%AE%97%E6%B3%95%E7%89%B9%E6%80%A7")
  • [📦 导入](#📦 导入 "#-%E5%AF%BC%E5%85%A5")
  • [💻 使用](#💻 使用 "#-%E4%BD%BF%E7%94%A8")
    • [⚡ Kotlin (Coroutines)](#⚡ Kotlin (Coroutines) "#-kotlin-coroutines")
    • [☕ Java / Builder 模式](#☕ Java / Builder 模式 "#-java--builder-%E6%A8%A1%E5%BC%8F")
  • [☕ 捐助](#☕ 捐助 "#-%E6%8D%90%E5%8A%A9")
  • [📄 License](#📄 License "#-license")

📖 项目描述

开源地址:Gitee | Github

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

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

因为是逆向推算,效果还没法跟微信一模一样,但是已经很接近微信朋友圈压缩后的效果,具体看以下对比!

本库是 LubanKotlin 重构版本 ,在升级核心算法的同时,利用 Kotlin CoroutinesTurboJPEG 进行了深度优化。新算法比原算法更加健壮和高效,提供更高效的异步处理和更优质的压缩效果。

📊 效果与对比

图片类型 原图(分辨率, 大小) Luban(分辨率, 大小) Wechat(分辨率, 大小)
标准拍照 3024×4032, 5.10MB 1440×1920, 305KB 1440×1920, 303KB
高清大图 4000×6000, 12.10MB 1440×2160, 318KB 1440×2160, 305KB
2K 截图 1440×3200, 2.10MB 1440×3200, 148KB 1440×3200, 256KB
超长记录 1242×22080, 6.10MB 758×13490, 290KB 744×13129, 256KB
全景横图 12000×5000, 8.10MB 1440×600, 126KB 1440×600, 123KB
设计原稿 6000×6000, 6.90MB 1440×1440, 263KB 1440×1440, 279KB

🔬 核心算法特性

本库采用自适应统一图像压缩算法 (Adaptive Unified Image Compression),通过原图的分辨率特征,动态应用差异化策略,实现画质与体积的最优平衡。

智能分辨率决策

  • 高清基准 (1440p):默认以 1440px 作为短边基准,确保在现代 2K/4K 屏幕上的视觉清晰度
  • 全景墙策略:自动识别超大全景图(长边 >10800px),锁定长边为 1440px,保留完整视野
  • 超大像素陷阱:对超过 4096万像素的超高像素图自动执行 1/4 降采样处理
  • 长图内存保护:针对超长截图建立 10.24MP 像素上限,通过等比缩放防止 OOM

自适应比特率控制

  • 极小图 (<0.5MP):几乎不进行有损压缩,防止压缩伪影
  • 高频信息图 (0.5-1MP):提高编码质量,补偿分辨率损失
  • 标准图片 (1-3MP):应用平衡系数,对标主流社交软件体验
  • 超大图/长图 (>3MP):应用高压缩率,显著减少体积

健壮性保障

  • 膨胀回退:压缩后体积大于原图时,自动透传原图,确保绝不"负优化"
  • 智能格式透传:保留小体积 PNG 的透明通道,大体积 PNG 自动转码为 JPEG
  • 输入防御:妥善处理极端分辨率输入(0、负数、1px 等),防止崩溃

📦 导入

确保项目的 build.gradlebuild.gradle.kts 已配置 Maven Central 仓库:

kotlin 复制代码
repositories {
    mavenCentral()
}

在模块的构建文件中添加依赖:

Kotlin DSL (build.gradle.kts):

kotlin 复制代码
dependencies {
    implementation("top.zibin:luban:2.0.0")
}

Groovy (build.gradle):

groovy 复制代码
dependencies {
    implementation 'top.zibin:luban:2.0.0'
}

注意:请访问 Maven Central 查看最新版本号。

💻 使用

⚡ Kotlin (Coroutines)

在 Kotlin 中,推荐使用 suspend 函数进行调用,代码更简洁。

压缩单张图片
kotlin 复制代码
lifecycleScope.launch {
    val inputUri: Uri = ... // 图片 Uri
    val outputDir = context.cacheDir
    
    Luban.compress(context, inputUri, outputDir)
        .onSuccess { file ->
            // 压缩成功,file 为压缩后的图片文件
            Log.d("Luban", "Compressed: ${file.absolutePath}")
        }
        .onFailure { error ->
            // 处理错误
            Log.e("Luban", "Error: ${error.message}")
        }
}
压缩单张图片文件
kotlin 复制代码
lifecycleScope.launch {
    val inputFile: File = ... 
    val outputDir = context.cacheDir
    
    Luban.compress(inputFile, outputDir)
        .onSuccess { file ->
            Log.d("Luban", "Compressed: ${file.absolutePath}")
        }
        .onFailure { error ->
            Log.e("Luban", "Error: ${error.message}")
        }
}
压缩到指定文件路径
kotlin 复制代码
lifecycleScope.launch {
    val inputFile: File = ...
    val outputFile = File(context.cacheDir, "custom_output.jpg")
    
    Luban.compressToFile(inputFile, outputFile)
        .onSuccess { file ->
            Log.d("Luban", "Compressed to: ${file.absolutePath}")
        }
        .onFailure { error ->
            Log.e("Luban", "Error: ${error.message}")
        }
}
并发压缩多张图片
kotlin 复制代码
lifecycleScope.launch {
    val uris: List<Uri> = ... 
    val outputDir = context.cacheDir

    val results = Luban.compress(context, uris, outputDir)
    
    results.forEach { result ->
        result.onSuccess { file -> 
            Log.d("Luban", "Compressed: ${file.absolutePath}")
        }
        .onFailure { error ->
            Log.e("Luban", "Error: ${error.message}")
        }
    }
}
并发压缩多个文件
kotlin 复制代码
lifecycleScope.launch {
    val files: List<File> = ...
    val outputDir = context.cacheDir

    val results = Luban.compress(files, outputDir)
    
    results.forEach { result ->
        result.onSuccess { file -> 
            Log.d("Luban", "Compressed: ${file.absolutePath}")
        }
        .onFailure { error ->
            Log.e("Luban", "Error: ${error.message}")
        }
    }
}
在其他协程作用域中使用

如果不在 Activity/Fragment 中使用,可以使用 CoroutineScope

kotlin 复制代码
val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())

scope.launch {
    val inputUri: Uri = ...
    val outputDir = context.cacheDir
    
    Luban.compress(context, inputUri, outputDir)
        .onSuccess { file ->
            // 处理成功
        }
        .onFailure { error ->
            // 处理错误
        }
}

☕ Java / Builder 模式

对于 Java 项目或偏好回调风格的开发者,可以使用兼容旧版风格的 Luban.with() API。

压缩单张图片
java 复制代码
Luban.with(context)
    .load(imageFile) // 支持 File, Uri, 或 String 路径
    .setTargetDir(context.getCacheDir())
    .bindLifecycle(lifecycleOwner) // 可选:页面销毁时自动取消
    .setCompressListener(new OnCompressListener() {
        @Override
        public void onStart() {
            // 开始压缩
        }

        @Override
        public void onSuccess(File file) {
            // 压缩成功
        }

        @Override
        public void onError(Throwable e) {
            // 发生错误
        }
    })
    .launch();
压缩多张图片
java 复制代码
List<String> imagePaths = ...; // 图片路径列表

Luban.with(context)
    .load(imagePaths) // 加载图片列表
    .setTargetDir(context.getCacheDir())
    .setCompressListener(new OnCompressListener() {
        @Override
        public void onStart() {
            // 开始压缩
        }

        @Override
        public void onSuccess(File file) {
            // 每张图片压缩成功后都会回调一次
            Log.d("Luban", "Compressed: " + file.getAbsolutePath());
        }

        @Override
        public void onError(Throwable e) {
            // 发生错误
        }
    })
    .launch();

彩蛋

FlutterLuban 2 即将上线,Android、iOS都能使用,敬请期待~

相关推荐
zhangphil18 小时前
Kotlin高阶函数及函数作为参数传递(2)
kotlin
Yang-Never18 小时前
Open GL ES -> 应用前后台、Recent切换,SurfaceView纹理贴图闪烁问题分析解决
android·开发语言·kotlin·android studio·贴图
Yang-Never19 小时前
Android 应用启动 -> Android 多种方式启动同一进程,Application.onCreate() 会多次执行吗?
android·java·开发语言·kotlin·android studio
陈思杰系统思考Jason19 小时前
系统思考:创造价值并非卖时间
百度·微信·微信公众平台·新浪微博·微信开放平台
梁同学与Android19 小时前
Android ---【Kotlin篇】Kotlin 协程中 StateFlow 与 SharedFlow 的网络状态对比与应用
android·网络·kotlin
开开心心_Every2 天前
家长控制电脑软件:定时锁屏管理使用时长
网络协议·tcp/ip·游戏·微信·pdf·excel·语音识别
android_cai_niao2 天前
kotlin魔法runCatching
kotlin·result·runcatching
马 孔 多 在下雨2 天前
Kotlin协程进阶王炸之作-Kotlin的协程到底是什么
android·开发语言·kotlin
冬奇Lab2 天前
【Kotlin系列15】多平台开发实战:一次编写,多端运行
android·开发语言·kotlin
小章UPUP2 天前
KMP、CMP、Kotlin 与 React Native 的详细对比
开发语言·react native·kotlin