diff --git a/app/src/main/java/io/legado/app/api/controller/BookController.kt b/app/src/main/java/io/legado/app/api/controller/BookController.kt index 30f887ed3..8771c8225 100644 --- a/app/src/main/java/io/legado/app/api/controller/BookController.kt +++ b/app/src/main/java/io/legado/app/api/controller/BookController.kt @@ -21,8 +21,8 @@ import io.legado.app.model.localBook.EpubFile import io.legado.app.model.localBook.LocalBook import io.legado.app.model.localBook.UmdFile import io.legado.app.model.webBook.WebBook -import io.legado.app.utils.* import io.legado.app.ui.book.read.page.provider.ImageProvider +import io.legado.app.utils.* import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking import splitties.init.appCtx @@ -87,9 +87,11 @@ object BookController { this.bookSource = appDb.bookSourceDao.getBookSource(book.origin) } this.bookUrl = bookUrl - return ImageProvider.getImage(book, src, bookSource, width, width)?.let { - returnData.setData(it) - } ?: returnData.setErrorMsg("图片加载失败或不存在") + val bitmap = runBlocking { + ImageProvider.cacheImage(book, src, bookSource) + ImageProvider.getImage(book, src, width, width) + } + return returnData.setData(bitmap) } /** diff --git a/app/src/main/java/io/legado/app/constant/AppLog.kt b/app/src/main/java/io/legado/app/constant/AppLog.kt index 75311752a..e4d6c2911 100644 --- a/app/src/main/java/io/legado/app/constant/AppLog.kt +++ b/app/src/main/java/io/legado/app/constant/AppLog.kt @@ -31,7 +31,7 @@ object AppLog { } fun putDebug(message: String?, throwable: Throwable? = null) { - if (AppConfig.recordLog) { + if (AppConfig.recordLog || BuildConfig.DEBUG) { put(message, throwable) } } diff --git a/app/src/main/java/io/legado/app/data/entities/Book.kt b/app/src/main/java/io/legado/app/data/entities/Book.kt index 568778d14..e042d2525 100644 --- a/app/src/main/java/io/legado/app/data/entities/Book.kt +++ b/app/src/main/java/io/legado/app/data/entities/Book.kt @@ -193,7 +193,14 @@ data class Book( } fun getUseReplaceRule(): Boolean { - return config.useReplaceRule ?: AppConfig.replaceEnableDefault + val useReplaceRule = config.useReplaceRule + if (useReplaceRule != null) { + return useReplaceRule + } + if (type == BookType.image) { + return false + } + return AppConfig.replaceEnableDefault } fun setReSegment(reSegment: Boolean) { diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index dfb7b5193..7e68c778c 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -1,5 +1,6 @@ package io.legado.app.help +import io.legado.app.constant.AppLog import io.legado.app.constant.AppPattern import io.legado.app.constant.EventBus import io.legado.app.data.appDb @@ -126,7 +127,7 @@ object BookHelp { ).writeBytes(it) } } catch (e: Exception) { - e.printOnDebug() + AppLog.putDebug("${src}下载错误", e) } finally { downloadImages.remove(src) } diff --git a/app/src/main/java/io/legado/app/help/http/cronet/AbsCallBack.kt b/app/src/main/java/io/legado/app/help/http/cronet/AbsCallBack.kt index 56f5b4bfd..0728b1db3 100644 --- a/app/src/main/java/io/legado/app/help/http/cronet/AbsCallBack.kt +++ b/app/src/main/java/io/legado/app/help/http/cronet/AbsCallBack.kt @@ -2,7 +2,7 @@ package io.legado.app.help.http.cronet import io.legado.app.help.http.okHttpClient import io.legado.app.utils.DebugLog -import io.legado.app.utils.rethrowAsIOException +import io.legado.app.utils.asIOException import okhttp3.* import okhttp3.EventListener import okhttp3.MediaType.Companion.toMediaTypeOrNull @@ -27,12 +27,24 @@ abstract class AbsCallBack( var mResponse: Response - var mException: IOException? = null private var followCount = 0 + @Throws(IOException::class) abstract fun waitForDone(urlRequest: UrlRequest): Response + /** + * 当发生错误时,通知子类终止阻塞抛出错误 + * @param error + */ + abstract fun onError(error: IOException) + + /** + * 请求成功后,通知子类结束阻塞,返回response + * @param response + */ + abstract fun onSuccess(response: Response) + override fun onRedirectReceived( request: UrlRequest, @@ -41,10 +53,13 @@ abstract class AbsCallBack( ) { if (followCount > MAX_FOLLOW_COUNT) { request.cancel() - mException = IOException("Too many redirect") + onError(IOException("Too many redirect")) + return } if (mCall.isCanceled()) { - mException = IOException("Request Canceled") + onError(IOException("Request Canceled")) + request.cancel() + return } followCount += 1 val client = okHttpClient @@ -55,7 +70,7 @@ abstract class AbsCallBack( } else if (okHttpClient.followRedirects) { request.followRedirect() } else { - mException = IOException("Too many redirect") + onError(IOException("Too many redirect")) request.cancel() } } @@ -73,7 +88,7 @@ abstract class AbsCallBack( } - @Throws(Exception::class) + @Throws(IOException::class) override fun onReadCompleted( request: UrlRequest, info: UrlResponseInfo, @@ -83,7 +98,7 @@ abstract class AbsCallBack( if (mCall.isCanceled()) { request.cancel() - mException = IOException("Request Canceled") + onError(IOException("Request Canceled")) } byteBuffer.flip() @@ -91,9 +106,9 @@ abstract class AbsCallBack( try { buffer.write(byteBuffer) } catch (e: IOException) { - DebugLog.i(javaClass.name, "IOException during ByteBuffer read. Details: ", e) - mException = IOException("IOException during ByteBuffer read. Details:", e) - throw e + DebugLog.e(javaClass.name, "IOException during ByteBuffer read. Details: ", e) + onError(IOException("IOException during ByteBuffer read. Details:", e)) + return } byteBuffer.clear() request.read(byteBuffer) @@ -108,7 +123,8 @@ abstract class AbsCallBack( buffer.asResponseBody(contentType) val newRequest = originalRequest.newBuilder().url(info.url).build() this.mResponse = this.mResponse.newBuilder().body(responseBody).request(newRequest).build() - DebugLog.i(javaClass.simpleName, "end[${info.negotiatedProtocol}]${info.url}") + onSuccess(this.mResponse) + //DebugLog.i(javaClass.simpleName, "end[${info.negotiatedProtocol}]${info.url}") eventListener?.callEnd(mCall) if (responseCallback != null) { @@ -123,8 +139,8 @@ abstract class AbsCallBack( //UrlResponseInfo可能为null override fun onFailed(request: UrlRequest, info: UrlResponseInfo?, error: CronetException) { - DebugLog.i(javaClass.name, error.message.toString()) - mException = error.rethrowAsIOException() + DebugLog.e(javaClass.name, error.message.toString()) + onError(error.asIOException()) this.eventListener?.callFailed(mCall, error) responseCallback?.onFailure(mCall, error) } @@ -132,7 +148,7 @@ abstract class AbsCallBack( override fun onCanceled(request: UrlRequest?, info: UrlResponseInfo?) { super.onCanceled(request, info) this.eventListener?.callEnd(mCall) - mException = IOException("Cronet Request Canceled") + onError(IOException("Cronet Request Canceled")) } diff --git a/app/src/main/java/io/legado/app/help/http/cronet/CronetHelper.kt b/app/src/main/java/io/legado/app/help/http/cronet/CronetHelper.kt index c3e2ae992..954d2f62f 100644 --- a/app/src/main/java/io/legado/app/help/http/cronet/CronetHelper.kt +++ b/app/src/main/java/io/legado/app/help/http/cronet/CronetHelper.kt @@ -2,6 +2,7 @@ package io.legado.app.help.http.cronet import io.legado.app.constant.AppLog import io.legado.app.help.config.AppConfig +import io.legado.app.help.http.okHttpClient import io.legado.app.utils.DebugLog import okhttp3.Headers import okhttp3.MediaType @@ -13,11 +14,8 @@ import org.chromium.net.UploadDataProviders import org.chromium.net.UrlRequest import splitties.init.appCtx -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors - -val executor: ExecutorService by lazy { Executors.newCachedThreadPool() } +//val executor: ExecutorService by lazy { Executors.newCachedThreadPool() } val cronetEngine: ExperimentalCronetEngine? by lazy { if (!AppConfig.isGooglePlay) { @@ -48,7 +46,11 @@ fun buildRequest(request: Request, callback: UrlRequest.Callback): UrlRequest? { val url = request.url.toString() val headers: Headers = request.headers val requestBody = request.body - return cronetEngine?.newUrlRequestBuilder(url, callback, executor)?.apply { + return cronetEngine?.newUrlRequestBuilder( + url, + callback, + okHttpClient.dispatcher.executorService + )?.apply { setHttpMethod(request.method)//设置 allowDirectExecutor() headers.forEachIndexed { index, _ -> @@ -65,7 +67,7 @@ fun buildRequest(request: Request, callback: UrlRequest.Callback): UrlRequest? { requestBody.writeTo(buffer) setUploadDataProvider( UploadDataProviders.create(buffer.readByteArray()), - executor + okHttpClient.dispatcher.executorService ) } diff --git a/app/src/main/java/io/legado/app/help/http/cronet/CronetInterceptor.kt b/app/src/main/java/io/legado/app/help/http/cronet/CronetInterceptor.kt index 124b6163f..74b685128 100644 --- a/app/src/main/java/io/legado/app/help/http/cronet/CronetInterceptor.kt +++ b/app/src/main/java/io/legado/app/help/http/cronet/CronetInterceptor.kt @@ -49,7 +49,6 @@ class CronetInterceptor(private val cookieJar: CookieJar?) : Interceptor { OldCallback(request, call) } buildRequest(request, callBack)?.let { - it.start() return callBack.waitForDone(it) } return null diff --git a/app/src/main/java/io/legado/app/help/http/cronet/CronetLoader.kt b/app/src/main/java/io/legado/app/help/http/cronet/CronetLoader.kt index b06d0719b..34ad3e5f5 100644 --- a/app/src/main/java/io/legado/app/help/http/cronet/CronetLoader.kt +++ b/app/src/main/java/io/legado/app/help/http/cronet/CronetLoader.kt @@ -268,7 +268,8 @@ object CronetLoader : CronetEngine.Builder.LibraryLoader() { return } download = true - executor.execute { + + Coroutine.async { val result = downloadFileIfNotExist(url, downloadTempFile) DebugLog.d(javaClass.simpleName, "download result:$result") //文件md5再次校验 @@ -279,7 +280,7 @@ object CronetLoader : CronetEngine.Builder.LibraryLoader() { downloadTempFile.deleteOnExit() } download = false - return@execute + return@async } DebugLog.d(javaClass.simpleName, "download success, copy to $destSuccessFile") //下载成功拷贝文件 @@ -289,6 +290,9 @@ object CronetLoader : CronetEngine.Builder.LibraryLoader() { @Suppress("SameParameterValue") deleteHistoryFile(parentFile!!, null) } +// executor.execute { +// +// } } /** diff --git a/app/src/main/java/io/legado/app/help/http/cronet/NewCallBack.kt b/app/src/main/java/io/legado/app/help/http/cronet/NewCallBack.kt index 6a0d0eeff..7960f54f8 100644 --- a/app/src/main/java/io/legado/app/help/http/cronet/NewCallBack.kt +++ b/app/src/main/java/io/legado/app/help/http/cronet/NewCallBack.kt @@ -6,11 +6,8 @@ import androidx.annotation.RequiresApi import okhttp3.Call import okhttp3.Request import okhttp3.Response -import org.chromium.net.CronetException import org.chromium.net.UrlRequest -import org.chromium.net.UrlResponseInfo import java.io.IOException -import java.nio.ByteBuffer import java.util.concurrent.CompletableFuture import java.util.concurrent.TimeUnit @@ -21,45 +18,29 @@ class NewCallBack(originalRequest: Request, mCall: Call) : AbsCallBack(originalR @Throws(IOException::class) override fun waitForDone(urlRequest: UrlRequest): Response { - return responseFuture.get(mCall.timeout().timeoutNanos(), TimeUnit.NANOSECONDS) - } - - override fun onRedirectReceived( - request: UrlRequest, - info: UrlResponseInfo, - newLocationUrl: String - ) { - super.onRedirectReceived(request, info, newLocationUrl) - if (mException != null) { - responseFuture.completeExceptionally(mException) + urlRequest.start() + return if (mCall.timeout().timeoutNanos() > 0) { + responseFuture.get(mCall.timeout().timeoutNanos(), TimeUnit.NANOSECONDS) + } else { + return responseFuture.get() } - } - - - override fun onReadCompleted( - request: UrlRequest, - info: UrlResponseInfo, - byteBuffer: ByteBuffer - ) { - super.onReadCompleted(request, info, byteBuffer) - if (mException != null) { - responseFuture.completeExceptionally(mException) - } - } - override fun onSucceeded(request: UrlRequest, info: UrlResponseInfo) { - super.onSucceeded(request, info) - responseFuture.complete(mResponse) } - override fun onFailed(request: UrlRequest, info: UrlResponseInfo?, error: CronetException) { - super.onFailed(request, info, error) - responseFuture.completeExceptionally(mException) + /** + * 当发生错误时,通知子类终止阻塞抛出错误 + * @param error + */ + override fun onError(error: IOException) { + responseFuture.completeExceptionally(error) } - override fun onCanceled(request: UrlRequest?, info: UrlResponseInfo?) { - super.onCanceled(request, info) - responseFuture.completeExceptionally(mException) + /** + * 请求成功后,通知子类结束阻塞,返回response + * @param response + */ + override fun onSuccess(response: Response) { + responseFuture.complete(response) } diff --git a/app/src/main/java/io/legado/app/help/http/cronet/OldCallback.kt b/app/src/main/java/io/legado/app/help/http/cronet/OldCallback.kt index 20ad29c60..3107187df 100644 --- a/app/src/main/java/io/legado/app/help/http/cronet/OldCallback.kt +++ b/app/src/main/java/io/legado/app/help/http/cronet/OldCallback.kt @@ -4,20 +4,19 @@ import android.os.ConditionVariable import okhttp3.Call import okhttp3.Request import okhttp3.Response -import org.chromium.net.CronetException import org.chromium.net.UrlRequest -import org.chromium.net.UrlResponseInfo import java.io.IOException -import java.nio.ByteBuffer class OldCallback(originalRequest: Request, mCall: Call) : AbsCallBack(originalRequest, mCall) { private val mResponseCondition = ConditionVariable() + private var mException: IOException? = null @Throws(IOException::class) override fun waitForDone(urlRequest: UrlRequest): Response { //获取okhttp call的完整请求的超时时间 val timeOutMs: Long = mCall.timeout().timeoutNanos() / 1000000 + urlRequest.start() if (timeOutMs > 0) { mResponseCondition.block(timeOutMs) } else { @@ -32,35 +31,25 @@ class OldCallback(originalRequest: Request, mCall: Call) : AbsCallBack(originalR if (mException != null) { throw mException as IOException } - return this.mResponse + return mResponse } - - override fun onReadCompleted( - request: UrlRequest, - info: UrlResponseInfo, - byteBuffer: ByteBuffer - ) { - super.onReadCompleted(request, info, byteBuffer) - if (mException != null) { - mResponseCondition.open() - } - } - - override fun onSucceeded(request: UrlRequest, info: UrlResponseInfo) { - super.onSucceeded(request, info) + /** + * 当发生错误时,通知子类终止阻塞抛出错误 + * @param error + */ + override fun onError(error: IOException) { + mException = error mResponseCondition.open() } - override fun onFailed(request: UrlRequest, info: UrlResponseInfo?, error: CronetException) { - super.onFailed(request, info, error) + /** + * 请求成功后,通知子类结束阻塞,返回response + * @param response + */ + override fun onSuccess(response: Response) { mResponseCondition.open() } - override fun onCanceled(request: UrlRequest?, info: UrlResponseInfo?) { - super.onCanceled(request, info) - mResponseCondition.open() - } - } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/read/PhotoDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/PhotoDialog.kt index c072debc4..50eb3a9e5 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/PhotoDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/PhotoDialog.kt @@ -5,9 +5,10 @@ import android.view.View import io.legado.app.R import io.legado.app.base.BaseDialogFragment import io.legado.app.databinding.DialogPhotoViewBinding +import io.legado.app.help.BookHelp +import io.legado.app.help.glide.ImageLoader import io.legado.app.model.BookCover import io.legado.app.model.ReadBook -import io.legado.app.ui.book.read.page.provider.ImageProvider import io.legado.app.utils.setLayout import io.legado.app.utils.viewbindingdelegate.viewBinding @@ -40,17 +41,12 @@ class PhotoDialog() : BaseDialogFragment(R.layout.dialog_photo_view) { arguments?.let { val path = it.getString("path") if (path.isNullOrEmpty()) { - val chapterIndex = it.getInt("chapterIndex") - val src = it.getString("src") ReadBook.book?.let { book -> - src?.let { - execute { - ImageProvider.getImage(book, src, ReadBook.bookSource) - }.onSuccess { bitmap -> - if (bitmap != null) { - binding.photoView.setImageBitmap(bitmap) - } - } + it.getString("src")?.let { src -> + val file = BookHelp.getImage(book, src) + ImageLoader.load(requireContext(), file) + .error(R.drawable.image_loading_error) + .into(binding.photoView) } } } else { diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt b/app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt index 5ba2d0958..5fd7e37cd 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt @@ -82,43 +82,36 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at private fun drawPage(canvas: Canvas) { var relativeOffset = relativeOffset(0) textPage.textLines.forEach { textLine -> - draw(canvas, textLine, relativeOffset) + draw(canvas, textPage, textLine, relativeOffset) } if (!callBack.isScroll) return //滚动翻页 if (!pageFactory.hasNext()) return - val nextPage = relativePage(1) + val textPage1 = relativePage(1) relativeOffset = relativeOffset(1) - nextPage.textLines.forEach { textLine -> - draw(canvas, textLine, relativeOffset) + textPage1.textLines.forEach { textLine -> + draw(canvas, textPage1, textLine, relativeOffset) } if (!pageFactory.hasNextPlus()) return relativeOffset = relativeOffset(2) if (relativeOffset < ChapterProvider.visibleHeight) { - relativePage(2).textLines.forEach { textLine -> - draw(canvas, textLine, relativeOffset) + val textPage2 = relativePage(2) + textPage2.textLines.forEach { textLine -> + draw(canvas, textPage2, textLine, relativeOffset) } } } private fun draw( canvas: Canvas, + textPage: TextPage, textLine: TextLine, relativeOffset: Float, ) { val lineTop = textLine.lineTop + relativeOffset val lineBase = textLine.lineBase + relativeOffset val lineBottom = textLine.lineBottom + relativeOffset - drawChars( - canvas, - textLine.textChars, - lineTop, - lineBase, - lineBottom, - textLine.isTitle, - textLine.isReadAloud, - textLine.isImage - ) + drawChars(canvas, textPage, textLine, lineTop, lineBase, lineBottom) } /** @@ -126,23 +119,21 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at */ private fun drawChars( canvas: Canvas, - textChars: List, + textPage: TextPage, + textLine: TextLine, lineTop: Float, lineBase: Float, lineBottom: Float, - isTitle: Boolean, - isReadAloud: Boolean, - isImageLine: Boolean ) { - val textPaint = if (isTitle) { + val textPaint = if (textLine.isTitle) { ChapterProvider.titlePaint } else { ChapterProvider.contentPaint } - val textColor = if (isReadAloud) context.accentColor else ReadBookConfig.textColor - textChars.forEach { + val textColor = if (textLine.isReadAloud) context.accentColor else ReadBookConfig.textColor + textLine.textChars.forEach { if (it.isImage) { - drawImage(canvas, it, lineTop, lineBottom, isImageLine) + drawImage(canvas, textPage, textLine, it, lineTop, lineBottom) } else { textPaint.color = textColor if (it.isSearchResult) { @@ -159,34 +150,34 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at /** * 绘制图片 */ + @Suppress("UNUSED_PARAMETER") private fun drawImage( canvas: Canvas, + textPage: TextPage, + textLine: TextLine, textChar: TextChar, lineTop: Float, - lineBottom: Float, - isImageLine: Boolean + lineBottom: Float ) { val book = ReadBook.book ?: return - ImageProvider.getImage( + val bitmap = ImageProvider.getImage( book, textChar.charData, - ReadBook.bookSource, (textChar.end - textChar.start).toInt(), (lineBottom - lineTop).toInt() - )?.let { bitmap -> - val rectF = if (isImageLine) { - RectF(textChar.start, lineTop, textChar.end, lineBottom) - } else { - /*以宽度为基准保持图片的原始比例叠加,当div为负数时,允许高度比字符更高*/ - val h = (textChar.end - textChar.start) / bitmap.width * bitmap.height - val div = (lineBottom - lineTop - h) / 2 - RectF(textChar.start, lineTop + div, textChar.end, lineBottom - div) - } - kotlin.runCatching { - canvas.drawBitmap(bitmap, null, rectF, null) - }.onFailure { e -> - context.toastOnUi(e.localizedMessage) - } + ) + val rectF = if (textLine.isImage) { + RectF(textChar.start, lineTop, textChar.end, lineBottom) + } else { + /*以宽度为基准保持图片的原始比例叠加,当div为负数时,允许高度比字符更高*/ + val h = (textChar.end - textChar.start) / bitmap.width * bitmap.height + val div = (lineBottom - lineTop - h) / 2 + RectF(textChar.start, lineTop + div, textChar.end, lineBottom - div) + } + kotlin.runCatching { + canvas.drawBitmap(bitmap, null, rectF, null) + }.onFailure { e -> + context.toastOnUi(e.localizedMessage) } } diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt index d8c821e6d..4b7fb2168 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt @@ -208,22 +208,23 @@ object ChapterProvider { imageStyle: String?, ): Float { var durY = y - ImageProvider.getImageSize(book, src, ReadBook.bookSource).let { + val size = ImageProvider.getImageSize(book, src, ReadBook.bookSource) + if (size.width > 0 && size.height > 0) { if (durY > visibleHeight) { textPages.last().height = durY textPages.add(TextPage()) durY = 0f } - var height = it.height - var width = it.width + var height = size.height + var width = size.width when (imageStyle?.toUpperCase(Locale.ROOT)) { Book.imgStyleFull -> { width = visibleWidth - height = it.height * visibleWidth / it.width + height = size.height * visibleWidth / size.width } else -> { - if (it.width > visibleWidth) { - height = it.height * visibleWidth / it.width + if (size.width > visibleWidth) { + height = size.height * visibleWidth / size.width width = visibleWidth } if (height > visibleHeight) { diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/provider/ImageProvider.kt b/app/src/main/java/io/legado/app/ui/book/read/page/provider/ImageProvider.kt index 605fc5eff..2de937b44 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/provider/ImageProvider.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/provider/ImageProvider.kt @@ -9,16 +9,13 @@ import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookSource import io.legado.app.help.BookHelp import io.legado.app.help.coroutine.Coroutine -import io.legado.app.help.glide.ImageLoader import io.legado.app.model.localBook.EpubFile +import io.legado.app.utils.BitmapUtils import io.legado.app.utils.FileUtils import io.legado.app.utils.isXml -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.suspendCancellableCoroutine import splitties.init.appCtx import java.io.File import java.io.FileOutputStream -import kotlin.coroutines.resume object ImageProvider { @@ -26,7 +23,7 @@ object ImageProvider { BitmapFactory.decodeResource(appCtx.resources, R.drawable.image_loading_error) } - private suspend fun cacheImage( + suspend fun cacheImage( book: Book, src: String, bookSource: BookSource? @@ -54,59 +51,26 @@ object ImageProvider { bookSource: BookSource? ): Size { val file = cacheImage(book, src, bookSource) - return suspendCancellableCoroutine { block -> - kotlin.runCatching { - ImageLoader.loadBitmap(appCtx, file.absolutePath).submit() - .getSize { width, height -> - block.resume(Size(width, height)) - } - }.onFailure { - block.resume(Size(errorBitmap.width, errorBitmap.height)) - } - } + val op = BitmapFactory.Options() + // inJustDecodeBounds如果设置为true,仅仅返回图片实际的宽和高,宽和高是赋值给opts.outWidth,opts.outHeight; + op.inJustDecodeBounds = true + BitmapFactory.decodeFile(file.absolutePath, op) + return Size(op.outWidth, op.outHeight) } fun getImage( book: Book, src: String, - bookSource: BookSource?, width: Int, height: Int - ): Bitmap? { - val vFile = runBlocking { - cacheImage(book, src, bookSource) - } - return try { - ImageLoader.loadBitmap(appCtx, vFile.absolutePath) - .submit(width, height) - .get() - } catch (e: Exception) { - Coroutine.async { - putDebug("${vFile.absolutePath} 解码失败\n${e.toString()}", e) - if (FileUtils.readText(vFile.absolutePath).isXml()) { - putDebug("${vFile.absolutePath}为xml,自动删除") - vFile.delete() - } - } - errorBitmap - } - } - - fun getImage( - book: Book, - src: String, - bookSource: BookSource? - ): Bitmap? { - val vFile = runBlocking { - cacheImage(book, src, bookSource) - } + ): Bitmap { + val vFile = BookHelp.getImage(book, src) + @Suppress("BlockingMethodInNonBlockingContext") return try { - ImageLoader.loadBitmap(appCtx, vFile.absolutePath) - .submit(ChapterProvider.visibleWidth, ChapterProvider.visibleHeight) - .get() + BitmapUtils.decodeBitmap(vFile.absolutePath, width, height) } catch (e: Exception) { Coroutine.async { - putDebug("${vFile.absolutePath} 解码失败\n${e.toString()}", e) + putDebug("${vFile.absolutePath} 解码失败\n$e", e) if (FileUtils.readText(vFile.absolutePath).isXml()) { putDebug("${vFile.absolutePath}为xml,自动删除") vFile.delete() diff --git a/app/src/main/java/io/legado/app/utils/BitmapUtils.kt b/app/src/main/java/io/legado/app/utils/BitmapUtils.kt index 92bfff174..9fbba9c02 100644 --- a/app/src/main/java/io/legado/app/utils/BitmapUtils.kt +++ b/app/src/main/java/io/legado/app/utils/BitmapUtils.kt @@ -7,7 +7,6 @@ import android.graphics.* import android.graphics.Bitmap.Config import android.view.View import com.google.android.renderscript.Toolkit -import java.io.FileInputStream import java.io.IOException import kotlin.math.* @@ -27,10 +26,9 @@ object BitmapUtils { @Throws(IOException::class) fun decodeBitmap(path: String, width: Int, height: Int): Bitmap { val op = BitmapFactory.Options() - val ips = FileInputStream(path) // inJustDecodeBounds如果设置为true,仅仅返回图片实际的宽和高,宽和高是赋值给opts.outWidth,opts.outHeight; op.inJustDecodeBounds = true - BitmapFactory.decodeFileDescriptor(ips.fd, null, op) + BitmapFactory.decodeFile(path, op) //获取比例大小 val wRatio = ceil((op.outWidth / width).toDouble()).toInt() val hRatio = ceil((op.outHeight / height).toDouble()).toInt() @@ -43,7 +41,7 @@ object BitmapUtils { } } op.inJustDecodeBounds = false - return BitmapFactory.decodeFileDescriptor(ips.fd, null, op) + return BitmapFactory.decodeFile(path, op) } /** 从path中获取Bitmap图片 @@ -53,12 +51,11 @@ object BitmapUtils { @Throws(IOException::class) fun decodeBitmap(path: String): Bitmap { val opts = BitmapFactory.Options() - val ips = FileInputStream(path) opts.inJustDecodeBounds = true - BitmapFactory.decodeFileDescriptor(ips.fd, null, opts) + BitmapFactory.decodeFile(path, opts) opts.inSampleSize = computeSampleSize(opts, -1, 128 * 128) opts.inJustDecodeBounds = false - return BitmapFactory.decodeFileDescriptor(ips.fd, null, opts) + return BitmapFactory.decodeFile(path, opts) } /** diff --git a/app/src/main/java/io/legado/app/utils/ThrowableExtensions.kt b/app/src/main/java/io/legado/app/utils/ThrowableExtensions.kt index a5bfaa8fc..088db9b3b 100644 --- a/app/src/main/java/io/legado/app/utils/ThrowableExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/ThrowableExtensions.kt @@ -12,8 +12,8 @@ val Throwable.msg: String } } -fun Throwable.rethrowAsIOException(): IOException { +fun Throwable.asIOException(): IOException { val newException = IOException(this.message) newException.initCause(this) - throw newException + return newException } \ No newline at end of file