|
@@ -18,6 +18,7 @@ import androidx.core.graphics.green
|
|
|
import androidx.core.graphics.red
|
|
|
import tachiyomi.decoder.Format
|
|
|
import tachiyomi.decoder.ImageDecoder
|
|
|
+import tachiyomi.decoder.ImageType
|
|
|
import java.io.ByteArrayInputStream
|
|
|
import java.io.ByteArrayOutputStream
|
|
|
import java.io.InputStream
|
|
@@ -41,30 +42,14 @@ object ImageUtil {
|
|
|
|
|
|
fun findImageType(stream: InputStream): ImageType? {
|
|
|
try {
|
|
|
- val bytes = ByteArray(8)
|
|
|
-
|
|
|
- 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 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
|
|
|
+ return when (getImageType(stream)?.format) {
|
|
|
+ // TODO: image-decoder library currently doesn't detect this
|
|
|
+ // Format.Avif -> ImageType.AVIF
|
|
|
+ Format.Gif -> ImageType.GIF
|
|
|
+ Format.Heif -> ImageType.HEIF
|
|
|
+ Format.Jpeg -> ImageType.JPEG
|
|
|
+ Format.Png -> ImageType.PNG
|
|
|
+ Format.Webp -> ImageType.WEBP
|
|
|
}
|
|
|
} catch (e: Exception) {
|
|
|
}
|
|
@@ -73,20 +58,7 @@ object ImageUtil {
|
|
|
|
|
|
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
|
|
|
+ val type = getImageType(stream) ?: return false
|
|
|
return when (type.format) {
|
|
|
Format.Gif -> true
|
|
|
// Coil supports animated WebP on Android 9.0+
|
|
@@ -99,23 +71,30 @@ object ImageUtil {
|
|
|
return false
|
|
|
}
|
|
|
|
|
|
- private fun ByteArray.compareWith(magic: ByteArray): Boolean {
|
|
|
- return magic.indices.none { this[it] != magic[it] }
|
|
|
- }
|
|
|
+ private fun getImageType(stream: InputStream): tachiyomi.decoder.ImageType? {
|
|
|
+ val bytes = ByteArray(32)
|
|
|
|
|
|
- private fun charByteArrayOf(vararg bytes: Int): ByteArray {
|
|
|
- return ByteArray(bytes.size).apply {
|
|
|
- for (i in bytes.indices) {
|
|
|
- set(i, bytes[i].toByte())
|
|
|
- }
|
|
|
+ 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 null
|
|
|
+ }
|
|
|
+
|
|
|
+ return ImageDecoder.findType(bytes)
|
|
|
}
|
|
|
|
|
|
enum class ImageType(val mime: String, val extension: String) {
|
|
|
- JPG("image/jpeg", "jpg"),
|
|
|
- PNG("image/png", "png"),
|
|
|
+ // AVIF("image/avif", "avif"),
|
|
|
GIF("image/gif", "gif"),
|
|
|
- WEBP("image/webp", "webp")
|
|
|
+ HEIF("image/heif", "heif"),
|
|
|
+ JPEG("image/jpeg", "jpg"),
|
|
|
+ PNG("image/png", "png"),
|
|
|
+ WEBP("image/webp", "webp"),
|
|
|
}
|
|
|
|
|
|
/**
|