Teknisk artikkel

XFDF-eksport og -import i Delphi med PDFium Component

PDFium-komponenten for Delphi og Lazarus utveksler skjemadata og annoteringer via XFDF, XML-utvekslingsformatet definert av ISO 19444-1. TPdf.ExportXFDF serialiserer hver skjemafeltverdi og hver støttet annotering i det lastede dokumentet til en XFDF-fil eller TStream; TPdf.ImportXFDF leser et XFDF-dokument tilbake, gjenoppretter annoteringer på sidene deres og bruker feltverdiene. Den ene rundreisen dekker to arbeidsflyter enhver dokumentapplikasjon til slutt trenger: en sensor markerer en PDF i Acrobat og sender deg kommentarene for fletting, eller en samsvarsregel sier at skjemadata må leve i en separat, diffbar, reviderbar fil i stedet for å være bakt inn i selve PDF-en

Støtter PDFium import og eksport av XFDF?

Selve PDFium-biblioteket gjør ikke det. Det innfødte C-API-et har ingen XFDF- eller FDF-funksjoner i det hele tatt — ingenting i de offentlige header-filene leser eller skriver noen av formatene, så ingen mengde innpakning får deg dit. PDFium-komponenten implementerer derfor hele XFDF-motoren i Pascal, i a dedikert enhet som bygger og tolker XML-en direkte på toppen av den eksisterende datamodellen for TPdf-annoteringer og skjemafelt. Skrivefunksjonen sender ut XML-en for hånd, og leseren er en håndskrevet tilstandsmaskin-tolker, så funksjonen legger ikke til noen avhengighet av Delphis XMLDoc eller FPCs DOM-enheter, og oppfører seg identisk på Delphi og Lazarus

Dette designvalget betyr noe når du evaluerer alternativer. Hvis du har kalt rå FPDF_*-funksjoner fra Pascal, XFDF er en vegg: funksjonaliteten er rett og slett ikke i DLL-en. Komponenten krysser denne veggen ved å behandle XFDF som et rent serialiseringsproblem — samle feltverdiene og annoteringspostene innpakningen allerede vet hvordan den skal lese, skrive dem ut som standard XML, og snu prosessen ved import

Hva inneholder en XFDF-fil?

ISO 19444-1 definerer XFDF som XML-representasjonen av FDF, og dataene deles inn i to toppnivåblokker. Elementet <fields> bærer hierarkiske skjemafeltnavn og verdiene deres — alt en bruker skrev, valgte eller krysset av i et AcroForm. Elementet <annots> bærer annoteringene: TPdf.ExportXFDF sender ut 18 undertyper — text, highlight, underline, strikeout, squiggly, line, circle, square, caret, polygon, polyline, stamp, ink, freetext, fileattachment, sound, link og redact. Widget-annoteringer mangler bevisst fra <annots> fordi dataene deres reiser i <fields>, og visningsinterne undertyper som Popup er ikke en del av XFDF-vokabularet

For å gjøre rundreisen trofast ble TPdfAnnotation-posten utvidet med metadataene XFDF forventer: Name (den unike NM-identifikatoren), Subject, ModificationDate, CreationDate, Icon, Opacity, linjeendepunkter, polygon- og polylinjemarginer, og blekkmønsterbaner. Hvert nye felt er parret med en boolsk vakt Has*, slik at kode som bygde annoteringer mot tidligere versjoner fortsetter å kompilere og produsere de samme ordbøkene — et udefinert felt blir aldri skrevet. Hvis du allerede oppretter oppmerking programmatisk, den samme posten du bruker for tekstoppmerkingsannoteringer med firkantpunkter nå bærer alt XFDF trenger

Hvordan eksporterer du skjemadata og annoteringer til XFDF?

Ett kall gjør hele dokumentet. Last inn PDF-en med skjemafyll aktivert, kall ExportXFDF, og komponenten går gjennom hver side, samler feltverdier og annoteringer, og skriver XML-en. Returverdien er antallet UTF-8-byte skrevet, noe som gir en rask rimelighetssjekk i loggene

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;

