commit
a59e903442
@ -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