Как работать со структурой PDF в TypeScript
Это руководство показывает, как создать навигацию по документу и логическую структуру в PDF-файлах с помощью Aspose.PDF FOSS для TypeScript: кликабельное оглавление на странице, оглавление закладок уровня документа, именованные назначения и тегированное дерево структуры для доступности. Требуется Node.js 22 или новее.
Пошаговое руководство
Шаг 1: Установите пакет
git clone https://github.com/aspose-pdf-foss/Aspose.PDF-FOSS-for-TypeScript.git
cd Aspose.PDF-FOSS-for-TypeScript
npm install
npm run buildПроверьте установку, импортировав класс Document в новый файл TypeScript — эта строка должна выполниться без ошибок после установки пакета:
import { Document } from '@asposefoss/pdf';Шаг 2: Импортируйте необходимые классы
Импортируйте Document, чтобы открыть файл, и OutlineItem для записей закладок, созданных на Шаге 4:
import { Document, OutlineItem } from '@asposefoss/pdf';Шаг 3: Добавить оглавление
Page.AddTOC() принимает массив записей { title, page }, ограничивающий rect и параметры стиля; он рисует пунктирные лидеры и кликабельные ссылки на целевые страницы:
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 },
);Шаг 4: Добавить закладки
Document.SetOutlines() заменяет панель закладок документа массивом объектов OutlineItem. Каждый элемент может содержать Dest (назначение страницы), стили (Color, Bold) и вложенный Children для сворачиваемого дерева:
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);Шаг 5: Считать контуры и именованные назначения
Document.GetOutlines() возвращает текущее дерево закладок. Document.GetNamedDestinations() возвращает каждое именованное назначение, зарегистрированное в документе, — полезно для проверки того, что каждая цель контура и ссылка из оглавления действительно ведут к реальной странице:
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());Шаг 6: Построить тегированное дерево структуры
Document.GetStructTree() возвращает существующее дерево структуры (или null, если документ не был помечен). StructTreeRoot.Append(tag) добавляет дочерний элемент, такой как 'H2' или 'P', и возвращает StructElement, а StructElement.MarkContent(page, quad) связывает этот элемент с содержимым страницы, которое он описывает:
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);
}
}Распространённые проблемы и их решения
Document.GetStructTree() returns null. Документ еще не помечен — вызовите Document.CreateStructTree() (или Document.AutoTag()) перед ручным созданием элементов с помощью StructTreeRoot.Append() / StructElement.MarkContent().
Элемент оглавления не переходит на правильную страницу. OutlineItem.Dest должен указывать существующее назначение — проверьте item.Dest.name against Document.GetNamedDestinations() перед сохранением, как показано в Шаге 5.
Page.AddTOC() записи указывают на неправильную страницу. page в каждой записи оглавления номер страницы целевого документа — подтвердите его против page.Number на реальном объекте Page, а не предполагаемый индекс массива.
Закладки исчезают после более позднего Document.SetOutlines() вызова. SetOutlines() заменяет всё дерево закладок — прочитайте текущее дерево с помощью Document.GetOutlines() сначала, измените массив, затем передайте весь массив обратно, если закладки добавляются, а не заменяются.
Часто задаваемые вопросы
Можно ли, чтобы закладка открывалась уже развернутой?
Да — установите Open: true на OutlineItem, чтобы дочерние элементы этого узла были видимы по умолчанию в панели закладок.
В чём разница между закладкой и именованным пунктом назначения?
Закладка (OutlineItem) — это видимый элемент в панели навигации; именованный пункт назначения (Document.GetNamedDestinations() / SetNamedDestination()) — это внутренний, переиспользуемый целевой объект страницы, на который могут ссылаться закладка, запись оглавления (TOC) или аннотация-ссылка по имени.
Влияет ли тегирование документа на его внешний вид?
Нет — дерево структуры (StructTreeRoot, StructElement) представляет собой параллельный логический слой, описывающий порядок чтения и семантику; оно не меняет видимое содержимое страницы.
Можно ли вкладывать закладки?
Да — установите Children в OutlineItem как массив дальнейших объектов OutlineItem, чтобы построить сворачиваемое многоуровневое дерево.