PagerPageHolder: Move chooseBackground call to IO thread (#5737)

* ImageUtil.chooseBackground: Use built-in decoder

* PagerPageHolder: Move chooseBackground call to IO thread

Also move stuffs and reuse image stream as bytes

(cherry picked from commit 11a8046c5fa00a6abbaf387ab5c75a9a294a01b8)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt
This commit is contained in:
Ivan Iskandar 2021-08-19 20:15:45 +07:00 committed by Jobobby04
parent acbc4c48fa
commit add234ce0b
2 changed files with 28 additions and 21 deletions

View File

@ -43,6 +43,7 @@ import rx.Subscription
import rx.android.schedulers.AndroidSchedulers import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers import rx.schedulers.Schedulers
import timber.log.Timber import timber.log.Timber
import java.io.ByteArrayInputStream
import java.io.InputStream import java.io.InputStream
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -349,38 +350,47 @@ class PagerPageHolder(
val streamFn = page.stream ?: return val streamFn = page.stream ?: return
val streamFn2 = extraPage?.stream val streamFn2 = extraPage?.stream
var openStream: InputStream? = null
readImageHeaderSubscription = Observable readImageHeaderSubscription = Observable
.fromCallable { .fromCallable {
val stream = streamFn().buffered(16) val stream = streamFn().buffered(16)
// SY --> // SY -->
val stream2 = if (extraPage != null) streamFn2?.invoke()?.buffered(16) else null val stream2 = if (extraPage != null) streamFn2?.invoke()?.buffered(16) else null
openStream = if (viewer.config.dualPageSplit) { val itemStream = if (viewer.config.dualPageSplit) {
process(item.first, stream) process(item.first, stream)
} else { } else {
mergePages(stream, stream2) mergePages(stream, stream2)
} }
// SY <-- // SY <--
try {
ImageUtil.isAnimatedAndSupported(stream) val streamBytes = itemStream.readBytes()
val isAnimated = ImageUtil.isAnimatedAndSupported(stream)
val background = if (!isAnimated && viewer.config.automaticBackground) {
ByteArrayInputStream(streamBytes).use { bais ->
ImageUtil.chooseBackground(context, bais)
}
} else {
null
}
Triple(streamBytes, isAnimated, background)
} finally {
stream.close()
itemStream.close()
}
} }
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.doOnNext { isAnimated -> .doOnNext { (streamBytes, isAnimated, background) ->
ByteArrayInputStream(streamBytes).use { bais ->
if (!isAnimated) { if (!isAnimated) {
this.background = background
initSubsamplingImageView().apply { initSubsamplingImageView().apply {
if (viewer.config.automaticBackground) { setImage(ImageSource.inputStream(bais))
background = ImageUtil.chooseBackground(context, openStream!!)
}
setImage(ImageSource.inputStream(openStream!!))
} }
} else { } else {
initImageView().setImage(openStream!!) initImageView().setImage(bais)
}
} }
} }
// Keep the Rx stream alive to close the input stream only when unsubscribed
.flatMap { Observable.never<Unit>() }
.doOnUnsubscribe { openStream?.close() }
.subscribe({}, {}) .subscribe({}, {})
} }

View File

@ -19,7 +19,6 @@ import androidx.core.graphics.green
import androidx.core.graphics.red import androidx.core.graphics.red
import tachiyomi.decoder.Format import tachiyomi.decoder.Format
import tachiyomi.decoder.ImageDecoder import tachiyomi.decoder.ImageDecoder
import tachiyomi.decoder.ImageType
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.io.InputStream import java.io.InputStream
@ -183,11 +182,9 @@ object ImageUtil {
* Algorithm for determining what background to accompany a comic/manga page * Algorithm for determining what background to accompany a comic/manga page
*/ */
fun chooseBackground(context: Context, imageStream: InputStream): Drawable { fun chooseBackground(context: Context, imageStream: InputStream): Drawable {
imageStream.mark(imageStream.available() + 1) val decoder = ImageDecoder.newInstance(imageStream)
val image = decoder?.decode()
val image = BitmapFactory.decodeStream(imageStream) decoder?.recycle()
imageStream.reset()
val whiteColor = Color.WHITE val whiteColor = Color.WHITE
if (image == null) return ColorDrawable(whiteColor) if (image == null) return ColorDrawable(whiteColor)