commit
						a045c4f1e2
					
				| @ -0,0 +1,51 @@ | ||||
| package io.legado.app.help.http.cronet | ||||
| 
 | ||||
| import okhttp3.RequestBody | ||||
| import okio.Buffer | ||||
| import org.chromium.net.UploadDataProvider | ||||
| import org.chromium.net.UploadDataSink | ||||
| import java.io.IOException | ||||
| import java.nio.ByteBuffer | ||||
| 
 | ||||
| class BodyUploadProvider(body: RequestBody) : UploadDataProvider(), AutoCloseable { | ||||
|     private val body: RequestBody | ||||
|     private val buffer: Buffer? | ||||
| 
 | ||||
|     init { | ||||
|         buffer = Buffer() | ||||
|         this.body = body | ||||
|         try { | ||||
|             body.writeTo(buffer) | ||||
|         } catch (e: IOException) { | ||||
|             e.printStackTrace() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Throws(IOException::class) | ||||
|     override fun getLength(): Long { | ||||
|         return body.contentLength() | ||||
|     } | ||||
| 
 | ||||
|     @Throws(IOException::class) | ||||
|     override fun read(uploadDataSink: UploadDataSink, byteBuffer: ByteBuffer) { | ||||
|         check(byteBuffer.hasRemaining()) { "Cronet passed a buffer with no bytes remaining" } | ||||
|         var read: Int | ||||
|         var bytesRead = 0 | ||||
|         while (bytesRead == 0) { | ||||
|             read = buffer!!.read(byteBuffer) | ||||
|             bytesRead += read | ||||
|         } | ||||
|         uploadDataSink.onReadSucceeded(false) | ||||
|     } | ||||
| 
 | ||||
|     @Throws(IOException::class) | ||||
|     override fun rewind(uploadDataSink: UploadDataSink) { | ||||
|         uploadDataSink.onRewindSucceeded() | ||||
|     } | ||||
| 
 | ||||
|     @Throws(IOException::class) | ||||
|     override fun close() { | ||||
|         buffer?.close() | ||||
|         super.close() | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,225 @@ | ||||
| package io.legado.app.model.localBook | ||||
| 
 | ||||
| import android.graphics.Bitmap | ||||
| import android.graphics.pdf.PdfRenderer | ||||
| import android.os.ParcelFileDescriptor | ||||
| import io.legado.app.constant.AppLog | ||||
| import io.legado.app.data.entities.Book | ||||
| import io.legado.app.data.entities.BookChapter | ||||
| import io.legado.app.help.book.getLocalUri | ||||
| import io.legado.app.utils.* | ||||
| import splitties.init.appCtx | ||||
| import java.io.File | ||||
| import java.io.FileOutputStream | ||||
| import java.io.InputStream | ||||
| import kotlin.math.ceil | ||||
| 
 | ||||
| 
 | ||||
| class PdfFile(var book: Book) { | ||||
|     companion object : BaseLocalBookParse { | ||||
|         private var pFile: PdfFile? = null | ||||
| 
 | ||||
|         /** | ||||
|          * pdf分页尺寸 | ||||
|          */ | ||||
|         const val PAGE_SIZE = 10 | ||||
| 
 | ||||
|         @Synchronized | ||||
|         private fun getPFile(book: Book): PdfFile { | ||||
|             if (pFile == null || pFile?.book?.bookUrl != book.bookUrl) { | ||||
|                 pFile = PdfFile(book) | ||||
|                 return pFile!! | ||||
|             } | ||||
|             pFile?.book = book | ||||
|             return pFile!! | ||||
|         } | ||||
| 
 | ||||
|         @Synchronized | ||||
|         override fun upBookInfo(book: Book) { | ||||
|             getPFile(book).upBookInfo() | ||||
|         } | ||||
| 
 | ||||
|         @Synchronized | ||||
|         override fun getChapterList(book: Book): ArrayList<BookChapter> { | ||||
|             return getPFile(book).getChapterList() | ||||
|         } | ||||
| 
 | ||||
|         @Synchronized | ||||
|         override fun getContent(book: Book, chapter: BookChapter): String? { | ||||
|             return getPFile(book).getContent(chapter) | ||||
|         } | ||||
| 
 | ||||
|         @Synchronized | ||||
|         override fun getImage(book: Book, href: String): InputStream? { | ||||
|             return getPFile(book).getImage(href) | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     private var fileDescriptor: ParcelFileDescriptor? = null | ||||
|     private var pdfRenderer: PdfRenderer? = null | ||||
|         get() { | ||||
|             if (field != null) { | ||||
|                 return field | ||||
|             } | ||||
|             field = readPdf() | ||||
|             return field | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|     init { | ||||
|         try { | ||||
|             pdfRenderer?.let { renderer -> | ||||
|                 if (book.coverUrl.isNullOrEmpty()) { | ||||
|                     book.coverUrl = FileUtils.getPath( | ||||
|                         appCtx.externalFiles, | ||||
|                         "covers", | ||||
|                         "${MD5Utils.md5Encode16(book.bookUrl)}.jpg" | ||||
|                     ) | ||||
|                 } | ||||
|                 if (!File(book.coverUrl!!).exists()) { | ||||
| 
 | ||||
|                     FileOutputStream(FileUtils.createFileIfNotExist(book.coverUrl!!)).use { out -> | ||||
|                         openPdfPage(renderer, 0)?.let { cover -> | ||||
|                             cover.compress(Bitmap.CompressFormat.JPEG, 90, out) | ||||
|                         } | ||||
|                         out.flush() | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } catch (e: Exception) { | ||||
|             AppLog.put("加载书籍封面失败\n${e.localizedMessage}", e) | ||||
|             e.printOnDebug() | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 读取PDF文件 | ||||
|      * | ||||
|      * @return | ||||
|      */ | ||||
|     private fun readPdf(): PdfRenderer? { | ||||
|         val uri = book.getLocalUri() | ||||
|         if (uri.isContentScheme()) { | ||||
|             fileDescriptor = appCtx.contentResolver.openFileDescriptor(uri, "r")?.also { | ||||
|                 pdfRenderer = PdfRenderer(it) | ||||
|             } | ||||
|         } else { | ||||
|             fileDescriptor = | ||||
|                 ParcelFileDescriptor.open(File(uri.path), ParcelFileDescriptor.MODE_READ_ONLY) | ||||
|                     ?.also { | ||||
|                         pdfRenderer = PdfRenderer(it) | ||||
|                     } | ||||
|         } | ||||
|         return pdfRenderer | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 关闭pdf文件 | ||||
|      * | ||||
|      */ | ||||
|     private fun closePdf() { | ||||
|         pdfRenderer?.close() | ||||
|         fileDescriptor?.close() | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * 渲染PDF页面 | ||||
|      * 根据index打开pdf页面,并渲染到Bitmap | ||||
|      * | ||||
|      * @param renderer | ||||
|      * @param index | ||||
|      * @return | ||||
|      */ | ||||
|     private fun openPdfPage(renderer: PdfRenderer, index: Int): Bitmap? { | ||||
|         if (index >= renderer.pageCount) { | ||||
|             return null | ||||
|         } | ||||
|         return renderer.openPage(index)?.use { page -> | ||||
|             Bitmap.createBitmap( | ||||
|                 SystemUtils.screenWidthPx, | ||||
|                 (SystemUtils.screenWidthPx.toDouble() * page.height / page.width).toInt(), | ||||
|                 Bitmap.Config.ARGB_8888 | ||||
|             ) | ||||
|                 .apply { | ||||
|                     page.render(this, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY) | ||||
|                 } | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     private fun getContent(chapter: BookChapter): String? = | ||||
|         if (pdfRenderer == null) { | ||||
|             null | ||||
|         } else { | ||||
|             pdfRenderer?.let { renderer -> | ||||
| 
 | ||||
|                 buildString { | ||||
|                     val start = chapter.index * PAGE_SIZE | ||||
|                     val end = Math.min((chapter.index + 1) * PAGE_SIZE, renderer.pageCount) | ||||
|                     (start until end).forEach { | ||||
|                         append("<img src=").append('"').append(it).append('"').append(" >") | ||||
|                             .append('\n') | ||||
|                     } | ||||
| 
 | ||||
|                 } | ||||
| 
 | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|     private fun getImage(href: String): InputStream? { | ||||
|         if (pdfRenderer == null) { | ||||
|             return null | ||||
|         } | ||||
|         return try { | ||||
|             val index = href.toInt() | ||||
|             val bitmap = openPdfPage(pdfRenderer!!, index) | ||||
|             if (bitmap != null) { | ||||
|                 BitmapUtils.toInputStream(bitmap).also { bitmap.recycle() } | ||||
|             } else { | ||||
|                 null | ||||
|             } | ||||
| 
 | ||||
|         } catch (e: Exception) { | ||||
|             return null | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private fun getChapterList(): ArrayList<BookChapter> { | ||||
|         val chapterList = ArrayList<BookChapter>() | ||||
| 
 | ||||
|         pdfRenderer?.let { renderer -> | ||||
|             if (renderer.pageCount > 0) { | ||||
|                 val chapterCount = ceil((renderer.pageCount.toDouble() / PAGE_SIZE)).toInt() | ||||
|                 (0 until chapterCount).forEach { | ||||
|                     val chapter = BookChapter() | ||||
|                     chapter.index = it | ||||
|                     chapter.bookUrl = book.bookUrl | ||||
|                     chapter.title = "分段_${it}" | ||||
|                     chapter.url = "pdf_${it}" | ||||
|                     chapterList.add(chapter) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return chapterList | ||||
|     } | ||||
| 
 | ||||
|     private fun upBookInfo() { | ||||
|         if (pdfRenderer == null) { | ||||
|             pFile = null | ||||
|             book.intro = "书籍导入异常" | ||||
|         } else { | ||||
|             if (book.name.isEmpty()) { | ||||
|                 book.name = book.originName.replace(".pdf", "") | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     protected fun finalize() { | ||||
|         closePdf() | ||||
|     } | ||||
| } | ||||
					Loading…
					
					
				
		Reference in new issue