Articol tehnic

Ieșire PDF 2.0, PDF/A-4 și PDF/UA-2 cu HotPDF în Delphi

HotPDF scrie documente PDF 2.0 native din Delphi și C++Builder, inclusiv cele trei profiluri de arhivare PDF/A-4 și ieșirea accesibilă PDF/UA-2 cu elemente de structură cu spații de nume. Selecția lor se rezumă la două proprietăți, dar standardele din spatele acelor proprietăți s-au schimbat mai mult decât sugerează numărul versiunii: PDF/A-4 a eliminat literele de conformanță pe care toată lumea le-a învățat cu PDF/A-2, iar PDF/UA-2 a introdus spații de nume de structură pe care un document de partea 1 nu le-a avut niciodată

Acest articol acoperă ce se schimbă de fapt în fișierul generat și ce greșeli HotPDF transformă într-o excepție la EndDoc, mai degrabă decât într-un document care eșuează validarea la client

Cum diferă identificarea PDF/A-4 față de partea 2 și 3

PDF/A-4 se identifică prin numărul de parte și anul reviziei, fără literă de conformanță pentru partea de bază. Setați PDFACompliance la '4', iar HotPDF emite pdfaid:part=4 cu pdfaid:rev=2020 și nicio intrare pdfaid:conformance deloc. Litera nu a dispărut — partea 4 nu are niveluri A/B/U, deoarece cerințele care le separau au fost pliate în partea de bază

Două extensii păstrează o literă. '4E' selectează PDF/A-4e pentru documente de inginerie și emite conformanța E, care permite căile de adnotare 3D și RichMedia pe care celelalte profiluri le interzic. '4F' selectează PDF/A-4f și emite conformanța F, care permite un fișier încorporat în orice format. Toate trei forțează anteturi PDF 2.0, cer verificările obișnuite de intenție de ieșire și metadate PDF/A și interzic criptarea — un fișier de arhivă criptat este o contradicție pe care standardul nu o acceptă

var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := 'invoice-archive.pdf';
    Pdf.PDFACompliance := '4F';   // PDF/A-4f: associated files of any format
    Pdf.BeginDoc;
    Pdf.CurrentPage.SetFont('Arial', [], 11);
    Pdf.CurrentPage.TextOut(50, 760, 0, 'Invoice 2026-0731');
    Pdf.AddPDFAssociatedFile('invoice.xml', 'text/xml',
      'Structured invoice data', 'Data', LoadInvoiceBytes);
    Pdf.EndDoc;
  finally
    Pdf.Free;
  end;
end;

AddPDFAssociatedFile încorporează fișierul, îi construiește FileSpec-ul cu un /AFRelationship, iar îl înregistrează atât în matricea /AF a Catalogului, cât și în arborele de nume EmbeddedFiles. Ambele înregistrări sunt obligatorii; un fișier listat doar într-una dintre ele este cel mai frecvent motiv pentru care o factură hibridă trece o verificare sumară vizuală dar eșuează la un validator real. Șirul de relație acceptă Source, Data, Alternative, Supplement sau Unspecified, iar profilul activ trebuie să fie PDF/A-3, PDF/A-4e sau PDF/A-4f — profilul de bază partea 4 nu admite fișiere asociate. Numele mai vechi AddPDFA3AssociatedFile funcționează încă pentru cod existent

Ce cere PDF/UA-2 și PDF/UA-1 nu cerea

PDF/UA-2 forțează PDF 2.0 și emite pdfuaid:part=2 cu pdfuaid:rev=2024, iar introduce spații de nume în arborele de structură. Un document de partea 1 avea un singur vocabular plat de roluri standard. Un document de partea 2 poate purta roluri personalizate atâta timp cât fiecare aparține unui spațiu de nume declarat, ceea ce face marcarea specifică domeniului lizibilă tehnologiei asistive în loc de a fi o ghicire

Două metode implementează asta. RegisterStructureNamespace creează sau reutilizează un dicționar indirect /Type /Namespace și îl listează în StructTreeRoot /Namespaces, returnând dicționarul astfel încât să îl puteți refolosi. AddStructureElementNS creează un element de structură a cărui intrare /NS pointează la acel dicționar, exact ceea ce licențiază un nume de rol în afara setului standard. Apelurile repetate cu același URI reutilizează un singur dicționar în loc să adune duplicate

var
  Root: THPDFDictionaryObject;
