Epub电子书切割
准备
这里我用到了Epublib这个jar包,详细资料参考下方
maven库搜索 epublib-core ,kxml2
pom文件引入依赖
<!-- https://mvnrepository.com/artifact/nl.siegmann.epublib/epublib-core -->
<dependency>
<groupId>nl.siegmann.epublib</groupId>
<artifactId>epublib-core</artifactId>
<version>3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/net.sf.kxml/kxml2 -->
<dependency>
<groupId>net.sf.kxml</groupId>
<artifactId>kxml2</artifactId>
<version>2.3.0</version>
</dependency>
分析
epub电子书结构
可以很清楚看见是由xhtml文件组成资源。关于content.opf ,toc.nxc等这些本来就是属于电子书的数据结构文件,可以自行网上查阅。
epublib中book数据结构
Resource数据结构
Resources类中又有一个HashMap,HashMap中的value为Resource,Resource的数据结构如下:
Metadata
Book里的Metadata相当于电子书的头部,可以获取电子书的基本数据,数据结构如下:
Spine
Book中的骨架结构,用来链接Book资源文件,数据结构如下
Resource 与ResourceReference 为关联,SpineReference是ResourceReference的父类。
在设置好Resouces后一定要设置相应的Spine中的Resouce,不然电子书打开,会无法识别。
TableOfContents
Book中目录对应的数据结构。有目录的名字,目录对应的Resource,对应的数据结构如下:
实战
Demo代码如下:
/**
* @Description: 按章节切分 电子书
* @Author: ouyangkang
* @CreateDate: 2018/9/28 17:41
* @Param [url]
*/
public static void segmentation(String url){
try {
// 获取网络资源
URL urlResource = new URL(url) ;
// 打开链接
HttpURLConnection conn = (HttpURLConnection) urlResource.openConnection();
// 建立链接
conn.connect();
// 读取电子书流
EpubReader epubReader = new EpubReader();
// 获取电子书
InputStream inputStream = conn.getInputStream();
if (inputStream == null){
return;
}
if (epubReader == null){
return;
}
Book book = epubReader.readEpub(inputStream);
if (book == null){
return;
}
// 获取电子书目录
TableOfContents tableOfContents = book.getTableOfContents();
// 电子书章节封装资源
List<SpineReference> spineReferences = book.getSpine().getSpineReferences();
// 电子书 章节Id 集合
List<String> resourceIds = new ArrayList<>(16);
// 获取所有资源href
Set<String> hrefs = (Set<String>) book.getResources().getAllHrefs();
// css 资源文件
List<String> hrefCss = new ArrayList<>();
hrefs.stream().forEach(href -> {
if (href.contains(".css")){
hrefCss.add(href);
}
});
spineReferences.stream().forEach(spineReference -> {
// 获取章节Id
resourceIds.add(spineReference.getResourceId());
});
// 电子书章节资源
Resources resources = new Resources();
// 写入电子书
EpubWriter epubWriter = new EpubWriter();
resourceIds.stream().forEach(resourceId -> {
// 电子书章节
Book bookChapter = new Book();
//章节导航
Spine spine = new Spine();
if (hrefCss.size() > 0){
hrefCss.stream().forEach(href -> {
resources.add(book.getResources().getByHref(href));
});
}
nl.siegmann.epublib.domain.Resource resource = book.getResources().getById(resourceId);
resources.add(resource);
// 获取图片资源
try {
String imageData = new String(resource.getData(),"UTF-8");
// 获取图片源
List<String> imagesHrefs = getImgSrc(imageData);
//添加该章节下的图片资源
imagesHrefs.stream().forEach(imagesHref -> {
nl.siegmann.epublib.domain.Resource resourceImage = book.getResources().getByHref(imagesHref);
resources.add(resourceImage);
});
//设置电子书资源
// 设置电子书导航文件
nl.siegmann.epublib.domain.Resource tocResource = book.getResources().getById("ncx");
if (tocResource != null){
// 发现有的电子书并不存在 toc.ncx 而是以一种toc.xhtml的文件存在
if (tocResource.getHref().contains("toc.ncx")) {
spine.setTocResource(tocResource);
} else {
resources.add(tocResource);
}
}
//添加章节资源
bookChapter.setResources(resources);
// 添加该章节骨架
spine.addSpineReference(new SpineReference(book.getResources().getById(resourceId)));
bookChapter.setSpine(spine);
// 添加该书的所有目录
bookChapter.setTableOfContents(tableOfContents);
//文件写入地址
String path = "D:\\ebook\\"+resourceId+".epub";
File file = new File(path);
if (!file.getParentFile().exists()){
file.getParentFile().mkdir();
}
epubWriter.write(bookChapter, new FileOutputStream(file));
} catch (IOException e) {
e.printStackTrace();
}finally {
conn.disconnect();
}
});
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 获取img标签中的src值
* @param content
* @return
*/
public static List<String> getImgSrc(String content){
List<String> list = new ArrayList<String>();
//目前img标签标示有3种表达式
//<img alt="" src="1.jpg"/> <img alt="" src="1.jpg"></img> <img alt="" src="1.jpg">
//开始匹配content中的<img />标签
Pattern p_img = Pattern.compile("<(img|IMG|image|IMAGE)(.*?)(/>|></img>|>|></image)");
Matcher m_img = p_img.matcher(content);
boolean result_img = m_img.find();
if (result_img) {
while (result_img) {
//获取到匹配的<img />标签中的内容
String str_img = m_img.group(2);
//开始匹配<img />标签中的src
Pattern p_src = Pattern.compile("(src|SRC|href|HREF)=(\"|\')(.*?)(\"|\')");
Matcher m_src = p_src.matcher(str_img);
if (m_src.find()) {
String str_src = m_src.group(3);
if (str_src.contains("Image")){
str_src = str_src.substring(str_src.indexOf("I"),str_src.length());
}else {
str_src = str_src.substring(str_src.indexOf("i"),str_src.length());
}
list.add(str_src);
}
//结束匹配<img />标签中的src
//匹配content中是否存在下一个<img />标签,有则继续以上步骤匹配<img />标签中的src
result_img = m_img.find();
}
}
return list;
}