From 89600fc7aa705bce329e10ef1dfe233f4ebcdf3b Mon Sep 17 00:00:00 2001 From: bucketmouse Date: Thu, 28 Jul 2022 16:03:09 -0700 Subject: [PATCH] Center padding option for Surface Duos/other foldables (#634) * Add center margin option for horizontal dual page view * Update readme to make the point of the fork obvious * Center margins now added to large single images that would display in place of two smaller pages * Cleanup; reworked preference into an int selector to specify which margins to add * Suggested fixes and and readme reversion which somehow got skipped last commit * Missed the build block in readme. Oops. --- README.md | 6 +- .../data/preference/PreferencesHelper.kt | 2 + .../tachiyomi/ui/reader/ReaderPresenter.kt | 2 +- .../setting/ReaderReadingModeSettings.kt | 1 + .../ui/reader/viewer/pager/PagerConfig.kt | 13 ++++ .../ui/reader/viewer/pager/PagerPageHolder.kt | 27 ++++++++- .../ui/setting/SettingsReaderController.kt | 12 ++++ .../kanade/tachiyomi/util/system/ImageUtil.kt | 60 +++++++++++++++---- .../main/res/layout/reader_pager_settings.xml | 7 +++ app/src/main/res/values/arrays_sy.xml | 7 +++ app/src/main/res/values/strings_sy.xml | 9 +++ 11 files changed, 129 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index bb9f44c02..7b58c75bf 100644 --- a/README.md +++ b/README.md @@ -85,8 +85,8 @@ Please make sure to read the full guidelines. Your issue may be closed without w
Bugs * Include version (More → About → Version) - * If not latest, try updating, it may have already been solved - * Preview version is equal to the number of commits as seen in the main page +* If not latest, try updating, it may have already been solved +* Preview version is equal to the number of commits as seen in the main page * Include steps to reproduce (if not obvious from description) * Include screenshot (if needed) * If it could be device-dependent, try reproducing on another device (if possible) @@ -119,4 +119,4 @@ See [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md). ## FAQ [See our website.](https://tachiyomi.org/) -You can also reach out to us on [Discord](https://discord.gg/tachiyomi). +You can also reach out to us on [Discord](https://discord.gg/tachiyomi). \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt index 7691ebced..60cab7072 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt @@ -517,5 +517,7 @@ class PreferencesHelper(val context: Context) { fun pageLayout() = flowPrefs.getInt("page_layout", PagerConfig.PageLayout.AUTOMATIC) + fun centerMarginType() = flowPrefs.getInt("center_margin_type", PagerConfig.CenterMarginType.NONE) + fun invertDoublePages() = flowPrefs.getBoolean("invert_double_pages", false) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt index f33890f98..54ef6b2f1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt @@ -856,7 +856,7 @@ class ReaderPresenter( return imageSaver.save( image = Image.Page( - inputStream = { ImageUtil.mergeBitmaps(imageBitmap, imageBitmap2, isLTR, bg) }, + inputStream = { ImageUtil.mergeBitmaps(imageBitmap, imageBitmap2, isLTR, 0, bg) }, name = filename, location = location, ), diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderReadingModeSettings.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderReadingModeSettings.kt index 85f633d44..a982d78ce 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderReadingModeSettings.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderReadingModeSettings.kt @@ -97,6 +97,7 @@ class ReaderReadingModeSettings @JvmOverloads constructor(context: Context, attr binding.pagerPrefsGroup.pageTransitionsPager.bindToPreference(preferences.pageTransitionsPager()) binding.pagerPrefsGroup.pageLayout.bindToPreference(preferences.pageLayout()) binding.pagerPrefsGroup.invertDoublePages.bindToPreference(preferences.invertDoublePages()) + binding.pagerPrefsGroup.centerMarginType.bindToPreference(preferences.centerMarginType()) // SY <-- } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt index fae597d11..4403f9e16 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt @@ -71,6 +71,9 @@ class PagerConfig( @ColorInt var pageCanvasColor = Color.WHITE + + var centerMarginType = CenterMarginType.NONE + // SY <-- init { @@ -150,6 +153,9 @@ class PagerConfig( }, ) + preferences.centerMarginType() + .register({ centerMarginType = it }, { imagePropertyChangedListener?.invoke() }) + preferences.invertDoublePages() .register({ invertDoublePages = it && dualPageSplit == false }, { imagePropertyChangedListener?.invoke() }) // SY <-- @@ -197,6 +203,13 @@ class PagerConfig( navigationModeChangedListener?.invoke() } + object CenterMarginType { + const val NONE = 0 + const val DOUBLE_PAGE_CENTER_MARGIN = 1 + const val WIDE_PAGE_CENTER_MARGIN = 2 + const val DOUBLE_AND_WIDE_CENTER_MARGIN = 3 + } + object PageLayout { const val SINGLE_PAGE = 0 const val DOUBLE_PAGES = 1 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt index e8d048701..f0d094e88 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt @@ -28,6 +28,7 @@ import java.io.BufferedInputStream import java.io.ByteArrayInputStream import java.io.InputStream import java.util.concurrent.TimeUnit +import kotlin.math.max import kotlin.math.roundToInt /** @@ -353,7 +354,18 @@ class PagerPageHolder( } private fun mergePages(imageStream: InputStream, imageStream2: InputStream?): InputStream { - imageStream2 ?: return imageStream + // Handle adding a center margin to wide images if requested + if (imageStream2 == null) { + if (imageStream is BufferedInputStream && ImageUtil.isWideImage(imageStream) && + viewer.config.centerMarginType and PagerConfig.CenterMarginType.WIDE_PAGE_CENTER_MARGIN > 0 && + !viewer.config.imageCropBorders + ) { + return ImageUtil.AddHorizontalCenterMargin(imageStream, getHeight(), context) + } else { + return imageStream + } + } + if (page.fullPage) return imageStream if (ImageUtil.isAnimatedAndSupported(imageStream)) { page.fullPage = true @@ -424,7 +436,12 @@ class PagerPageHolder( imageStream.close() imageStream2.close() - return ImageUtil.mergeBitmaps(imageBitmap, imageBitmap2, isLTR, viewer.config.pageCanvasColor) { + + val centerMargin = if (viewer.config.centerMarginType and PagerConfig.CenterMarginType.DOUBLE_PAGE_CENTER_MARGIN > 0 && + !viewer.config.imageCropBorders + ) 96 / (max(1, getHeight()) / max(height, height2)) else 0 + + return ImageUtil.mergeBitmaps(imageBitmap, imageBitmap2, isLTR, centerMargin, viewer.config.pageCanvasColor) { viewer.scope.launchUI { if (it == 100) { progressIndicator.hide() @@ -461,7 +478,11 @@ class PagerPageHolder( } } - return ImageUtil.splitInHalf(imageStream, side) + val sideMargin = if ((viewer.config.centerMarginType and PagerConfig.CenterMarginType.DOUBLE_PAGE_CENTER_MARGIN) > 0 && + viewer.config.doublePages && !viewer.config.imageCropBorders + ) 48 else 0 + + return ImageUtil.splitInHalf(imageStream, side, sideMargin) } private fun onPageSplit(page: ReaderPage) { 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 9442c1681..1de8d357a 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 @@ -508,6 +508,18 @@ class SettingsReaderController : SettingsController() { titleRes = R.string.invert_double_pages visibleIf(preferences.pageLayout()) { it != PagerConfig.PageLayout.SINGLE_PAGE } } + + intListPreference { + bindTo(preferences.centerMarginType()) + titleRes = R.string.center_margin + entriesRes = arrayOf( + R.string.center_margin_none, + R.string.center_margin_double_page, + R.string.center_margin_wide_page, + R.string.center_margin_double_and_wide_page, + ) + entryValues = arrayOf("0", "1", "2", "3") + } } // SY <-- } 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 3c8497d41..149f24fc7 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 @@ -1,5 +1,4 @@ package eu.kanade.tachiyomi.util.system - import android.content.Context import android.content.res.Configuration import android.graphics.Bitmap @@ -128,16 +127,16 @@ object ImageUtil { /** * Extract the 'side' part from imageStream and return it as InputStream. */ - fun splitInHalf(imageStream: InputStream, side: Side): InputStream { + fun splitInHalf(imageStream: InputStream, side: Side, sidePadding: Int): InputStream { val imageBytes = imageStream.readBytes() val imageBitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size) val height = imageBitmap.height val width = imageBitmap.width - val singlePage = Rect(0, 0, width / 2, height) + val singlePage = Rect(0, 0, width / 2 + sidePadding, height) - val half = createBitmap(width / 2, height) + val half = createBitmap(width / 2 + sidePadding, height) val part = when (side) { Side.RIGHT -> Rect(width - width / 2, 0, width, height) Side.LEFT -> Rect(0, 0, width / 2, height) @@ -152,7 +151,8 @@ object ImageUtil { } /** - * Split the image into left and right parts, then merge them into a new image. + * Split the image into left and right parts, then merge them into a + * new vertically-aligned image. */ fun splitAndMerge(imageStream: InputStream, upperSide: Side): InputStream { val imageBytes = imageStream.readBytes() @@ -187,6 +187,40 @@ object ImageUtil { enum class Side { RIGHT, LEFT } + // SY --> + /** + * Split the image into left and right parts, then merge them into a + * new image with added center padding scaled relative to the height of the display view + * to compensate for scaling. + */ + + fun AddHorizontalCenterMargin(imageStream: InputStream, viewHeight: Int, backgroundContext: Context): InputStream { + val imageBitmap = ImageDecoder.newInstance(imageStream)?.decode()!! + val height = imageBitmap.height + val width = imageBitmap.width + + val centerPadding = 96 / (max(1, viewHeight) / height) + + val leftSourcePart = Rect(0, 0, width / 2, height) + val rightSourcePart = Rect(width / 2, 0, width, height) + val leftTargetPart = Rect(0, 0, width / 2, height) + val rightTargetPart = Rect(width / 2 + centerPadding, 0, width + centerPadding, height) + + val bgColor = chooseBackground(backgroundContext, imageStream) + bgColor.setBounds(width / 2, 0, width / 2 + centerPadding, height) + val result = createBitmap(width + centerPadding, height) + + result.applyCanvas { + drawBitmap(imageBitmap, leftSourcePart, leftTargetPart, null) + drawBitmap(imageBitmap, rightSourcePart, rightTargetPart, null) + bgColor.draw(this) + } + + val output = ByteArrayOutputStream() + result.compress(Bitmap.CompressFormat.JPEG, 100, output) + return ByteArrayInputStream(output.toByteArray()) + } + // SY <-- /** * Check whether the image is considered a tall image. @@ -534,31 +568,37 @@ object ImageUtil { imageBitmap: Bitmap, imageBitmap2: Bitmap, isLTR: Boolean, + centerMargin: Int, @ColorInt background: Int = Color.WHITE, + progressCallback: ((Int) -> Unit)? = null, ): ByteArrayInputStream { val height = imageBitmap.height val width = imageBitmap.width val height2 = imageBitmap2.height val width2 = imageBitmap2.width + val maxHeight = max(height, height2) - val result = Bitmap.createBitmap(width + width2, max(height, height2), Bitmap.Config.ARGB_8888) + + val result = Bitmap.createBitmap(width + width2 + centerMargin, max(height, height2), Bitmap.Config.ARGB_8888) val canvas = Canvas(result) canvas.drawColor(background) val upperPart = Rect( - if (isLTR) 0 else width2, + if (isLTR) 0 else width2 + centerMargin, (maxHeight - imageBitmap.height) / 2, - (if (isLTR) 0 else width2) + imageBitmap.width, + (if (isLTR) 0 else width2 + centerMargin) + imageBitmap.width, imageBitmap.height + (maxHeight - imageBitmap.height) / 2, ) + canvas.drawBitmap(imageBitmap, imageBitmap.rect, upperPart, null) progressCallback?.invoke(98) val bottomPart = Rect( - if (!isLTR) 0 else width, + if (!isLTR) 0 else width + centerMargin, (maxHeight - imageBitmap2.height) / 2, - (if (!isLTR) 0 else width) + imageBitmap2.width, + (if (!isLTR) 0 else width + centerMargin) + imageBitmap2.width, imageBitmap2.height + (maxHeight - imageBitmap2.height) / 2, ) + canvas.drawBitmap(imageBitmap2, imageBitmap2.rect, bottomPart, null) progressCallback?.invoke(99) diff --git a/app/src/main/res/layout/reader_pager_settings.xml b/app/src/main/res/layout/reader_pager_settings.xml index ea3e9949f..3e42ee864 100644 --- a/app/src/main/res/layout/reader_pager_settings.xml +++ b/app/src/main/res/layout/reader_pager_settings.xml @@ -116,6 +116,13 @@ android:textColor="?android:attr/textColorSecondary" android:text="@string/invert_double_pages" /> + + @string/double_pages @string/automatic_orientation + + + @string/center_margin_none + @string/center_margin_double_page + @string/center_margin_wide_page + @string/center_margin_double_and_wide_page + \ No newline at end of file diff --git a/app/src/main/res/values/strings_sy.xml b/app/src/main/res/values/strings_sy.xml index 567709371..790c10625 100644 --- a/app/src/main/res/values/strings_sy.xml +++ b/app/src/main/res/values/strings_sy.xml @@ -314,6 +314,15 @@ While using automatic page layout, you can still switch between layouts while reading without overriding this setting Invert double pages + + Center Margin + None + Add to double Page + Add to wide Page + Add to both + Center margin type + Insert spacer to accommodate deadspace on foldable devices. + See Recommendations