begin
  Pdf.PDFUACompliance := True;
  Pdf.PDFUAPart := 2;             // part 2 forces PDF 2.0
  Pdf.Lang := 'en-US';
  Pdf.BeginDoc;
  Root := Pdf.AddStructureElement('Document', nil);
  Pdf.AddStructureElementNS('WidgetGroup',
    'https://example.com/ns/widgets', Root);
  Pdf.EndDoc;
end;

Lang nu este decorație aici. Un document etichetat fără limbă naturală declarată lasă un cititor de ecran să ghicească pronunția, iar PDF/UA tratează omisiunea ca defect, nu ca preferință

Ce erori de structură prinde EndDoc?

Patru, iar fiecare corespunde unui document care altfel ar ajunge rupt la un validator. Rădăcina de structură trebuie să conțină exact un element Document la nivel superior. Fiecare dicționar de spațiu de nume trebuie să fie indirect, tipizat ca Namespace, și să poarte un URI unic nevid. Fiecare referință /NS a unui element de structură trebuie să se rezolve la un dicționar listat efectiv în matricea rădăcină /Namespaces. Iar un rol fără spațiu de nume trebuie să fie un rol standard PDF 2.0 sau să se rezolve prin RoleMap

Acestea se declanșează la EndDoc deoarece acela este ultimul moment în care întregul arbore există în memorie și primul moment în care este complet. Prinderea lor mai devreme ar însemna respingerea stărilor intermediare valide; prinderea lor mai târziu ar însemna să nu le prindă deloc. Consecința practică pentru codul dumneavoastră este că un bug de structură apare la sfârșitul generării cu un mesaj care numește problema, în loc să apară săptămâni mai târziu ca un raport veraPDF pe care cineva îl înaintează de la un client

Rolurile PDF 2.0 pe care merită să le cunoașteți

Enumerarea tipizată de roluri câștigă DocumentFragment, Aside, Title, FENote, Sub, Em, Strong și Artifact. Trei dintre ele schimbă modul în care marcați documente obișnuite de afaceri. Aside dă în sfârșit barilor laterale și citatelor scoase un cămin care nu este un Sect folosit greșit. FENote marchează notele de subsol și notele de final ca ceea ce sunt, astfel încât un cititor să le poată oferi în loc să le intercaleze cu textul-corp. Em și Strong înlocuiesc ghicirea semantică care venea din marcarea accentuării ca formatare la nivel de span

Supraîncărcarea cu șir acceptă suplimentar forma deschisă Hn, inclusiv H7 și dincolo. PDF 1.7 se oprea la H6, ceea ce forța documentele tehnice profunde să își aplatizeze schița sau să reutilizeze niveluri. Dacă generați documente de standarde, coduri juridice sau cataloage de piese, numai asta poate fi motivul să mutați ieșirea la PDF 2.0

Ce să verificați înainte de a schimba ieșirea de producție

PDF 2.0 este o schimbare de antet cu o coadă lungă. Uneltele de ingestie de arhivă mai vechi, unele RIP-uri de tipar și un număr surprinzător de vizualizatoare line-of-business acceptă doar până la PDF 1.7, iar ele eșuează pe antet mai degrabă decât pe orice ați fi făcut greșit. Înainte de a schimba, confirmați sistemele consumatoare, iar amintiți-vă că selectarea unui profil PDF/A-4 selectează PDF 2.0 indiferent dacă ați cerut sau nu asta

O secvență sigură este să păstrați PDF/A-3 pentru documentele care merg către cititori necunoscuți, să folosiți PDF/A-4f pentru arhive interne unde controlați ingestia, iar să adoptați PDF/UA-2 doar acolo unde politica de accesibilitate îl numește. Dacă lucrați mai întâi pe partea de arhivare, ghidurile despre validarea PDF/A, PDF/X și PDF/UA și despre facturile hibride ZUGFeRD și Factur-X pe PDF/A-3 acoperă alegerile de profil care contează înainte de numărul versiunii, iar notele despre raportarea automată de preflight arată cum să faceți verdictul parte din construcția dumneavoastră în loc de un pas manual

HotPDF livrează întreaga suprafață de autorie PDF 2.0 ca VCL nativ pentru Delphi și C++Builder, astfel încât ieșirea PDF/A-4 și PDF/UA-2 nu are nevoie de niciun motor extern sau redistribuibil — pagina componentei HotPDF listează profilurile suportate și versiunile RAD Studio