Merge pull request #935 from ag2s20150909/master

导出epub时支持导出已经缓存的插图
pull/942/head
kunfei 4 years ago committed by GitHub
commit 094be3725f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 27
      app/src/main/java/io/legado/app/model/localBook/LocalBook.kt
  2. 55
      app/src/main/java/io/legado/app/ui/book/cache/CacheViewModel.kt
  3. 22
      epublib/src/main/java/me/ag2s/epublib/util/ResourceUtil.java
  4. 16
      epublib/src/main/java/me/ag2s/epublib/util/StringUtil.java

@ -65,31 +65,38 @@ object LocalBook {
|| (fileName.contains(" by ", true)) || (fileName.contains(" by ", true))
) { ) {
//匹配(知轩藏书常用格式) 《书名》其它信息作者:作者名.txt //匹配(知轩藏书常用格式) 《书名》其它信息作者:作者名.txt
val m1 = Pattern val m1 = Pattern
.compile("《(.*?)》.*?作者:(.*?).txt") .compile("《(.*?)》.*?作者:(.*?)\\.txt")
.matcher(fileName) .matcher(fileName)
//匹配 书名 by 作者名.txt //匹配 书名 by 作者名.txt
val m2 = Pattern val m2 = Pattern
.compile("(.*?) by (.*?).txt") .compile("txt\\.(.*?) yb (.*?)$")
.matcher(fileName) .matcher(fileName.reversed())
if (m1.find()) { if (m1.find()) {
name = m1.group(1) name = m1.group(1) ?: fileName.replace(".txt", "")
author = m1.group(2) author = m1.group(2) ?: ""
BookHelp.formatBookAuthor(author) BookHelp.formatBookAuthor(author)
} else if (m2.find()) { } else if (m2.find()) {
name = m2.group(1) var temp = m2.group(2)
author = m2.group(2) name = if (temp==null||temp == "") {
fileName.replace(".txt", "")
} else {
temp.reversed()
}
temp = m2.group(1) ?: ""
author = temp.reversed()
BookHelp.formatBookAuthor(author) BookHelp.formatBookAuthor(author)
} else { } else {
val st = fileName.indexOf(""); val st = fileName.indexOf("")
val e = fileName.indexOf(""); val e = fileName.indexOf("")
name = if (e > st && st != -1) { name = if (e > st && st != -1) {
fileName.substring(st + 1, e) fileName.substring(st + 1, e)
} else { } else {
fileName fileName.replace(".txt", "")
} }

@ -13,6 +13,7 @@ import io.legado.app.base.BaseViewModel
import io.legado.app.constant.AppPattern import io.legado.app.constant.AppPattern
import io.legado.app.data.appDb import io.legado.app.data.appDb
import io.legado.app.data.entities.Book import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookChapter
import io.legado.app.help.AppConfig import io.legado.app.help.AppConfig
import io.legado.app.help.BookHelp import io.legado.app.help.BookHelp
import io.legado.app.help.ContentProcessor import io.legado.app.help.ContentProcessor
@ -23,6 +24,7 @@ import me.ag2s.epublib.epub.EpubWriter
import me.ag2s.epublib.util.ResourceUtil import me.ag2s.epublib.util.ResourceUtil
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.io.File import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream import java.io.FileOutputStream
import java.nio.charset.Charset import java.nio.charset.Charset
@ -125,10 +127,10 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
appDb.bookChapterDao.getChapterList(book.bookUrl).forEach { chapter -> appDb.bookChapterDao.getChapterList(book.bookUrl).forEach { chapter ->
BookHelp.getContent(book, chapter)?.let { content -> BookHelp.getContent(book, chapter)?.let { content ->
content.split("\n").forEachIndexed { index, text -> content.split("\n").forEachIndexed { index, text ->
val matcher = AppPattern.imgPattern.matcher(text) val matches = AppPattern.imgPattern.toRegex().findAll(input = text)
if (matcher.find()) { matches.forEach { matchResult ->
matcher.group(1)?.let { matchResult.groupValues[1].let {
val src = NetworkUtils.getAbsoluteURL(chapter.url, it) val src=NetworkUtils.getAbsoluteURL(chapter.url, it)
srcList.add(Triple(chapter.title, index, src)) srcList.add(Triple(chapter.title, index, src))
} }
} }
@ -205,7 +207,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
//set css //set css
epubBook.resources.add( epubBook.resources.add(
Resource( Resource(
"body{background:white;margin:0;}h2{color:#005a9c;text-align:left;}p{text-indent:2em;text-align:justify;}".encodeToByteArray(), "body,div{background:white;margin:0 auto;padding:0;outline:none;width:100%;}h2{color:#005a9c;text-align:left;}p{text-indent:2em;text-align:justify;}img{display:inline-block;width:100%;height:100%;max-width: 100%;max-height:100%;}".encodeToByteArray(),
"css/style.css" "css/style.css"
) )
) )
@ -215,13 +217,14 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
Glide.with(context) Glide.with(context)
.asBitmap() .asBitmap()
.load(book.coverUrl) .load(book.getDisplayCover())
.into(object : CustomTarget<Bitmap>() { .into(object : CustomTarget<Bitmap>() {
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) { override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
val stream = ByteArrayOutputStream() val stream = ByteArrayOutputStream()
resource.compress(Bitmap.CompressFormat.JPEG, 100, stream) resource.compress(Bitmap.CompressFormat.JPEG, 100, stream)
val byteArray: ByteArray = stream.toByteArray() val byteArray: ByteArray = stream.toByteArray()
resource.recycle() resource.recycle()
stream.close()
epubBook.coverImage = Resource(byteArray, "cover.jpg") epubBook.coverImage = Resource(byteArray, "cover.jpg")
} }
@ -232,13 +235,15 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
}) })
} }
private fun setEpubContent(book: Book, epubBook: EpubBook) { private fun setEpubContent(book: Book, epubBook: EpubBook) {
val useReplace = AppConfig.exportUseReplace val useReplace = AppConfig.exportUseReplace
val contentProcessor = ContentProcessor(book.name, book.origin) val contentProcessor = ContentProcessor(book.name, book.origin)
appDb.bookChapterDao.getChapterList(book.bookUrl).forEach { chapter -> appDb.bookChapterDao.getChapterList(book.bookUrl).forEach { chapter ->
BookHelp.getContent(book, chapter).let { content -> BookHelp.getContent(book, chapter).let { content ->
val content1 = contentProcessor var content1 = fixPic(epubBook, book, content ?: "null", chapter)
.getContent(book, chapter.title, content ?: "null", false, useReplace) content1 = contentProcessor
.getContent(book, chapter.title, content1, false, useReplace)
.joinToString("\n") .joinToString("\n")
.replace(chapter.title, "") .replace(chapter.title, "")
@ -250,10 +255,42 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
} }
} }
private fun setPic(src: String, book: Book, epubBook: EpubBook) {
val vFile = BookHelp.getImage(book, src)
if (vFile.exists()) {
val img = Resource(FileInputStream(vFile), MD5Utils.md5Encode16(src) + ".jpg")
epubBook.resources.add(img)
}
}
private fun fixPic(
epubBook: EpubBook,
book: Book,
content: String,
chapter: BookChapter
): String {
val data = StringBuilder("")
content.split("\n").forEach { text ->
var text1 = text
val matches = AppPattern.imgPattern.toRegex().findAll(input = text)
matches.forEach { matchResult ->
matchResult.groupValues[1].let {
val src=NetworkUtils.getAbsoluteURL(chapter.url, it)
setPic(src, book, epubBook)
text1 = text1.replace(src, MD5Utils.md5Encode16(src) + ".jpg")
}
}
data.append(text1).append("\n")
}
return data.toString()
}
private fun setEpubMetadata(book: Book, epubBook: EpubBook) { private fun setEpubMetadata(book: Book, epubBook: EpubBook) {
val metadata = Metadata() val metadata = Metadata()
metadata.titles.add(book.name)//书籍的名称 metadata.titles.add(book.name)//书籍的名称
metadata.authors.add(Author(book.author))//书籍的作者 metadata.authors.add(Author(book.getRealAuthor()))//书籍的作者
metadata.language = "zh"//数据的语言 metadata.language = "zh"//数据的语言
metadata.dates.add(Date())//数据的创建日期 metadata.dates.add(Date())//数据的创建日期
metadata.publishers.add("Legado APP")//数据的创建者 metadata.publishers.add("Legado APP")//数据的创建者

@ -29,7 +29,8 @@ import me.ag2s.epublib.epub.EpubProcessorSupport;
public class ResourceUtil { public class ResourceUtil {
/** /**
* 快速创建HTML类型的Resource * 快速创建HTML类型的Resource
* @param title 章节的标题 *
* @param title 章节的标题
* @param string 章节的正文 * @param string 章节的正文
* @return 返回Resource * @return 返回Resource
*/ */
@ -42,9 +43,10 @@ public class ResourceUtil {
/** /**
* 快速创建HTML类型的Resource * 快速创建HTML类型的Resource
* @param title 章节的标题 *
* @param title 章节的标题
* @param string 章节的正文 * @param string 章节的正文
* @param href Resource的href * @param href Resource的href
* @return 返回Resource * @return 返回Resource
*/ */
@ -60,9 +62,18 @@ public class ResourceUtil {
private static String createHtml(String title, String txt) { private static String createHtml(String title, String txt) {
StringBuilder body = new StringBuilder(); StringBuilder body = new StringBuilder();
for (String s : txt.split("\\r?\\n")) { for (String s : txt.split("\\r?\\n")) {
s = s.trim(); //移除多余的开头结尾的空白字符,节省epub的体积
s = StringUtil.FixTrim(s);
if (s.length() != 0) { if (s.length() != 0) {
body.append("<p>").append(s).append("</p>"); if (s.contains("<img")) {
//加上div的话多看能点看大图,但掌阅的图会因为排版变得非常小。
//body.append("<div class=\"duokan-image-single img-note\">")
body.append(s);
//.append("</div>");
} else {
body.append("<p>").append(s).append("</p>");
}
} }
} }
@ -80,6 +91,7 @@ public class ResourceUtil {
/** /**
* 快速从File创建Resource * 快速从File创建Resource
*
* @param file File * @param file File
* @return Resource * @return Resource
* @throws IOException IOException * @throws IOException IOException

@ -3,6 +3,8 @@ package me.ag2s.epublib.util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** /**
* Various String utility functions. * Various String utility functions.
@ -271,4 +273,18 @@ public class StringUtil {
} }
return text.substring(cPos + 1); return text.substring(cPos + 1);
} }
public static String FixTrim(String s) {
if (s==null){
return "null";
}
Pattern r = Pattern.compile("^[\\s]{1,9}(.*?)[\\s]{1,9}$");
Matcher m = r.matcher(s);
if (m.find()) {
s= m.group(1);
}
//移除GBK中文全角空格
s = s.replace(" ", "");
return s;
}
} }

Loading…
Cancel
Save