Display animated webp whenever possible

Support AVIF and HEIF images
Handle HEIF images
Using new decoder

Co-Authored-By: arkon <4098258+arkon@users.noreply.github.com>
This commit is contained in:
Jays2Kings 2021-07-04 14:37:37 -04:00
parent a8a23c153d
commit 756f285675
4 changed files with 61 additions and 37 deletions

View File

@ -89,7 +89,10 @@ android {
dependencies {
// Modified dependencies
implementation("com.github.jays2kings:subsampling-scale-image-view:dfd3e43")
implementation("com.github.jays2kings:subsampling-scale-image-view:dfd3e43") {
exclude(module = "image-decoder")
}
implementation("com.github.tachiyomiorg:image-decoder:0e91111")
// Source models and interfaces from Tachiyomi 1.x
implementation("tachiyomi.sourceapi:source-api:1.1")

View File

@ -349,8 +349,8 @@ class PagerPageHolder(
val stream2 = if (extraPage != null) streamFn2?.invoke()?.buffered(16) else null
openStream = this@PagerPageHolder.mergePages(stream, stream2)
ImageUtil.findImageType(stream) == ImageUtil.ImageType.GIF ||
if (stream2 != null) ImageUtil.findImageType(stream2) == ImageUtil.ImageType.GIF else false
ImageUtil.isAnimatedAndSupported(stream) ||
if (stream2 != null) ImageUtil.isAnimatedAndSupported(stream2) else false
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
@ -654,11 +654,11 @@ class PagerPageHolder(
private fun mergePages(imageStream: InputStream, imageStream2: InputStream?): InputStream {
imageStream2 ?: return imageStream
if (page.fullPage) return imageStream
if (ImageUtil.findImageType(imageStream) == ImageUtil.ImageType.GIF) {
if (ImageUtil.isAnimatedAndSupported(imageStream)) {
page.fullPage = true
skipExtra = true
return imageStream
} else if (ImageUtil.findImageType(imageStream2) == ImageUtil.ImageType.GIF) {
} else if (ImageUtil.isAnimatedAndSupported(imageStream)) {
page.isolatedPage = true
extraPage?.fullPage = true
skipExtra = true

View File

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

View File

@ -9,8 +9,11 @@ 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.annotation.ColorInt
import eu.kanade.tachiyomi.R
import tachiyomi.decoder.Format
import tachiyomi.decoder.ImageDecoder
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.InputStream
@ -35,7 +38,46 @@ object ImageUtil {
fun findImageType(stream: InputStream): ImageType? {
try {
val bytes = ByteArray(8)
return when (getImageType(stream)?.format) {
Format.Avif -> ImageType.AVIF
Format.Gif -> ImageType.GIF
Format.Heif -> ImageType.HEIF
Format.Jpeg -> ImageType.JPEG
Format.Png -> ImageType.PNG
Format.Webp -> ImageType.WEBP
else -> null
}
} catch (e: Exception) {
}
return null
}
fun isAnimatedAndSupported(stream: InputStream): Boolean {
try {
val type = getImageType(stream) ?: 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
}
enum class ImageType(val mime: String, val extension: String) {
AVIF("image/avif", "avif"),
GIF("image/gif", "gif"),
HEIF("image/heif", "heif"),
JPEG("image/jpeg", "jpg"),
PNG("image/png", "png"),
WEBP("image/webp", "webp"),
}
private fun getImageType(stream: InputStream): tachiyomi.decoder.ImageType? {
val bytes = ByteArray(32)
val length = if (stream.markSupported()) {
stream.mark(bytes.size)
@ -48,21 +90,7 @@ object ImageUtil {
return null
}
if (bytes.compareWith(charByteArrayOf(0xFF, 0xD8, 0xFF))) {
return ImageType.JPG
}
if (bytes.compareWith(charByteArrayOf(0x89, 0x50, 0x4E, 0x47))) {
return ImageType.PNG
}
if (bytes.compareWith("GIF8".toByteArray())) {
return ImageType.GIF
}
if (bytes.compareWith("RIFF".toByteArray())) {
return ImageType.WEBP
}
} catch (e: Exception) {
}
return null
return ImageDecoder.findType(bytes)
}
fun autoSetBackground(image: Bitmap?, alwaysUseWhite: Boolean, context: Context): Drawable {
@ -325,11 +353,4 @@ object ImageUtil {
}
}
}
enum class ImageType(val mime: String, val extension: String) {
JPG("image/jpeg", "jpg"),
PNG("image/png", "png"),
GIF("image/gif", "gif"),
WEBP("image/webp", "webp")
}
}