Technical Article

PDF анотации в Delphi с HotPDF: Типове и координати

Анотацията не е част от съдържанието на страницата. Когато извикате TextOut или изчертаете правоъгълник, означенията стават част от потока със съдържание (content stream) на страницата â€?вградени в байтовете, които четецът изобразява. Анотацията е отделен речник (dictionary), който се прикрепя към страницата чрез нейния масив /Annots, като притежава собствен правоъгълник, собствен облик и собствен жизнен цикъл. Даден четец може да я отвори, премести, скрие или премахне, без да променя нито един символ от основната страница. Това разделение е причината за съществуването на анотациите и също така е източникът на двете неща, които изненадват разработчиците в началото: къде се позиционира анотацията и как изглежда тя, след като се отвори в конкретна програма.

HotPDF предоставя достъп до подтиповете анотации по ISO 32000 чрез група извиквания AddXxxAnnotation за обекта на страницата. Всички те споделят една и съща структура: правоъгълник, който фиксира анотацията върху страницата в потребителското пространство на PDF (PDF user space), съдържание (текст, име на печат, двойка точки) и цвят. Позиционирайте правоъгълника правилно и по-голямата част от работата е свършена. Останалата част е да знаете кои подтипове имат свой собствен облик и кои разчитат на четеца за изчертаването им.

A PDF page produced by HotPDF showing text note icons, free text boxes, square and line markups, and approval stamps placed across the page
Една страница, съдържаща няколко подтипа анотации едновременно: текстови бележки, свободен текст, геометрични фигури и печати

Правоъгълникът е самата анотация, а не текстът

Всяко извикване на анотация приема структура TRect, като този правоъгълник означава нещо различно от координатите, които предавате на TextOut. За текстова бележка това е чувствителната при щракване зона (hotspot) â€?малката област, където се намира иконата на бележката и където щракването отваря коментара. За правоъгълна фигура или текстово поле със свободен текст това е видимият обхват на анотацията. За печат това е правоъгълникът, в който се мащабира изображението на печата. Числата представляват пунктове в потребителското пространство на 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 контролира дали изскачащият прозорец (popup) се вижда при зареждане на документа. Задайте стойност True за няколко бележки и те ще се насложат една върху друга и върху съдържанието, така че запазете тази опция само за бележката, която наистина искате читателят да види веднага.

Името на иконата идва от типа THPDFTextAnnotationType, който съответства на стандартните икони за бележки: taComment, taKey, taNote, taHelp, taParagraph, taNewParagraph, и taInsert. Иконата е единственото нещо, което се променя от този тип. Тя не променя поведението и е добре да знаете, че не всеки четец изчертава и седемте типа; най-сигурните при по-старите и новите програми са taComment, taNote и taHelp.

Свободният текст се изписва върху страницата, но остава анотация

Анотацията със свободен текст (free text) изглежда като съдържание на страницата, тъй като текстът се вижда без щракване, разположен в своя правоъгълник като надпис. Тя обаче остава анотация с цялата самостоятелност, която това предполага â€?точно това, което искате за печат за преглед или етикет за чернова, които някой трябва да може да премахне по-късно. Сигнатурата на метода заменя иконата и флага за отваряне с параметър за подравняване.

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 и съдържа само трите стойности. Тъй като свободният текст е анотация за маркиране (markup annotation), потребител, който отвори файла в редактор, може да я избере, премести или изтрие като едно цяло â€?разликата, която определя дали да изберете свободен текст или просто да изчертаете думите с 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 â€?начало и край, тъй като линията се дефинира от крайните си точки, а не от ограничаваща рамка. Цветът определя контура (stroke). Ако желаете стрелки в краищата, HotPDF има претоварени версии (overloads) на AddLineAnnotation, които приемат стилове за завършек на линията, но основната форма с три аргумента чертае обикновена линия, което обикновено е напълно достатъчно.

Подтиповете за маркиране на текст работят върху област, която вече сте оформили. Методът AddHighlightAnnotation приема правоъгълник, незадължително съдържание и цвят, който по подразбиране е жълт, като оцветява областта по начина, по който го прави маркера. Той е предназначен да стои над реален текст, така че правоъгълникът трябва да съвпада с границите на думите, които сте изчертали, което означава, че трябва да го изчислите от същите координати, които сте предали на TextOut, вместо да гадаете.

Печатите разчитат на четеца за визуализирането им

Анотацията с печат (stamp) е тази, която е най-вероятно да изглежда различно при различните програми, и причината за това е добре да се разбере. Методът AddStampAnnotation определя стандартен печат чрез THPDFStampAnnotationType със стойности като satApproved, satConfidential, satFinal, satDraft, и satForComment.

Pdf.CurrentPage.AddStampAnnotation(
  'Approved for release on review',
  Rect(50, 400, 200, 440),
  satApproved,
  clGreen);

Името на печата е просто заявка. PDF спецификацията дефинира набора от стандартни имена за печати, но не и графичното изображение зад тях. Ето защо всеки четец предлага собствена визуализация на „APPROVEDâ€?или „CONFIDENTIALâ€? а някои програми не показват нищо за имена, които не разпознават. Правоъгълникът определя рамката, в която се мащабира изображението, а цветът е просто насока, която четецът може и да не спази. Ако печатът трябва да изглежда абсолютно еднакво навсякъде, най-сигурният начин е изобщо да не използвате стандартен печат: изчертайте го сами с TextOut и чертожните методи или го поставете като анотация със свободен текст, чийто облик контролирате изцяло. Използвайте стандартния печат, когато искате познатия облик на съответния четец и разминаванията не са проблем за вас.

Прикачените файлове следват същата структура от правоъгълник и съдържание. Методът AddFileAttachmentAnnotation приема описанието, пътя до файла за вграждане, правоъгълник за иконата с кламер и цвят. Файлът се записва вътре в PDF документа, а иконата е елементът, който читателят използва, за да го извлече.

Разлики между анотациите и полетата на AcroForm

Объркването, което коства най-много време, е третирането на анотацията като поле от формуляр. И двете се прикрепят към страницата чрез масива /Annots, а полето от формуляр всъщност е специален подтип анотация (джаджа или widget) â€?именно затова изглеждат свързани. Те обаче не са взаимнозаменяеми. Полето от формуляр има стойност, име, участва в реда на преминаване с табулация (tab order) и може да бъде изпращано, нулирано или да изпълнява скриптове; вие създавате тези елементи чрез извиквания като AddTextField, AddCheckBox, и AddPushButton, а не чрез анотациите, описани тук. Анотацията за маркиране съдържа коментар или фигура, няма стойност за изпращане и е грешният инструмент, когато трябва да събирате данни от потребителя.

Практическата проверка е проста. Ако потребителят трябва да въвежда текст, да избира опция или да щрака и документът трябва да запази това действие, ви е необходимо поле от AcroForm. Ако оставяте бележка, маркирате област или поставяте печат за статус, който се предава с файла, но не представлява данни, ви е необходима анотация. Смесването им води до документи, които изглеждат правилно, но се държат грешно: „полеâ€? което никой не може да попълни, или коментар, който изчезва при нулиране на формата. Интерактивната част с типове полета, валидиране и изпращане на данни е отделна тема, разгледана в ръководството за полета на AcroForm и действия.

Сглобяване на страницата

Анотациите се прикрепят към 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.