@@ -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 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,
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
class Factory : Decoder.Factory {
|
||||
|
||||
Reference in New Issue
Block a user