Luban README

The project's README from github.com/Curzibn/Luban. As one markdown file: README.md.

Luban 2

License Maven Central API

中文 | English

Luban 2(鲁班 2) —— 高效简洁的 Android 图片压缩工具库,像素级还原微信朋友圈压缩策略。

📑 目录

📖 项目描述

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

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

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

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

如果你需要在线或命令行的图片压缩(PNG / JPEG / GIF / WebP / AVIF,免费,网页 / API / CLI 共用一份额度),可以看看同一系列的 LubanPNG(鲁班刨):https://lubanpng.wizthink.cn/?utm_source=luban2&utm_medium=readme&utm_campaign=launch

📊 效果与对比

图片类型 原图(分辨率, 大小) 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),通过原图的分辨率特征,动态应用差异化策略,实现画质与体积的最优平衡。

智能分辨率决策

自适应比特率控制

健壮性保障

📦 导入

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

repositories {
    mavenCentral()
}

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

Kotlin DSL (build.gradle.kts):

dependencies {
    implementation("top.zibin:luban:2.0.2")
}

Groovy (build.gradle):

dependencies {
    implementation 'top.zibin:luban:2.0.2'
}

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

💻 使用

⚡ Kotlin (Coroutines)

Luban 提供了三种 Kotlin 调用方式,从最符合 Kotlin 习惯到传统方式:

1. DSL 风格(推荐)

最符合 Kotlin 习惯的方式是使用 DSL API:

lifecycleScope.launch {
    val results = luban(context) {
        outputDir = File(context.cacheDir, "compressed")
        
        compress(imageUri1)
        compress(imageUri2)
        compress(imageFile1)
        compress(listOf(imageFile2, imageFile3))
        compress(listOf(imageUri3, imageUri4))
    }
    
    results.forEach { result ->
        result.getOrNull()?.let { file ->
            Log.d("Luban", "压缩成功: ${file.absolutePath}")
        } ?: run {
            val error = result.exceptionOrNull()
            Log.e("Luban", "压缩失败: ${error?.message}")
        }
    }
}

注意:

2. 扩展函数

你也可以使用扩展函数,获得更流畅的 API:

lifecycleScope.launch {
    val result = imageUri.compressTo(context)
    
    result.getOrElse { error ->
        Log.e("Luban", "压缩失败: ${error.message}")
        return@launch
    }.let { file ->
        Log.d("Luban", "压缩成功: ${file.absolutePath}")
    }
}

压缩单个文件:

val result = inputFile.compressTo(outputDir)

压缩到指定文件:

val result = inputFile.compressToFile(outputFile)

批量压缩:

val results = fileList.compressTo(outputDir)
val results = uriList.compressTo(context)

3. 传统静态方法

使用传统静态方法:

lifecycleScope.launch {
    val result = Luban.compress(context, inputUri, outputDir)
    
    result.getOrElse { error ->
        Log.e("Luban", "压缩失败: ${error.message}")
        return@launch
    }.let { file ->
        Log.d("Luban", "压缩成功: ${file.absolutePath}")
    }
}

可用方法:

在其他协程作用域中使用:

val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())

scope.launch {
    val result = Luban.compress(context, inputUri)
    
    result.getOrElse { error ->
        // 处理错误
        return@launch
    }.let { file ->
        // 处理成功
    }
}

☕ Java / Builder 模式

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

压缩单张图片

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();

压缩多张图片

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();

☕ 捐助

如果这个项目对您有帮助,欢迎通过以下方式支持我的工作。您的支持是我持续改进和维护这个项目的动力。

支付宝收款码 微信收款码

感谢您的支持!🙏

📄 License

Copyright 2025 郑梓斌

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 (Curzibn/Luban)

Searching Database…

13.8K ·GitHub
这是什么?Luban(鲁班)是一个 Android 图片压缩库,它复刻了微信朋友圈的压缩策略,在缩小照片体积的同时,尽量让视觉效果接近原图。
它是独立应用,还是需要加入项目的库?它是一个库,通过 Gradle(Maven Central)作为依赖添加到项目中,而不是独立应用。
怎么把它加入项目并使用?在 build.gradle(.kts) 中添加 Maven Central 依赖,然后根据你的习惯调用:Kotlin DSL API、扩展函数、静态方法 Luban.compress,或 Java 的 Luban.with() 构建器。
除了这个库本身,还需要别的东西吗?这个版本用 Kotlin 重写,内部借助 Kotlin 协程和 TurboJPEG 进行优化后的异步处理,所以你的项目需要支持 Kotlin 协程才能使用 Kotlin API(同时也提供了兼容 Java 的构建器 API)。
压缩会失败,或者反而让图片变大吗?不会:如果压缩后的输出比原文件还大,Luban 会自动直接使用原文件,因此不会出现所谓的“负优化”。
它如何决定压缩到什么分辨率?它采用自适应算法:普通照片以短边 1440 像素为基准;全景图(长边超过 10800 像素)会把长边固定为 1440 像素;超过 4000 万像素的图片会自动降采样为原来的 1/4;超长截图则以 10.24MP(1024 万像素)为上限等比例缩放,以避免内存溢出错误。
它会保留 PNG 的透明通道吗?会。体积较小的 PNG 文件会保留透明通道,而较大的 PNG 会被自动转码为 JPEG,以获得更好的压缩效果。
压缩结果和微信自带的压缩有多接近?README 中的对比表显示,在多种照片类型下,输出的文件大小和分辨率都与微信朋友圈非常接近。例如,一张 3024×4032、5.10MB 的照片,压缩后为 1440×1920、305KB,微信的结果是 1440×1920、303KB。
当初为什么要做这个库?作者上传了近 100 张不同分辨率的照片,并将原图与微信压缩后的输出进行对比,从而反向推导出了微信朋友圈的压缩方式,因为当时没有任何公开文档可以参考。
Creator
Curzibn
Size
11.6 MB
Stars
13.8K
Age
10y
Commits · 90 Days