Merge pull request #957 from ag2s20150909/master

图片解码优化,epub读取导出优化。
pull/967/head
kunfei 4 years ago committed by GitHub
commit 428660171e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      app/build.gradle
  2. 25
      app/src/main/java/io/legado/app/help/BookHelp.kt
  3. 46
      app/src/main/java/io/legado/app/model/localBook/EpubFile.kt
  4. 7
      app/src/main/java/io/legado/app/model/localBook/LocalBook.kt
  5. 12
      app/src/main/java/io/legado/app/ui/book/cache/CacheViewModel.kt
  6. 2
      app/src/main/java/io/legado/app/ui/book/read/page/provider/ImageProvider.kt
  7. 20
      app/src/main/java/io/legado/app/utils/BitmapUtils.kt
  8. 38
      app/src/main/java/io/legado/app/utils/FileUtils.kt
  9. 38
      epublib/src/main/java/me/ag2s/epublib/domain/FileResourceProvider.java
  10. 56
      epublib/src/main/java/me/ag2s/epublib/epub/DOMUtil.java
  11. 6
      epublib/src/main/java/me/ag2s/epublib/epub/NCXDocumentV2.java
  12. 13
      epublib/src/main/java/me/ag2s/epublib/epub/NCXDocumentV3.java
  13. 23
      epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentMetadataReader.java
  14. 59
      epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentReader.java
  15. 32
      epublib/src/main/java/me/ag2s/epublib/epub/ResourcesLoader.java
  16. 11
      epublib/src/main/java/me/ag2s/epublib/util/IOUtil.java

