700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 使用itext为已有的pdf文档生成书签

使用itext为已有的pdf文档生成书签

时间:2024-03-20 03:41:15

相关推荐

使用itext为已有的pdf文档生成书签

代码具有很强的局限性,并不适合所有的电子书目录。代码生成目录主要是针对于 《啊哈!算法》,其他的目录结构可能生成结果不符合预期。

有些时候我们下载的电子书没有书签,虽然不影响阅读,但是使用体验很差,尤其是需要跳转时。因为之前在项目中也是用过itext用于生成企业的信用报告(图片,目录,水印,锚点),所以相对来说比较熟悉些,看过官网的文档也知道可以实现。然后就在网上找了些demo试着使用itext生成书签,解放双手。

准备

该版本比较简单,局限性特别大,只能识别特定的简单目录结构。

引入依赖

<dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.11</version></dependency>

获取PDF文档的目录

在当当上或者京东等网站上找到对应的书籍,在商品介绍里面一般都会提供书籍的目录信息。复制目录,并对目录做一些小的处理。

复制的目录中的空格是中文空格,需要将所有的中文空格修改为英文空格。当然也可以使用中文空格(代码需要修改)为了操作方便,删除了“目录”文本部分。当然也可以对目录页也添加对应的页码关系需要手动的找出文档正文的起始页码。 比如啊哈!算法的正文是第13页。如果想要把目录也放在文件中,需要进行文本转码(utf-8)。Windows记事本的转码的utf8文件实际上是utf-8-bom,这种格式是不对的。

啊哈!算法。 文本中带目录对应页码信息的的文本。注意需要手动的找出目录对应的实际页数

目录 11第1章 一大波数正在靠近——排序 1第1节 最快最简单的排序——桶排序 2第2节 邻居好说话——冒泡排序 7第3节 最常用的排序——快速排序 12第4节 小哼买书 20..............................

spring源码解析的目录

第一部分 核心实现第1章 Spring整体架构和环境搭建 21.1 Spring的整体架构 21.2 环境搭建 41.2.1 安装GitHub 41.2.2 安装Gradle 51.2.3 下载Spring 6第2章 容器的基本实现 102.1 容器基本用法 102.2 功能分析 112.3 工程搭建 12。。。。。。。。。。.。。。。

代码针对了这两种格式的目录文件(嗯,第二种没有测试,可能有问题)。

生成书签

下面以啊哈!算法的书签生成为例

手动的找到正文的实际页码,即“第1章 一大波数正在靠近——排序 1 ”是第13页。

代码

注意需要对目录文件进行utf8转码(utf8-no-bom),utf8转码,utf8转码,utf8转码,utf8转码,可以使用editplus等文本编辑工具来修改编码。Windows记事本的转码是utf-8-with-bom。

不进行转码的话,书签会生成失败。因为下面代码永不执行。因为使用IDE工具会发现,

sectionNumberStr实际上等于"\ufeff目录"。这是因为Microsoft 建议所有的 Unicode 文件应该以\uFEFF字符开头,作为标记字节顺序存储的标记。标准的utf8编码是不需要设置 这个字节顺序标记。

else if("目录".equals(sectionNumberStr)){}

该方式需要传入目录对应的实际页码

目录 11第1章 一大波数正在靠近——排序 1第1节 最快最简单的排序——桶排序 2第2节 邻居好说话——冒泡排序 7第3节 最常用的排序——快速排序 12第4节 小哼买书 20

