Компонентът PDFium Component за Delphi и Lazarus обменя данни от формуляри и анотации чрез XFDF – XML форматът за обмен на данни, дефиниран от ISO 19444-1. Методът TPdf.ExportXFDF сериализира всяка стойност на поле от формуляр и всяка поддържана анотация в заредения документ в XFDF файл или TStream; методът TPdf.ImportXFDF прочита XFDF документа обратно, пресъздавайки анотациите на съответните страници и прилагайки стойностите на полетата. Този двупосочен процес покрива два работни потока, от които всяко документно приложение в крайна сметка се нуждае: рецензент маркира PDF файл в Acrobat и ви изпраща коментарите за сглобяване, или правило за съвместимост изисква данните от формуляри да съществуват в отделен, подлежащ на одит файл, вместо да бъдат вградени в самия PDF
Поддържа ли PDFium импорт и експорт на XFDF?
Самата библиотека PDFium не поддържа това. Нативният C API изобщо няма XFDF или FDF функции – нищо в неговите публични хедъри не чете или записва тези формати, така че никакво обвиване (wrapping) на кода няма да ви помогне. Поради тази причина PDFium Component имплементира цялото XFDF ядро в Pascal, в отделен модул, който изгражда и анализира XML кода директно върху съществуващия модел за данни на анотации и формуляри в TPdf. Записващият метод генерира XML ръчно, а четецът е ръчно написан синтактичен анализатор, така че функцията не добавя зависимости към Delphi XMLDoc или DOM модулите на FPC и работи идентично под Delphi и Lazarus
Това дизайнерско решение е важно при оценка на алтернативите. Ако сте извиквали чисти FPDF_* функции от Pascal, XFDF е пречка: тази функционалност просто не съществува в DLL файла. Компонентът преодолява това ограничение, като разглежда XFDF като чист проблем на сериализация – събиране на стойностите на полетата и записите на анотации, които обвиващият клас вече знае как да чете, записването им като стандартен XML и извършване на обратния процес при импортиране
Какво съдържа един XFDF файл?
Стандартът ISO 19444-1 дефинира XFDF като XML репрезентация на FDF, и неговото съдържание се разделя на два основни блока. Елементът <fields> пренася йерархичните имена на полета от формуляри и техните стойности – всичко, което потребителят е написал, избрал или отбелязал в AcroForm. Елементът <annots> съдържа анотациите: методът TPdf.ExportXFDF поддържа 18 подтипа – text, highlight, underline, strikeout, squiggly, line, circle, square, caret, polygon, polyline, stamp, ink, freetext, fileattachment, sound, link и redact. Анотациите тип Widget нарочно липсват в <annots>, тъй като техните данни се пренасят в <fields>, а вътрешните за четците подтипове като Popup не са част от дефинициите на XFDF
За осигуряване на съвместимост, записът TPdfAnnotation бе разширен с метаданните, които XFDF очаква: Name (уникалният идентификатор NM), Subject, ModificationDate, CreationDate, Icon, Opacity, крайни точки на линии, върхове на полигони и полилинии, както и пътища на жестове с мастило. Всяко ново поле е придружено от булево свойство Has*, така че код, класически писан за по-ранни версии, продължава да се компилира и да генерира същите данни – незададено поле никога не се записва. Ако вече създавате маркировки програмно, същият запис, който използвате за текстови анотации с QuadPoints, сега съдържа всичко необходимо за XFDF
Как се експортират данни от формуляри и анотации към XFDF?
Едно-единствено извикване обработва целия документ. Заредете PDF файла с активирано попълване на формуляри, извикайте ExportXFDF, и компонентът ще обходи всяка страница, ще събере стойностите на полетата и анотациите и ще ги запише в XML. Върнатата стойност е броят на записаните UTF-8 байтове, което служи за бърза проверка в системните дневници
var
Pdf: TPdf;
Bytes: Integer;
begin
Pdf := TPdf.Create(Self);
Pdf.FormFill := True; // needed so field values are live
Pdf.FileName := 'expense-report.pdf';
Pdf.Active := True;
Bytes := Pdf.ExportXFDF('expense-report.xfdf');
ShowMessage(Format('%d bytes of XFDF written', [Bytes]));
end;
И двата процеса поддържат претоварване с TStream, така че няма нужда от използване на временни файлове на диска. Експортирането в TMemoryStream е най-подходящият метод, когато XFDF е насочен към HTTP отговор, база данни или компресиран архив
var
Buffer: TMemoryStream;
begin
Buffer := TMemoryStream.Create;
try
Pdf.ExportXFDF(Buffer); // same XML, no file involved
Buffer.Position := 0;
// hand the stream to a web response, blob column, or zip entry
finally
Buffer.Free;
end;
end;
Как ImportXFDF обединява коментарите обратно в документа?
Импортирането е етапът, в който процесът на рецензиране приключва. Колега анотира договор в Acrobat, експортира коментарите като XFDF и ви изпраща файл от няколко килобайта вместо пълно копие на PDF документа. Методът TPdf.ImportXFDF анализира файла, създава всяка анотация на страницата, указана в атрибута page, и записва стойностите в съответните widget анотации. Функцията връща общия брой на приложените полета и анотации, така че интерфейсът може да потвърди какво точно е заредено
var
Applied: Integer;
begin
Applied := Pdf.ImportXFDF('review-comments.xfdf');
StatusBar.SimpleText :=
Format('%d fields and annotations merged', [Applied]);
end;
Синтактичният анализатор е ръчно написан скенер за тагове, разработен за висока толерантност: непознати елементи се пропускат, инструкции за обработка, декларации DOCTYPE и коментари се игнорират, непрепоръчителни флагове се премахват, а стойностите на атрибутите се декодират през пълния набор от XML препратки, включително UTF-16 сурогатни двойки. XFDF файлове, създадени от Acrobat, уеб четци или други инструменти, се обединяват директно. След като анотациите са в документа, цикълът на рецензиране продължава с функциите за отговори и статуси, описани в статията за изграждане на процес за рецензиране на анотации с PDFium Component, а импортираните стойности на полета участват в логиката за навигация, разгледана в навигация на полета на формуляри
Защо десетичните разделители са важни за XFDF?
Всяка анотация в XFDF се позиционира чрез координатни низове – rect="70.5,540,200,560" и подобни – и стандартът ISO 19444-1 изисква използването на точка за десетичен разделител. Подразбиращото се форматиране на числа с плаваща запетая в Delphi следва регионалните настройки на Windows, така че на немска или френска система функцията FloatToStr превръща 70.5 в 70,5, което поврежда разделения със запетаи списък с координати. Компонентът PDFium Component нормализира всяко число, което записва: десетичният разделител се заменя с точка и излишните нули се премахват, така че експортираният файл е идентичен по байтове, независимо дали е генериран на en-US или de-DE система. Ако някога сте дебъгвали PDF инструмент, който работи в офиса ви, но дава грешки при клиенти в Европа, сте се сблъсквали точно с този клас грешки – добре е да знаете, че компонентът се справя с него автоматично
Какви са ограниченията при двупосочния процес?
Две основни ограничения трябва да се посочат ясно. Първо, XFDF пренася данните за анотациите, а не техния визуален облик (appearance streams не са част от формата), така че приемащият четец регенерира изгледа от свойствата. Маркиране (highlight) или квадрат се изобразяват коректно навсякъде, но печат с персонализиран изглед ще се върне към дизайна, който целевият четец рисува за съответното име. Второ, вграденото PDFium API поддържа задаване на стойности за низове, но не и за числови параметри или геометрия на пътища на анотации, така че Opacity, крайни точки на линии, върхове и жестове с мастило се поддържат само при експорт: компонентът ги запазва коректно при запис на XFDF, но не може да ги запише обратно в PDF при импортиране. Стойности на полета, съдържание, цветове, размери (rects), QuadPoints, дати и метаданни за идентичност се поддържат напълно двупосочно
За бърз старт демонстрационният проект XfdfLab се доставя с примерите за Delphi, C++Builder и Lazarus и свързва двете извиквания с бутони над всеки отворен PDF файл. Поддръжката на XFDF е включена в текущата версия на PDFium Component, заедно с програмните интерфейси за анотации и формуляри, на които тя се базира