Jak pracować ze strukturą PDF w TypeScript
Ten przewodnik pokazuje, jak zbudować nawigację w dokumencie i logiczną strukturę w plikach PDF przy użyciu Aspose.PDF FOSS dla TypeScript: klikalny spis treści na stronie, spis zakładek na poziomie dokumentu, nazwane cele oraz oznaczony drzewo struktury dla dostępności. Wymaga Node.js 22 lub nowszej wersji.
Przewodnik krok po kroku
Krok 1: Zainstaluj pakiet
git clone https://github.com/aspose-pdf-foss/Aspose.PDF-FOSS-for-TypeScript.git
cd Aspose.PDF-FOSS-for-TypeScript
npm install
npm run buildZweryfikuj instalację, importując klasę Document w nowym pliku TypeScript — ta linia powinna zostać rozwiązana bez błędu po zainstalowaniu pakietu:
import { Document } from '@asposefoss/pdf';Krok 2: Zaimportuj wymagane klasy
Importuj Document, aby otworzyć plik i OutlineItem dla wpisów zakładek utworzonych w Kroku 4:
import { Document, OutlineItem } from '@asposefoss/pdf';Krok 3: Dodaj spis treści
Page.AddTOC() przyjmuje tablicę wpisów { title, page }, ograniczający rect oraz opcje stylu; rysuje przerywane prowadnice i klikalne odnośniki do stron docelowych:
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 },
);Krok 4: Dodaj zakładki
Document.SetOutlines() zastępuje panel zakładek dokumentu tablicą obiektów OutlineItem. Każdy element może zawierać Dest (cel strony), stylizację (Color, Bold) oraz zagnieżdżone Children tworzące zwijalne drzewo:
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);Krok 5: Odczytaj spisy i nazwane cele
Document.GetOutlines() zwraca aktualne drzewo zakładek. Document.GetNamedDestinations() zwraca wszystkie nazwane cele zarejestrowane w dokumencie — przydatne do weryfikacji, czy każdy cel spisu i odnośnik w spisie treści rzeczywiście prowadzi do istniejącej strony:
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());Krok 6: Zbuduj tagowane drzewo struktury
Document.GetStructTree() zwraca istniejące drzewo struktury (lub null, jeśli dokument nie został otagowany). StructTreeRoot.Append(tag) dodaje element podrzędny, taki jak 'H2' lub 'P', i zwraca StructElement, a StructElement.MarkContent(page, quad) kojarzy ten element z treścią strony, którą opisuje:
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);
}
}Typowe problemy i rozwiązania
Document.GetStructTree() returns null. Dokument nie został jeszcze otagowany — wywołaj Document.CreateStructTree() (lub Document.AutoTag()) przed ręcznym tworzeniem elementów z StructTreeRoot.Append() / StructElement.MarkContent().
Element konspektu nie przeskakuje do właściwej strony. OutlineItem.Dest musi wskazywać docelowy punkt, który rzeczywiście istnieje — sprawdź krzyżowo item.Dest.name against Document.GetNamedDestinations() przed zapisaniem, jak pokazano w Kroku 5.
Page.AddTOC() pozycje wskazują niewłaściwą stronę. page w każdej pozycji spisu treści jest własny numer strony docelowej — potwierdź to względem page.Number na rzeczywistym celu Page, a nie przypuszczalny indeks tablicy.
Zakładki znikają po późniejszym Document.SetOutlines() wywołaniu. SetOutlines() zastępuje całe drzewo zakładek — odczytaj bieżące drzewo za pomocą Document.GetOutlines() najpierw, zmodyfikuj tablicę, a następnie przekaż całą tablicę z powrotem, jeśli zakładki są dodawane, a nie zastępowane.
Najczęściej zadawane pytania
Czy zakładka może otworzyć się już rozwinięta?
Tak — ustaw Open: true na OutlineItem, aby dzieci tego węzła były domyślnie widoczne w panelu zakładek.
Jaka jest różnica między zakładką a nazwanym miejscem docelowym?
Zakładka (OutlineItem) jest widocznym wpisem w panelu nawigacji; nazwane miejsce docelowe (Document.GetNamedDestinations() / SetNamedDestination()) jest wewnętrznym, wielokrotnego użytku celem strony, na który mogą wskazywać zakładka, wpis spisu treści lub adnotacja linku, używając nazwy.
Czy tagowanie dokumentu wpływa na jego wygląd?
Nie — drzewo struktury (StructTreeRoot, StructElement) jest równoległą warstwą logiczną opisującą kolejność czytania i semantykę; nie zmienia ono widocznej zawartości strony.
Czy mogę zagnieżdżać zakładki?
Tak — ustaw Children na OutlineItem jako tablicę dalszych obiektów OutlineItem, aby zbudować zwijalne, wielopoziomowe drzewo.