Begge retninger har en TStream-overbelastning, så ingenting tvinger frem en midlertidig fil på disken. Eksport til en TMemoryStream er den naturlige formen når XFDF-en skal sendes til en HTTP-respons, en database-blob eller en signert arkivoppføring

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;

Hvordan fletter ImportXFDF kommentarer tilbake inn i dokumentet?

Importsiden er der sensorens arbeidsflyt lukkes. En kollega annoterer kontrakten i Acrobat, eksporterer kommentarer som XFDF, og sender deg noen kilobyte XML i stedet for en ekstra kopi av PDF-en. TPdf.ImportXFDF tolker den filen, oppretter hver annotering på siden som oppgis i page-attributtet, og skriver feltverdier inn i de matchende widget-annoteringene. Funksjonen returnerer det kombinerte antallet felt pluss annoteringer som er brukt, slik at brukergrensesnittet kan bekrefte nøyaktig hvor mye som ankom

var
  Applied: Integer;
begin
  Applied := Pdf.ImportXFDF('review-comments.xfdf');
  StatusBar.SimpleText :=
    Format('%d fields and annotations merged', [Applied]);
end;

Tolkeren er en håndskrevet tagg-skanner bygd for toleranse snarere enn strenghet: ukjente elementer hoppes over, prosesseringsinstruksjoner, DOCTYPE-deklarasjoner og kommentarer ignoreres, ukjente flaggnavn droppes, og attributtverdier blir konvertert tilbake via det fulle settet av XML-enheter og numeriske tegnreferanser, inkludert UTF-16 surrogate-par. XFDF produsert av Acrobat, en webviser eller et annet verktøy flettes uten oppstyr. Når annoteringer er i dokumentet, fortsetter evalueringssyklusen med svar- og statusmaskineriet beskrevet i bygging av en arbeidsflyt for annoteringsevaluering med PDFium Component, og importerte feltverdier deler i den vanlige tabulatorrekkefølge-logikken dekket i skjemafeltnavigasjon

Hvorfor desimalskilletegn noe for XFDF?

Hver annotering i XFDF er plassert ved hjelp av koordinatstrenger — som rect="70.5,540,200,560" og lignende — og ISO 19444-1 krever punktum som desimalskilletegn. Delphis standard flyttallsformatering følger Windows-lokalen, så på et tysk eller fransk system gjør en naiv FloatToStr gjør 70.5 om til 70,5, noe som ødelegger en kommaseparert koordinatliste til søppel som andre prosessorer avviser eller misforstår. PDFium-komponenten normaliserer hvert tall den skriver: lokalens desimalskilletegn skrives om to et punktum, og etterfølgende nuller trimmes, slik at den eksporterte filen er byte-identisk enten den ble produsert på en en-US- eller en de-DE-maskin. Hvis du noen gang har feilsøkt et PDF-verktøy som fungerte på kontoret og feilet hos en europeisk kunde, har du møtt akkurat denne feilklassen — verdt å vite at komponenten håndterer det for deg

Hva er grensene for rundreisen?

To grenser er verdt å nevne tydelig. For det første transporterer XFDF annoteringsdata, ikke rendrede utseender — utseendestrømmer (appearance streams) er ikke en del av formatet, så den mottakende viseren gjenoppretter utseendet til hver annotering fra dens egenskaper. En markering eller firkant vil tegnes riktig overalt; et stempel med et tilpasset utseende vil falle tilbake på det målviseren tegner for det stempelnavnet. For det andre har det underliggende PDFium-API-et settere for strenger, men ingen for annoteringsnumre eller banedgeometri, så Opacity, linjeendepunkter, hjørner og blekkmønstre er kun for eksport: komponenten bevarer dem trofast når den skriver XFDF, men kan ikke skrive dem tilbake inn i en PDF ved import. Feltverdier, innhold, farger, rektangler, firkantpunkter, datoer og identitetsmetadata kjører rundreise i begge retninger

For en praktisk start leveres XfdfLab-eksempelet i demosettene for Delphi, C++Builder og Lazarus, og kobler begge kallene til knapper over enhver PDF du åpner. XFDF-støtte er inkludert i den gjeldende utgivelsen av PDFium Component, ved siden av annoterings- og skjema-API-ene den bygger på