許多電子書 PDF 缺乏書籤(大綱),閱讀體驗不佳。本工具讀取純文字目錄(每行「標題 頁碼」,縮排代表層級),解析後注入既有 PDF,輸出含書籤的新檔案。
第1章 HTTP 概述 3
1.1 HTTP——因特網的多媒體信使 4
1.2 Web 客戶端和服務器 4
1.3 資源 5
1.3.1 媒體類型 6
1.3.2 URI 7
...
1.、1.1.、1.3.1.)決定書籤層級(點號數量 = 層級)。AddPdfOutLineFromTxtcreatePdf(dest, source, reader, pattern):讀取源 PDF,依 pattern 決定保留舊書籤、捨棄或保留第一個。addBookmarks(bufRead, outlines, preOutline, preLevel):遞迴讀取每行,解析層級與頁碼,建立 HashMap 結構(iText SimpleBookmark 格式),維護父書籤堆疊處理層級跳轉。parseFormmattedText(line):切分標題與頁碼,計算點號數量為層級。parseBookmarkToHashMap(bookmark):產出 {Title, Action:"GoTo", Page:"N Fit"}。PdfStamper.setOutlines(outlines) 寫入新 PDF。// 遞迴建立書籤樹
private void addBookmarks(BufferedReader in, List<Map<String,Object>> outlines,
Map<String,Object> parent, int parentLevel) throws IOException {
in.mark(1);
String line = in.readLine();
if (line == null) return;
FormattedBookmark bm = parseFormmattedText(line);
Map<String,Object> node = parseBookmarkToHashMap(bm);
int level = bm.getLevel();
if (level == parentLevel) { // 同層
outlines.add(node);
addBookmarks(in, outlines, node, level);
} else if (level > parentLevel) { // 子層
List<Map<String,Object>> kids = new ArrayList<>();
kids.add(node);
parent.put("Kids", kids);
parentStack.push(new OutlineInfo(parent, outlines, parentLevel));
addBookmarks(in, kids, node, level);
} else { // 回到上層
in.reset();
OutlineInfo oi = parentStack.pop();
addBookmarks(in, oi.getOutlines(), oi.getPreOutline(), oi.getPreLevel());
}
}
// 解析單行
private FormattedBookmark parseFormmattedText(String line) {
FormattedBookmark bm = new FormattedBookmark();
int lastSpace = line.lastIndexOf(' ');
String title = (lastSpace == -1) ? line : line.substring(0, lastSpace);
String page = (lastSpace == -1) ? "1" : line.substring(lastSpace + 1);
int level = title.split(" ")[0].split("\\.").length - 1; // 點號數 = 層級
bm.setTitle(title); bm.setPage(page); bm.setLevel(level);
return bm;
}
RESERVED_OLD_OUTLINE:合併舊書籤與新解析書籤。RESERVED_FIRST_OUTLINE:僅保留第一個舊書籤(通常為書名)。RESERVED_NONE:完全取代。<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13.3</version>
</dependency>
public class PdfBookmarkDemo {
public static void main(String[] args) throws Exception {
try (BufferedReader br = new BufferedReader(new FileReader("toc.txt"));
FileOutputStream fos = new FileOutputStream("output_with_bookmarks.pdf")) {
PdfReader reader = new PdfReader("input.pdf");
PdfStamper stamper = new PdfStamper(reader, fos);
new AddPdfOutLineFromTxt().createPdf("output_with_bookmarks.pdf",
"input.pdf", br, AddBookmarkConstants.RESERVED_OLD_OUTLINE);
stamper.close();
reader.close();
}
}
}
BufferedReader 使用正確字元集(UTF-8/Big5)。PdfOutline 相關類別。PdfReader。