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