AVIF images downsampling

(cherry picked from commit 5d890cb3d0)
master
Koitharu 1 year ago
parent 4fb1db47ab
commit 9cf496b7c4
Signed by: Koitharu
GPG Key ID: 676DEE768C17A9D7

@ -2,17 +2,21 @@ package org.koitharu.kotatsu.core.image
import android.graphics.Bitmap
import androidx.core.graphics.createBitmap
import androidx.core.graphics.scale
import coil3.ImageLoader
import coil3.asImage
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.maxBitmapSize
import coil3.util.component1
import coil3.util.component2
import com.davemorrissey.labs.subscaleview.decoder.ImageDecodeException
import kotlinx.coroutines.runInterruptible
import org.aomedia.avif.android.AvifDecoder
import org.aomedia.avif.android.AvifDecoder.Info
import org.koitharu.kotatsu.core.util.ext.readByteBuffer
class AvifImageDecoder(
@ -22,24 +26,51 @@ class AvifImageDecoder(
override suspend fun decode(): DecodeResult = runInterruptible {
val bytes = source.source().readByteBuffer()
val info = Info()
if (!AvifDecoder.getInfo(bytes, bytes.remaining(), info)) {
throw ImageDecodeException(
null,
"avif",
"Requested to decode byte buffer which cannot be handled by AvifDecoder",
val decoder = AvifDecoder.create(bytes) ?: throw ImageDecodeException(
uri = source.fileOrNull()?.toString(),
format = "avif",
message = "Requested to decode byte buffer which cannot be handled by AvifDecoder",
)
try {
val config = if (decoder.depth == 8 || decoder.alphaPresent) {
Bitmap.Config.ARGB_8888
} else {
Bitmap.Config.RGB_565
}
val bitmap = createBitmap(decoder.width, decoder.height, config)
val result = decoder.nextFrame(bitmap)
if (result != 0) {
bitmap.recycle()
throw ImageDecodeException(
uri = source.fileOrNull()?.toString(),
format = "avif",
message = AvifDecoder.resultToString(result),
)
}
// downscaling
val (dstWidth, dstHeight) = DecodeUtils.computeDstSize(
srcWidth = bitmap.width,
srcHeight = bitmap.height,
targetSize = options.size,
scale = options.scale,
maxSize = options.maxBitmapSize,
)
if (dstWidth < bitmap.width || dstHeight < bitmap.height) {
val scaled = bitmap.scale(dstWidth, dstHeight)
bitmap.recycle()
DecodeResult(
image = scaled.asImage(),
isSampled = true,
)
} else {
DecodeResult(
image = bitmap.asImage(),
isSampled = false,
)
}
} finally {
decoder.release()
}
val config = if (info.depth == 8 || info.alphaPresent) Bitmap.Config.ARGB_8888 else Bitmap.Config.RGB_565
val bitmap = createBitmap(info.width, info.height, config)
if (!AvifDecoder.decode(bytes, bytes.remaining(), bitmap)) {
bitmap.recycle()
throw ImageDecodeException(null, "avif")
}
DecodeResult(
image = bitmap.asImage(),
isSampled = false,
)
}
class Factory : Decoder.Factory {

Loading…
Cancel
Save