From 8c18a14dfd4ed51001b135a469434fe6f8103929 Mon Sep 17 00:00:00 2001 From: inorichi Date: Tue, 25 May 2021 19:42:48 +0200 Subject: [PATCH] Display animated webp whenever possible, otherwise fallback to static image. Fixes #5139 --- app/build.gradle.kts | 5 ++- .../ui/reader/viewer/pager/PagerPageHolder.kt | 2 +- .../viewer/webtoon/WebtoonPageHolder.kt | 2 +- .../kanade/tachiyomi/util/system/ImageUtil.kt | 31 +++++++++++++++++++ 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 34b480d93d..5d4111f279 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -205,7 +205,10 @@ dependencies { implementation("io.coil-kt:coil:$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 implementation("com.jakewharton.timber:timber:4.7.1") diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt index 7b78bafaf2..22955f3b60 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt @@ -232,7 +232,7 @@ class PagerPageHolder( val stream = streamFn().buffered(16) openStream = process(item, stream) - ImageUtil.findImageType(stream) == ImageUtil.ImageType.GIF + ImageUtil.isAnimatedAndSupported(stream) } .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt index 5092572b25..9c6886357b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt @@ -279,7 +279,7 @@ class WebtoonPageHolder( val stream = streamFn().buffered(16) openStream = process(stream) - ImageUtil.findImageType(stream) == ImageUtil.ImageType.GIF + ImageUtil.isAnimatedAndSupported(stream) } .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/ImageUtil.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/ImageUtil.kt index 6a178a0903..6d82108186 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/system/ImageUtil.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/ImageUtil.kt @@ -10,11 +10,14 @@ import android.graphics.Rect import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable import android.graphics.drawable.GradientDrawable +import android.os.Build import androidx.core.graphics.alpha import androidx.core.graphics.blue import androidx.core.graphics.createBitmap import androidx.core.graphics.green import androidx.core.graphics.red +import tachiyomi.decoder.Format +import tachiyomi.decoder.ImageDecoder import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.io.InputStream @@ -68,6 +71,34 @@ object ImageUtil { 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 { return magic.indices.none { this[it] != magic[it] } }