Technický článek

Import a export anotací PDF jako XFDF v Delphi s HotPDF

HotPDF exportuje a importuje anotace PDF jako XFDF pomocí dvou funkcí, které pracují s aktuálně načteným dokumentem: ExportLoadedAnnotationsToXFDF a ImportLoadedAnnotationsFromXFDF. XFDF je formát pro výměnu anotací v XML standardizovaný jako ISO 19444-1 a tato dvojice umožňuje programu v Delphi nebo C++Builder předat své komentáře Acrobatu nebo revizním nástrojům třetích stran a převzít zpět výsledky s poznámkami, to vše bez přepisování obsahu stránek, na kterých anotace leží

Představte si dva směry, které to řeší. Recenzent otevře váš vygenerovaný report v Acrobatu, umístí červenou šipku na špatně zarovnaný obrázek, zakroužkuje chybný součet a napíše poznámku na okraj, pak komentáře exportuje do malého souboru XFDF. Nebo naopak: značky vytvoří váš program sám a potřebujete je poslat někomu, jehož nástroj není HotPDF. V obou případech anotace putují jako XML, kterému rozumějí obě strany, a stránky PDF zůstávají bajt po bajtu tím, čím byly

Diagram HotPDF znázorňující obousměrný přenos XFDF: načtené PDF exportuje anotace do souboru XFDF a importuje je zpět, zatímco stránky zůstávají nedotčené
Jeden soubor XFDF přenáší komentáře v obou směrech, zatímco stránky PDF zůstávají bajtově totožné

Jaký je rozdíl mezi FDF a XFDF?

FDF a XFDF nesou stejný obsah ve dvou různých syntaxích a rozdíl začne být důležitý ve chvíli, kdy se rozhodujete, který soubor předat jinému nástroji. FDF je starší Forms Data Format definovaný přímo ve specifikaci PDF: používá syntaxi objektů PDF, takže soubor FDF vypadá jako osekané PDF a k přečtení potřebuje parser, který PDF rozumí. XFDF je vyjádření týchž dat v XML, standardizované samostatně jako ISO 19444-1, což znamená, že jej dokáže otevřít, porovnat nebo vygenerovat jakákoli knihovna XML na jakékoli platformě. Oba formáty mohou nést hodnoty formulářových polí ve stromu <fields>, který upravuje článek 6.3 normy ISO 19444-1, a anotace ve stromu <annots>; HotPDF tyto odpovědnosti rozděluje: formulářová data směruje přes ExportLoadedFormToXFDF a ExportLoadedAnnotationsToXFDF vyhrazuje pro stranu <annots>. Když si vyměňujete komentáře s webovou službou, revizním serverem v Javě nebo skriptem, je XFDF formát, který druhou stranu nenutí zabudovat parser PDF

Diagram HotPDF porovnávající FDF a XFDF, tentýž obsah anotací zapsaný syntaxí objektů PDF nebo jako XML podle ISO 19444-1
FDF mluví syntaxí objektů PDF, zatímco XFDF mluví XML, takže stejný obsah dosáhne na mnohem více čtenářů

Jak exportovat anotace PDF jako XFDF v Delphi?

HotPDF exportuje anotace tak, že projde každou stránku načteného dokumentu, pro každou podporovanou anotaci vydá jeden prvek XFDF a vrátí počet zapsaných anotací. Nejprve načtěte PDF, poté zavolejte ExportLoadedAnnotationsToXFDF s cílovou cestou. Celočíselný výsledek je počet serializovaných anotací; výsledek nula nebo méně znamená, že nebylo exportováno nic a žádný soubor nebyl zapsán, což je signál, že dokument neobsahoval žádné anotace podporovaného podtypu

var
  Pdf: THotPDF;
  Written: Integer;
begin
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('report-reviewed.pdf', '') > 0 then
    begin
      // Zapíše jeden prvek XFDF pro každou podporovanou anotaci na každé stránce
      Written := Pdf.ExportLoadedAnnotationsToXFDF('comments.xfdf');
      if Written <= 0 then
        ShowMessage('No supported annotations were found');
    end;
  finally
    Pdf.Free;
  end;
