package eu.kanade.tachiyomi.util import java.io.InputStream import java.net.URLConnection object ImageUtil { fun isImage(name: String, openStream: (() -> InputStream)? = null): Boolean { val contentType = try { URLConnection.guessContentTypeFromName(name) } catch (e: Exception) { null } ?: openStream?.let { findImageType(it)?.mime } return contentType?.startsWith("image/") ?: false } fun findImageType(openStream: () -> InputStream): ImageType? { return openStream().use { findImageType(it) } } 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 } } catch(e: Exception) { } return null } private fun ByteArray.compareWith(magic: ByteArray): Boolean { for (i in 0 until magic.size) { if (this[i] != magic[i]) return false } return true } private fun charByteArrayOf(vararg bytes: Int): ByteArray { return ByteArray(bytes.size).apply { for (i in 0 until bytes.size) { set(i, bytes[i].toByte()) } } } 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") } }