Аннотация не является контентом страницы. Когда вы вызываете TextOut или рисуете прямоугольник, отметки становятся частью потока контента страницы, встроенного в байты, которые рисует средство рендеринга. Аннотация — это отдельный словарь, который привязан к странице через ее массив /Annots, со своим собственным прямоугольником, своим внешним видом и своим жизненным циклом. Читатель может открыть ее, переместить, скрыть или удалить, не затрагивая ни единого глифа нижележащей страницы. Это разделение является основной причиной существования аннотаций, и оно также является источником двух вещей, которые в первую очередь удивляют людей: где аннотация приземляется и как она выглядит после того, как к ней обратится конкретная программа просмотра
HotPDF раскрывает подтипы аннотаций ISO 32000 через семейство вызовов AddXxxAnnotation объекта страницы. Все они имеют одинаковую форму: прямоугольник, который фиксирует аннотацию на странице в пользовательском пространстве PDF, некоторую полезную нагрузку (текст, название штампа, пара точек) и цвет. Правильно задайте прямоугольник, и большая часть работы будет сделана. Остальное — знать, какие подтипы имеют собственный внешний вид, а какие опираются на программу просмотра для их отрисовки

Прямоугольник — это аннотация, а не текст
Каждый вызов аннотации принимает TRect, и этот прямоугольник означает нечто иное, чем координаты, которые вы передаете в TextOut. Для текстовой заметки это интерактивная горячая зона, небольшая область, в которой находится значок заметки и где щелчок открывает комментарий. Для квадрата или поля со свободным текстом это видимая часть разметки. Для штампа это поле, в которое масштабируется изображение штампа. Числа — это пункты пользовательского пространства PDF, измеряемые от левого нижнего угла страницы, при этом Y увеличивается вверх, та же конвенция, которую использует остальная часть HotPDF
Текстовая заметка — самый легкий подтип. Вы даете ей основной текст, прямоугольник для значка, флаг того, открывается ли она по умолчанию, имя значка и цвет
Pdf.CurrentPage.AddTextAnnotation(
'Reviewer: confirm the totals on this line before sign-off.',
Rect(120, 700, 140, 720), // icon hotspot, ~20pt square
False, // closed until the reader clicks it
taComment, // bubble icon
clBlue);
Прямоугольник здесь намеренно маленький, около двадцати пунктов с каждой стороны, потому что текстовая заметка — это всего лишь значок, пока на него кто-нибудь не нажмет. Если сделать прямоугольник большим, вы не получите большую заметку; вы получите негабаритную цель для щелчка со значком, прикрепленным к одному углу. Флаг Open контролирует, отображается ли всплывающее окно при загрузке документа. Установите для нескольких заметок True, и они будут накладываться друг на друга и поверх контента, поэтому зарезервируйте это для той единственной заметки, которую вы действительно хотите, чтобы читатель увидел немедленно
Имя значка берется из THPDFTextAnnotationType, который сопоставляется со стандартными значками заметок: taComment, taKey, taNote, taHelp, taParagraph, taNewParagraph и taInsert. Значок — это единственное, что изменяет тип. Это не меняет поведение, и стоит знать, что не каждая программа просмотра рисует все семь; безопасными во всех старых и новых программах для чтения являются taComment, taNote и taHelp
Свободный текст пишется на странице, но остается аннотацией
Аннотация свободного текста выглядит как контент, потому что текст виден без щелчка, находясь в своем прямоугольнике, как подпись. Это по-прежнему аннотация со всей вытекающей отсюда отделимостью, что именно то, что вам нужно для штампа рецензии или черновой метки, которую кто-то должен иметь возможность удалить позже. Сигнатура заменяет значок и флаг открытия на значение выравнивания
Pdf.CurrentPage.AddFreeTextAnnotation(
'DRAFT - not for distribution',
Rect(200, 210, 400, 235), // the box the text is laid into
ftCenter, // ftLeftJust / ftCenter / ftRightJust
clRed);
Здесь прямоугольник имеет большее значение, чем для текстовой заметки, потому что текст переносится и выравнивается внутри него. Если размер поля слишком мал, текст обрезается по нижнему краю; если он слишком узок, текст переносится в тех местах, где вы этого не хотели. Выравнивание берется из THPDFFreeTextAnnotationJust и имеет только три значения. Поскольку свободный текст — это аннотация разметки, читатель, открывающий файл в редакторе, может выбрать его, переместить или удалить как единое целое, и это отличие определяет, обращаетесь ли вы к свободному тексту или просто рисуете слова с помощью TextOut. Если метка должна быть постоянной, нарисуйте ее. Если она редакционная и должна быть удалена, сделайте ее аннотацией
Геометрическая и линейная разметка для указания на объекты
Квадраты, круги и линии — это разметка, которую вы используете для указания на область, а не для описания ее словами. AddCircleSquareAnnotation охватывает две формы блоков через THPDFCSAnnotationType из csCircle или csSquare, при этом прямоугольник задает границы формы
// A box drawn around a figure that needs attention
Pdf.CurrentPage.AddCircleSquareAnnotation(
'Check this region against the source data',
Rect(50, 300, 120, 360),
csSquare,
clGreen);
// A line, given two points rather than a rectangle
var
StartPt, EndPt: THPDFCurrPoint;
begin
StartPt.X := 130; StartPt.Y := 360;
EndPt.X := 250; EndPt.Y := 320;
Pdf.CurrentPage.AddLineAnnotation(
'Points from the note to the figure',
StartPt, EndPt,
clBlue);
end;
Обратите внимание, что линейная аннотация нарушает шаблон прямоугольника: она принимает две записи THPDFCurrPoint, начало и конец, потому что линия определяется ее конечными точками, а не ограничивающей рамкой. Цвет задает штрих. Если вам нужны наконечники стрелок, в HotPDF есть перегрузки AddLineAnnotation, которые принимают стили завершения линий, но простая форма с тремя аргументами рисует голую линию, что обычно и требуется от выноски
Подтипы разметки текста работают с областью, которую вы уже разметили. AddHighlightAnnotation принимает прямоугольник, необязательное содержимое и цвет, который по умолчанию желтый, и тонирует область так же, как маркер. Предполагается, что она будет располагаться поверх реального текста, поэтому прямоугольник должен соответствовать границам нарисованных вами слов, а это означает, что вы обычно вычисляете ее на основе тех же координат, которые вы передали в TextOut, а не угадываете
Штампы зависят от программы просмотра для их рендеринга
Аннотация штампа — это та, которая с наибольшей вероятностью будет выглядеть по-разному в зависимости от программы для чтения, и причину стоит понимать. AddStampAnnotation называет стандартный штамп через THPDFStampAnnotationType со значениями типа satApproved, satConfidential, satFinal, satDraft и satForComment
Pdf.CurrentPage.AddStampAnnotation(
'Approved for release on review',
Rect(50, 400, 200, 440),
satApproved,
clGreen);
Имя штампа — это запрос. PDF определяет набор стандартных названий штампов, но не иллюстрации, стоящие за ними, поэтому каждая программа просмотра поставляет собственную визуализацию «УТВЕРЖДЕНО» или «КОНФИДЕНЦИАЛЬНО», а некоторые вообще ничего не отображают для названий, которые они не распознают. Прямоугольник управляет полем, в которое масштабируется иллюстрация, а цвет — это подсказка, которую программа просмотра может учесть, а может и нет. Если штамп должен выглядеть одинаково везде, надежный путь — это вообще не стандартный штамп: нарисуйте отметку самостоятельно с помощью TextOut и вызовов рисования или поместите ее как аннотацию со свободным текстом, внешний вид которой вы контролируете. Обращайтесь к стандартному штампу, когда вы хотите получить знакомый внешний вид программы просмотра и можете смириться с различиями
Вложения файлов имеют ту же форму прямоугольник плюс полезная нагрузка. AddFileAttachmentAnnotation принимает описание, путь к встраиваемому файлу, прямоугольник для значка скрепки и цвет. Файл находится внутри PDF, а значок — это маркер, который читатель использует для его извлечения
Чем аннотации отличаются от полей AcroForm
Путаница, которая стоит больше всего времени — это отношение к аннотации как к полю формы. Оба они прикрепляются к странице через /Annots, а поле формы фактически является специальным подтипом аннотации (виджетом), вот почему они выглядят родственными. Они не взаимозаменяемы. Поле формы содержит значение, имеет имя, участвует в порядке перехода по Tab и может быть отправлено, сброшено или заскриптовано; вы создаете их с помощью вызовов AddTextField, AddCheckBox и AddPushButton, а не с помощью вызовов аннотаций на этой странице. Аннотация разметки содержит комментарий или форму, не имеет значения для отправки и является неправильным инструментом в тот момент, когда вам нужно собрать ввод
Практический тест прост. Если предполагается, что пользователь наберет текст, выберет или нажмет и заставит документ запомнить это, вам нужно поле AcroForm. Если вы оставляете заметку, помечаете область или ставите штамп о статусе, который перемещается вместе с файлом, но не является данными, вам нужна аннотация. Смешивание их создает документы, которые выглядят правильно, но ведут себя неправильно: «поле», которое никто не может заполнить, или комментарий, который исчезает при сбросе формы. Интерактивная сторона с типами полей, проверкой и действиями по отправке — это отдельная тема, рассматриваемая в пошаговом руководстве по полям и действиям AcroForm
Собираем страницу вместе
Части компонуются так же, как и остальная часть HotPDF. Задайте свойства документа, вызовите BeginDoc, нарисуйте любой контент страницы, который вам нужен, с помощью вызовов текста и графики, добавьте аннотации сверху и закройте EndDoc. Аннотации прикрепляются к CurrentPage, поэтому после AddPage они попадают на новую страницу, и заметка, которую вы предназначали для первой страницы, тихо появится на второй странице, если вы добавите ее после разрыва
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'annotated.pdf';
Pdf.Compression := cmFlateDecode;
Pdf.FontEmbedding := True;
Pdf.BeginDoc;
Pdf.CurrentPage.SetFont('Arial', [], 11);
Pdf.CurrentPage.TextOut(50, 740, 0, 'Quarterly figures, draft for review');
Pdf.CurrentPage.AddTextAnnotation(
'Confirm the totals before sign-off.',
Rect(50, 720, 70, 740), False, taComment, clBlue);
Pdf.CurrentPage.AddFreeTextAnnotation(
'DRAFT', Rect(450, 720, 540, 745), ftCenter, clRed);
Pdf.CurrentPage.AddStampAnnotation(
'For comment', Rect(50, 660, 180, 695), satForComment, clGreen);
Pdf.EndDoc;
finally
Pdf.Free;
end;
Последний рефлекс, который стоит выработать, когда вывод выглядит неправильным: откройте файл более чем в одной программе просмотра, прежде чем решить, что код сломан. Штампы и более редкие значки заметок являются обычными виновниками, и поскольку аннотация является запросом к читателю, а не нарисованными пикселями, разница между Acrobat и легковесной программой просмотра часто является спецификацией, работающей так, как задумано, а не ошибкой в вашем вызове
Вызовы аннотаций, показанные здесь, являются частью компонента HotPDF для Delphi и C++Builder