end;

XFDF, které vznikne, je prosté, čitelné XML. HotPDF zapíše kořenový prvek <xfdf> ve jmenném prostoru ISO 19444-1, kontejner <annots> a jeden dceřiný prvek na anotaci s indexem stránky počítaným od nuly, barvou a geometrií jako atributy nebo dceřiné prvky. Čára se žlutou výplní a otevřenou šipkou vedle vyplněného polygonu se serializuje takto

<?xml version="1.0" encoding="UTF-8"?>
<xfdf xmlns="http://ns.adobe.com/xfdf/">
  <annots>
    <line page="0" start="72,700" end="220,700"
          color="#FF0000" interior-color="#FFFF00"
          head="OpenArrow" tail="None">
      <contents-richtext>Baseline looks off</contents-richtext>
    </line>
    <polygon page="0" color="#0000FF" interior-color="#CCE5FF">
      <vertices>72,120;180,120;180,200;72,200</vertices>
    </polygon>
  </annots>
</xfdf>

Jak se podtypy anotací mapují na prvky XFDF

Každý podtyp anotace se mapuje na konkrétní prvek ISO 19444-1 s vlastní konvencí geometrie a HotPDF se těchto struktur drží, místo aby vymýšlel vlastní. Čárové anotace nesou atributy start a end s dvojicemi souřadnic obou koncových bodů převzatými přímo z pole L anotace, zatímco styly zakončení čar LE se stanou atributy head a tail. Anotace polygonů a lomených čar přesouvají svůj seznam bodů do dceřiného prvku <vertices> jako dvojice x,y oddělené středníky, nikoli do atributu, protože čtečka očekávající dceřiný prvek by body ukryté kdekoli jinde tiše zahodila. Anotace typu ink, které mohou obsahovat několik samostatných tahů, vnořují prvek <inklist> s jedním dceřiným prvkem <gesture> na tah, takže podpis z více tahů přežije cestu jako samostatná gesta, ne jako jedna slitá skvrna

Formátovaný text, barva a styl ohraničení přežívají spolu s geometrií. Tělo poznámky s formátovaným textem se zapisuje jako dceřiný prvek <contents-richtext>; vnitřní výplň, kterou PDF ukládá v poli IC, tedy barva uvnitř kruhu, čtverce, polygonu nebo šipky čáry a výplň redakčního rámečku, přechází jako atribut interior-color ve tvaru #RRGGBB; a šířka ohraničení, vzor čárkování a efekt oblačného okraje se mapují na atributy width, dashes, style a intensity, takže popisek s oblačným obrysem se na druhém konci stále čte jako oblačný. HotPDF také zachovává vyskakovací okno připojené ke značkovací anotaci, importuje geometrii dceřiného prvku popup a jeho otevřený nebo zavřený stav do slovníku Popup anotace, a přenáší stavy otevření a revize textových anotací, takže revidovaný dokument si zachová nejen tvary, ale i metadata pracovního postupu, na která recenzenti spoléhají

Diagram HotPDF mapující vlastnosti anotací PDF typu čára, polygon, ink a formátovaný text na jejich atributy a dceřiné prvky XFDF
Každý podtyp anotace sleduje svou konvenci geometrie podle ISO 19444-1 místo soukromého dialektu

Import XFDF zpět do načteného dokumentu

HotPDF importuje XFDF tak, že rozparsuje XML, pro každý prvek vytvoří pomocí NewLoadedAnnotation novou anotaci, připojí ji ke stránce, kterou prvek uvádí, a vrátí počet přidaných anotací. Pracovní postup je symetrický s exportem: načtěte základní PDF, zavolejte ImportLoadedAnnotationsFromXFDF se souborem od recenzenta a poté načtený dokument uložte, aby se nové značky zachovaly. Pokud soubor chybí nebo XML nelze rozparsovat, funkce vrátí nulu a načtený dokument zůstane nedotčen

var
  Pdf: THotPDF;
  Added: Integer;
