Display animated webp whenever possible, otherwise fallback to static image. Fixes #5139

This commit is contained in:
inorichi 2021-05-25 19:42:48 +02:00
parent 9a801cfdfb
commit 8c18a14dfd
4 changed files with 37 additions and 3 deletions

View file

@ -205,7 +205,10 @@ dependencies {
implementation("io.coil-kt:coil:$coilVersion") implementation("io.coil-kt:coil:$coilVersion")
implementation("io.coil-kt:coil-gif:$coilVersion") implementation("io.coil-kt:coil-gif:$coilVersion")
implementation("com.github.tachiyomiorg:subsampling-scale-image-view:846abe0") implementation("com.github.tachiyomiorg:subsampling-scale-image-view:846abe0") {
exclude(module = "image-decoder")
}
implementation("com.github.tachiyomiorg:image-decoder:e6d680f")
// Logging // Logging
implementation("com.jakewharton.timber:timber:4.7.1") implementation("com.jakewharton.timber:timber:4.7.1")

View file

@ -232,7 +232,7 @@ class PagerPageHolder(
val stream = streamFn().buffered(16) val stream = streamFn().buffered(16)
openStream = process(item, stream) openStream = process(item, stream)
ImageUtil.findImageType(stream) == ImageUtil.ImageType.GIF ImageUtil.isAnimatedAndSupported(stream)
} }
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())

View file

@ -279,7 +279,7 @@ class WebtoonPageHolder(
val stream = streamFn().buffered(16) val stream = streamFn().buffered(16)
openStream = process(stream) openStream = process(stream)
ImageUtil.findImageType(stream) == ImageUtil.ImageType.GIF ImageUtil.isAnimatedAndSupported(stream)
} }
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())

View file

@ -10,11 +10,14 @@ import android.graphics.Rect
import android.graphics.drawable.ColorDrawable import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable import android.graphics.drawable.GradientDrawable
import android.os.Build
import androidx.core.graphics.alpha import androidx.core.graphics.alpha
import androidx.core.graphics.blue import androidx.core.graphics.blue
import androidx.core.graphics.createBitmap import androidx.core.graphics.createBitmap
import androidx.core.graphics.green import androidx.core.graphics.green
import androidx.core.graphics.red import androidx.core.graphics.red
import tachiyomi.decoder.Format
import tachiyomi.decoder.ImageDecoder
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.io.InputStream import java.io.InputStream
@ -68,6 +71,34 @@ object ImageUtil {
return null return null
} }
fun isAnimatedAndSupported(stream: InputStream): Boolean {
try {
val bytes = ByteArray(32)
val length = if (stream.markSupported()) {
stream.mark(bytes.size)
stream.read(bytes, 0, bytes.size).also { stream.reset() }
} else {
stream.read(bytes, 0, bytes.size)
}
if (length == -1) {
return false
}
val type = ImageDecoder.findType(bytes) ?: return false
return when (type.format) {
Format.Gif -> true
// Coil supports animated WebP on Android 9.0+
// https://coil-kt.github.io/coil/getting_started/#supported-image-formats
Format.Webp -> type.isAnimated && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P
else -> false
}
} catch (e: Exception) {
}
return false
}
private fun ByteArray.compareWith(magic: ByteArray): Boolean { private fun ByteArray.compareWith(magic: ByteArray): Boolean {
return magic.indices.none { this[it] != magic[it] } return magic.indices.none { this[it] != magic[it] }
} }