diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt index 37d6883f0..94345ac0b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt @@ -292,7 +292,7 @@ class SettingsReaderController : SettingsController() { switchPreference { bindTo(preferences.longStripSplitWebtoon()) titleRes = R.string.pref_long_strip_split - summaryRes = R.string.pref_long_strip_split_summary + summaryRes = R.string.split_tall_images_summary } } 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 d465491f5..bf4c120be 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 @@ -50,8 +50,8 @@ object ImageUtil { } fun findImageType(stream: InputStream): ImageType? { - try { - return when (getImageType(stream)?.format) { + return try { + when (getImageType(stream)?.format) { Format.Avif -> ImageType.AVIF Format.Gif -> ImageType.GIF Format.Heif -> ImageType.HEIF @@ -62,8 +62,8 @@ object ImageUtil { else -> null } } catch (e: Exception) { + null } - return null } fun getExtensionFromMimeType(mime: String?): String { @@ -185,7 +185,8 @@ object ImageUtil { } enum class Side { - RIGHT, LEFT + RIGHT, + LEFT, } /** @@ -206,24 +207,20 @@ object ImageUtil { return true } - val bitmapRegionDecoder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - BitmapRegionDecoder.newInstance(imageFile.openInputStream()) - } else { - @Suppress("DEPRECATION") - BitmapRegionDecoder.newInstance(imageFile.openInputStream(), false) - } - + val bitmapRegionDecoder = getBitmapRegionDecoder(imageFile.openInputStream()) if (bitmapRegionDecoder == null) { logcat { "Failed to create new instance of BitmapRegionDecoder" } return false } - val options = extractImageOptions(imageFile.openInputStream(), resetAfterExtraction = false).apply { inJustDecodeBounds = false } + val options = extractImageOptions(imageFile.openInputStream(), resetAfterExtraction = false).apply { + inJustDecodeBounds = false + } // Values are stored as they get modified during split loop val imageWidth = options.outWidth - val splitDataList = getSplitDataForOptions(options) + val splitDataList = options.splitData return try { splitDataList.forEach { splitData -> @@ -264,8 +261,8 @@ object ImageUtil { */ fun isStripSplitNeeded(imageStream: BufferedInputStream): Boolean { if (isAnimatedAndSupported(imageStream)) return false - val options = extractImageOptions(imageStream) + val options = extractImageOptions(imageStream) val imageHeightIsBiggerThanWidth = options.outHeight > options.outWidth val imageHeightBiggerThanScreenHeight = options.outHeight > getDisplayMaxHeightInPx return imageHeightIsBiggerThanWidth && imageHeightBiggerThanScreenHeight @@ -275,16 +272,8 @@ object ImageUtil { * Split the imageStream according to the provided splitData */ fun splitStrip(imageStream: InputStream, splitData: SplitData): InputStream { - val bitmapRegionDecoder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - BitmapRegionDecoder.newInstance(imageStream) - } else { - @Suppress("DEPRECATION") - BitmapRegionDecoder.newInstance(imageStream, false) - } - - if (bitmapRegionDecoder == null) { - throw Exception("Failed to create new instance of BitmapRegionDecoder") - } + val bitmapRegionDecoder = getBitmapRegionDecoder(imageStream) + ?: throw Exception("Failed to create new instance of BitmapRegionDecoder") logcat { "WebtoonSplit #${splitData.index} with topOffset=${splitData.topOffset} " + @@ -308,42 +297,41 @@ object ImageUtil { } fun getSplitDataForStream(imageStream: InputStream): List { - val options = extractImageOptions(imageStream) - return getSplitDataForOptions(options) + return extractImageOptions(imageStream).splitData } - private fun getSplitDataForOptions(options: BitmapFactory.Options): List { - val imageHeight = options.outHeight + private val BitmapFactory.Options.splitData + get(): List { + val imageHeight = outHeight - val splitHeight = (getDisplayMaxHeightInPx * 1.5).toInt() - // -1 so it doesn't try to split when imageHeight = splitHeight - val partCount = (imageHeight - 1) / splitHeight + 1 + val splitHeight = (getDisplayMaxHeightInPx * 1.5).toInt() + // -1 so it doesn't try to split when imageHeight = splitHeight + val partCount = (imageHeight - 1) / splitHeight + 1 + val optimalSplitHeight = imageHeight / partCount - val optimalSplitHeight = imageHeight / partCount + logcat { + "Generating SplitData for image (height: $imageHeight): " + + "$partCount parts @ ${optimalSplitHeight}px height per part" + } - logcat { - "Generating SplitData for image with height of $imageHeight. " + - "Estimated $partCount part and ${optimalSplitHeight}px height per part" - } + return mutableListOf().apply { + for (index in (0 until partCount)) { + // Only continue if the list is empty or there is image remaining + if (isNotEmpty() && imageHeight <= last().bottomOffset) break - return mutableListOf().apply { - for (index in (0 until partCount)) { - // Only continue if the list is empty or there is image remaining - if (isNotEmpty() && imageHeight <= last().bottomOffset) break + val topOffset = index * optimalSplitHeight + var outputImageHeight = min(optimalSplitHeight, imageHeight - topOffset) - val topOffset = index * optimalSplitHeight - var outputImageHeight = min(optimalSplitHeight, imageHeight - topOffset) - - val remainingHeight = imageHeight - (topOffset + outputImageHeight) - // If remaining height is smaller or equal to 1/10th of - // optimal split height then include it in current page - if (remainingHeight <= (optimalSplitHeight / 10)) { - outputImageHeight += remainingHeight + val remainingHeight = imageHeight - (topOffset + outputImageHeight) + // If remaining height is smaller or equal to 1/10th of + // optimal split height then include it in current page + if (remainingHeight <= (optimalSplitHeight / 10)) { + outputImageHeight += remainingHeight + } + add(SplitData(index, topOffset, outputImageHeight)) } - add(SplitData(index, topOffset, outputImageHeight)) } } - } data class SplitData( val index: Int, @@ -584,6 +572,15 @@ object ImageUtil { return options } + private fun getBitmapRegionDecoder(imageStream: InputStream): BitmapRegionDecoder? { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + BitmapRegionDecoder.newInstance(imageStream) + } else { + @Suppress("DEPRECATION") + BitmapRegionDecoder.newInstance(imageStream, false) + } + } + // Android doesn't include some mappings private val SUPPLEMENTARY_MIMETYPE_MAPPING = mapOf( // https://issuetracker.google.com/issues/182703810 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e787150e6..e3c3c1c12 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -297,8 +297,7 @@ Dual page split Invert dual page split placement If the placement of the dual page split doesn\'t match reading direction - Split tall images (Alpha) - Improves reader performance + Split tall images (BETA) Show content in cutout area Animate page transitions Double tap animation speed