mirror of
https://github.com/null2264/yokai.git
synced 2025-06-21 10:44:42 +00:00
refactor: Use Okio instead of java.io
pt.1
This is the easy part... the next part is hell :')
This commit is contained in:
parent
7ddb15f312
commit
32ab87df61
6 changed files with 89 additions and 79 deletions
|
@ -32,8 +32,8 @@ import coil3.request.allowRgb565
|
||||||
import coil3.request.crossfade
|
import coil3.request.crossfade
|
||||||
import coil3.util.DebugLogger
|
import coil3.util.DebugLogger
|
||||||
import eu.kanade.tachiyomi.appwidget.TachiyomiWidgetManager
|
import eu.kanade.tachiyomi.appwidget.TachiyomiWidgetManager
|
||||||
|
import eu.kanade.tachiyomi.data.coil.BufferedSourceFetcher
|
||||||
import eu.kanade.tachiyomi.data.coil.CoilDiskCache
|
import eu.kanade.tachiyomi.data.coil.CoilDiskCache
|
||||||
import eu.kanade.tachiyomi.data.coil.InputStreamFetcher
|
|
||||||
import eu.kanade.tachiyomi.data.coil.MangaCoverFetcher
|
import eu.kanade.tachiyomi.data.coil.MangaCoverFetcher
|
||||||
import eu.kanade.tachiyomi.data.coil.MangaCoverKeyer
|
import eu.kanade.tachiyomi.data.coil.MangaCoverKeyer
|
||||||
import eu.kanade.tachiyomi.data.coil.TachiyomiImageDecoder
|
import eu.kanade.tachiyomi.data.coil.TachiyomiImageDecoder
|
||||||
|
@ -199,7 +199,7 @@ open class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.F
|
||||||
add(TachiyomiImageDecoder.Factory())
|
add(TachiyomiImageDecoder.Factory())
|
||||||
add(MangaCoverFetcher.Factory(callFactoryLazy, diskCacheLazy))
|
add(MangaCoverFetcher.Factory(callFactoryLazy, diskCacheLazy))
|
||||||
add(MangaCoverKeyer())
|
add(MangaCoverKeyer())
|
||||||
add(InputStreamFetcher.Factory())
|
add(BufferedSourceFetcher.Factory())
|
||||||
}
|
}
|
||||||
diskCache(diskCacheLazy::value)
|
diskCache(diskCacheLazy::value)
|
||||||
memoryCache { MemoryCache.Builder().maxSizePercent(this@App, 0.40).build() }
|
memoryCache { MemoryCache.Builder().maxSizePercent(this@App, 0.40).build() }
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
package eu.kanade.tachiyomi.data.coil
|
||||||
|
|
||||||
|
import coil3.ImageLoader
|
||||||
|
import coil3.decode.DataSource
|
||||||
|
import coil3.decode.ImageSource
|
||||||
|
import coil3.fetch.FetchResult
|
||||||
|
import coil3.fetch.Fetcher
|
||||||
|
import coil3.fetch.SourceFetchResult
|
||||||
|
import coil3.request.Options
|
||||||
|
import okio.BufferedSource
|
||||||
|
|
||||||
|
class BufferedSourceFetcher(
|
||||||
|
private val data: BufferedSource,
|
||||||
|
private val options: Options,
|
||||||
|
) : Fetcher {
|
||||||
|
override suspend fun fetch(): FetchResult {
|
||||||
|
return SourceFetchResult(
|
||||||
|
source = ImageSource(
|
||||||
|
source = data,
|
||||||
|
fileSystem = options.fileSystem,
|
||||||
|
),
|
||||||
|
mimeType = null,
|
||||||
|
dataSource = DataSource.MEMORY,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Factory : Fetcher.Factory<BufferedSource> {
|
||||||
|
override fun create(data: BufferedSource, options: Options, imageLoader: ImageLoader): Fetcher {
|
||||||
|
return BufferedSourceFetcher(data, options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -781,7 +781,7 @@ class ReaderViewModel(
|
||||||
val imageBytes2 = stream2().readBytes()
|
val imageBytes2 = stream2().readBytes()
|
||||||
val imageBitmap2 = BitmapFactory.decodeByteArray(imageBytes2, 0, imageBytes2.size)
|
val imageBitmap2 = BitmapFactory.decodeByteArray(imageBytes2, 0, imageBytes2.size)
|
||||||
|
|
||||||
val stream = ImageUtil.mergeBitmaps(imageBitmap, imageBitmap2, isLTR, bg)
|
val stream = ImageUtil.mergeBitmaps(imageBitmap, imageBitmap2, isLTR, bg).inputStream()
|
||||||
|
|
||||||
val chapter = page1.chapter.chapter
|
val chapter = page1.chapter.chapter
|
||||||
val context = Injekt.get<Application>()
|
val context = Injekt.get<Application>()
|
||||||
|
|
|
@ -38,8 +38,7 @@ import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||||
import eu.kanade.tachiyomi.util.system.GLUtil
|
import eu.kanade.tachiyomi.util.system.GLUtil
|
||||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||||
import eu.kanade.tachiyomi.util.system.animatorDurationScale
|
import eu.kanade.tachiyomi.util.system.animatorDurationScale
|
||||||
import java.io.InputStream
|
import okio.BufferedSource
|
||||||
import java.nio.ByteBuffer
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A wrapper view for showing page image.
|
* A wrapper view for showing page image.
|
||||||
|
@ -99,13 +98,13 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setImage(inputStream: InputStream, isAnimated: Boolean, config: Config) {
|
fun setImage(source: BufferedSource, isAnimated: Boolean, config: Config) {
|
||||||
if (isAnimated) {
|
if (isAnimated) {
|
||||||
prepareAnimatedImageView()
|
prepareAnimatedImageView()
|
||||||
setAnimatedImage(inputStream, config)
|
setAnimatedImage(source, config)
|
||||||
} else {
|
} else {
|
||||||
prepareNonAnimatedImageView()
|
prepareNonAnimatedImageView()
|
||||||
setNonAnimatedImage(inputStream, config)
|
setNonAnimatedImage(source, config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +224,7 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
val useCoilPipeline = isWebtoon && data is InputStream && !ImageUtil.isMaxTextureSizeExceeded(data)
|
val useCoilPipeline = isWebtoon && data is BufferedSource && !ImageUtil.isMaxTextureSizeExceeded(data)
|
||||||
|
|
||||||
if (isWebtoon && useCoilPipeline) {
|
if (isWebtoon && useCoilPipeline) {
|
||||||
val request = ImageRequest.Builder(context)
|
val request = ImageRequest.Builder(context)
|
||||||
|
@ -252,7 +251,7 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||||
} else {
|
} else {
|
||||||
when (data) {
|
when (data) {
|
||||||
is BitmapDrawable -> setImage(ImageSource.bitmap(data.bitmap))
|
is BitmapDrawable -> setImage(ImageSource.bitmap(data.bitmap))
|
||||||
is InputStream -> setImage(ImageSource.inputStream(data))
|
is BufferedSource -> setImage(ImageSource.inputStream(data.inputStream()))
|
||||||
else -> throw IllegalArgumentException("Not implemented for class ${data::class.simpleName}")
|
else -> throw IllegalArgumentException("Not implemented for class ${data::class.simpleName}")
|
||||||
}
|
}
|
||||||
isVisible = true
|
isVisible = true
|
||||||
|
@ -299,18 +298,13 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setAnimatedImage(
|
private fun setAnimatedImage(
|
||||||
image: Any,
|
data: Any,
|
||||||
config: Config,
|
config: Config,
|
||||||
) = (pageView as? AppCompatImageView)?.apply {
|
) = (pageView as? AppCompatImageView)?.apply {
|
||||||
if (this is PhotoView) {
|
if (this is PhotoView) {
|
||||||
setZoomTransitionDuration(config.zoomDuration.getSystemScaledDuration())
|
setZoomTransitionDuration(config.zoomDuration.getSystemScaledDuration())
|
||||||
}
|
}
|
||||||
|
|
||||||
val data = when (image) {
|
|
||||||
is Drawable -> image
|
|
||||||
is InputStream -> ByteBuffer.wrap(image.readBytes())
|
|
||||||
else -> throw IllegalArgumentException("Not implemented for class ${image::class.simpleName}")
|
|
||||||
}
|
|
||||||
val request = ImageRequest.Builder(context)
|
val request = ImageRequest.Builder(context)
|
||||||
.data(data)
|
.data(data)
|
||||||
.memoryCachePolicy(CachePolicy.DISABLED)
|
.memoryCachePolicy(CachePolicy.DISABLED)
|
||||||
|
|
|
@ -28,10 +28,9 @@ import kotlinx.coroutines.MainScope
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.supervisorScope
|
import kotlinx.coroutines.supervisorScope
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
import okio.Buffer
|
||||||
|
import okio.BufferedSource
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.BufferedInputStream
|
|
||||||
import java.io.InputStream
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holder of the webtoon reader for a single page of a chapter.
|
* Holder of the webtoon reader for a single page of a chapter.
|
||||||
|
@ -232,13 +231,11 @@ class WebtoonPageHolder(
|
||||||
|
|
||||||
val streamFn = page?.stream ?: return
|
val streamFn = page?.stream ?: return
|
||||||
|
|
||||||
val (openStream, isAnimated) = try {
|
val (source, isAnimated) = try {
|
||||||
withIOContext {
|
withIOContext {
|
||||||
val stream = streamFn().buffered(16)
|
val source = streamFn().use { process(Buffer().readFrom(it)) }
|
||||||
val openStream = process(stream)
|
val isAnimated = ImageUtil.isAnimatedAndSupported(source)
|
||||||
|
Pair(source, isAnimated)
|
||||||
val isAnimated = ImageUtil.isAnimatedAndSupported(stream)
|
|
||||||
Pair(openStream, isAnimated)
|
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e)
|
Timber.e(e)
|
||||||
|
@ -247,7 +244,7 @@ class WebtoonPageHolder(
|
||||||
}
|
}
|
||||||
withUIContext {
|
withUIContext {
|
||||||
frame.setImage(
|
frame.setImage(
|
||||||
openStream,
|
source,
|
||||||
isAnimated,
|
isAnimated,
|
||||||
ReaderPageImageView.Config(
|
ReaderPageImageView.Config(
|
||||||
zoomDuration = viewer.config.doubleTapAnimDuration,
|
zoomDuration = viewer.config.doubleTapAnimDuration,
|
||||||
|
@ -258,23 +255,19 @@ class WebtoonPageHolder(
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// Suspend the coroutine to close the input stream only when the WebtoonPageHolder is recycled
|
|
||||||
suspendCancellableCoroutine<Nothing> { continuation ->
|
|
||||||
continuation.invokeOnCancellation { openStream.close() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun process(imageStream: BufferedInputStream): InputStream {
|
private fun process(imageSource: BufferedSource): BufferedSource {
|
||||||
if (!viewer.config.splitPages) {
|
if (!viewer.config.splitPages) {
|
||||||
return imageStream
|
return imageSource
|
||||||
}
|
}
|
||||||
|
|
||||||
val isDoublePage = ImageUtil.isWideImage(imageStream)
|
val isDoublePage = ImageUtil.isWideImage(imageSource)
|
||||||
if (!isDoublePage) {
|
if (!isDoublePage) {
|
||||||
return imageStream
|
return imageSource
|
||||||
}
|
}
|
||||||
|
|
||||||
return ImageUtil.splitAndStackBitmap(imageStream, viewer.config.invertDoublePages, viewer.hasMargins)
|
return ImageUtil.splitAndStackBitmap(imageSource, viewer.config.invertDoublePages, viewer.hasMargins)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -25,12 +25,11 @@ import androidx.core.graphics.red
|
||||||
import androidx.core.graphics.scale
|
import androidx.core.graphics.scale
|
||||||
import com.hippo.unifile.UniFile
|
import com.hippo.unifile.UniFile
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
import okio.Buffer
|
||||||
|
import okio.BufferedSource
|
||||||
import tachiyomi.decoder.Format
|
import tachiyomi.decoder.Format
|
||||||
import tachiyomi.decoder.ImageDecoder
|
import tachiyomi.decoder.ImageDecoder
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.BufferedInputStream
|
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
import java.io.ByteArrayOutputStream
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
@ -92,9 +91,9 @@ object ImageUtil {
|
||||||
?: "jpg"
|
?: "jpg"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isAnimatedAndSupported(stream: InputStream): Boolean {
|
fun isAnimatedAndSupported(source: BufferedSource): Boolean {
|
||||||
return try {
|
return try {
|
||||||
val type = getImageType(stream) ?: return false
|
val type = getImageType(source.peek().inputStream()) ?: return false
|
||||||
// https://coil-kt.github.io/coil/getting_started/#supported-image-formats
|
// https://coil-kt.github.io/coil/getting_started/#supported-image-formats
|
||||||
when (type.format) {
|
when (type.format) {
|
||||||
Format.Gif -> true
|
Format.Gif -> true
|
||||||
|
@ -335,7 +334,7 @@ object ImageUtil {
|
||||||
imageBitmap: Bitmap,
|
imageBitmap: Bitmap,
|
||||||
secondHalf: Boolean,
|
secondHalf: Boolean,
|
||||||
progressCallback: ((Int) -> Unit)? = null,
|
progressCallback: ((Int) -> Unit)? = null,
|
||||||
): ByteArrayInputStream {
|
): BufferedSource {
|
||||||
val height = imageBitmap.height
|
val height = imageBitmap.height
|
||||||
val width = imageBitmap.width
|
val width = imageBitmap.width
|
||||||
val result = Bitmap.createBitmap(width / 2, height, Bitmap.Config.ARGB_8888)
|
val result = Bitmap.createBitmap(width / 2, height, Bitmap.Config.ARGB_8888)
|
||||||
|
@ -343,10 +342,10 @@ object ImageUtil {
|
||||||
progressCallback?.invoke(98)
|
progressCallback?.invoke(98)
|
||||||
canvas.drawBitmap(imageBitmap, Rect(if (!secondHalf) 0 else width / 2, 0, if (secondHalf) width else width / 2, height), result.rect, null)
|
canvas.drawBitmap(imageBitmap, Rect(if (!secondHalf) 0 else width / 2, 0, if (secondHalf) width else width / 2, height), result.rect, null)
|
||||||
progressCallback?.invoke(99)
|
progressCallback?.invoke(99)
|
||||||
val output = ByteArrayOutputStream()
|
val output = Buffer()
|
||||||
result.compress(Bitmap.CompressFormat.JPEG, 100, output)
|
result.compress(Bitmap.CompressFormat.JPEG, 100, output.outputStream())
|
||||||
progressCallback?.invoke(100)
|
progressCallback?.invoke(100)
|
||||||
return ByteArrayInputStream(output.toByteArray())
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -354,20 +353,18 @@ object ImageUtil {
|
||||||
*
|
*
|
||||||
* @return true if the width is greater than the height
|
* @return true if the width is greater than the height
|
||||||
*/
|
*/
|
||||||
fun isWideImage(imageStream: BufferedInputStream): Boolean {
|
fun isWideImage(imageSource: BufferedSource): Boolean {
|
||||||
val options = extractImageOptions(imageStream)
|
val options = extractImageOptions(imageSource)
|
||||||
imageStream.reset()
|
|
||||||
return options.outWidth > options.outHeight
|
return options.outWidth > options.outHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
fun splitAndStackBitmap(
|
fun splitAndStackBitmap(
|
||||||
imageStream: InputStream,
|
imageSource: BufferedSource,
|
||||||
rightSideOnTop: Boolean,
|
rightSideOnTop: Boolean,
|
||||||
hasMargins: Boolean,
|
hasMargins: Boolean,
|
||||||
progressCallback: ((Int) -> Unit)? = null,
|
progressCallback: ((Int) -> Unit)? = null,
|
||||||
): ByteArrayInputStream {
|
): BufferedSource {
|
||||||
val imageBytes = imageStream.readBytes()
|
val imageBitmap = BitmapFactory.decodeStream(imageSource.inputStream())
|
||||||
val imageBitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size)
|
|
||||||
|
|
||||||
val height = imageBitmap.height
|
val height = imageBitmap.height
|
||||||
val width = imageBitmap.width
|
val width = imageBitmap.width
|
||||||
|
@ -411,10 +408,10 @@ object ImageUtil {
|
||||||
null,
|
null,
|
||||||
)
|
)
|
||||||
progressCallback?.invoke(99)
|
progressCallback?.invoke(99)
|
||||||
val output = ByteArrayOutputStream()
|
val output = Buffer()
|
||||||
result.compress(Bitmap.CompressFormat.JPEG, 100, output)
|
result.compress(Bitmap.CompressFormat.JPEG, 100, output.outputStream())
|
||||||
progressCallback?.invoke(100)
|
progressCallback?.invoke(100)
|
||||||
return ByteArrayInputStream(output.toByteArray())
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
fun mergeBitmaps(
|
fun mergeBitmaps(
|
||||||
|
@ -425,7 +422,7 @@ object ImageUtil {
|
||||||
hingeGap: Int = 0,
|
hingeGap: Int = 0,
|
||||||
context: Context? = null,
|
context: Context? = null,
|
||||||
progressCallback: ((Int) -> Unit)? = null,
|
progressCallback: ((Int) -> Unit)? = null,
|
||||||
): ByteArrayInputStream {
|
): BufferedSource {
|
||||||
var imageBitmap = iBitmap
|
var imageBitmap = iBitmap
|
||||||
var imageBitmap2 = iBitmap2
|
var imageBitmap2 = iBitmap2
|
||||||
var height = imageBitmap.height
|
var height = imageBitmap.height
|
||||||
|
@ -473,10 +470,10 @@ object ImageUtil {
|
||||||
canvas.drawBitmap(imageBitmap2, imageBitmap2.rect, bottomPart, null)
|
canvas.drawBitmap(imageBitmap2, imageBitmap2.rect, bottomPart, null)
|
||||||
progressCallback?.invoke(99)
|
progressCallback?.invoke(99)
|
||||||
|
|
||||||
val output = ByteArrayOutputStream()
|
val output = Buffer()
|
||||||
result.compress(Bitmap.CompressFormat.JPEG, 100, output)
|
result.compress(Bitmap.CompressFormat.JPEG, 100, output.outputStream())
|
||||||
progressCallback?.invoke(100)
|
progressCallback?.invoke(100)
|
||||||
return ByteArrayInputStream(output.toByteArray())
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
fun padSingleImage(
|
fun padSingleImage(
|
||||||
|
@ -487,7 +484,7 @@ object ImageUtil {
|
||||||
hingeGap: Int,
|
hingeGap: Int,
|
||||||
context: Context,
|
context: Context,
|
||||||
progressCallback: ((Int) -> Unit)? = null,
|
progressCallback: ((Int) -> Unit)? = null,
|
||||||
): ByteArrayInputStream {
|
): BufferedSource {
|
||||||
val height = imageBitmap.height
|
val height = imageBitmap.height
|
||||||
val width = imageBitmap.width
|
val width = imageBitmap.width
|
||||||
val isFullPageSpread = height < width
|
val isFullPageSpread = height < width
|
||||||
|
@ -523,10 +520,10 @@ object ImageUtil {
|
||||||
canvas.drawBitmap(imageBitmap, imageBitmap.rect, upperPart, null)
|
canvas.drawBitmap(imageBitmap, imageBitmap.rect, upperPart, null)
|
||||||
}
|
}
|
||||||
progressCallback?.invoke(99)
|
progressCallback?.invoke(99)
|
||||||
val output = ByteArrayOutputStream()
|
val output = Buffer()
|
||||||
result.compress(Bitmap.CompressFormat.JPEG, 100, output)
|
result.compress(Bitmap.CompressFormat.JPEG, 100, output.outputStream())
|
||||||
progressCallback?.invoke(100)
|
progressCallback?.invoke(100)
|
||||||
return ByteArrayInputStream(output.toByteArray())
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -534,8 +531,8 @@ object ImageUtil {
|
||||||
*
|
*
|
||||||
* @return true if the height:width ratio is greater than 3.
|
* @return true if the height:width ratio is greater than 3.
|
||||||
*/
|
*/
|
||||||
private fun isTallImage(imageStream: InputStream): Boolean {
|
private fun isTallImage(imageSource: BufferedSource): Boolean {
|
||||||
val options = extractImageOptions(imageStream, false)
|
val options = extractImageOptions(imageSource)
|
||||||
return (options.outHeight / options.outWidth) > 3
|
return (options.outHeight / options.outWidth) > 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -543,15 +540,16 @@ object ImageUtil {
|
||||||
* Splits tall images to improve performance of reader
|
* Splits tall images to improve performance of reader
|
||||||
*/
|
*/
|
||||||
fun splitTallImage(imageFile: UniFile, imageFilePath: String): Boolean {
|
fun splitTallImage(imageFile: UniFile, imageFilePath: String): Boolean {
|
||||||
if (isAnimatedAndSupported(imageFile.openInputStream()) || !isTallImage(imageFile.openInputStream())) {
|
val imageSource = imageFile.openInputStream().use { Buffer().readFrom(it) }
|
||||||
|
if (isAnimatedAndSupported(imageSource) || !isTallImage(imageSource)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
val bitmapRegionDecoder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
val bitmapRegionDecoder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
BitmapRegionDecoder.newInstance(imageFile.openInputStream())
|
BitmapRegionDecoder.newInstance(imageSource.peek().inputStream())
|
||||||
} else {
|
} else {
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
BitmapRegionDecoder.newInstance(imageFile.openInputStream(), false)
|
BitmapRegionDecoder.newInstance(imageSource.peek().inputStream(), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bitmapRegionDecoder == null) {
|
if (bitmapRegionDecoder == null) {
|
||||||
|
@ -559,7 +557,7 @@ object ImageUtil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
val options = extractImageOptions(imageFile.openInputStream(), resetAfterExtraction = false).apply {
|
val options = extractImageOptions(imageSource).apply {
|
||||||
inJustDecodeBounds = false
|
inJustDecodeBounds = false
|
||||||
}
|
}
|
||||||
val splitDataList = options.splitData
|
val splitDataList = options.splitData
|
||||||
|
@ -773,16 +771,9 @@ object ImageUtil {
|
||||||
/**
|
/**
|
||||||
* Used to check an image's dimensions without loading it in the memory.
|
* Used to check an image's dimensions without loading it in the memory.
|
||||||
*/
|
*/
|
||||||
private fun extractImageOptions(
|
private fun extractImageOptions(imageSource: BufferedSource): BitmapFactory.Options {
|
||||||
imageStream: InputStream,
|
|
||||||
resetAfterExtraction: Boolean = true,
|
|
||||||
): BitmapFactory.Options {
|
|
||||||
imageStream.mark(imageStream.available() + 1)
|
|
||||||
|
|
||||||
val imageBytes = imageStream.readBytes()
|
|
||||||
val options = BitmapFactory.Options().apply { inJustDecodeBounds = true }
|
val options = BitmapFactory.Options().apply { inJustDecodeBounds = true }
|
||||||
BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size, options)
|
BitmapFactory.decodeStream(imageSource.peek().inputStream(), null, options)
|
||||||
if (resetAfterExtraction) imageStream.reset()
|
|
||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -792,8 +783,8 @@ object ImageUtil {
|
||||||
"image/jxl" to "jxl",
|
"image/jxl" to "jxl",
|
||||||
)
|
)
|
||||||
|
|
||||||
fun isMaxTextureSizeExceeded(imageStream: InputStream): Boolean {
|
fun isMaxTextureSizeExceeded(imageSource: BufferedSource): Boolean {
|
||||||
val opts = extractImageOptions(imageStream)
|
val opts = extractImageOptions(imageSource)
|
||||||
return maxOf(opts.outWidth, opts.outHeight) > GLUtil.maxTextureSize
|
return maxOf(opts.outWidth, opts.outHeight) > GLUtil.maxTextureSize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue