Fix image loading

(cherry picked from commit 257f583f78)
This commit is contained in:
Koitharu
2025-04-30 17:27:41 +03:00
parent 14b89fbee2
commit 4fb1db47ab
6 changed files with 47 additions and 16 deletions

View File

@@ -13,7 +13,7 @@ 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.toByteBuffer
import org.koitharu.kotatsu.core.util.ext.readByteBuffer
class AvifImageDecoder(
private val source: ImageSource,
@@ -21,9 +21,7 @@ class AvifImageDecoder(
) : Decoder {
override suspend fun decode(): DecodeResult = runInterruptible {
val bytes = source.source().use {
it.inputStream().toByteBuffer()
}
val bytes = source.source().readByteBuffer()
val info = Info()
if (!AvifDecoder.getInfo(bytes, bytes.remaining(), info)) {
throw ImageDecodeException(

View File

@@ -9,12 +9,15 @@ import androidx.annotation.RequiresApi
import androidx.core.graphics.createBitmap
import com.davemorrissey.labs.subscaleview.decoder.ImageDecodeException
import okio.IOException
import okio.buffer
import okio.source
import org.aomedia.avif.android.AvifDecoder
import org.aomedia.avif.android.AvifDecoder.Info
import org.jetbrains.annotations.Blocking
import org.koitharu.kotatsu.core.util.MimeTypes
import org.koitharu.kotatsu.core.util.ext.MimeType
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.core.util.ext.readByteBuffer
import org.koitharu.kotatsu.core.util.ext.toByteBuffer
import org.koitharu.kotatsu.core.util.ext.toMimeTypeOrNull
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
@@ -28,7 +31,7 @@ object BitmapDecoderCompat {
@Blocking
fun decode(file: File): Bitmap = when (val format = probeMimeType(file)?.subtype) {
FORMAT_AVIF -> file.inputStream().use { decodeAvif(it.toByteBuffer()) }
FORMAT_AVIF -> file.source().buffer().use { decodeAvif(it.readByteBuffer()) }
else -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
ImageDecoder.decodeBitmap(ImageDecoder.createSource(file))
} else {

View File

@@ -25,7 +25,7 @@ class CbzFetcher(
val entryName = requireNotNull(uri.fragment)
val fs = options.fileSystem.openZip(filePath)
SourceFetchResult(
source = ImageSource(entryName.toPath(), fs, closeable = fs),
source = ImageSource(entryName.toPath(), fs),
mimeType = MimeTypes.getMimeTypeFromExtension(entryName)?.toString(),
dataSource = DataSource.DISK,
)

View File

@@ -23,6 +23,7 @@ import coil3.size.Scale
import coil3.size.Size
import coil3.size.isOriginal
import coil3.size.pxOrElse
import org.koitharu.kotatsu.core.util.ext.copyWithNewSource
import kotlin.math.roundToInt
class RegionBitmapDecoder(
@@ -34,16 +35,21 @@ class RegionBitmapDecoder(
override suspend fun decode(): DecodeResult? {
val regionDecoder = BitmapDecoderCompat.createRegionDecoder(fetchResult.source.source().inputStream())
if (regionDecoder == null) {
val fallbackDecoder = imageLoader.components.newDecoder(
result = fetchResult,
options = options,
imageLoader = imageLoader,
startIndex = 0,
)?.first
return if (fallbackDecoder == null || fallbackDecoder is RegionBitmapDecoder) {
null
} else {
fallbackDecoder.decode()
val revivedFetchResult = fetchResult.copyWithNewSource()
return try {
val fallbackDecoder = imageLoader.components.newDecoder(
result = revivedFetchResult,
options = options,
imageLoader = imageLoader,
startIndex = 0,
)?.first
if (fallbackDecoder == null || fallbackDecoder is RegionBitmapDecoder) {
null
} else {
fallbackDecoder.decode()
}
} finally {
revivedFetchResult.source.close()
}
}
val bitmapOptions = BitmapFactory.Options()

View File

@@ -6,10 +6,13 @@ import android.widget.ImageView
import androidx.core.graphics.ColorUtils
import androidx.core.graphics.drawable.toDrawable
import androidx.lifecycle.LifecycleOwner
import androidx.annotation.CheckResult
import coil3.Extras
import coil3.ImageLoader
import coil3.asDrawable
import coil3.decode.ImageSource
import coil3.fetch.FetchResult
import coil3.fetch.SourceFetchResult
import coil3.request.ErrorResult
import coil3.request.ImageRequest
import coil3.request.ImageResult
@@ -28,6 +31,7 @@ import coil3.toBitmap
import coil3.util.CoilUtils
import com.google.android.material.progressindicator.BaseProgressIndicator
import org.koitharu.kotatsu.R
import okio.buffer
import org.koitharu.kotatsu.bookmarks.domain.Bookmark
import org.koitharu.kotatsu.core.image.RegionBitmapDecoder
import org.koitharu.kotatsu.core.ui.image.AnimatedPlaceholderDrawable
@@ -163,3 +167,14 @@ private class CompositeImageRequestListener(
val mangaKey = Extras.Key<Manga?>(null)
val bookmarkKey = Extras.Key<Bookmark?>(null)
val mangaSourceKey = Extras.Key<MangaSource?>(null)
@CheckResult
fun SourceFetchResult.copyWithNewSource(): SourceFetchResult = SourceFetchResult(
source = ImageSource(
source = source.fileSystem.source(source.file()).buffer(),
fileSystem = source.fileSystem,
metadata = source.metadata,
),
mimeType = mimeType,
dataSource = dataSource,
)

View File

@@ -7,6 +7,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.withContext
import okhttp3.ResponseBody
import okio.BufferedSink
import okio.BufferedSource
import okio.FileSystem
import okio.IOException
import okio.Path
@@ -30,6 +31,14 @@ suspend fun BufferedSink.writeAllCancellable(source: Source) = withContext(Dispa
writeAll(source.cancellable())
}
fun BufferedSource.readByteBuffer(): ByteBuffer {
val bytes = readByteArray()
return ByteBuffer.allocateDirect(bytes.size)
.put(bytes)
.rewind() as ByteBuffer
}
@Deprecated("")
fun InputStream.toByteBuffer(): ByteBuffer {
val outStream = ByteArrayOutputStream(available())
copyTo(outStream)