PDF文档转换成mobi格式(for kindle),并解决排版问题

您所在的位置:网站首页 pdf是图像格式吗为什么 PDF文档转换成mobi格式(for kindle),并解决排版问题

PDF文档转换成mobi格式(for kindle),并解决排版问题

2024-07-12 09:40| 来源: 网络整理| 查看: 265

PDF文档转换成mobi格式,并解决排版问题 0. 前言1. 下载和安装calibre2. PDF导入calibre,并转换为azw3格式3. 编辑电子书,获取HTML内容和图片4. 程序处理HTML文档5. 将HTML文档导入calibre,并转换成azw3格式6. 编辑azw3文档7. 将azw3文档转换成mobi格式8. 附录

0. 前言

正式介绍之前,先回答下面几个问题: 在这里插入图片描述

1. 为什么要将PDF转换成mobi? 想要将PDF转换成mobi格式,初衷在于想在kindle上面看一些从网上获取到的PDF文档。直接将PDF导入kindle本来也可以,但是效果不是很好——要么竖着看,但是字体很小;要么横着看,字体会大一些,但是总感觉比较别扭,而且PDF的一页需要在kindle上翻3页。 kindle支持azw3、mobi等格式,但是不支持直接将azw3格式的文档直接导入到kindle,所以需要将PDF文档转换成mobi格式

2. 为什么不直接用在线转换工具? 其实网上有很多工具支持将PDF转换成mobi格式,但是效果都很差:

章节标题和正文内容没有区别;正文内容格式混乱,在kindle上看是以PDF的一行进行的分段,行首也没有空格 在这里插入图片描述

3. 将PDF转换成mobi格式,我大概怎么做? 将PDF转换成mobi格式,我主要是借助于calibre工具: 在这里插入图片描述

4. 转换效果如何? 转换之后效果如下图,其中对章节标题和段落划分进行了处理: 在这里插入图片描述

1. 下载和安装calibre

calibre下载地址: https://calibre-ebook.com/download

根据自己的系统下载安装即可

2. PDF导入calibre,并转换为azw3格式

打开calibre,点击菜单栏的“添加数据”,选择PDF格式文件,点击“Open” 在这里插入图片描述 在calibre的主窗口中选中刚导入的图书,点击菜单栏的“转换书籍”,在弹出的转换窗口,将输出格式选择为“AZW3”,然后点击“确定”。

转换过程可能会持续一小段时间,看calibre主窗口右下角的任务执行结束即转换完成 在这里插入图片描述 【注】这里有一个坑,图书转换的设置,目录针对章节有一个默认的最大值,需要根据图书的实际情况进行调整。我一般将两个值分别设置为1000,50 在这里插入图片描述

3. 编辑电子书,获取HTML内容和图片

在calibre主窗口选中目标电子书,点击菜单栏的“编辑书籍”打开编辑书籍窗口

在编辑书籍窗口,选中文本下的“part0000.html”,点击右键,选择“导出part0000.html”

同样的方式,全选图片下的所有图片,然后导出 在这里插入图片描述

4. 程序处理HTML文档

由上一步可以看到,直接由PDF转换得到的HTML文档,PDF里面的每一行转换之后在HTML文档中都独立成了一段,而且段首也没有空格,章节标题也没有突出展示。 在这里插入图片描述 针对这个问题,于是自己写了一段Java代码,主要是根据语义对文档内容进行分段,同时将标题突出,然后将每一张的起始位置独立成页。

具体的代码见文末,里面也有比较详细的注释,有一些特殊情况的处理可以根据自己的要求适当修改代码。 在这里插入图片描述

5. 将HTML文档导入calibre,并转换成azw3格式

首先,将calibre中已有的同名电子书删掉,操作方式是:在calibre主窗口,选中要删除的电子书,右键,选择“移除书籍” > “移除选定书籍”,之后在弹出窗口做二次确认 在这里插入图片描述 然后,将处理之后的HTML文档导入到calibre,操作方式同第2章。

最后,由于直接导入的HTML文档是ZIP格式,不能直接进行编辑,所以需要再次将文档转换成azw3格式,操作方式同第3章。可以看到,导入HTML文档之后,图书的封面丢失了,可以在转换的时候,直接修改封面图(可以用第3章导出保存的图片),如下图: 在这里插入图片描述

6. 编辑azw3文档

这一步是非必须的,但是如果电子书中有插图,那么就需要在这一步进行补充。另外也可以在文件预览中检查各个HTML文件,如有必要,也可以进行简单编辑。

进入编辑操作同第3章所介绍,这里主要介绍一下补充图片。

在编辑书籍窗口,点击菜单栏的“新增文件”按钮。

然后在弹出框选择“导入文件”,选择需要导入的图片。注意,文件的路径最终要是“images/xx”格式。

最后点击“确定”。

如果有多张图片,则重复上面的操作。目前calibre不支持批量导入。

编辑完成之后,点击编辑书籍窗口菜单栏的“保存”按钮进行保存。 在这里插入图片描述

7. 将azw3文档转换成mobi格式

在calibre主窗口,选中电子书,点击“转换书籍”,在弹出窗口中,输入格式选择“AZW3” ,输出格式选择“MOBI”。点击“确定”。然后等转换任务结束。 在这里插入图片描述 转换结束之后,在calibre主窗口,选中电子书,在右侧边栏,点击“点击打开”即可获取到mobi格式的电子书。然后将其共享至kindle就可以了。 在这里插入图片描述

8. 附录

推荐的PDF电子书网址: http://www.80pdf.com/ (大家有其他好的电子书链接也欢迎评论区共享。)

HTML格式文档处理代码:

package com.amwalle.walle.util; import org.springframework.util.StringUtils; import java.io.*; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; public class PDFConverter { public static void main(String[] args) throws IOException { Scanner scanner = new Scanner(System.in); System.out.println("请输入要转换的文件路径: "); String filePath = scanner.nextLine(); System.out.println(filePath); convert(filePath); } public enum HeaderLevel { Part("H1", ".*第.*部分.*"), Chapter("H2", "(.*第.*章.*)|(.*[1-9].*)"); private String headerLevel; private String expression; HeaderLevel(String headerLevel, String expression) { this.headerLevel = headerLevel; this.expression = expression; } public static String getHeaderLevel(String input) { if (StringUtils.isEmpty(input) || (!input.contains("") && !input.contains("

"))) { return null; } String dummy = preHandleHeader(input); for (HeaderLevel level : HeaderLevel.values()) { Pattern pattern = Pattern.compile(level.expression); Matcher matcher = pattern.matcher(dummy); if (matcher.find()) { return level.headerLevel; } } return null; } private static String preHandleHeader(String input) { String dummy = input; if (input.contains("") && input.contains("

")) { dummy = dummy.substring(dummy.indexOf("") + 4, dummy.indexOf("

")); } else if (input.contains("

") && input.contains("

")) { dummy = dummy.substring(dummy.indexOf("

") + 20, dummy.indexOf("

")); } dummy = dummy.replaceAll(" ", ""); dummy = dummy.replaceAll("", ""); dummy = dummy.replaceAll(" ", ""); dummy = dummy.replaceAll("", ""); dummy = removeSpace(dummy); return dummy; } public String getHeaderLevel() { return headerLevel; } public void setHeaderLevel(String headerLevel) { this.headerLevel = headerLevel; } public String getExpression() { return expression; } public void setExpression(String expression) { this.expression = expression; } } public static void convert(String filePath) throws IOException { File file = new File(filePath); if (!file.isFile() || !file.canRead() || !file.getName().endsWith(".html")) { System.out.println("请输入正确的html文件路径,并保证文件可读!"); } String title = file.getName(); title = title.replace(".html", ""); File outFile = new File(filePath.replace(".html", "1.html")); if (outFile.exists()) { outFile.delete(); outFile.createNewFile(); } try (Scanner scanner = new Scanner(file, "UTF-8"); BufferedWriter outWriter = new BufferedWriter(new FileWriter(outFile))) { Set catalog = new HashSet(); StringBuffer output = new StringBuffer(); boolean isIndentationNeeded = false; int count = 0; while (scanner.hasNextLine()) { count++; // 有些文件太大,需要在中间存一下文件 if (count >= 10000) { outWriter.append(output); count = 0; output.delete(0, output.length()); } String line = scanner.nextLine(); // 目录前面的内容(封面、版权等) if (catalog.isEmpty() && !line.startsWith("

") + 2, line.indexOf("

")); temp = removeSpace(temp); catalog.add(temp); continue; } if (StringUtils.isEmpty(line)) { output.append("\n"); continue; } // 处理章节标题 if (isLineATitle(line, catalog)) { isIndentationNeeded = true; String titleLevel = HeaderLevel.getHeaderLevel(line); if (HeaderLevel.Part.headerLevel.equals(titleLevel)) { output.append(addPagination(title)); output.append("").append(line).append("").append("\n"); continue; } if (HeaderLevel.Chapter.headerLevel.equals(titleLevel)) { output.append(addPagination(title)); output.append("").append(line).append("").append("\n"); continue; } output.append("").append(line).append("").append("\n"); continue; } // 首行缩进 if (isIndentationNeeded) { line = line.replace("

", "

"); line = line.replace("

", ""); output.append(line).append("\n"); isIndentationNeeded = false; continue; } // 文本内容分段 if (isParagraphEnd(line)) { isIndentationNeeded = true; line = line.replace("

", ""); line = line.replace("

", ""); output.append(line).append("\n"); continue; } // 普通行处理:去掉换行 if (line.startsWith("

") && line.endsWith("

")) { line = line.replace("

", ""); line = line.replace("

", ""); output.append(line); continue; } output.append(line).append("\n"); } outWriter.append(output); System.out.println("********************************************"); System.out.println("Done! 生成的新文件路径: "); System.out.println(outFile.getPath()); } catch (FileNotFoundException e) { System.out.println("File convert failed!"); e.printStackTrace(); } } private static String removeSpace(String input) { String result = input.trim().replaceAll("\\.", "").replaceAll("·", ""); result = result.replaceAll("\\s*", "").replaceAll("\\u00a0", "").replaceAll((char) 12288 + "", ""); return result; } private static String addPagination(String title) { return "\n" + "\n" + "\n" + "\n" + "\n" + "" + title + "\n" + " \n" + " \n" + "\n" + "\n" + "\n"; } private static boolean isLineATitle(String input, Set catalog) { if (StringUtils.isEmpty(input) || (!input.contains("") && !input.contains("

"))) { return false; } String dummy = HeaderLevel.preHandleHeader(input); for (String catalogEntry : catalog) { if (StringUtils.isEmpty(catalogEntry)) { continue; } if (catalogEntry.equals(dummy)) { return true; } } return false; } private static boolean isParagraphEnd(String input) { Pattern pattern = Pattern.compile(".*(\\w

)$"); Matcher matcher = pattern.matcher(input); if (matcher.matches()) { return false; } // 句子结尾的标点符号:./!/?/……/"」 (英文+中文) Pattern pattern1 = Pattern.compile(".*(([\\.|!|\\?|\"|\\u3002|\\uff01|\\uff1f|\\u2026|\\u201d|\\u300d])|(\\. ))

$"); Matcher matcher1 = pattern1.matcher(input); return matcher1.matches(); } }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3