Cách làm việc với cấu trúc PDF trong TypeScript
Hướng dẫn này chỉ cách xây dựng điều hướng tài liệu và cấu trúc logic trong các tệp PDF bằng Aspose.PDF FOSS cho TypeScript: một mục lục có thể nhấp trên một trang, một dàn phác thảo dấu trang ở mức độ tài liệu, các đích được đặt tên, và một cây cấu trúc được gắn thẻ để hỗ trợ khả năng truy cập. Yêu cầu Node.js 22 trở lên.
Hướng dẫn từng bước
Bước 1: Cài đặt gói
git clone https://github.com/aspose-pdf-foss/Aspose.PDF-FOSS-for-TypeScript.git
cd Aspose.PDF-FOSS-for-TypeScript
npm install
npm run buildXác minh việc cài đặt bằng cách nhập lớp Document trong một tệp TypeScript mới — dòng này nên được giải quyết mà không có lỗi khi gói đã được cài đặt:
import { Document } from '@asposefoss/pdf';Bước 2: Nhập các lớp cần thiết
Nhập Document để mở tệp và OutlineItem cho các mục đánh dấu được tạo trong Bước 4:
import { Document, OutlineItem } from '@asposefoss/pdf';Bước 3: Thêm mục lục
Page.AddTOC() nhận một mảng các mục { title, page }, một rect giới hạn, và các tùy chọn kiểu; nó vẽ các đường dẫn chấm và các liên kết có thể nhấp tới các trang mục tiêu:
const page = doc.Pages[0];
page.AddTOC(
[
{ title: '1. Introduction', page: 2 },
{ title: '2. Methodology', page: 5 },
{ title: '3. Results', page: 9 },
],
[72, 160, 400, 600],
{ font: 'Helvetica', fontSize: 13, color: [0.1, 0.1, 0.15], rowGap: 18 },
);Bước 4: Thêm đánh dấu
Document.SetOutlines() thay thế bảng điều khiển đánh dấu của tài liệu bằng một mảng các đối tượng OutlineItem. Mỗi mục có thể chứa một Dest (đích trang), kiểu dáng (Color, Bold), và Children lồng nhau cho cây có thể thu gọn:
const items: OutlineItem[] = [
{ Title: 'Sales', Dest: { name: 'section.sales' }, Open: true, Color: [0.1, 0.4, 0.1] },
{ Title: 'Appendix', Dest: { name: 'section.appendix' } },
];
doc.SetOutlines(items);Bước 5: Đọc đề cương và các đích danh
Document.GetOutlines() trả về cây đánh dấu hiện tại. Document.GetNamedDestinations() trả về mọi đích danh đã đăng ký trên tài liệu — hữu ích để xác minh rằng mỗi mục tiêu đề cương và liên kết mục lục thực sự dẫn đến một trang thực:
const destNames = new Set(doc.GetNamedDestinations().map((d) => d.name));
const walk = (nodes: OutlineItem[]): void => {
for (const item of nodes) {
if (item.Dest && 'name' in item.Dest) {
console.log(destNames.has(item.Dest.name), item.Title);
}
if (item.Children) walk(item.Children);
}
};
walk(doc.GetOutlines());Bước 6: Xây dựng cây cấu trúc có thẻ
Document.GetStructTree() trả về cây cấu trúc hiện có (hoặc null nếu tài liệu chưa được gắn thẻ). StructTreeRoot.Append(tag) thêm một phần tử con như 'H2' hoặc 'P' và trả về một StructElement, và StructElement.MarkContent(page, quad) liên kết phần tử đó với nội dung trang mà nó mô tả:
function tagPage(doc: Document, page: Page, headingText: string): void {
const root = doc.GetStructTree();
if (!root) throw new Error('tagPage: the document is not tagged yet');
for (const block of page.GetStructuredText()) {
const text = block.text.trim();
if (text.length === 0) continue;
const el = root.Append(text.startsWith(headingText) ? 'H2' : 'P');
el.MarkContent(page, block.quad);
}
}Các vấn đề phổ biến và cách khắc phục
Document.GetStructTree() returns null. Tài liệu chưa được gắn thẻ — gọi Document.CreateStructTree() (hoặc Document.AutoTag()) trước khi tự tạo các phần tử bằng StructTreeRoot.Append() / StructElement.MarkContent().
Mục đề mục không nhảy tới trang đúng. OutlineItem.Dest phải đặt tên cho một đích mà thực sự tồn tại — kiểm tra chéo item.Dest.name against Document.GetNamedDestinations() trước khi lưu, như đã chỉ ra ở Bước 5.
Page.AddTOC() các mục trỏ tới trang sai. page trong mỗi mục mục lục là số trang của trang đích — xác nhận với page.Number trên mục tiêu thực tế Page, không phải một chỉ mục mảng được giả định.
Các dấu trang biến mất sau một lần gọi sau Document.SetOutlines() gọi. SetOutlines() thay thế toàn bộ cây dấu trang — đọc cây hiện tại bằng Document.GetOutlines() đầu tiên, sửa đổi mảng, sau đó truyền toàn bộ mảng trở lại nếu các dấu trang đang được thêm vào thay vì được thay thế.
Câu hỏi thường gặp
Liệu một dấu trang có thể mở sẵn ở trạng thái mở rộng không?
Có — đặt Open: true trên OutlineItem để các nút con của nút đó hiển thị mặc định trong bảng dấu trang.
Sự khác nhau giữa dấu trang và đích đặt tên là gì?
Một dấu trang (OutlineItem) là một mục hiển thị trong bảng điều hướng; một đích đặt tên (Document.GetNamedDestinations() / SetNamedDestination()) là một mục tiêu trang nội bộ, có thể tái sử dụng mà dấu trang, mục mục lục, hoặc chú thích liên kết đều có thể trỏ tới bằng tên.
Việc gắn thẻ tài liệu có ảnh hưởng đến cách hiển thị của nó không?
Không — cây cấu trúc (StructTreeRoot, StructElement) là một lớp logic song song mô tả thứ tự đọc và ngữ nghĩa; nó không thay đổi nội dung hiển thị của trang.
Tôi có thể lồng dấu trang không?
Có — đặt Children trên một OutlineItem thành một mảng các đối tượng OutlineItem tiếp theo để xây dựng một cây có thể thu gọn, đa cấp.