add flip image functionality

This commit is contained in:
M Naufal Shidqi 2024-05-02 16:49:27 +07:00
parent 80461d883f
commit 1650c57ca7
8 changed files with 42 additions and 0 deletions

View file

@ -117,6 +117,10 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel)
label = stringResource(MR.strings.pref_inverted_colors), label = stringResource(MR.strings.pref_inverted_colors),
pref = screenModel.preferences.invertedColors(), pref = screenModel.preferences.invertedColors(),
) )
CheckboxItem(
label = stringResource(MR.strings.pref_flip_horizontally),
pref = screenModel.preferences.flipHorizontally(),
)
} }
private fun getColorValue(currentColor: Int, color: Int, mask: Long, bitShift: Int): Int { private fun getColorValue(currentColor: Int, color: Int, mask: Long, bitShift: Int): Int {

View file

@ -109,6 +109,8 @@ class ReaderPreferences(
fun invertedColors() = preferenceStore.getBoolean("pref_inverted_colors", false) fun invertedColors() = preferenceStore.getBoolean("pref_inverted_colors", false)
fun flipHorizontally() = preferenceStore.getBoolean("flip_horizontally", false)
// endregion // endregion
// region Controls // region Controls

View file

@ -48,6 +48,9 @@ class PagerConfig(
var landscapeZoom = false var landscapeZoom = false
private set private set
var flipHorizontally = false
private set
init { init {
readerPreferences.readerTheme() readerPreferences.readerTheme()
.register( .register(
@ -106,6 +109,9 @@ class PagerConfig(
{ dualPageRotateToFitInvert = it }, { dualPageRotateToFitInvert = it },
{ imagePropertyChangedListener?.invoke() }, { imagePropertyChangedListener?.invoke() },
) )
readerPreferences.flipHorizontally()
.register({ flipHorizontally = it }, { imagePropertyChangedListener?.invoke() })
} }
private fun zoomTypeFromPreference(value: Int) { private fun zoomTypeFromPreference(value: Int) {

View file

@ -174,6 +174,10 @@ class PagerPageHolder(
} }
private fun process(page: ReaderPage, imageSource: BufferedSource): BufferedSource { private fun process(page: ReaderPage, imageSource: BufferedSource): BufferedSource {
if (viewer.config.flipHorizontally) {
return ImageUtil.flipImage(imageSource, true, false)
}
if (viewer.config.dualPageRotateToFit) { if (viewer.config.dualPageRotateToFit) {
return rotateDualPage(imageSource) return rotateDualPage(imageSource)
} }

View file

@ -44,6 +44,9 @@ class WebtoonConfig(
val theme = readerPreferences.readerTheme().get() val theme = readerPreferences.readerTheme().get()
var flipHorizontally = false
private set
init { init {
readerPreferences.cropBordersWebtoon() readerPreferences.cropBordersWebtoon()
.register({ imageCropBorders = it }, { imagePropertyChangedListener?.invoke() }) .register({ imageCropBorders = it }, { imagePropertyChangedListener?.invoke() })
@ -96,6 +99,9 @@ class WebtoonConfig(
.distinctUntilChanged() .distinctUntilChanged()
.onEach { themeChangedListener?.invoke() } .onEach { themeChangedListener?.invoke() }
.launchIn(scope) .launchIn(scope)
readerPreferences.flipHorizontally()
.register({ flipHorizontally = it }, { imagePropertyChangedListener?.invoke() })
} }
override var navigator: ViewerNavigation = defaultNavigation() override var navigator: ViewerNavigation = defaultNavigation()

View file

@ -213,6 +213,10 @@ class WebtoonPageHolder(
} }
private fun process(imageSource: BufferedSource): BufferedSource { private fun process(imageSource: BufferedSource): BufferedSource {
if (viewer.config.flipHorizontally) {
return ImageUtil.flipImage(imageSource, true, false)
}
if (viewer.config.dualPageRotateToFit) { if (viewer.config.dualPageRotateToFit) {
return rotateDualPage(imageSource) return rotateDualPage(imageSource)
} }

View file

@ -163,11 +163,26 @@ object ImageUtil {
return output return output
} }
fun flipImage(imageSource: BufferedSource, flipX: Boolean, flipY: Boolean): BufferedSource {
val imageBitmap = BitmapFactory.decodeStream(imageSource.inputStream())
val flipped = flipBitMap(imageBitmap, flipX, flipY)
val output = Buffer()
flipped.compress(Bitmap.CompressFormat.JPEG, 100, output.outputStream())
return output
}
private fun rotateBitMap(bitmap: Bitmap, degrees: Float): Bitmap { private fun rotateBitMap(bitmap: Bitmap, degrees: Float): Bitmap {
val matrix = Matrix().apply { postRotate(degrees) } val matrix = Matrix().apply { postRotate(degrees) }
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true) return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
} }
private fun flipBitMap(bitmap: Bitmap, flipX: Boolean, flipY: Boolean): Bitmap {
val matrix = Matrix().apply { postScale(if (flipX) -1f else 1f, if (flipY) -1f else 1f) }
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
}
/** /**
* 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 image.
*/ */

View file

@ -375,6 +375,7 @@
<string name="pref_custom_brightness">Custom brightness</string> <string name="pref_custom_brightness">Custom brightness</string>
<string name="pref_grayscale">Grayscale</string> <string name="pref_grayscale">Grayscale</string>
<string name="pref_inverted_colors">Inverted</string> <string name="pref_inverted_colors">Inverted</string>
<string name="pref_flip_horizontally">Flip horizontally</string>
<string name="pref_custom_color_filter">Custom color filter</string> <string name="pref_custom_color_filter">Custom color filter</string>
<string name="pref_color_filter_mode">Color filter blend mode</string> <string name="pref_color_filter_mode">Color filter blend mode</string>
<string name="filter_mode_overlay">Overlay</string> <string name="filter_mode_overlay">Overlay</string>