Use Coil pipeline instead of SSIV for image decode (#692)
This commit is contained in:
@@ -1,12 +1,16 @@
|
||||
package eu.kanade.tachiyomi.data.coil
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import coil3.ImageLoader
|
||||
import coil3.asCoilImage
|
||||
import coil3.decode.DecodeResult
|
||||
import coil3.decode.DecodeUtils
|
||||
import coil3.decode.Decoder
|
||||
import coil3.decode.ImageSource
|
||||
import coil3.fetch.SourceFetchResult
|
||||
import coil3.request.Options
|
||||
import coil3.request.bitmapConfig
|
||||
import eu.kanade.tachiyomi.util.system.GLUtil
|
||||
import okio.BufferedSource
|
||||
import tachiyomi.core.common.util.system.ImageUtil
|
||||
import tachiyomi.decoder.ImageDecoder
|
||||
@@ -18,27 +22,55 @@ class TachiyomiImageDecoder(private val resources: ImageSource, private val opti
|
||||
|
||||
override suspend fun decode(): DecodeResult {
|
||||
val decoder = resources.sourceOrNull()?.use {
|
||||
ImageDecoder.newInstance(it.inputStream())
|
||||
ImageDecoder.newInstance(it.inputStream(), options.cropBorders, displayProfile)
|
||||
}
|
||||
|
||||
check(decoder != null && decoder.width > 0 && decoder.height > 0) { "Failed to initialize decoder" }
|
||||
|
||||
val bitmap = decoder.decode()
|
||||
val srcWidth = decoder.width
|
||||
val srcHeight = decoder.height
|
||||
|
||||
val dstWidth = options.size.widthPx(options.scale) { srcWidth }
|
||||
val dstHeight = options.size.heightPx(options.scale) { srcHeight }
|
||||
|
||||
val sampleSize = DecodeUtils.calculateInSampleSize(
|
||||
srcWidth = srcWidth,
|
||||
srcHeight = srcHeight,
|
||||
dstWidth = dstWidth,
|
||||
dstHeight = dstHeight,
|
||||
scale = options.scale,
|
||||
)
|
||||
|
||||
var bitmap = decoder.decode(sampleSize = sampleSize)
|
||||
decoder.recycle()
|
||||
|
||||
check(bitmap != null) { "Failed to decode image" }
|
||||
|
||||
if (
|
||||
options.bitmapConfig == Bitmap.Config.HARDWARE &&
|
||||
maxOf(bitmap.width, bitmap.height) <= GLUtil.maxTextureSize
|
||||
) {
|
||||
val hwBitmap = bitmap.copy(Bitmap.Config.HARDWARE, false)
|
||||
if (hwBitmap != null) {
|
||||
bitmap.recycle()
|
||||
bitmap = hwBitmap
|
||||
}
|
||||
}
|
||||
|
||||
return DecodeResult(
|
||||
image = bitmap.asCoilImage(),
|
||||
isSampled = false,
|
||||
isSampled = sampleSize > 1,
|
||||
)
|
||||
}
|
||||
|
||||
class Factory : Decoder.Factory {
|
||||
|
||||
override fun create(result: SourceFetchResult, options: Options, imageLoader: ImageLoader): Decoder? {
|
||||
if (!isApplicable(result.source.source())) return null
|
||||
return TachiyomiImageDecoder(result.source, options)
|
||||
return if (options.customDecoder || isApplicable(result.source.source())) {
|
||||
TachiyomiImageDecoder(result.source, options)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun isApplicable(source: BufferedSource): Boolean {
|
||||
@@ -55,4 +87,8 @@ class TachiyomiImageDecoder(private val resources: ImageSource, private val opti
|
||||
|
||||
override fun hashCode() = javaClass.hashCode()
|
||||
}
|
||||
|
||||
companion object {
|
||||
var displayProfile: ByteArray? = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package eu.kanade.tachiyomi.data.coil
|
||||
|
||||
import coil3.Extras
|
||||
import coil3.getExtra
|
||||
import coil3.request.ImageRequest
|
||||
import coil3.request.Options
|
||||
import coil3.size.Dimension
|
||||
import coil3.size.Scale
|
||||
import coil3.size.Size
|
||||
import coil3.size.isOriginal
|
||||
import coil3.size.pxOrElse
|
||||
|
||||
internal inline fun Size.widthPx(scale: Scale, original: () -> Int): Int {
|
||||
return if (isOriginal) original() else width.toPx(scale)
|
||||
}
|
||||
|
||||
internal inline fun Size.heightPx(scale: Scale, original: () -> Int): Int {
|
||||
return if (isOriginal) original() else height.toPx(scale)
|
||||
}
|
||||
|
||||
internal fun Dimension.toPx(scale: Scale): Int = pxOrElse {
|
||||
when (scale) {
|
||||
Scale.FILL -> Int.MIN_VALUE
|
||||
Scale.FIT -> Int.MAX_VALUE
|
||||
}
|
||||
}
|
||||
|
||||
fun ImageRequest.Builder.cropBorders(enable: Boolean) = apply {
|
||||
extras[cropBordersKey] = enable
|
||||
}
|
||||
|
||||
val Options.cropBorders: Boolean
|
||||
get() = getExtra(cropBordersKey)
|
||||
|
||||
private val cropBordersKey = Extras.Key(default = false)
|
||||
|
||||
fun ImageRequest.Builder.customDecoder(enable: Boolean) = apply {
|
||||
extras[customDecoderKey] = enable
|
||||
}
|
||||
|
||||
val Options.customDecoder: Boolean
|
||||
get() = getExtra(customDecoderKey)
|
||||
|
||||
private val customDecoderKey = Extras.Key(default = false)
|
||||
Reference in New Issue
Block a user