@ -178,7 +178,8 @@ dependencies {
implementation 'com.github.gedoor:rhino-android:1.5'
//
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
//noinspection GradleDependency
implementation 'com.squareup.okhttp3:okhttp:4.9.1'
implementation 'com.ljx.rxhttp:rxhttp:2.5.7'
kapt 'com.ljx.rxhttp:rxhttp-compiler:2.5.7'

@ -1,5 +1,6 @@
package io.legado.app.help
import android.net.Uri
import io.legado.app.constant.AppPattern
import io.legado.app.constant.EventBus
import io.legado.app.data.appDb
@ -55,6 +56,28 @@ object BookHelp {
}
}
fun getEpubFile(book: Book,): File {
val file = FileUtils.getFile(
downloadDir,
cacheFolderName,
book.getFolderName(),
"index.epubx"
)
if(!file.exists()){
val input = if (book.bookUrl.isContentScheme()) {
val uri = Uri.parse(book.bookUrl)
appCtx.contentResolver.openInputStream(uri)
} else {
File(book.bookUrl).inputStream()
}
if (input != null) {
FileUtils.writeInputStream(file, input)
}
}
return file
}
suspend fun saveContent(book: Book, bookChapter: BookChapter, content: String) {
if (content.isEmpty()) return
//保存文本
@ -113,7 +136,7 @@ object BookHelp {
)
}
private fun getImageSuffix(src: String): String {
fun getImageSuffix(src: String): String {
var suffix = src.substringAfterLast(".").substringBefore(",")
if (suffix.length > 5) {
suffix = ".jpg"

@ -2,16 +2,16 @@ package io.legado.app.model.localBook
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.text.TextUtils
import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookChapter
import io.legado.app.utils.*
import io.legado.app.help.BookHelp
import io.legado.app.utils.FileUtils
import io.legado.app.utils.HtmlFormatter
import io.legado.app.utils.MD5Utils
import io.legado.app.utils.externalFilesDir
import me.ag2s.epublib.domain.EpubBook
import me.ag2s.epublib.domain.MediaTypes
import me.ag2s.epublib.domain.Resources
import me.ag2s.epublib.epub.EpubReader
import me.ag2s.epublib.util.ResourceUtil
import org.jsoup.Jsoup
import splitties.init.appCtx
import java.io.File
@ -20,8 +20,7 @@ import java.io.IOException
import java.io.InputStream
import java.nio.charset.Charset
import java.util.*
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
import java.util.zip.ZipFile
class EpubFile(var book: Book) {
@ -30,6 +29,7 @@ class EpubFile(var book: Book) {
@Synchronized
private fun getEFile(book: Book): EpubFile {
BookHelp.getEpubFile(book)
if (eFile == null || eFile?.book?.bookUrl != book.bookUrl) {
eFile = EpubFile(book)
return eFile!!
@ -101,32 +101,12 @@ class EpubFile(var book: Book) {
/*重写epub文件解析代码,直接读出压缩包文件生成Resources给epublib,这样的好处是可以逐一修改某些文件的格式错误*/
private fun readEpub(): EpubBook? {
try {
val input = if (book.bookUrl.isContentScheme()) {
val uri = Uri.parse(book.bookUrl)
appCtx.contentResolver.openInputStream(uri)
} else {
File(book.bookUrl).inputStream()
}
input ?: return null
val inZip = ZipInputStream(input)
var zipEntry: ZipEntry?
val resources = Resources()
do {
zipEntry = inZip.nextEntry
if ((zipEntry == null) || zipEntry.isDirectory || zipEntry == ZipEntry("<error>")) continue
val resource = ResourceUtil.createResource(zipEntry, inZip)
if (resource.mediaType == MediaTypes.XHTML) resource.inputEncoding = "UTF-8"
if (zipEntry.name.endsWith(".opf")) {
/*掌上书苑有很多自制书OPF的nameSpace格式不标准,强制修复成正确的格式*/
val newS = String(resource.data).replace(
"\\smlns=\"http://www.idpf.org/2007/opf\"".toRegex(),
" xmlns=\"http://www.idpf.org/2007/opf\""
)
resource.data = newS.toByteArray()
}
resources.add(resource)
} while (zipEntry != null)
if (resources.size() > 0) return EpubReader().readEpub(resources)
val file = BookHelp.getEpubFile(book)
//通过懒加载读取epub
return EpubReader().readEpubLazy(ZipFile(file), "utf-8")
} catch (e: Exception) {
e.printStackTrace()
}

@ -138,6 +138,13 @@ object LocalBook {
val bookFile = FileUtils.getFile(cacheFolder, book.originName)
bookFile.delete()
}
if(book.isEpub()){
val bookFile=BookHelp.getEpubFile(book).parentFile
if (bookFile!=null&&bookFile.exists()){
FileUtils.delete(bookFile,true)
}
}
if (deleteOriginal) {
if (book.bookUrl.isContentScheme()) {

@ -24,7 +24,6 @@ import me.ag2s.epublib.epub.EpubWriter
import me.ag2s.epublib.util.ResourceUtil
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.nio.charset.Charset
@ -184,6 +183,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
}
}
private fun exportEpub(file: File, book: Book) {
val filename = "${book.name} by ${book.author}.epub"
val epubBook = EpubBook()
@ -254,9 +254,12 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
}
private fun setPic(src: String, book: Book, epubBook: EpubBook) {
val href = "${MD5Utils.md5Encode16(src)}${BookHelp.getImageSuffix(src)}"
val vFile = BookHelp.getImage(book, src)
val fp = FileResourceProvider(vFile.parent)
if (vFile.exists()) {
val img = Resource(FileInputStream(vFile), MD5Utils.md5Encode16(src) + ".jpg")
val img = LazyResource(fp, href)
epubBook.resources.add(img)
}
}
@ -275,7 +278,10 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
matchResult.groupValues[1].let {
val src = NetworkUtils.getAbsoluteURL(chapter.url, it)
setPic(src, book, epubBook)
text1 = text1.replace(src, MD5Utils.md5Encode16(src) + ".jpg")
text1 = text1.replace(
src,
"${MD5Utils.md5Encode16(src)}${BookHelp.getImageSuffix(src)}"
)
}
}

@ -54,7 +54,9 @@ object ImageProvider {
ChapterProvider.visibleWidth,
ChapterProvider.visibleHeight
)
if (bitmap != null) {
setCache(chapterIndex, src, bitmap)
}
bitmap
} catch (e: Exception) {
null

@ -9,6 +9,7 @@ import android.renderscript.RenderScript
import android.renderscript.ScriptIntrinsicBlur
import android.view.View
import splitties.init.appCtx
import java.io.FileInputStream
import java.io.IOException
import kotlin.math.*
@ -25,11 +26,13 @@ object BitmapUtils {
* @param height 想要显示的图片的高度
* @return
*/
fun decodeBitmap(path: String, width: Int, height: Int): Bitmap {
fun decodeBitmap(path: String, width: Int, height: Int): Bitmap? {
val op = BitmapFactory.Options()
op.inPreferredConfig = Config.RGB_565
var ips = FileInputStream(path)
// inJustDecodeBounds如果设置为true,仅仅返回图片实际的宽和高,宽和高是赋值给opts.outWidth,opts.outHeight;
op.inJustDecodeBounds = true
BitmapFactory.decodeFile(path, op) //获取尺寸信息
BitmapFactory.decodeStream(ips, null, op)
//获取比例大小
val wRatio = ceil((op.outWidth / width).toDouble()).toInt()
val hRatio = ceil((op.outHeight / height).toDouble()).toInt()
@ -42,21 +45,26 @@ object BitmapUtils {
}
}
op.inJustDecodeBounds = false
return BitmapFactory.decodeFile(path, op)
ips = FileInputStream(path)
return BitmapFactory.decodeStream(ips, null, op)
}
/** 从path中获取Bitmap图片
* @param path 图片路径
* @return
*/
fun decodeBitmap(path: String): Bitmap {
fun decodeBitmap(path: String): Bitmap? {
val opts = BitmapFactory.Options()
opts.inPreferredConfig = Config.RGB_565
var ips = FileInputStream(path)
opts.inJustDecodeBounds = true
BitmapFactory.decodeFile(path, opts)
BitmapFactory.decodeStream(ips, null, opts)
opts.inSampleSize = computeSampleSize(opts, -1, 128 * 128)
opts.inJustDecodeBounds = false
ips = FileInputStream(path)
return BitmapFactory.decodeFile(path, opts)
return BitmapFactory.decodeStream(ips, null, opts)
}
/**

@ -517,6 +517,44 @@ object FileUtils {
closeSilently(fos)
}
}
/**
* 保存文件内容
*/
fun writeInputStream(filepath: String, data: InputStream): Boolean {
val file = File(filepath)
return writeInputStream(file,data)
}
/**
* 保存文件内容
*/
fun writeInputStream(file: File, data: InputStream): Boolean {
var fos: FileOutputStream? = null
return try {
if (!file.exists()) {
file.parentFile?.mkdirs()
file.createNewFile()
}
val buffer=ByteArray(1024*4)
fos = FileOutputStream(file)
while (true) {
val len = data.read(buffer, 0, buffer.size)
if (len == -1) {
break
} else {
fos.write(buffer, 0, len)
}
}
data.close()
fos.flush()
true
} catch (e: IOException) {
false
} finally {
closeSilently(fos)
}
}
/**
* 追加文本内容

@ -0,0 +1,38 @@
package me.ag2s.epublib.domain;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* 用于创建epub添加大文件如大量图片时容易OOM使用LazyResource避免OOM.
*
*/
public class FileResourceProvider implements LazyResourceProvider {
//需要导入资源的父目录
String dir;
/**
* 创建一个文件夹里面文件夹的LazyResourceProvider用于LazyResource
* @param dir 文件的目录
*/
public FileResourceProvider(String dir) {
this.dir = dir;
}
/**
* 创建一个文件夹里面文件夹的LazyResourceProvider用于LazyResource
* @param dirfile 文件夹
*/
@SuppressWarnings("unused")
public FileResourceProvider(File dirfile) {
this.dir = dirfile.getPath();
}
@Override
public InputStream getResourceStream(String href) throws IOException {
return new FileInputStream(new File(dir, href));
}
}

@ -1,19 +1,20 @@
package me.ag2s.epublib.epub;
import me.ag2s.epublib.util.StringUtil;
import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import java.util.ArrayList;
import java.util.List;
import me.ag2s.epublib.util.StringUtil;
/**
* Utility methods for working with the DOM.
*
* @author paul
*
*/
// package
class DOMUtil {
@ -83,6 +84,47 @@ class DOMUtil {
return null;
}
/**
* Gets the first element that is a child of the parentElement and has the given namespace and tagName
*
* @param parentElement parentElement
* @param namespace namespace
* @param tagName tagName
* @return Element
*/
public static NodeList getElementsByTagNameNS(Element parentElement,
String namespace, String tagName) {
NodeList nodes = parentElement.getElementsByTagNameNS(namespace, tagName);
if (nodes.getLength() != 0) {
return nodes;
}
nodes = parentElement.getElementsByTagName(tagName);
if (nodes.getLength() == 0) {
return null;
}
return nodes;
}
/**
* Gets the first element that is a child of the parentElement and has the given namespace and tagName
*
* @param parentElement parentElement
* @param namespace namespace
* @param tagName tagName
* @return Element
*/
public static NodeList getElementsByTagNameNS(Document parentElement,
String namespace, String tagName) {
NodeList nodes = parentElement.getElementsByTagNameNS(namespace, tagName);
if (nodes.getLength() != 0) {
return nodes;
}
nodes = parentElement.getElementsByTagName(tagName);
if (nodes.getLength() == 0) {
return null;
}
return nodes;
}
/**
* Gets the first element that is a child of the parentElement and has the given namespace and tagName
*
@ -97,8 +139,8 @@ class DOMUtil {
if (nodes.getLength() != 0) {
return (Element) nodes.item(0);
}
nodes= parentElement.getElementsByTagName(tagName);
if (nodes.getLength()==0){
nodes = parentElement.getElementsByTagName(tagName);
if (nodes.getLength() == 0) {
return null;
}
return (Element) nodes.item(0);
@ -107,7 +149,7 @@ class DOMUtil {
/**
* The contents of all Text nodes that are children of the given parentElement.
* The result is trim()-ed.
*
* <p>
* The reason for this more complicated procedure instead of just returning the data of the firstChild is that
* when the text is Chinese characters then on Android each Characater is represented in the DOM as
* an individual Text node.

@ -148,9 +148,9 @@ public class NCXDocumentV2 {
if (resource == null) {
Log.e(TAG, "Resource with href " + href + " in NCX document not found");
}
Log.d(TAG, "label:" + label);
Log.d(TAG, "href:" + href);
Log.d(TAG, "fragmentId:" + fragmentId);
Log.v(TAG, "label:" + label);
Log.v(TAG, "href:" + href);
Log.v(TAG, "fragmentId:" + fragmentId);
TOCReference result = new TOCReference(label, resource, fragmentId);
List<TOCReference> childTOCReferences = readTOCReferences(
navpointElement.getChildNodes(), book);

@ -107,12 +107,21 @@ public class NCXDocumentV3 {
if (ncxResource == null) {
return null;
}
//Log.d(TAG, ncxResource.getHref());
//一些epub 3 文件没有按照epub3的标准使用删除掉ncx目录文件
if (ncxResource.getHref().endsWith(".ncx")){
Log.v(TAG,"该epub文件不标准,使用了epub2的目录文件");
return NCXDocumentV2.read(book, epubReader);
}
Log.d(TAG, ncxResource.getHref());
Document ncxDocument = ResourceUtil.getAsDocument(ncxResource);
//Log.d(TAG, ncxDocument.getNodeName());
Log.d(TAG, ncxDocument.getNodeName());
Element navMapElement = (Element) ncxDocument.getElementsByTagName(XHTMLTgs.nav).item(0);
if(navMapElement==null){
Log.d(TAG,"epub3目录文件未发现nav节点,尝试使用epub2的规则解析");
return NCXDocumentV2.read(book, epubReader);
}
navMapElement = (Element) navMapElement.getElementsByTagName(XHTMLTgs.ol).item(0);
Log.d(TAG, navMapElement.getTagName());

@ -22,7 +22,7 @@ import me.ag2s.epublib.util.StringUtil;
/**
* Reads the package document metadata.
*
* <p>
* In its own separate class because the PackageDocumentReader became a bit large and unwieldy.
*
* @author paul
@ -30,7 +30,7 @@ import me.ag2s.epublib.util.StringUtil;
// package
class PackageDocumentMetadataReader extends PackageDocumentBase {
private static final String TAG= PackageDocumentMetadataReader.class.getName();
private static final String TAG = PackageDocumentMetadataReader.class.getName();
public static Metadata readMetadata(Document packageDocument) {
Metadata result = new Metadata();
@ -38,7 +38,7 @@ class PackageDocumentMetadataReader extends PackageDocumentBase {
.getFirstElementByTagNameNS(packageDocument.getDocumentElement(),
NAMESPACE_OPF, OPFTags.metadata);
if (metadataElement == null) {
Log.e(TAG,"Package does not contain element " + OPFTags.metadata);
Log.e(TAG, "Package does not contain element " + OPFTags.metadata);
return result;
}
result.setTitles(DOMUtil
@ -78,6 +78,7 @@ class PackageDocumentMetadataReader extends PackageDocumentBase {
/**
* consumes meta tags that have a property attribute as defined in the standard. For example:
* &lt;meta property="rendition:layout"&gt;pre-paginated&lt;/meta&gt;
*
* @param metadataElement metadataElement
* @return Map<QName, String>
*/
@ -103,6 +104,7 @@ class PackageDocumentMetadataReader extends PackageDocumentBase {
/**
* consumes meta tags that have a property attribute as defined in the standard. For example:
* &lt;meta property="rendition:layout"&gt;pre-paginated&lt;/meta&gt;
*
* @param metadataElement metadataElement
* @return Map<String, String>
*/
@ -128,8 +130,8 @@ class PackageDocumentMetadataReader extends PackageDocumentBase {
if (packageElement == null) {
return null;
}
return packageElement
.getAttributeNS(NAMESPACE_OPF, OPFAttributes.uniqueIdentifier);
return DOMUtil.getAttribute(packageElement, NAMESPACE_OPF, OPFAttributes.uniqueIdentifier);
}
private static List<Author> readCreators(Element metadataElement) {
@ -165,10 +167,10 @@ class PackageDocumentMetadataReader extends PackageDocumentBase {
Date date;
try {
date = new Date(DOMUtil.getTextChildrenContent(dateElement),
dateElement.getAttributeNS(NAMESPACE_OPF, OPFAttributes.event));
DOMUtil.getAttribute(dateElement, NAMESPACE_OPF, OPFAttributes.event));
result.add(date);
} catch (IllegalArgumentException e) {
Log.e(TAG,e.getMessage());
Log.e(TAG, e.getMessage());
}
}
return result;
@ -189,7 +191,7 @@ class PackageDocumentMetadataReader extends PackageDocumentBase {
authorString.substring(spacePos + 1));
}
result.setRole(
authorElement.getAttributeNS(NAMESPACE_OPF, OPFAttributes.role));
DOMUtil.getAttribute(authorElement, NAMESPACE_OPF, OPFAttributes.role));
return result;
}
@ -198,7 +200,7 @@ class PackageDocumentMetadataReader extends PackageDocumentBase {
NodeList identifierElements = metadataElement
.getElementsByTagNameNS(NAMESPACE_DUBLIN_CORE, DCTags.identifier);
if (identifierElements.getLength() == 0) {
Log.e(TAG,"Package does not contain element " + DCTags.identifier);
Log.e(TAG, "Package does not contain element " + DCTags.identifier);
return new ArrayList<>();
}
String bookIdId = getBookIdId(metadataElement.getOwnerDocument());
@ -206,8 +208,7 @@ class PackageDocumentMetadataReader extends PackageDocumentBase {
identifierElements.getLength());
for (int i = 0; i < identifierElements.getLength(); i++) {
Element identifierElement = (Element) identifierElements.item(i);
String schemeName = identifierElement
.getAttributeNS(NAMESPACE_OPF, DCAttributes.scheme);
String schemeName = DOMUtil.getAttribute(identifierElement, NAMESPACE_OPF, DCAttributes.scheme);
String identifierValue = DOMUtil
.getTextChildrenContent(identifierElement);
if (StringUtil.isBlank(identifierValue)) {

@ -36,13 +36,12 @@ import me.ag2s.epublib.util.StringUtil;
* Reads the opf package document as defined by namespace http://www.idpf.org/2007/opf
*
* @author paul
*
*/
public class PackageDocumentReader extends PackageDocumentBase {
private static final String TAG= PackageDocumentReader.class.getName();
private static final String TAG = PackageDocumentReader.class.getName();
private static final String[] POSSIBLE_NCX_ITEM_IDS = new String[]{"toc",
"ncx", "ncxtoc","htmltoc"};
"ncx", "ncxtoc", "htmltoc"};
public static void read(
@ -56,7 +55,7 @@ public class PackageDocumentReader extends PackageDocumentBase {
// Books sometimes use non-identifier ids. We map these here to legal ones
Map<String, String> idMapping = new HashMap<>();
String version=DOMUtil.getAttribute(packageDocument.getDocumentElement(),PREFIX_OPF,PackageDocumentBase.version);
String version = DOMUtil.getAttribute(packageDocument.getDocumentElement(), PREFIX_OPF, PackageDocumentBase.version);
resources = readManifest(packageDocument, packageHref, epubReader,
resources, idMapping);
@ -119,18 +118,18 @@ public class PackageDocumentReader extends PackageDocumentBase {
try {
href = URLDecoder.decode(href, Constants.CHARACTER_ENCODING);
} catch (UnsupportedEncodingException e) {
Log.e(TAG,e.getMessage());
Log.e(TAG, e.getMessage());
}
String mediaTypeName = DOMUtil
.getAttribute(itemElement, NAMESPACE_OPF, OPFAttributes.media_type);
Resource resource = resources.remove(href);
if (resource == null) {
Log.e(TAG,"resource with href '" + href + "' not found");
Log.e(TAG, "resource with href '" + href + "' not found");
continue;
}
resource.setId(id);
//for epub3
String properties=DOMUtil.getAttribute(itemElement,NAMESPACE_OPF,OPFAttributes.properties);
String properties = DOMUtil.getAttribute(itemElement, NAMESPACE_OPF, OPFAttributes.properties);
resource.setProperties(properties);
MediaType mediaType = MediaTypes.getMediaTypeByName(mediaTypeName);
@ -175,14 +174,14 @@ public class PackageDocumentReader extends PackageDocumentBase {
Resource resource = resources.getByHref(StringUtil
.substringBefore(resourceHref, Constants.FRAGMENT_SEPARATOR_CHAR));
if (resource == null) {
Log.e(TAG,"Guide is referencing resource with href " + resourceHref
Log.e(TAG, "Guide is referencing resource with href " + resourceHref
+ " which could not be found");
continue;
}
String type = DOMUtil
.getAttribute(referenceElement, NAMESPACE_OPF, OPFAttributes.type);
if (StringUtil.isBlank(type)) {
Log.e(TAG,"Guide is referencing resource with href " + resourceHref
Log.e(TAG, "Guide is referencing resource with href " + resourceHref
+ " which is missing the 'type' attribute");
continue;
}
@ -201,7 +200,7 @@ public class PackageDocumentReader extends PackageDocumentBase {
/**
* Strips off the package prefixes up to the href of the packageHref.
*
* <p>
* Example:
* If the packageHref is "OEBPS/content.opf" then a resource href like "OEBPS/foo/bar.html" will be turned into "foo/bar.html"
*
@ -241,31 +240,32 @@ public class PackageDocumentReader extends PackageDocumentBase {
.getFirstElementByTagNameNS(packageDocument.getDocumentElement(),
NAMESPACE_OPF, OPFTags.spine);
if (spineElement == null) {
Log.e(TAG,"Element " + OPFTags.spine
Log.e(TAG, "Element " + OPFTags.spine
+ " not found in package document, generating one automatically");
return generateSpineFromResources(resources);
}
Spine result = new Spine();
String tocResourceId = DOMUtil
.getAttribute(spineElement, NAMESPACE_OPF, OPFAttributes.toc);
result
.setTocResource(findTableOfContentsResource(tocResourceId, resources));
NodeList spineNodes = packageDocument
.getElementsByTagNameNS(NAMESPACE_OPF, OPFTags.itemref);
List<SpineReference> spineReferences = new ArrayList<>(
spineNodes.getLength());
String tocResourceId = DOMUtil.getAttribute(spineElement, NAMESPACE_OPF, OPFAttributes.toc);
Log.v(TAG,tocResourceId);
result.setTocResource(findTableOfContentsResource(tocResourceId, resources));
NodeList spineNodes = DOMUtil.getElementsByTagNameNS(packageDocument, NAMESPACE_OPF, OPFTags.itemref);
if(spineNodes==null){
Log.e(TAG,"spineNodes is null");
return result;
}
List<SpineReference> spineReferences = new ArrayList<>(spineNodes.getLength());
for (int i = 0; i < spineNodes.getLength(); i++) {
Element spineItem = (Element) spineNodes.item(i);
String itemref = DOMUtil
.getAttribute(spineItem, NAMESPACE_OPF, OPFAttributes.idref);
String itemref = DOMUtil.getAttribute(spineItem, NAMESPACE_OPF, OPFAttributes.idref);
if (StringUtil.isBlank(itemref)) {
Log.e(TAG,"itemref with missing or empty idref"); // XXX
Log.e(TAG, "itemref with missing or empty idref"); // XXX
continue;
}
String id = idMapping.get(itemref);
if (id == null) {
id = itemref;
}
Resource resource = resources.getByIdOrHref(id);
if (resource == null) {
Log.e(TAG, "resource with id '" + id + "' not found");
@ -308,7 +308,7 @@ public class PackageDocumentReader extends PackageDocumentBase {
/**
* The spine tag should contain a 'toc' attribute with as value the resource id of the table of contents resource.
*
* <p>
* Here we try several ways of finding this table of contents resource.
* We try the given attribute value, some often-used ones and finally look through all resources for the first resource with the table of contents mimetype.
*
@ -318,7 +318,13 @@ public class PackageDocumentReader extends PackageDocumentBase {
*/
static Resource findTableOfContentsResource(String tocResourceId,
Resources resources) {
Resource tocResource = null;
Resource tocResource;
//一些epub3的文件为了兼容epub2,保留的epub2的目录文件,这里优先选择epub3的xml目录
tocResource = resources.getByProperties("nav");
if (tocResource != null) {
return tocResource;
}
if (StringUtil.isNotBlank(tocResourceId)) {
tocResource = resources.getByIdOrHref(tocResourceId);
}
@ -343,10 +349,7 @@ public class PackageDocumentReader extends PackageDocumentBase {
}
}
}
//For EPUB3
if (tocResource==null){
tocResource=resources.getByProperties("nav");
}
if (tocResource == null) {
Log.e(TAG,

@ -2,16 +2,6 @@ package me.ag2s.epublib.epub;
import android.util.Log;
import me.ag2s.epublib.domain.EpubResourceProvider;
import me.ag2s.epublib.domain.LazyResource;
import me.ag2s.epublib.domain.LazyResourceProvider;
import me.ag2s.epublib.domain.MediaType;
import me.ag2s.epublib.domain.MediaTypes;
import me.ag2s.epublib.domain.Resource;
import me.ag2s.epublib.domain.Resources;
import me.ag2s.epublib.util.CollectionUtil;
import me.ag2s.epublib.util.ResourceUtil;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
@ -22,6 +12,16 @@ import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import me.ag2s.epublib.domain.EpubResourceProvider;
import me.ag2s.epublib.domain.LazyResource;
import me.ag2s.epublib.domain.LazyResourceProvider;
import me.ag2s.epublib.domain.MediaType;
import me.ag2s.epublib.domain.MediaTypes;
import me.ag2s.epublib.domain.Resource;
import me.ag2s.epublib.domain.Resources;
import me.ag2s.epublib.util.CollectionUtil;
import me.ag2s.epublib.util.ResourceUtil;
/**
* Loads Resources from inputStreams, ZipFiles, etc
@ -72,6 +72,12 @@ public class ResourcesLoader {
} else {
resource = ResourceUtil
.createResource(zipEntry, zipFile.getInputStream(zipEntry));
/*掌上书苑有很多自制书OPF的nameSpace格式不标准,强制修复成正确的格式*/
if (href.endsWith("opf")) {
String string = new String(resource.getData()).replace("smlns=\"", "xmlns=\"");
resource.setData(string.getBytes());
}
}
if (resource.getMediaType() == MediaTypes.XHTML) {
@ -123,9 +129,15 @@ public class ResourcesLoader {
if ((zipEntry == null) || zipEntry.isDirectory()) {
continue;
}
String href = zipEntry.getName();
// store resource
Resource resource = ResourceUtil.createResource(zipEntry, zipInputStream);
///*掌上书苑有很多自制书OPF的nameSpace格式不标准,强制修复成正确的格式*/
if (href.endsWith("opf")) {
String string = new String(resource.getData()).replace("smlns=\"", "xmlns=\"");
resource.setData(string.getBytes());
}
if (resource.getMediaType() == MediaTypes.XHTML) {
resource.setInputEncoding(defaultHtmlEncoding);
}

@ -1,5 +1,7 @@
package me.ag2s.epublib.util;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.EOFException;
@ -18,6 +20,7 @@ import java.nio.CharBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.Charset;
import me.ag2s.epublib.epub.PackageDocumentReader;
import me.ag2s.epublib.util.commons.io.IOConsumer;
/**
@ -28,6 +31,7 @@ import me.ag2s.epublib.util.commons.io.IOConsumer;
* and using my own implementation saves the inclusion of a 200Kb jar file.
*/
public class IOUtil {
private static final String TAG = IOUtil.class.getName();
/**
* Represents the end-of-file (or stream).
@ -142,11 +146,7 @@ public class IOUtil {
//
public static void copy(InputStream in, OutputStream result) throws IOException {
int buffer=in.available();
if(buffer>IOUtil.DEFAULT_BUFFER_SIZE||buffer==0){
buffer=IOUtil.DEFAULT_BUFFER_SIZE;
}
copy(in, result,buffer);
copy(in, result,DEFAULT_BUFFER_SIZE);
}
/**
@ -450,6 +450,7 @@ public class IOUtil {
output.write(buffer, 0, n);
count += n;
}
//input.close();
}
return count;
}

Loading…
Cancel
Save