Automatic background color for PagerViewer (#4996)
* Add J2K implementation of automatic background Co-authored-by: Jays2Kings <8617760+Jays2Kings@users.noreply.github.com> * Tweak the monstrosity called automatic background * Add ability to choose Automatic as a background * More tweaks Co-authored-by: Jays2Kings <8617760+Jays2Kings@users.noreply.github.com> (cherry picked from commit 122cdae5bcbb0421c98e271521d32fadc7c95beb) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt # app/src/main/java/eu/kanade/tachiyomi/util/system/ImageUtil.kt # app/src/main/res/values/arrays.xml
This commit is contained in:
parent
7e612e63b4
commit
6238f06d39
@ -34,7 +34,7 @@ android {
|
||||
minSdkVersion(AndroidConfig.minSdk)
|
||||
targetSdkVersion(AndroidConfig.targetSdk)
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
versionCode = 17
|
||||
versionCode = 18
|
||||
versionName = "1.6.2"
|
||||
|
||||
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
|
||||
|
@ -1,15 +1,12 @@
|
||||
package eu.kanade.tachiyomi.ui.reader.loader
|
||||
|
||||
import android.graphics.BitmapFactory
|
||||
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerPageHolder
|
||||
import eu.kanade.tachiyomi.util.lang.plusAssign
|
||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||
import exh.source.isEhBasedSource
|
||||
import rx.Completable
|
||||
import rx.Observable
|
||||
@ -258,20 +255,6 @@ class HttpPageLoader(
|
||||
}
|
||||
}
|
||||
.doOnNext {
|
||||
// SY -->
|
||||
val readerTheme = preferences.readerTheme().get()
|
||||
if (readerTheme >= 3) {
|
||||
val stream = chapterCache.getImageFile(imageUrl).inputStream()
|
||||
val image = BitmapFactory.decodeStream(stream)
|
||||
page.bg = ImageUtil.autoSetBackground(
|
||||
image,
|
||||
readerTheme == 3,
|
||||
preferences.context
|
||||
)
|
||||
page.bgType = PagerPageHolder.getBGType(readerTheme, preferences.context)
|
||||
stream.close()
|
||||
}
|
||||
// SY <--
|
||||
page.stream = { chapterCache.getImageFile(imageUrl).inputStream() }
|
||||
page.status = Page.READY
|
||||
}
|
||||
|
@ -23,6 +23,9 @@ class PagerConfig(
|
||||
preferences: PreferencesHelper = Injekt.get()
|
||||
) : ViewerConfig(preferences, scope) {
|
||||
|
||||
var automaticBackground = false
|
||||
private set
|
||||
|
||||
var dualPageSplitChangedListener: ((Boolean) -> Unit)? = null
|
||||
|
||||
var imageScaleType = 1
|
||||
@ -39,6 +42,9 @@ class PagerConfig(
|
||||
// SY <--
|
||||
|
||||
init {
|
||||
preferences.readerTheme()
|
||||
.register({ automaticBackground = it == 3 }, { imagePropertyChangedListener?.invoke() })
|
||||
|
||||
preferences.imageScaleType()
|
||||
.register({ imageScaleType = it }, { imagePropertyChangedListener?.invoke() })
|
||||
|
||||
|
@ -1,11 +1,8 @@
|
||||
package eu.kanade.tachiyomi.ui.reader.viewer.pager
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.PointF
|
||||
import android.graphics.drawable.Animatable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.view.GestureDetector
|
||||
import android.view.Gravity
|
||||
import android.view.MotionEvent
|
||||
@ -24,26 +21,19 @@ import com.davemorrissey.labs.subscaleview.ImageSource
|
||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
||||
import com.github.chrisbanes.photoview.PhotoView
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.ui.reader.model.InsertPage
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressBar
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerConfig.ZoomType
|
||||
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
|
||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||
import eu.kanade.tachiyomi.widget.ViewPagerAdapter
|
||||
import exh.util.isInNightMode
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.schedulers.Schedulers
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.InputStream
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.concurrent.TimeUnit
|
||||
@ -104,12 +94,6 @@ class PagerPageHolder(
|
||||
*/
|
||||
private var readImageHeaderSubscription: Subscription? = null
|
||||
|
||||
// SY -->
|
||||
private val readerTheme by lazy {
|
||||
Injekt.get<PreferencesHelper>().readerTheme().get()
|
||||
}
|
||||
// SY <--
|
||||
|
||||
init {
|
||||
addView(progressBar)
|
||||
observeStatus()
|
||||
@ -254,30 +238,12 @@ class PagerPageHolder(
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnNext { isAnimated ->
|
||||
if (!isAnimated) {
|
||||
// SY -->
|
||||
if (readerTheme >= 3) {
|
||||
val imageView = initSubsamplingImageView()
|
||||
if (page.bg != null && page.bgType == getBGType(readerTheme, context)) {
|
||||
imageView.setImage(ImageSource.inputStream(openStream!!))
|
||||
imageView.background = page.bg
|
||||
initSubsamplingImageView().apply {
|
||||
if (viewer.config.automaticBackground) {
|
||||
background = ImageUtil.chooseBackground(context, openStream!!)
|
||||
}
|
||||
// if the user switches to automatic when pages are already cached, the bg needs to be loaded
|
||||
else {
|
||||
val bytesArray = openStream!!.readBytes()
|
||||
val bytesStream = bytesArray.inputStream()
|
||||
imageView.setImage(ImageSource.inputStream(bytesStream))
|
||||
bytesStream.close()
|
||||
|
||||
launchUI {
|
||||
imageView.background = setBG(bytesArray)
|
||||
page.bg = imageView.background
|
||||
page.bgType = getBGType(readerTheme, context)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
initSubsamplingImageView().setImage(ImageSource.inputStream(openStream!!))
|
||||
setImage(ImageSource.inputStream(openStream!!))
|
||||
}
|
||||
// SY <--
|
||||
} else {
|
||||
initImageView().setImage(openStream!!)
|
||||
}
|
||||
@ -331,22 +297,6 @@ class PagerPageHolder(
|
||||
viewer.onPageSplit(page, newPage)
|
||||
}
|
||||
|
||||
// SY -->
|
||||
private suspend fun setBG(bytesArray: ByteArray): Drawable {
|
||||
return withContext(Dispatchers.Default) {
|
||||
ImageUtil.autoSetBackground(
|
||||
BitmapFactory.decodeByteArray(
|
||||
bytesArray,
|
||||
0,
|
||||
bytesArray.size
|
||||
),
|
||||
readerTheme == 3,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
|
||||
/**
|
||||
* Called when the page has an error.
|
||||
*/
|
||||
@ -550,14 +500,4 @@ class PagerPageHolder(
|
||||
.build()
|
||||
context.imageLoader.enqueue(request)
|
||||
}
|
||||
|
||||
// SY -->
|
||||
companion object {
|
||||
fun getBGType(readerTheme: Int, context: Context): Int {
|
||||
return if (readerTheme == 4) {
|
||||
if (context.isInNightMode) 2 else 1
|
||||
} else 0
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
@ -120,8 +120,8 @@ class SettingsReaderController : SettingsController() {
|
||||
intListPreference {
|
||||
key = Keys.readerTheme
|
||||
titleRes = R.string.pref_reader_theme
|
||||
entriesRes = arrayOf(R.string.black_background, R.string.gray_background, R.string.white_background, R.string.smart_based_on_page, R.string.smart_based_on_page_and_theme)
|
||||
entryValues = arrayOf("1", "2", "0", "3", "4")
|
||||
entriesRes = arrayOf(R.string.black_background, R.string.gray_background, R.string.white_background, R.string.automatic_background)
|
||||
entryValues = arrayOf("1", "2", "0", "3")
|
||||
defaultValue = "3"
|
||||
summary = "%s"
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package eu.kanade.tachiyomi.util.system
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Canvas
|
||||
@ -9,8 +10,11 @@ import android.graphics.Rect
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import androidx.core.graphics.alpha
|
||||
import androidx.core.graphics.blue
|
||||
import androidx.core.graphics.createBitmap
|
||||
import eu.kanade.tachiyomi.R
|
||||
import androidx.core.graphics.green
|
||||
import androidx.core.graphics.red
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.InputStream
|
||||
@ -161,16 +165,22 @@ object ImageUtil {
|
||||
RIGHT, LEFT
|
||||
}
|
||||
|
||||
// SY -->
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
fun autoSetBackground(image: Bitmap?, alwaysUseWhite: Boolean, context: Context): Drawable {
|
||||
val backgroundColor = if (alwaysUseWhite) Color.WHITE else {
|
||||
context.getResourceColor(R.attr.colorPrimary)
|
||||
}
|
||||
if (image == null) return ColorDrawable(backgroundColor)
|
||||
/**
|
||||
* Algorithm for determining what background to accompany a comic/manga page
|
||||
*/
|
||||
fun chooseBackground(context: Context, imageStream: InputStream): Drawable {
|
||||
imageStream.mark(imageStream.available() + 1)
|
||||
|
||||
val image = BitmapFactory.decodeStream(imageStream)
|
||||
|
||||
imageStream.reset()
|
||||
|
||||
val whiteColor = Color.WHITE
|
||||
if (image == null) return ColorDrawable(whiteColor)
|
||||
if (image.width < 50 || image.height < 50) {
|
||||
return ColorDrawable(backgroundColor)
|
||||
return ColorDrawable(whiteColor)
|
||||
}
|
||||
|
||||
val top = 5
|
||||
val bot = image.height - 5
|
||||
val left = (image.width * 0.0275).toInt()
|
||||
@ -178,42 +188,52 @@ object ImageUtil {
|
||||
val midX = image.width / 2
|
||||
val midY = image.height / 2
|
||||
val offsetX = (image.width * 0.01).toInt()
|
||||
val offsetY = (image.height * 0.01).toInt()
|
||||
val topLeftIsDark = isDark(image.getPixel(left, top))
|
||||
val topRightIsDark = isDark(image.getPixel(right, top))
|
||||
val midLeftIsDark = isDark(image.getPixel(left, midY))
|
||||
val midRightIsDark = isDark(image.getPixel(right, midY))
|
||||
val topMidIsDark = isDark(image.getPixel(midX, top))
|
||||
val botLeftIsDark = isDark(image.getPixel(left, bot))
|
||||
val botRightIsDark = isDark(image.getPixel(right, bot))
|
||||
val leftOffsetX = left - offsetX
|
||||
val rightOffsetX = right + offsetX
|
||||
|
||||
val topLeftPixel = image.getPixel(left, top)
|
||||
val topRightPixel = image.getPixel(right, top)
|
||||
val midLeftPixel = image.getPixel(left, midY)
|
||||
val midRightPixel = image.getPixel(right, midY)
|
||||
val topCenterPixel = image.getPixel(midX, top)
|
||||
val botLeftPixel = image.getPixel(left, bot)
|
||||
val bottomCenterPixel = image.getPixel(midX, bot)
|
||||
val botRightPixel = image.getPixel(right, bot)
|
||||
|
||||
val topLeftIsDark = topLeftPixel.isDark()
|
||||
val topRightIsDark = topRightPixel.isDark()
|
||||
val midLeftIsDark = midLeftPixel.isDark()
|
||||
val midRightIsDark = midRightPixel.isDark()
|
||||
val topMidIsDark = topCenterPixel.isDark()
|
||||
val botLeftIsDark = botLeftPixel.isDark()
|
||||
val botRightIsDark = botRightPixel.isDark()
|
||||
|
||||
var darkBG = (topLeftIsDark && (botLeftIsDark || botRightIsDark || topRightIsDark || midLeftIsDark || topMidIsDark)) ||
|
||||
(topRightIsDark && (botRightIsDark || botLeftIsDark || midRightIsDark || topMidIsDark))
|
||||
|
||||
if (!isWhite(image.getPixel(left, top)) && pixelIsClose(image.getPixel(left, top), image.getPixel(midX, top)) &&
|
||||
!isWhite(image.getPixel(midX, top)) && pixelIsClose(image.getPixel(midX, top), image.getPixel(right, top)) &&
|
||||
!isWhite(image.getPixel(right, top)) && pixelIsClose(image.getPixel(right, top), image.getPixel(right, bot)) &&
|
||||
!isWhite(image.getPixel(right, bot)) && pixelIsClose(image.getPixel(right, bot), image.getPixel(midX, bot)) &&
|
||||
!isWhite(image.getPixel(midX, bot)) && pixelIsClose(image.getPixel(midX, bot), image.getPixel(left, bot)) &&
|
||||
!isWhite(image.getPixel(left, bot)) && pixelIsClose(image.getPixel(left, bot), image.getPixel(left, top))
|
||||
) {
|
||||
return ColorDrawable(image.getPixel(left, top))
|
||||
val topAndBotPixels = listOf(topLeftPixel, topCenterPixel, topRightPixel, botRightPixel, bottomCenterPixel, botLeftPixel)
|
||||
val isNotWhiteAndCloseTo = topAndBotPixels.mapIndexed { index, color ->
|
||||
val other = topAndBotPixels[(index + 1) % topAndBotPixels.size]
|
||||
!color.isWhite() && color.isCloseTo(other)
|
||||
}
|
||||
if (isNotWhiteAndCloseTo.all { it }) {
|
||||
return ColorDrawable(topLeftPixel)
|
||||
}
|
||||
|
||||
if (isWhite(image.getPixel(left, top)).toInt() +
|
||||
isWhite(image.getPixel(right, top)).toInt() +
|
||||
isWhite(image.getPixel(left, bot)).toInt() +
|
||||
isWhite(image.getPixel(right, bot)).toInt() > 2
|
||||
) {
|
||||
val cornerPixels = listOf(topLeftPixel, topRightPixel, botLeftPixel, botRightPixel)
|
||||
val numberOfWhiteCorners = cornerPixels.map { cornerPixel -> cornerPixel.isWhite() }
|
||||
.filter { it }
|
||||
.size
|
||||
if (numberOfWhiteCorners > 2) {
|
||||
darkBG = false
|
||||
}
|
||||
|
||||
var blackPixel = when {
|
||||
topLeftIsDark -> image.getPixel(left, top)
|
||||
topRightIsDark -> image.getPixel(right, top)
|
||||
botLeftIsDark -> image.getPixel(left, bot)
|
||||
botRightIsDark -> image.getPixel(right, bot)
|
||||
else -> backgroundColor
|
||||
var blackColor = when {
|
||||
topLeftIsDark -> topLeftPixel
|
||||
topRightIsDark -> topRightPixel
|
||||
botLeftIsDark -> botLeftPixel
|
||||
botRightIsDark -> botRightPixel
|
||||
else -> whiteColor
|
||||
}
|
||||
|
||||
var overallWhitePixels = 0
|
||||
@ -222,32 +242,32 @@ object ImageUtil {
|
||||
var topWhiteStreak = 0
|
||||
var botBlackStreak = 0
|
||||
var botWhiteStreak = 0
|
||||
outer@ for (x in intArrayOf(left, right, left - offsetX, right + offsetX)) {
|
||||
outer@ for (x in intArrayOf(left, right, leftOffsetX, rightOffsetX)) {
|
||||
var whitePixelsStreak = 0
|
||||
var whitePixels = 0
|
||||
var blackPixelsStreak = 0
|
||||
var blackPixels = 0
|
||||
var blackStreak = false
|
||||
var whiteStrak = false
|
||||
var whiteStreak = false
|
||||
val notOffset = x == left || x == right
|
||||
for ((index, y) in (0 until image.height step image.height / 25).withIndex()) {
|
||||
inner@ for ((index, y) in (0 until image.height step image.height / 25).withIndex()) {
|
||||
val pixel = image.getPixel(x, y)
|
||||
val pixelOff = image.getPixel(x + (if (x < image.width / 2) -offsetX else offsetX), y)
|
||||
if (isWhite(pixel)) {
|
||||
if (pixel.isWhite()) {
|
||||
whitePixelsStreak++
|
||||
whitePixels++
|
||||
if (notOffset) {
|
||||
overallWhitePixels++
|
||||
}
|
||||
if (whitePixelsStreak > 14) {
|
||||
whiteStrak = true
|
||||
whiteStreak = true
|
||||
}
|
||||
if (whitePixelsStreak > 6 && whitePixelsStreak >= index - 1) {
|
||||
topWhiteStreak = whitePixelsStreak
|
||||
}
|
||||
} else {
|
||||
whitePixelsStreak = 0
|
||||
if (isDark(pixel) && isDark(pixelOff)) {
|
||||
if (pixel.isDark() && pixelOff.isDark()) {
|
||||
blackPixels++
|
||||
if (notOffset) {
|
||||
overallBlackPixels++
|
||||
@ -256,7 +276,7 @@ object ImageUtil {
|
||||
if (blackPixelsStreak >= 14) {
|
||||
blackStreak = true
|
||||
}
|
||||
continue
|
||||
continue@inner
|
||||
}
|
||||
}
|
||||
if (blackPixelsStreak > 6 && blackPixelsStreak >= index - 1) {
|
||||
@ -271,11 +291,11 @@ object ImageUtil {
|
||||
}
|
||||
when {
|
||||
blackPixels > 22 -> {
|
||||
if (x == right || x == right + offsetX) {
|
||||
blackPixel = when {
|
||||
topRightIsDark -> image.getPixel(right, top)
|
||||
botRightIsDark -> image.getPixel(right, bot)
|
||||
else -> blackPixel
|
||||
if (x == right || x == rightOffsetX) {
|
||||
blackColor = when {
|
||||
topRightIsDark -> topRightPixel
|
||||
botRightIsDark -> botRightPixel
|
||||
else -> blackColor
|
||||
}
|
||||
}
|
||||
darkBG = true
|
||||
@ -284,11 +304,11 @@ object ImageUtil {
|
||||
}
|
||||
blackStreak -> {
|
||||
darkBG = true
|
||||
if (x == right || x == right + offsetX) {
|
||||
blackPixel = when {
|
||||
topRightIsDark -> image.getPixel(right, top)
|
||||
botRightIsDark -> image.getPixel(right, bot)
|
||||
else -> blackPixel
|
||||
if (x == right || x == rightOffsetX) {
|
||||
blackColor = when {
|
||||
topRightIsDark -> topRightPixel
|
||||
botRightIsDark -> botRightPixel
|
||||
else -> blackColor
|
||||
}
|
||||
}
|
||||
if (blackPixels > 18) {
|
||||
@ -296,7 +316,7 @@ object ImageUtil {
|
||||
break@outer
|
||||
}
|
||||
}
|
||||
whiteStrak || whitePixels > 22 -> darkBG = false
|
||||
whiteStreak || whitePixels > 22 -> darkBG = false
|
||||
}
|
||||
}
|
||||
|
||||
@ -308,58 +328,57 @@ object ImageUtil {
|
||||
if (topIsBlackStreak && bottomIsBlackStreak) {
|
||||
darkBG = true
|
||||
}
|
||||
if (darkBG) {
|
||||
return if (isWhite(image.getPixel(left, bot)) && isWhite(image.getPixel(right, bot))) {
|
||||
GradientDrawable(
|
||||
GradientDrawable.Orientation.TOP_BOTTOM,
|
||||
intArrayOf(blackPixel, blackPixel, backgroundColor, backgroundColor)
|
||||
)
|
||||
} else if (isWhite(image.getPixel(left, top)) && isWhite(image.getPixel(right, top))) {
|
||||
GradientDrawable(
|
||||
GradientDrawable.Orientation.TOP_BOTTOM,
|
||||
intArrayOf(backgroundColor, backgroundColor, blackPixel, blackPixel)
|
||||
)
|
||||
} else ColorDrawable(blackPixel)
|
||||
|
||||
val isLandscape = context.resources.configuration?.orientation == Configuration.ORIENTATION_LANDSCAPE
|
||||
if (isLandscape) {
|
||||
return when {
|
||||
darkBG -> ColorDrawable(blackColor)
|
||||
else -> ColorDrawable(whiteColor)
|
||||
}
|
||||
}
|
||||
if (topIsBlackStreak || (
|
||||
topLeftIsDark && topRightIsDark &&
|
||||
isDark(image.getPixel(left - offsetX, top)) && isDark(image.getPixel(right + offsetX, top)) &&
|
||||
(topMidIsDark || overallBlackPixels > 9)
|
||||
)
|
||||
) {
|
||||
return GradientDrawable(
|
||||
GradientDrawable.Orientation.TOP_BOTTOM,
|
||||
intArrayOf(blackPixel, blackPixel, backgroundColor, backgroundColor)
|
||||
)
|
||||
} else if (bottomIsBlackStreak || (
|
||||
botLeftIsDark && botRightIsDark &&
|
||||
isDark(image.getPixel(left - offsetX, bot)) && isDark(image.getPixel(right + offsetX, bot)) &&
|
||||
(isDark(image.getPixel(midX, bot)) || overallBlackPixels > 9)
|
||||
)
|
||||
) {
|
||||
return GradientDrawable(
|
||||
GradientDrawable.Orientation.TOP_BOTTOM,
|
||||
intArrayOf(backgroundColor, backgroundColor, blackPixel, blackPixel)
|
||||
)
|
||||
|
||||
val botCornersIsWhite = botLeftPixel.isWhite() && botRightPixel.isWhite()
|
||||
val topCornersIsWhite = topLeftPixel.isWhite() && topRightPixel.isWhite()
|
||||
|
||||
val topCornersIsDark = topLeftIsDark && topRightIsDark
|
||||
val botCornersIsDark = botLeftIsDark && botRightIsDark
|
||||
|
||||
val topOffsetCornersIsDark = image.getPixel(leftOffsetX, top).isDark() && image.getPixel(rightOffsetX, top).isDark()
|
||||
val botOffsetCornersIsDark = image.getPixel(leftOffsetX, bot).isDark() && image.getPixel(rightOffsetX, bot).isDark()
|
||||
|
||||
val gradient = when {
|
||||
darkBG && botCornersIsWhite -> {
|
||||
intArrayOf(blackColor, blackColor, whiteColor, whiteColor)
|
||||
}
|
||||
darkBG && topCornersIsWhite -> {
|
||||
intArrayOf(whiteColor, whiteColor, blackColor, blackColor)
|
||||
}
|
||||
darkBG -> {
|
||||
return ColorDrawable(blackColor)
|
||||
}
|
||||
topIsBlackStreak || (topCornersIsDark && topOffsetCornersIsDark && (topMidIsDark || overallBlackPixels > 9)) -> {
|
||||
intArrayOf(blackColor, blackColor, whiteColor, whiteColor)
|
||||
}
|
||||
bottomIsBlackStreak || (botCornersIsDark && botOffsetCornersIsDark && (bottomCenterPixel.isDark() || overallBlackPixels > 9)) -> {
|
||||
intArrayOf(whiteColor, whiteColor, blackColor, blackColor)
|
||||
}
|
||||
else -> {
|
||||
return ColorDrawable(whiteColor)
|
||||
}
|
||||
}
|
||||
return ColorDrawable(backgroundColor)
|
||||
|
||||
return GradientDrawable(
|
||||
GradientDrawable.Orientation.TOP_BOTTOM,
|
||||
gradient
|
||||
)
|
||||
}
|
||||
|
||||
private fun isDark(color: Int): Boolean {
|
||||
return Color.red(color) < 40 && Color.blue(color) < 40 && Color.green(color) < 40 &&
|
||||
Color.alpha(color) > 200
|
||||
}
|
||||
private fun Int.isDark(): Boolean =
|
||||
red < 40 && blue < 40 && green < 40 && alpha > 200
|
||||
|
||||
private fun isWhite(color: Int): Boolean {
|
||||
return Color.red(color) + Color.blue(color) + Color.green(color) > 740
|
||||
}
|
||||
private fun Int.isCloseTo(other: Int): Boolean =
|
||||
abs(red - other.red) < 30 && abs(green - other.green) < 30 && abs(blue - other.blue) < 30
|
||||
|
||||
private fun Boolean.toInt() = if (this) 1 else 0
|
||||
|
||||
private fun pixelIsClose(color1: Int, color2: Int): Boolean {
|
||||
return abs(Color.red(color1) - Color.red(color2)) < 30 &&
|
||||
abs(Color.green(color1) - Color.green(color2)) < 30 &&
|
||||
abs(Color.blue(color1) - Color.blue(color2)) < 30
|
||||
}
|
||||
// SY <--
|
||||
private fun Int.isWhite(): Boolean =
|
||||
red + blue + green > 740
|
||||
}
|
||||
|
@ -275,6 +275,15 @@ object EXHMigrations {
|
||||
.build()
|
||||
)
|
||||
}
|
||||
if (oldVersion under 18) {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
val readerTheme = prefs.getInt("pref_reader_theme_key", 3)
|
||||
if (readerTheme == 4) {
|
||||
prefs.edit {
|
||||
putInt("pref_reader_theme_key", 3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if (oldVersion under 1) { } (1 is current release version)
|
||||
// do stuff here when releasing changed crap
|
||||
|
@ -180,7 +180,6 @@
|
||||
<string name="library_group_updates_all">Lancer des mises à jour de catégorie tout le temps</string>
|
||||
|
||||
<!-- Browse settings -->
|
||||
<string name="pref_latest_tab_language_code">Afficher le code de langue à côté du nom</string>
|
||||
<string name="pref_latest_position">Dernière position de l\'onglet</string>
|
||||
<string name="pref_latest_position_summery">Voulez-vous que le dernier onglet soit le premier onglet de la navigation? Cela en fera l\'onglet par défaut lors de l\'ouverture de la navigation, non recommandé si vous êtes sur des données ou un réseau mesuré</string>
|
||||
<string name="pref_source_navigation">Remplacer le dernier bouton</string>
|
||||
@ -232,8 +231,6 @@
|
||||
<string name="auto_webtoon_mode">Mode Webtoon automatique</string>
|
||||
<string name="auto_webtoon_mode_summary">Utilisez le mode Webtoon automatique pour les mangas détectés comme susceptibles d\'utiliser le format de bande longue</string>
|
||||
<string name="enable_zoom_out">Activer le zoom arrière</string>
|
||||
<string name="smart_based_on_page">Intelligent(basé sur la page)</string>
|
||||
<string name="smart_based_on_page_and_theme">Intelligent(basé sur la page et le thème)</string>
|
||||
<string name="tap_scroll_page">Appuyez sur faire défiler par page</string>
|
||||
|
||||
<!-- <string name="tap_scroll_page_summary">Tapping will scroll by page instead of screen size when this option is enabled</string>-->
|
||||
|
@ -209,8 +209,6 @@
|
||||
<string name="auto_webtoon_mode">Modo Auto Webtoon</string>
|
||||
<string name="auto_webtoon_mode_summary">Use o modo webtoon automático para mangás que são detectados provavelmente no formato longstrip</string>
|
||||
<string name="enable_zoom_out">Enable zoom out</string>
|
||||
<string name="smart_based_on_page">Inteligente (Baseado na página)</string>
|
||||
<string name="smart_based_on_page_and_theme">Inteligente (baseado na página e no tema)</string>
|
||||
<string name="tap_scroll_page">Tap scroll by page</string>
|
||||
<string name="tap_scroll_page_summary">Tapping will scroll by page instead of screen size when this option is enabled</string>
|
||||
|
||||
|
@ -240,8 +240,6 @@
|
||||
<string name="auto_webtoon_mode">Автоматический веб-комикс</string>
|
||||
<string name="auto_webtoon_mode_summary">Использовать автоматический режим для веб-комикса, в которых выявлены вероятно, использовать длинные полосы формате</string>
|
||||
<string name="enable_zoom_out">Включить зум</string>
|
||||
<string name="smart_based_on_page">Умный (по странице)</string>
|
||||
<string name="smart_based_on_page_and_theme">Умный (по странице и теме)</string>
|
||||
<string name="tap_scroll_page">Нажмите прокрутить по странице</string>
|
||||
<string name="tap_scroll_page_summary">Нажатие будет прокручиваться по странице, а не по размеру экрана, если эта опция включена</string>
|
||||
|
||||
|
@ -13,8 +13,7 @@
|
||||
<item>@string/black_background</item>
|
||||
<item>@string/gray_background</item>
|
||||
<item>@string/white_background</item>
|
||||
<item>@string/smart_based_on_page</item>
|
||||
<item>@string/smart_based_on_page_and_theme</item>
|
||||
<item>@string/automatic_background</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="reader_themes_values">
|
||||
@ -22,7 +21,6 @@
|
||||
<item>2</item>
|
||||
<item>0</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="image_scale_type">
|
||||
|
@ -303,6 +303,7 @@
|
||||
<string name="white_background">White</string>
|
||||
<string name="gray_background">Gray</string>
|
||||
<string name="black_background">Black</string>
|
||||
<string name="automatic_background">Automatic</string>
|
||||
<string name="pref_viewer_type">Default reading mode</string>
|
||||
<string name="default_viewer">Default</string>
|
||||
<string name="default_nav">Default</string>
|
||||
|
@ -249,8 +249,6 @@
|
||||
<string name="auto_webtoon_mode">Auto Webtoon Mode</string>
|
||||
<string name="auto_webtoon_mode_summary">Use auto webtoon mode for manga that are detected to likely use the long strip format</string>
|
||||
<string name="enable_zoom_out">Enable zoom out</string>
|
||||
<string name="smart_based_on_page">Smart (based on page)</string>
|
||||
<string name="smart_based_on_page_and_theme">Smart (based on page and theme)</string>
|
||||
<string name="tap_scroll_page">Tap scroll by page</string>
|
||||
<string name="tap_scroll_page_summary">Tapping will scroll by page instead of screen size when this option is enabled</string>
|
||||
<string name="reader_bottom_buttons">Reader Bottom Buttons</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user