forjrking / kluban Goto Github PK
View Code? Open in Web Editor NEWLifecycle + Kotlin 协程 + flow + LiveData + Glide 识别和内存优化 + Luban采样算法 = KLuban图片压缩
Lifecycle + Kotlin 协程 + flow + LiveData + Glide 识别和内存优化 + Luban采样算法 = KLuban图片压缩
调用方法
Luban.with() .load(bitmap) .ignoreBy(500) .format(Bitmap.CompressFormat.WEBP) .compressObserver { onStart = { //Log.d(TAG, "onStart: ") } onCompletion = { Log.d(TAG, "onCompletion") } onSuccess = { Toast.makeText(this@MainActivity, "file" + it.name, Toast.LENGTH_LONG).show() mIv!!.setImageURI(Uri.fromFile(it)) } onError = { a, b -> Log.e(TAG, a.toString()) } }.launch()
中的compressObserver实现不会写,请教该怎么写 - -、
我目前是这么写的
Luban.Companion.with().load("").compressObserver(new Function1<CompressResult<String, File>, Unit>() { @Override public Unit invoke(CompressResult<String, File> stringFileCompressResult) { return null; } }).launch();
你好,压缩的话,怎么直接传list集合,
.load(list)
而不是
.load(uri, uri)
heic图片查看exif是有数据的,我看了源码的实现,是通过glide的一部分核心获取角度的,由于是heic,格式不同,所以取到的ImageType是UNKNOWN,所以角度获取到的是未知。但是glide显示却是正常的,KLuban直接拿了这个数据就有问题
Luban.Companion.with(ProcessLifecycleOwner.get())
.load(bitmap)
.setOutPutDir(PathUtils.getExternalAppPicturesPath())
.useDownSample(true) //(可选)压缩算法 true采用邻近采样,否则使用双线性采样(纯文字图片效果绝佳)
.format(Bitmap.CompressFormat.JPEG)//(可选)压缩后输出文件格式 支持 JPG,PNG,WEBP
.ignoreBy(250) //(可选)期望大小,大小和图片呈现质量不能均衡所以压缩后不一定小于此值,
.quality(100) //(可选)质量压缩系数 0-100
.compressObserver(new Function1<CompressResult<Bitmap, File>, Unit>() {
@OverRide
public Unit invoke(CompressResult<Bitmap, File> bitmapFileCompressResult) {
bitmapFileCompressResult.setOnSuccess(new Function1<File, Unit>() {
@OverRide
public Unit invoke(File file) {
return null;
}
});
return null;
}
})
.launch();
并不是所有图片都会抛异常,只有小部分图片会,但不知道是什么原因,希望可以排查一下
W/System.err: com.forjrking.lubankt.io.BufferedInputStreamWrap$InvalidMarkException: Mark has been invalidated, pos: 1423393 markLimit: 5242880
W/System.err: at com.forjrking.lubankt.io.BufferedInputStreamWrap.reset(BufferedInputStreamWrap.java:318)
W/System.err: at com.forjrking.lubankt.Checker$getOrientation$reader$1.getOrientation(Checker.kt:137)
W/System.err: at com.forjrking.lubankt.Checker.getOrientationInternal(Checker.kt:147)
W/System.err: at com.forjrking.lubankt.Checker.getOrientation(Checker.kt:141)
W/System.err: at com.forjrking.lubankt.Checker.getRotateDegree(Checker.kt:167)
W/System.err: at com.forjrking.lubankt.CompressEngine.compress(CompressEngine.kt:48)
W/System.err: at com.forjrking.lubankt.AbstractFileBuilder$compress$2.invokeSuspend(Luban.kt:294)
W/System.err: at com.forjrking.lubankt.AbstractFileBuilder$compress$2.invoke(Unknown Source:10)
W/System.err: at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:91)
W/System.err: at kotlinx.coroutines.BuildersKt__Builders_commonKt.withContext(Builders.common.kt:165)
W/System.err: at kotlinx.coroutines.BuildersKt.withContext(Unknown Source:1)
W/System.err: at com.forjrking.lubankt.AbstractFileBuilder.compress(Luban.kt:272)
W/System.err: at com.forjrking.lubankt.SingleRequestBuild$asyncRun$1$1.invokeSuspend(Luban.kt:320)
W/System.err: at com.forjrking.lubankt.SingleRequestBuild$asyncRun$1$1.invoke(Unknown Source:10)
W/System.err: at kotlinx.coroutines.flow.SafeFlow.collectSafely(Builders.kt:61)
W/System.err: at kotlinx.coroutines.flow.AbstractFlow.collect(Flow.kt:212)
W/System.err: at kotlinx.coroutines.flow.internal.ChannelFlowOperatorImpl.flowCollect(ChannelFlow.kt:207)
W/System.err: at kotlinx.coroutines.flow.internal.ChannelFlowOperator.collectTo$suspendImpl(ChannelFlow.kt:169)
W/System.err: at kotlinx.coroutines.flow.internal.ChannelFlowOperator.collectTo(Unknown Source:0)
W/System.err: at kotlinx.coroutines.flow.internal.ChannelFlow$collectToFun$1.invokeSuspend(ChannelFlow.kt:60)
W/System.err: at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
W/System.err: at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
W/System.err: at java.lang.Thread.run(Thread.java:923)
图片地址:
谷歌网盘
fun calculateQuality(context: Context): Int {
val dm = DisplayMetrics()
(context.getSystemService(Context.WINDOW_SERVICE) as WindowManager)
.defaultDisplay.getMetrics(dm)
val density = dm.density
return if (density > 3f) {
DEFAULT_LOW_QUALITY
} else if (density > 2.5f && density <= 3f) {
DEFAULT_QUALITY
} else if (density > 2f && density <= 2.5f) {
DEFAULT_HEIGHT_QUALITY
} else if (density > 1.5f && density <= 2f) {
DEFAULT_X_HEIGHT_QUALITY
} else {
DEFAULT_XX_HEIGHT_QUALITY
}
}
按我的理解,应该越低dpi的手机才应该压缩的越狠吧
是否考虑添加直接返回结果集合的方法?
load传入知乎图片选择框架返回的List,onSuccess返回的list为空
我在测试16K的图片压缩时发现,压缩虽然能够完成,但是图片的画面完全丢失
1、建议提供压缩完直接返回bitmap的方法
2、load(bitmap) 支持
当文件不存在时,执行压缩会导致应用闪退,Android 11,onError有回调,导致闪退的异常是:java.io.FileNotFoundException: No content provider: xxx
// 建议这么修改
fun load(bitmap: Bitmap) = loadGeneric(bitmap) {
val os = ByteArrayOutputStream()
if (bitmap.config == Bitmap.Config.RGB_565 || !bitmap.hasAlpha()){
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os)
}else{
bitmap.compress(Bitmap.CompressFormat.PNG, 100, os)
bitmap.density
}
bitmap.recycle()
ByteArrayInputStream(os.toByteArray())
}
D/Luban: handlerCatch -> java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
另外还有个疑问,并行时,压缩后的数据是否和传入顺序一致,还是乱序
设备信息:小米 MIX 2S MIUI12开发版 20.9.4
Android 10
报错信息:
com.forjrking.lubankt.io.BufferedInputStreamWrap$InvalidMarkException: Mark has been invalidated, pos: 2497492 markLimit: 5242880
at com.forjrking.lubankt.io.BufferedInputStreamWrap.reset(BufferedInputStreamWrap.java:318)
at com.forjrking.lubankt.Checker$getOrientation$reader$1.getOrientation(Checker.kt:117)
at com.forjrking.lubankt.Checker.getOrientationInternal(Checker.kt:138)
at com.forjrking.lubankt.Checker.getOrientation(Checker.kt:121)
at com.forjrking.lubankt.CompressEngine.compress(CompressEngine.kt:48)
at com.forjrking.lubankt.Builder$compress$2.invokeSuspend(Luban.kt:270)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
at com.forjrking.lubankt.CompressThreadFactory$newThread$thread$1.run(Luban.kt:385)
Mark has been invalidated, pos: 1300464 markLimit: 5242880
引用你这个图片压缩顺带还把协程和LiveData引入了
2 files found with path 'META-INF/library_release.kotlin_module'.
Adding a packagingOptions block may help, please refer to
https://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.PackagingOptions.html
for more information
implementation的另一个model也使用了 model 名称为library
,且没有自定义命名。
model build.gradle
...
compileOptions {
kotlinOptions.freeCompilerArgs += ['-module-name', "com.forjrking.lubankt.library"]
}
...
作者您好,首先感谢开源并持续维护这么好用的压缩库。
我在使用的过程中发现,压缩正常大小图片(50005000左右)速度正常,大概耗时不到1秒钟。
但如果是超长或超宽图片,会非常耗时。在荣耀30Pro上,108035120(11.58MB)的图片压缩,耗时6秒钟。
希望作者可以优化下。
期待回复,感谢!
如题
您好,我在项目中引用了一个图片选择库,并且剪裁之后使用您的库进行压缩,然而打印日志发现了一个问题。剪裁出的圆形图片压缩后,file依然是原文件,使用其他剪裁出来的图片可以正常压缩,想请教一下是什么原因。
这是我用的图片库地址:https://github.com/yangpeixing/YImagePicker
源代码:
//组合一个名字给输出文件
val cacheFile = "$mOutPutDir/${System.nanoTime()}.${type.suffix}"
//重命名接口
val outFile = if (mRenamePredicate != null) {
File(mRenamePredicate!!.invoke(cacheFile))
} else {
File(cacheFile)
}
而且有了 setOutPutDir 设置输出目录
rename这里应该就是只修改文件名
另:
我觉得压缩后文件名应该使用原文件名,这样比较合理;
上传后展示上传的文件名,用时间戳是区分不出来哪个对哪个的。
override fun asyncRun(scope: CoroutineScope, liveData: CompressLiveData<T, List<File>>) {
val result by lazy { ArrayList<File>() }
val handler = CoroutineExceptionHandler { _, exception ->
Checker.logger("handlerCatch -> $exception") //这里面不应该回调State.Error吗
}
图片压缩前和压缩后出现90度旋转
如题
如题,因为在为公司写一个标准化的SDK,该SDK会对接多个APP平台,所以有些项目还未把androidX做迁移,所以是否可以提供一个非androidX的版本呢?
型号:魅族 PRO6
版本号:Flyme 7.3.0.0A
android版本 7.1.1
//不加载进内存
options.inJustDecodeBounds = true
//不加载进内存解析一次 获取宽高
BitmapFactory.decodeStream(srcStream.rewindAndGet(), null, options)
在这之后,markPos变成-1。想不通,为啥这个decodeStream会读取整个文件流导致超出marklimit。
这个文件流是一个大图片
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.