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