优化图片下载

pull/352/head
gedoor 4 years ago
parent 401581f614
commit dc24fc18f3
  1. 15
      app/src/main/java/io/legado/app/help/BookHelp.kt
  2. 2
      app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt
  3. 18
      app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt
  4. 8
      app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt
  5. 17
      app/src/main/java/io/legado/app/ui/book/read/page/provider/ImageProvider.kt
  6. 12
      app/src/main/java/io/legado/app/ui/widget/dialog/PhotoDialog.kt

@ -13,16 +13,19 @@ import io.legado.app.model.localBook.LocalBook
import io.legado.app.utils.* import io.legado.app.utils.*
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.apache.commons.text.similarity.JaccardSimilarity import org.apache.commons.text.similarity.JaccardSimilarity
import org.jetbrains.anko.toast import org.jetbrains.anko.toast
import java.io.File import java.io.File
import java.util.concurrent.CopyOnWriteArraySet
import kotlin.math.min import kotlin.math.min
object BookHelp { object BookHelp {
private const val cacheFolderName = "book_cache" private const val cacheFolderName = "book_cache"
private const val cacheImageFolderName = "images" private const val cacheImageFolderName = "images"
private val downloadDir: File = App.INSTANCE.externalFilesDir private val downloadDir: File = App.INSTANCE.externalFilesDir
private val downloadImages = CopyOnWriteArraySet<String>()
fun formatChapterName(bookChapter: BookChapter): String { fun formatChapterName(bookChapter: BookChapter): String {
return String.format( return String.format(
@ -61,7 +64,7 @@ object BookHelp {
} }
} }
fun saveContent(book: Book, bookChapter: BookChapter, content: String) { suspend fun saveContent(book: Book, bookChapter: BookChapter, content: String) {
if (content.isEmpty()) return if (content.isEmpty()) return
//保存文本 //保存文本
FileUtils.createFileIfNotExist( FileUtils.createFileIfNotExist(
@ -84,7 +87,14 @@ object BookHelp {
postEvent(EventBus.SAVE_CONTENT, bookChapter) postEvent(EventBus.SAVE_CONTENT, bookChapter)
} }
fun saveImage(book: Book, src: String) { suspend fun saveImage(book: Book, src: String) {
while (downloadImages.contains(src)) {
delay(100)
}
if (getImage(book, src).exists()) {
return
}
downloadImages.add(src)
val analyzeUrl = AnalyzeUrl(src) val analyzeUrl = AnalyzeUrl(src)
analyzeUrl.getImageBytes(book.origin)?.let { analyzeUrl.getImageBytes(book.origin)?.let {
FileUtils.createFileIfNotExist( FileUtils.createFileIfNotExist(
@ -95,6 +105,7 @@ object BookHelp {
"${MD5Utils.md5Encode16(src)}${getImageSuffix(src)}" "${MD5Utils.md5Encode16(src)}${getImageSuffix(src)}"
).writeBytes(it) ).writeBytes(it)
} }
downloadImages.remove(src)
} }
fun getImage(book: Book, src: String): File { fun getImage(book: Book, src: String): File {

@ -55,6 +55,7 @@ import io.legado.app.ui.widget.dialog.TextDialog
import io.legado.app.utils.* import io.legado.app.utils.*
import kotlinx.android.synthetic.main.activity_book_read.* import kotlinx.android.synthetic.main.activity_book_read.*
import kotlinx.android.synthetic.main.view_read_menu.* import kotlinx.android.synthetic.main.view_read_menu.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.sdk27.listeners.onClick
@ -84,6 +85,7 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
override val viewModel: ReadBookViewModel override val viewModel: ReadBookViewModel
get() = getViewModel(ReadBookViewModel::class.java) get() = getViewModel(ReadBookViewModel::class.java)
override val scope: CoroutineScope get() = this
override val isInitFinish: Boolean get() = viewModel.isInitFinish override val isInitFinish: Boolean get() = viewModel.isInitFinish
private val mHandler = Handler() private val mHandler = Handler()

@ -20,6 +20,7 @@ import io.legado.app.ui.widget.dialog.PhotoDialog
import io.legado.app.utils.activity import io.legado.app.utils.activity
import io.legado.app.utils.getCompatColor import io.legado.app.utils.getCompatColor
import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.getPrefBoolean
import kotlinx.coroutines.CoroutineScope
class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, attrs) { class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, attrs) {
@ -105,7 +106,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
private fun draw( private fun draw(
canvas: Canvas, canvas: Canvas,
textLine: TextLine, textLine: TextLine,
relativeOffset: Float relativeOffset: Float,
) { ) {
val lineTop = textLine.lineTop + relativeOffset val lineTop = textLine.lineTop + relativeOffset
val lineBase = textLine.lineBase + relativeOffset val lineBase = textLine.lineBase + relativeOffset
@ -135,7 +136,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
lineBase: Float, lineBase: Float,
lineBottom: Float, lineBottom: Float,
isTitle: Boolean, isTitle: Boolean,
isReadAloud: Boolean isReadAloud: Boolean,
) { ) {
val textPaint = if (isTitle) ChapterProvider.titlePaint else ChapterProvider.contentPaint val textPaint = if (isTitle) ChapterProvider.titlePaint else ChapterProvider.contentPaint
textPaint.color = textPaint.color =
@ -155,16 +156,14 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
canvas: Canvas, canvas: Canvas,
textLine: TextLine, textLine: TextLine,
lineTop: Float, lineTop: Float,
lineBottom: Float lineBottom: Float,
) { ) {
textLine.textChars.forEach { textChar -> textLine.textChars.forEach { textChar ->
val rectF = RectF(textChar.start, lineTop, textChar.end, lineBottom) val rectF = RectF(textChar.start, lineTop, textChar.end, lineBottom)
ImageProvider.getImage( ImageProvider.getImage(ReadBook.book!!,
ReadBook.book!!,
textPage.chapterIndex, textPage.chapterIndex,
textChar.charData, textChar.charData,
true true)?.let {
)?.let {
canvas.drawBitmap(it, null, rectF, null) canvas.drawBitmap(it, null, rectF, null)
} }
} }
@ -211,7 +210,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
fun selectText( fun selectText(
x: Float, x: Float,
y: Float, y: Float,
select: (relativePage: Int, lineIndex: Int, charIndex: Int) -> Unit select: (relativePage: Int, lineIndex: Int, charIndex: Int) -> Unit,
) { ) {
if (!selectAble) return if (!selectAble) return
if (!visibleRect.contains(x, y)) return if (!visibleRect.contains(x, y)) return
@ -257,7 +256,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
lineIndex: Int, lineIndex: Int,
charIndex: Int, charIndex: Int,
relativeOffset: Float, relativeOffset: Float,
select: (relativePage: Int, lineIndex: Int, charIndex: Int) -> Unit select: (relativePage: Int, lineIndex: Int, charIndex: Int) -> Unit,
) { ) {
if (textChar.isImage) { if (textChar.isImage) {
activity?.supportFragmentManager?.let { activity?.supportFragmentManager?.let {
@ -613,5 +612,6 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
fun onCancelSelect() fun onCancelSelect()
val headerHeight: Int val headerHeight: Int
val pageFactory: TextPageFactory val pageFactory: TextPageFactory
val scope: CoroutineScope
} }
} }

@ -45,12 +45,12 @@ object ChapterProvider {
/** /**
* 获取拆分完的章节数据 * 获取拆分完的章节数据
*/ */
fun getTextChapter( suspend fun getTextChapter(
book: Book, book: Book,
bookChapter: BookChapter, bookChapter: BookChapter,
contents: List<String>, contents: List<String>,
chapterSize: Int, chapterSize: Int,
imageStyle: String? imageStyle: String?,
): TextChapter { ): TextChapter {
val textPages = arrayListOf<TextPage>() val textPages = arrayListOf<TextPage>()
val pageLines = arrayListOf<Int>() val pageLines = arrayListOf<Int>()
@ -110,13 +110,13 @@ object ChapterProvider {
) )
} }
private fun setTypeImage( private suspend fun setTypeImage(
book: Book, book: Book,
chapter: BookChapter, chapter: BookChapter,
src: String, src: String,
y: Float, y: Float,
textPages: ArrayList<TextPage>, textPages: ArrayList<TextPage>,
imageStyle: String? imageStyle: String?,
): Float { ): Float {
var durY = y var durY = y
ImageProvider.getImage(book, chapter.index, src)?.let { ImageProvider.getImage(book, chapter.index, src)?.let {

@ -1,13 +1,12 @@
package io.legado.app.ui.book.read.page.provider package io.legado.app.ui.book.read.page.provider
import android.graphics.Bitmap import android.graphics.Bitmap
import io.legado.app.App
import io.legado.app.data.entities.Book import io.legado.app.data.entities.Book
import io.legado.app.help.BookHelp import io.legado.app.help.BookHelp
import io.legado.app.model.localBook.EPUBFile import io.legado.app.model.localBook.EPUBFile
import io.legado.app.utils.BitmapUtils import io.legado.app.utils.BitmapUtils
import io.legado.app.utils.FileUtils import io.legado.app.utils.FileUtils
import io.legado.app.utils.externalFilesDir import kotlinx.coroutines.runBlocking
import java.io.FileOutputStream import java.io.FileOutputStream
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
@ -37,14 +36,16 @@ object ImageProvider {
val vFile = BookHelp.getImage(book, src) val vFile = BookHelp.getImage(book, src)
if (!vFile.exists()) { if (!vFile.exists()) {
if (book.isEpub()) { if (book.isEpub()) {
EPUBFile.getImage(book, src).use { EPUBFile.getImage(book, src)?.use { input ->
val out = FileOutputStream(FileUtils.createFileIfNotExist(vFile.absolutePath)) val newFile = FileUtils.createFileIfNotExist(vFile.absolutePath)
it?.copyTo(out) FileOutputStream(newFile).use { output ->
out.flush() input.copyTo(output)
out.close() }
} }
} else if (!onUi) { } else if (!onUi) {
BookHelp.saveImage(book, src) runBlocking {
BookHelp.saveImage(book, src)
}
} }
} }
return try { return try {

@ -20,7 +20,7 @@ class PhotoDialog : BaseDialogFragment() {
fun show( fun show(
fragmentManager: FragmentManager, fragmentManager: FragmentManager,
chapterIndex: Int, chapterIndex: Int,
src: String src: String,
) { ) {
PhotoDialog().apply { PhotoDialog().apply {
val bundle = Bundle() val bundle = Bundle()
@ -45,7 +45,7 @@ class PhotoDialog : BaseDialogFragment() {
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?,
): View? { ): View? {
return inflater.inflate(R.layout.dialog_photo_view, container) return inflater.inflate(R.layout.dialog_photo_view, container)
} }
@ -56,8 +56,12 @@ class PhotoDialog : BaseDialogFragment() {
val src = it.getString("src") val src = it.getString("src")
ReadBook.book?.let { book -> ReadBook.book?.let { book ->
src?.let { src?.let {
ImageProvider.getImage(book, chapterIndex, src)?.let { bitmap -> execute {
photo_view.setImageBitmap(bitmap) ImageProvider.getImage(book, chapterIndex, src)
}.onSuccess { bitmap ->
if (bitmap != null) {
photo_view.setImageBitmap(bitmap)
}
} }
} }
} }

Loading…
Cancel
Save