Как работать с аннотациями в TypeScript
В этом руководстве показано, как добавлять, уплощать и искать PDF-аннотации с помощью Aspose.PDF FOSS для TypeScript. Класс Page предоставляет по одному методу Add* для каждого подтипа аннотации — разметка (highlight, underline, strikeout, squiggly), формы (square, circle, line, polygon, ink), текст (sticky note, free text) и ссылки — каждый из которых возвращает типизированный Annotation дескриптор, который можно позже прочитать или уплощать. Требуется 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, чтобы открыть файл, и Page для сигнатур типов аннотаций, используемых в шагах ниже:
import { Document, Page } from '@asposefoss/pdf';Шаг 3: Добавить разметочные аннотации
Page.AddHighlight(), Page.AddUnderline(), Page.AddSquiggly() и Page.AddStrikeOut() принимают массив quads — один 8-числовой квадр (x1,y1,x2,y2,x3,y3,x4,y4) для каждой выделенной области текста — плюс color и необязательный contents. Библиотека автоматически генерирует поток отображения (/AP) для всех четырёх подтипов:
import { Document } from '@asposefoss/pdf';
const doc = Document.OpenFile('input.pdf');
const page = doc.Pages[0];
page.AddHighlight({
quads: [72, 700, 300, 700, 72, 685, 300, 685],
color: [1, 1, 0],
contents: 'Yellow highlight',
});
page.AddUnderline({
quads: [72, 660, 300, 660, 72, 645, 300, 645],
color: [0, 0, 1],
});
page.AddStrikeOut({
quads: [72, 620, 300, 620, 72, 605, 300, 605],
color: [1, 0, 0],
});
doc.WriteTo('annotated.pdf');Шаг 4: Добавить фигурные и чернильные аннотации
Page.AddSquare() и Page.AddCircle() принимают ограничивающий rect плюс color (обводка) и необязательный fill. Page.AddLine() принимает 4-числовой line (x1,y1,x2,y2) и необязательные концы-стрелки. Page.AddInk() принимает paths — массив плоских массивов пар точек, по одному для каждого штриха пера:
page.AddSquare({ rect: [100, 500, 220, 560], color: [0.8, 0, 0], fill: [1, 1, 0.5], width: 2 });
page.AddCircle({ rect: [250, 500, 370, 560], color: [0, 0.5, 0], width: 2 });
page.AddLine({
line: [100, 470, 370, 470],
color: [0, 0, 0.7],
width: 2,
startEnding: 'OpenArrow',
endEnding: 'ClosedArrow',
});
page.AddInk({
paths: [[100, 400, 130, 430, 160, 390, 190, 420]],
color: [0.6, 0, 0.6],
width: 2,
});Шаг 5: Добавить стикер-заметку и свободный текст
Page.AddTextNote() размещает кликабельный значок, который открывает всплывающее окно комментария. Page.AddFreeText() рисует текст непосредственно на странице внутри своего rect:
page.AddTextNote({
rect: [400, 700, 420, 720],
icon: 'Note',
author: 'Reviewer',
contents: 'This is a sticky-note annotation.',
});
page.AddFreeText({
rect: [400, 600, 550, 660],
contents: 'FreeText sample',
fontSize: 10,
align: 'center',
fill: [1, 1, 0.8],
width: 1,
});Шаг 6: Преобразовать аннотацию в статическое содержимое
Каждый дескриптор аннотации, возвращаемый вызовом Add*, имеет метод Flatten(), который встраивает внешний вид аннотации в поток содержимого страницы и удаляет её из /Annots. После сплющивания ничего не остаётся, что можно было бы кликнуть или отредактировать в просмотрщике:
const note = page.AddFreeText({
rect: [210, 535, 470, 590],
contents: 'Sticky note — flattened into the page.',
fontSize: 11,
align: 'left',
});
note.Flatten(); // -> boolean; bakes the annotation, unwires itself from /Annots
Шаг 7: Поиск текста аннотации
Page.SearchAnnotationText() and Page.SearchAnnotations() не пересекаются в обоих направлениях: SearchAnnotationText() соответствует буквальному метаданному аннотации (/Contents, /T, /Subj), в то время как SearchAnnotations() соответствует rendered тексту разметочных аннотаций, таким как FreeText:
const metadataHits = page.SearchAnnotationText('confidential');
for (const hit of metadataHits) {
console.log(hit.key, hit.value); // e.g. 'Contents', 'confidential'
}
const renderedHits = page.SearchAnnotations('confidential');
console.log(renderedHits.length);Распространённые проблемы и решения
Page.AddHighlight() (или другой метод разметки) отрисовывается не в том месте. quads является одномерным массивом из 8 чисел (x1,y1,x2,y2,x3,y3,x4,y4), не a rect — передача прямоугольника из 4 чисел приводит к вырожденному или отсутствующему кваду. Создайте один квад на каждую строку выделенного текста.
Flattened аннотация всё ещё кликабельна. Flatten() должен быть вызван у объекта, возвращённого Add* вызов, и документ должен быть сохранён (doc.WriteTo() / doc.Save()) после flattening — изменение существует только в памяти, пока файл не будет записан обратно.
SearchAnnotationText() не возвращает результатов, хотя текст виден на странице. Он ищет только поля метаданных аннотации (/Contents, /T, /Subj) — видимый разметочный текст, полученный из собственного отображения аннотации (например, a FreeText body) находится с помощью SearchAnnotations() вместо этого, и ни один из них не ищет обычное содержимое страницы (используйте Page.GetText() or Page.Search() для этого).
Пометки редактирования не отображаются при поиске аннотаций. Page.AddRedact() создаёт RedactAnnotation, отдельный подтип от разметки/формы/текстовых аннотаций, рассмотренных здесь — см. Redaction руководство.
Часто задаваемые вопросы
Сколько подтипов аннотаций поддерживает Page?
Библиотека генерирует внешние виды для разметки (highlight, underline, strikeout, squiggly), фигур (square, circle, line, polygon, ink), текста (sticky note, free text), ссылок и штампов — а также аннотаций вложения файлов и редактирования, которые описаны в отдельных руководствах.
Могу ли я прочитать аннотации, которые уже существуют на странице?
Да — Page.Annotations возвращает существующие аннотации в виде массива типизированных дескрипторов, которые вы можете просматривать, редактировать или уплощать, а Page.RemoveAnnotation(a) удаляет одну.
В чем разница между уплощением аннотации и применением редактирования?
Flatten() встраивает аннотацию appearance в страницу и удаляет объект аннотации, но любой текст или изображение под ним остаются нетронутыми. ApplyRedactions() разрушительно переписывает поток содержимого, поэтому покрытый контент исчезает — см. Redaction guide для деталей.
Сохраняются ли аннотации при цикле сохранения/открытия?
Да — аннотации, добавленные до doc.WriteTo() / doc.Save(), записываются в PDF и корректно читаются при следующем Document.Open() / Document.OpenFile().