import com.itextpdf.text.Document;import com.itextpdf.text.DocumentException;import com.itextpdf.text.pdf.*;import java.io.BufferedReader;import java.io.FileOutputStream;import java.io.FileReader;import java.io.IOException;import java.util.*;import java.util.regex.Matcher;import java.util.regex.Pattern;public class GenerateBookmarkUtil {private Pattern spacePattern = pile("\\s*");public static void main(String[] args) {GenerateBookmarkUtil zcc = new GenerateBookmarkUtil();String sourceDocPath = "E:\\BaiduNetdiskDownload\\啊哈!算法.pdf"; //电子书路径String sourceTextPath = "C:\\Users\\Administrator\\Desktop\\aha.txt";//生成的目录文本路径String desFilename = "D:\\testhaha1.pdf"; // 生成的带有目录的文件的路径(问价是复制,不是覆盖)try {zcc.createPdf(sourceTextPath, sourceDocPath, desFilename,13);} catch (DocumentException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}/***@param sTxtPath 书签文件的路径*@param sPdfPath 需要生成书签的文件*@param filename 生成书签后的文件路径*@param startPage 正文的实际页数-1*/public void createPdf(String sTxtPath, String sPdfPath, String filename,int startPage) throws DocumentException, IOException {if(startPage>0)startpage--;//可以创建新的文件,也可以直接操作源文件,添加书签// step 1Document document = new Document();// step 2 输出文件PdfCopy writer = new PdfCopy(document, new FileOutputStream(filename)); // step 3writer.setViewerPreferences(PdfWriter.PageModeUseOutlines);//设置打开pdf文件时显示书签document.open();// step 4 逐页读入pdf文件并写入输出文件PdfReader reader = new PdfReader(sPdfPath);int n = reader.getNumberOfPages();for (int page = 1; page <= n; page++) {writer.addPage(writer.getImportedPage(reader, page));}writer.freeReader(reader);// step 5 添加书签PdfOutline root = writer.getRootOutline();PdfAction action;//标识书签点击后的跳转动作,通过它设置跳转的页码try {//读入保存书签的TXT文件,分拆为书签名及跳转页码;BufferedReader bufRead = new BufferedReader(new FileReader(sTxtPath));String str;String[] ss = null;int skipPage = startPage; //正文书签跳过的页数/*数据的存储结构** page 页码*title 标题* kids 子书签 page,title ,kids*/List<Map<String, Object>> outlines = new ArrayList<>();//存放解析的数据String pageNumStr = null;int pageNum = 0;//遍历读取目录文件,每次读取一行,并解析出该行的标题和页码值while ((str = bufRead.readLine()) != null) {String title = "";int parentPage = 0;String childTitle = "";int childPage = 0;str = str.trim();//过滤空行Matcher matcher = spacePattern.matcher(str);if (matcher.matches()) {continue;}//获取页码ss = str.split(" ");pageNumStr = ss[ss.length - 1].trim();//不包含页码的标题for (int j = 0; j < ss.length - 1; j++) {title += ss[j] + " ";}if (pageNumStr.matches("\\d+")) {//存在页码try {pageNum = Integer.valueOf(pageNumStr);pageNum += skipPage;} catch (Exception e) {}String category="目录";String sectionNumberStr = ss[0]; //获取标题的序号if (sectionNumberStr.contains("章")) {//章节List<Map<String, Object>> kids = null;kids = new ArrayList();Map<String, Object> chapterMap = new HashMap<>();chapterMap.put("title", title);chapterMap.put("page", pageNum);chapterMap.put("kids", kids);outlines.add(chapterMap);}else if("目录".equals(sectionNumberStr)){//目录书签new PdfOutline(root,PdfAction.gotoLocalPage(pageNum-skipPage, new PdfDestination(PdfDestination.FIT), writer), "目 录");}else {//小节List<Map<String, Object>> kids = (List<Map<String, Object>>) outlines.get(outlines.size() - 1).get("kids");//将小节添追加到自书签列表Map<String, Object> littleChapter = new HashMap<>();littleChapter.put("title", title);littleChapter.put("page", pageNum);littleChapter.put("kids", new ArrayList<>());kids.add(littleChapter);}} else {//不存在页码,可能是大标题 或者目录 例如:第一部分 核心实现Map<String, Object> bigSection = new HashMap<>();bigSection.put("title", title);bigSection.put("page", -1);bigSection.put("kids", new ArrayList<>());outlines.add(bigSection);}}//数据遍历,添加书签outlines.forEach(map -> {String sectionTitle = (String) map.get("title");int page = (int) map.get("page");List<Map<String, Object>> kids = (List<Map<String, Object>>) map.get("kids");PdfOutline sectionOutline = null;if (page < 0) {//该部分是大类别int parentPage = (int) kids.get(0).get("page") - 1; //获取大分类的页数,一般就是子目录页数减一PdfAction action1 = PdfAction.gotoLocalPage(parentPage,new PdfDestination(PdfDestination.FIT), writer);//设置书签动作sectionOutline = new PdfOutline(root, action1, sectionTitle, false); //大分类的} else {PdfAction action1 = PdfAction.gotoLocalPage(page,new PdfDestination(PdfDestination.FIT), writer);//设置书签动作sectionOutline = new PdfOutline(root, action1, sectionTitle, false); //一级章节标题;}for (Map<String, Object> kid : kids) {//一级章节String firstTitle = (String) kid.get("title");int firstPage = (int) kid.get("page");List<Map<String, Object>> firstKids = (List<Map<String, Object>>) kid.get("kids");PdfAction action2 = PdfAction.gotoLocalPage(firstPage,new PdfDestination(PdfDestination.FIT), writer);//设置书签动作PdfOutline firstOutline = new PdfOutline(sectionOutline, action2, firstTitle, false); //一级标题的outlinefor (Map<String, Object> secondKid : firstKids) {//二级章节String secondTitle = (String) kid.get("title");int secondPage = (int) kid.get("page");List<Map<String, Object>> secondKids = (List<Map<String, Object>>) kid.get("kids");PdfAction action3 = PdfAction.gotoLocalPage(secondPage,new PdfDestination(PdfDestination.FIT), writer);//设置书签动作PdfOutline secondOutline = new PdfOutline(firstOutline, action2, secondTitle, false); //二级标题的outline}}});} catch (IOException ioe) {}document.close();}}

生成好的书签。代码的局限性比较高,可以自定义自己的书签类

参考文章:使用itext写的pdf文件添加书签的小工具

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。