使用itext为已有的pdf文档生成书签
代碼具有很強的局限性,并不適合所有的電子書目錄。代碼生成目錄主要是針對于 《啊哈!算法》,其他的目錄結(jié)構(gòu)可能生成結(jié)果不符合預(yù)期。
有些時候我們下載的電子書沒有書簽,雖然不影響閱讀,但是使用體驗很差,尤其是需要跳轉(zhuǎn)時。因為之前在項目中也是用過itext用于生成企業(yè)的信用報告(圖片,目錄,水印,錨點),所以相對來說比較熟悉些,看過官網(wǎng)的文檔也知道可以實現(xiàn)。然后就在網(wǎng)上找了些demo試著使用itext生成書簽,解放雙手。
準(zhǔn)備
該版本比較簡單,局限性特別大,只能識別特定的簡單目錄結(jié)構(gòu)。
引入依賴
<dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.11</version> </dependency>獲取PDF文檔的目錄
在當(dāng)當(dāng)上或者京東等網(wǎng)站上找到對應(yīng)的書籍,在商品介紹里面一般都會提供書籍的目錄信息。復(fù)制目錄,并對目錄做一些小的處理。
啊哈!算法。 文本中帶目錄對應(yīng)頁碼信息的的文本。注意需要手動的找出目錄對應(yīng)的實際頁數(shù)
目錄 11 第1章 一大波數(shù)正在靠近——排序 1第1節(jié) 最快最簡單的排序——桶排序 2第2節(jié) 鄰居好說話——冒泡排序 7第3節(jié) 最常用的排序——快速排序 12第4節(jié) 小哼買書 20..............................spring源碼解析的目錄
第一部分 核心實現(xiàn)第1章 Spring整體架構(gòu)和環(huán)境搭建 2 1.1 Spring的整體架構(gòu) 2 1.2 環(huán)境搭建 4 1.2.1 安裝GitHub 4 1.2.2 安裝Gradle 5 1.2.3 下載Spring 6第2章 容器的基本實現(xiàn) 10 2.1 容器基本用法 10 2.2 功能分析 11 2.3 工程搭建 12 。。。。。。。。。。.。。。。代碼針對了這兩種格式的目錄文件(嗯,第二種沒有測試,可能有問題)。
生成書簽
下面以啊哈!算法的書簽生成為例
手動的找到正文的實際頁碼,即“第1章 一大波數(shù)正在靠近——排序 1 ”是第13頁。
代碼
注意需要對目錄文件進(jìn)行utf8轉(zhuǎn)碼(utf8-no-bom),utf8轉(zhuǎn)碼,utf8轉(zhuǎn)碼,utf8轉(zhuǎn)碼,utf8轉(zhuǎn)碼,可以使用editplus等文本編輯工具來修改編碼。Windows記事本的轉(zhuǎn)碼是utf-8-with-bom。
不進(jìn)行轉(zhuǎn)碼的話,書簽會生成失敗。因為下面代碼永不執(zhí)行。因為使用IDE工具會發(fā)現(xiàn),
sectionNumberStr實際上等于"\ufeff目錄"。這是因為Microsoft 建議所有的 Unicode 文件應(yīng)該以 \uFEFF 字符開頭,作為標(biāo)記字節(jié)順序存儲的標(biāo)記。標(biāo)準(zhǔn)的utf8編碼是不需要設(shè)置 這個字節(jié)順序標(biāo)記。
該方式需要傳入目錄對應(yīng)的實際頁碼。
目錄 11 第1章 一大波數(shù)正在靠近——排序 1第1節(jié) 最快最簡單的排序——桶排序 2第2節(jié) 鄰居好說話——冒泡排序 7第3節(jié) 最常用的排序——快速排序 12第4節(jié) 小哼買書 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 = Pattern.compile("\\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"; // 生成的帶有目錄的文件的路徑(問價是復(fù)制,不是覆蓋)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 正文的實際頁數(shù)-1*/public void createPdf(String sTxtPath, String sPdfPath, String filename,int startPage) throws DocumentException, IOException {if(startPage>0)startpage--;//可以創(chuàng)建新的文件,也可以直接操作源文件,添加書簽// step 1Document document = new Document();// step 2 輸出文件PdfCopy writer = new PdfCopy(document, new FileOutputStream(filename)); // step 3writer.setViewerPreferences(PdfWriter.PageModeUseOutlines);//設(shè)置打開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;//標(biāo)識書簽點擊后的跳轉(zhuǎn)動作,通過它設(shè)置跳轉(zhuǎn)的頁碼try {//讀入保存書簽的TXT文件,分拆為書簽名及跳轉(zhuǎn)頁碼;BufferedReader bufRead = new BufferedReader(new FileReader(sTxtPath));String str;String[] ss = null;int skipPage = startPage; //正文書簽跳過的頁數(shù)/*數(shù)據(jù)的存儲結(jié)構(gòu)** page 頁碼*title 標(biāo)題* kids 子書簽 page,title ,kids*/List<Map<String, Object>> outlines = new ArrayList<>();//存放解析的數(shù)據(jù)String pageNumStr = null;int pageNum = 0;//遍歷讀取目錄文件,每次讀取一行,并解析出該行的標(biāo)題和頁碼值 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();//不包含頁碼的標(biāo)題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]; //獲取標(biāo)題的序號if (sectionNumberStr.contains("章")) {//章節(jié)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 {//小節(jié)List<Map<String, Object>> kids = (List<Map<String, Object>>) outlines.get(outlines.size() - 1).get("kids");//將小節(jié)添追加到自書簽列表Map<String, Object> littleChapter = new HashMap<>();littleChapter.put("title", title);littleChapter.put("page", pageNum);littleChapter.put("kids", new ArrayList<>());kids.add(littleChapter);}} else {//不存在頁碼,可能是大標(biāo)題 或者目錄 例如:第一部分 核心實現(xiàn)Map<String, Object> bigSection = new HashMap<>();bigSection.put("title", title);bigSection.put("page", -1);bigSection.put("kids", new ArrayList<>());outlines.add(bigSection);}}//數(shù)據(jù)遍歷,添加書簽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; //獲取大分類的頁數(shù),一般就是子目錄頁數(shù)減一PdfAction action1 = PdfAction.gotoLocalPage(parentPage,new PdfDestination(PdfDestination.FIT), writer);//設(shè)置書簽動作sectionOutline = new PdfOutline(root, action1, sectionTitle, false); //大分類的} else {PdfAction action1 = PdfAction.gotoLocalPage(page,new PdfDestination(PdfDestination.FIT), writer);//設(shè)置書簽動作sectionOutline = new PdfOutline(root, action1, sectionTitle, false); //一級章節(jié)標(biāo)題;}for (Map<String, Object> kid : kids) { //一級章節(jié)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);//設(shè)置書簽動作PdfOutline firstOutline = new PdfOutline(sectionOutline, action2, firstTitle, false); //一級標(biāo)題的outlinefor (Map<String, Object> secondKid : firstKids) {//二級章節(jié)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);//設(shè)置書簽動作PdfOutline secondOutline = new PdfOutline(firstOutline, action2, secondTitle, false); //二級標(biāo)題的outline}}});} catch (IOException ioe) {}document.close();}}生成好的書簽。代碼的局限性比較高,可以自定義自己的書簽類
參考文章:使用itext寫的pdf文件添加書簽的小工具
總結(jié)
以上是生活随笔為你收集整理的使用itext为已有的pdf文档生成书签的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: kibana设置端口密码
- 下一篇: 20210101英语单词学习(仅供自己记