begin
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('report.pdf', '') > 0 then
    begin
      Added := Pdf.ImportLoadedAnnotationsFromXFDF('comments.xfdf');
      if Added > 0 then
        Pdf.SaveLoadedDocument('report-annotated.pdf');
    end;
  finally
    Pdf.Free;
  end;
end;

Protože každý prvek XFDF uvádí vlastní index stránky, anotace přistanou na stránkách, pro které byly vytvořeny, i když importujete několik souborů za sebou, a je tedy bezpečné shromáždit komentáře od více recenzentů do téhož načteného dokumentu před jediným uložením. Příklad níže slučuje dva recenzenty do jedné sloučené kopie. Pokud chcete objekty anotací vytvářet a upravovat přímo v kódu, místo abyste si je vyměňovali jako soubory, podívejte se, jak HotPDF vytváří a upravuje objekty anotací PDF přímo z Delphi

var
  Pdf: THotPDF;
  Total, I: Integer;
  Files: array[0..1] of string;
begin
  Files[0] := 'alice-comments.xfdf';
  Files[1] := 'bob-comments.xfdf';
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('master.pdf', '') > 0 then
    begin
      Total := 0;
      for I := Low(Files) to High(Files) do
        Inc(Total, Pdf.ImportLoadedAnnotationsFromXFDF(Files[I]));
      if Total > 0 then
        Pdf.SaveLoadedDocument('master-merged.pdf');
    end;
  finally
    Pdf.Free;
  end;
end;

Co se přenese čistě a co ne

HotPDF obousměrně přenáší podtypy anotací, kterým ISO 19444-1 dává místo, a ostatní záměrně přeskakuje, místo aby vydával něco, co by si čtečka vyložila špatně. Podporovaná množina pokrývá značkovací typy, které v reálné revizní práci převládají: textové poznámky, volný text, čáru, čtverec, kruh, polygon, lomenou čáru, čtyři typy textového značkování (zvýraznění, podtržení, přeškrtnutí a vlnovku), razítko, ink a caret, plus přílohu souboru, zvuk, redakci a odkaz, celkem osmnáct podtypů. Anotace, jejíž podtyp leží mimo tento seznam, je při exportu vynechána, a protože je přeskočena místo zapsána prázdná, nenavyšuje počet, který funkce vrací

Formátovaný text je poctivá výhrada. HotPDF zachovává tělo <contents-richtext>, takže stylovaný text i prostý obsah cestu absolvují, ale XFDF nese text komentáře a značky stylu, nikoli vykreslený vzhledový stream, takže přijímající aplikace překreslí popup vlastními fonty a rozvržením, místo aby reprodukovala přesné pixely HotPDF. Berte obousměrný přenos jako věrný obsahu a záměru, ne vykreslení na obrazovce do posledního pixelu. Pokud váš stylovaný obsah žije ve formulářových datech XFA místo v anotačních streamech, platí jiná pravidla a tuto samostatnou cestu popisuje článek jak HotPDF zpracovává XFA exData, formátovaný text a hypertextové odkazy

Zpracování na úrovni znaků je přísnější, než vypadá, což je přesně to, co chcete. HotPDF při zápisu textu uplatňuje pravidla escapování z článku 5.8.2 normy ISO 19444-1, kóduje znaky významné pro XML i řídicí bajty, takže komentář obsahující ampersand, lomenou závorku nebo zalomení řádku vytvoří dobře formované XML, které přijme každý vyhovující parser, a při importu tatáž pravidla obrací. Proto se poznámka vložená z tabulky, i s veškerou interpunkcí, vrátí neporušená, místo aby soubor poškodila

Výměna anotací je jen jednou částí toho, co API načteného dokumentu umí, a skládá se se zbytkem: importujte XFDF od recenzenta, upravte stránky nebo upravte metadata dokumentu, sloučte anotace do obsahu nebo změňte oprávnění souboru a poté exportujte čerstvé XFDF pro další kolo. To vše je součástí standardní komponenty HotPDF pro Delphi pro Delphi a C++Builder, jejíž referenční dokumentace popisuje úplné pokrytí podtypů anotací i doprovodné funkce XFDF pro formulářová data