Skip to content

Commit

Permalink
Fix some issues when reading/saving images
Browse files Browse the repository at this point in the history
(mihonapp/mihon#993)

* Fix unsupported mime type error when saving images

Avoid using platform mime type map to get extensions as it may not have
all mime types we support.

* Fix jxl images downloading/reading

(cherry picked from commit daa47e0)
  • Loading branch information
FooIbar authored and cuong-tran committed Jul 8, 2024
1 parent b127357 commit 0496c60
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import logcat.LogPriority
import tachiyomi.core.common.i18n.stringResource
import tachiyomi.core.common.storage.extension
import tachiyomi.core.common.util.lang.launchIO
import tachiyomi.core.common.util.system.ImageUtil
import tachiyomi.core.common.util.system.logcat
import tachiyomi.domain.category.interactor.GetCategories
import tachiyomi.domain.chapter.model.Chapter
Expand Down Expand Up @@ -170,7 +171,7 @@ class DownloadManager(
source,
)
val files = chapterDir?.listFiles().orEmpty()
.filter { "image" in it.type.orEmpty() }
.filter { it.isFile && ImageUtil.isImage(it.name) { it.openInputStream() } }

if (files.isEmpty()) {
throw Exception(context.stringResource(MR.strings.page_list_empty_error))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -553,14 +553,8 @@ class Downloader(
* @param file the file where the image is already downloaded.
*/
private fun getImageExtension(response: Response, file: UniFile): String {
// Read content type if available.
val mime = response.body.contentType()?.run { if (type == "image") "image/$subtype" else null }
// Else guess from the uri.
?: context.contentResolver.getType(file.uri)
// Else read magic numbers.
?: ImageUtil.findImageType { file.openInputStream() }?.mime

return ImageUtil.getExtensionFromMimeType(mime)
return ImageUtil.getExtensionFromMimeType(mime) { file.openInputStream() }
}

private fun splitTallImageIfNeeded(page: Page, tmpDir: UniFile) {
Expand Down Expand Up @@ -758,7 +752,7 @@ class Downloader(
download.status = Download.State.NOT_DOWNLOADED
}
}
queue - downloads
queue - downloads.toSet()
}
}

Expand Down
18 changes: 12 additions & 6 deletions app/src/main/java/eu/kanade/tachiyomi/data/saver/ImageSaver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import android.webkit.MimeTypeMap
import androidx.annotation.RequiresApi
import androidx.core.content.contentValuesOf
import androidx.core.net.toUri
Expand Down Expand Up @@ -65,21 +66,26 @@ class ImageSaver(
filename: String,
data: () -> InputStream,
): Uri {
val pictureDir =
val isMimeTypeSupported = MimeTypeMap.getSingleton().hasMimeType(type.mime)

val pictureDir = if (isMimeTypeSupported) {
MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
} else {
MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
}

val imageLocation = (image.location as Location.Pictures).relativePath
val relativePath = listOf(
Environment.DIRECTORY_PICTURES,
if (isMimeTypeSupported) Environment.DIRECTORY_PICTURES else Environment.DIRECTORY_DOCUMENTS,
context.stringResource(MR.strings.app_name),
imageLocation,
).joinToString(File.separator)

val contentValues = contentValuesOf(
MediaStore.Images.Media.RELATIVE_PATH to relativePath,
MediaStore.Images.Media.DISPLAY_NAME to image.name,
MediaStore.Images.Media.MIME_TYPE to type.mime,
MediaStore.Images.Media.DATE_MODIFIED to Instant.now().epochSecond,
MediaStore.MediaColumns.RELATIVE_PATH to relativePath,
MediaStore.MediaColumns.DISPLAY_NAME to if (isMimeTypeSupported) image.name else filename,
MediaStore.MediaColumns.MIME_TYPE to type.mime,
MediaStore.MediaColumns.DATE_MODIFIED to Instant.now().epochSecond,
)

val picture = findUriOrDefault(relativePath, filename) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.os.Build
import android.webkit.MimeTypeMap
import androidx.annotation.ColorInt
import androidx.core.graphics.alpha
import androidx.core.graphics.applyCanvas
Expand All @@ -32,7 +31,6 @@ import tachiyomi.decoder.Format
import tachiyomi.decoder.ImageDecoder
import java.io.File
import java.io.InputStream
import java.net.URLConnection
import java.security.SecureRandom
import java.util.Locale
import kotlin.math.abs
Expand All @@ -47,12 +45,8 @@ object ImageUtil {
if (File(name).extension.equals("cbi", ignoreCase = true)) return true
// SY <--

val contentType = try {
URLConnection.guessContentTypeFromName(name)
} catch (e: Exception) {
null
} ?: openStream?.let { findImageType(it)?.mime }
return contentType?.startsWith("image/") ?: false
val extension = name.substringAfterLast('.')
return ImageType.entries.any { it.extension == extension } || openStream?.let { findImageType(it) } != null
}

fun findImageType(openStream: () -> InputStream): ImageType? {
Expand All @@ -76,10 +70,9 @@ object ImageUtil {
}
}

fun getExtensionFromMimeType(mime: String?): String {
return MimeTypeMap.getSingleton().getExtensionFromMimeType(mime)
?: SUPPLEMENTARY_MIMETYPE_MAPPING[mime]
?: "jpg"
fun getExtensionFromMimeType(mime: String?, openStream: () -> InputStream): String {
val type = mime?.let { ImageType.entries.find { it.mime == mime } } ?: findImageType(openStream)
return type?.extension ?: "jpg"
}

fun isAnimatedAndSupported(source: BufferedSource): Boolean {
Expand Down Expand Up @@ -217,7 +210,6 @@ object ImageUtil {
* new image with added center padding scaled relative to the height of the display view
* to compensate for scaling.
*/

fun addHorizontalCenterMargin(imageSource: BufferedSource, viewHeight: Int, backgroundContext: Context): BufferedSource {
val imageBitmap = ImageDecoder.newInstance(imageSource.inputStream())?.decode()!!
val height = imageBitmap.height
Expand Down Expand Up @@ -623,12 +615,7 @@ object ImageUtil {

private val optimalImageHeight = getDisplayMaxHeightInPx * 2

// Android doesn't include some mappings
private val SUPPLEMENTARY_MIMETYPE_MAPPING = mapOf(
// https://issuetracker.google.com/issues/182703810
"image/jxl" to "jxl",
)

// SY -->
fun mergeBitmaps(
imageBitmap: Bitmap,
imageBitmap2: Bitmap,
Expand Down Expand Up @@ -674,6 +661,7 @@ object ImageUtil {

private val Bitmap.rect: Rect
get() = Rect(0, 0, width, height)
// SY <--
}

val getDisplayMaxHeightInPx: Int
Expand Down

0 comments on commit 0496c60

Please sign in to comment.