fix: Switch to hardware bitmap in reader only if device can handle it

This commit is contained in:
AntsyLich 2024-11-20 21:20:00 +07:00 committed by Ahmad Ansori Palembani
parent fbe2d8c701
commit 01fcd7d122
Signed by: null2264
GPG key ID: BA64F8B60AF3EFB6
4 changed files with 50 additions and 56 deletions

View file

@ -50,7 +50,7 @@ class TachiyomiImageDecoder(private val resources: ImageSource, private val opti
if ( if (
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
options.bitmapConfig == Bitmap.Config.HARDWARE && options.bitmapConfig == Bitmap.Config.HARDWARE &&
maxOf(bitmap.width, bitmap.height) <= GLUtil.maxTextureSize !ImageUtil.isMaxTextureSizeExceeded(bitmap)
) { ) {
val hwBitmap = bitmap.copy(Bitmap.Config.HARDWARE, false) val hwBitmap = bitmap.copy(Bitmap.Config.HARDWARE, false)
if (hwBitmap != null) { if (hwBitmap != null) {

View file

@ -18,6 +18,7 @@ import androidx.annotation.CallSuper
import androidx.annotation.StyleRes import androidx.annotation.StyleRes
import androidx.appcompat.widget.AppCompatImageView import androidx.appcompat.widget.AppCompatImageView
import androidx.core.view.isVisible import androidx.core.view.isVisible
import coil3.BitmapImage
import coil3.asDrawable import coil3.asDrawable
import coil3.dispose import coil3.dispose
import coil3.imageLoader import coil3.imageLoader
@ -225,41 +226,44 @@ open class ReaderPageImageView @JvmOverloads constructor(
}, },
) )
val useCoilPipeline = if (isWebtoon) { when (data) {
try { !ImageUtil.isMaxTextureSizeExceeded(data) } catch (_: IllegalStateException) { false } is BitmapDrawable -> {
} else { setImage(ImageSource.bitmap(data.bitmap))
false isVisible = true
} }
is BufferedSource -> {
if (useCoilPipeline) { if (!isWebtoon || !ImageUtil.isMaxTextureSizeExceeded(data)) {
val request = ImageRequest.Builder(context) setHardwareConfig(!ImageUtil.isMaxTextureSizeExceeded(data))
.data(data) setImage(ImageSource.inputStream(data.inputStream()))
.memoryCachePolicy(CachePolicy.DISABLED) isVisible = true
.diskCachePolicy(CachePolicy.DISABLED) return@apply
.target( }
onSuccess = { result ->
val image = result.asDrawable(context.resources) as BitmapDrawable ImageRequest.Builder(context)
setImage(ImageSource.bitmap(image.bitmap)) .data(data)
isVisible = true .memoryCachePolicy(CachePolicy.DISABLED)
}, .diskCachePolicy(CachePolicy.DISABLED)
onError = { .target(
this@ReaderPageImageView.onImageLoadError() onSuccess = { result ->
}, val image = result as BitmapImage
) setImage(ImageSource.bitmap(image.bitmap))
.size(ViewSizeResolver(this@ReaderPageImageView)) isVisible = true
.precision(Precision.INEXACT) },
.cropBorders(config.cropBorders) onError = {
.customDecoder(true) this@ReaderPageImageView.onImageLoadError()
.crossfade(false) },
.build() )
context.imageLoader.enqueue(request) .size(ViewSizeResolver(this@ReaderPageImageView))
} else { .precision(Precision.INEXACT)
when (data) { .cropBorders(config.cropBorders)
is BitmapDrawable -> setImage(ImageSource.bitmap(data.bitmap)) .customDecoder(true)
is BufferedSource -> setImage(ImageSource.inputStream(data.inputStream())) .crossfade(false)
else -> throw IllegalArgumentException("Not implemented for class ${data::class.simpleName}") .build()
.let(context.imageLoader::enqueue)
}
else -> {
throw IllegalArgumentException("Not implemented for class ${data::class.simpleName}")
} }
isVisible = true
} }
} }

View file

@ -776,27 +776,17 @@ object ImageUtil {
return options return options
} }
fun isMaxTextureSizeExceeded(data: Any): Boolean { fun isMaxTextureSizeExceeded(source: BufferedSource): Boolean =
val width: Int extractImageOptions(source).let { opts -> isMaxTextureSizeExceeded(opts.outWidth, opts.outHeight) }
val height: Int
when (data) {
is BufferedSource -> {
val opts = extractImageOptions(data)
width = opts.outWidth
height = opts.outHeight
}
is BitmapDrawable -> {
width = data.bitmap.width
height = data.bitmap.height
}
is Bitmap -> {
width = data.width
height = data.height
}
else -> throw IllegalArgumentException("Not implemented for class ${data::class.simpleName}")
}
if (minOf(width, height) <= 0) throw IllegalStateException("Invalid bitmap size") fun isMaxTextureSizeExceeded(drawable: BitmapDrawable): Boolean =
isMaxTextureSizeExceeded(drawable.bitmap)
fun isMaxTextureSizeExceeded(bitmap: Bitmap): Boolean =
isMaxTextureSizeExceeded(data.width, data.height)
private fun isMaxTextureSizeExceeded(width: Int, height: Int): Boolean {
if (minOf(width, height) <= 0) return false
return maxOf(width, height) > GLUtil.maxTextureSize return maxOf(width, height) > GLUtil.maxTextureSize
} }

View file

@ -89,7 +89,7 @@ sqldelight-android-driver = { module = "app.cash.sqldelight:android-driver", ver
sqldelight-android-paging = { module = "app.cash.sqldelight:androidx-paging3-extensions", version.ref = "sqldelight" } sqldelight-android-paging = { module = "app.cash.sqldelight:androidx-paging3-extensions", version.ref = "sqldelight" }
sqldelight-dialects-sql = { module = "app.cash.sqldelight:sqlite-3-38-dialect", version.ref = "sqldelight" } sqldelight-dialects-sql = { module = "app.cash.sqldelight:sqlite-3-38-dialect", version.ref = "sqldelight" }
subsamplingscaleimageview = { module = "com.github.null2264:subsampling-scale-image-view", version = "338caedb5f" } subsamplingscaleimageview = { module = "com.github.null2264:subsampling-scale-image-view", version = "f7b674ebdd" }
shizuku-api = { module = "dev.rikka.shizuku:api", version.ref = "shizuku" } shizuku-api = { module = "dev.rikka.shizuku:api", version.ref = "shizuku" }
shizuku-provider = { module = "dev.rikka.shizuku:provider", version.ref = "shizuku" } shizuku-provider = { module = "dev.rikka.shizuku:provider", version.ref = "shizuku" }
taptargetview = { module = "com.getkeepsafe.taptargetview:taptargetview", version = "1.13.3" } taptargetview = { module = "com.getkeepsafe.taptargetview:taptargetview", version = "1.13.3" }