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 android.graphics.Bitmap
import androidx.core.graphics.createBitmap import androidx.core.graphics.createBitmap
import androidx.core.graphics.scale
import coil3.ImageLoader import coil3.ImageLoader
import coil3.asImage import coil3.asImage
import coil3.decode.DecodeResult import coil3.decode.DecodeResult
import coil3.decode.DecodeUtils
import coil3.decode.Decoder import coil3.decode.Decoder
import coil3.decode.ImageSource import coil3.decode.ImageSource
import coil3.fetch.SourceFetchResult import coil3.fetch.SourceFetchResult
import coil3.request.Options import coil3.request.Options
import coil3.request.maxBitmapSize
import coil3.util.component1
import coil3.util.component2
import com.davemorrissey.labs.subscaleview.decoder.ImageDecodeException import com.davemorrissey.labs.subscaleview.decoder.ImageDecodeException
import kotlinx.coroutines.runInterruptible import kotlinx.coroutines.runInterruptible
import org.aomedia.avif.android.AvifDecoder import org.aomedia.avif.android.AvifDecoder
import org.aomedia.avif.android.AvifDecoder.Info
import org.koitharu.kotatsu.core.util.ext.readByteBuffer import org.koitharu.kotatsu.core.util.ext.readByteBuffer
class AvifImageDecoder( class AvifImageDecoder(
@ -22,24 +26,51 @@ class AvifImageDecoder(
override suspend fun decode(): DecodeResult = runInterruptible { override suspend fun decode(): DecodeResult = runInterruptible {
val bytes = source.source().readByteBuffer() val bytes = source.source().readByteBuffer()
val info = Info() val decoder = AvifDecoder.create(bytes) ?: throw ImageDecodeException(
if (!AvifDecoder.getInfo(bytes, bytes.remaining(), info)) { uri = source.fileOrNull()?.toString(),
throw ImageDecodeException( format = "avif",
null, message = "Requested to decode byte buffer which cannot be handled by AvifDecoder",
"avif", )
"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 { class Factory : Decoder.Factory {

Loading…
Cancel
Save