Articol tehnic

Generarea fișierelor PDF/A, PDF/X și PDF/UA în Delphi: ghid HotPDF

PDF/A, PDF/X și PDF/UA sunt trei standarde diferite care rezolvă trei probleme diferite: arhivarea pe termen lung, schimbul pentru tipărire și accesibilitatea. Nu sunt trei căsuțe de bifat pe un singur formular de conformitate, iar cea mai comună greșeală este să le tratați ca atare. Un fișier poate fi PDF/A impecabil și inutil pentru o tipografie; un master de tipărire perfect poate fi ilizibil pentru un cititor de ecran. Mai rău, toate trei sunt constrângeri asupra structurii interne a fișierului, nu asupra modului în care arată. Un document care se deschide curat în fiecare vizualizator pe care îl dețineți poate totuși eșua la validare de la prima încercare, și de obicei chiar eșuează

HotPDF, biblioteca PDF nativă VCL a losLab, tratează conformitatea ca pe ceva ce declarați înainte ca prima pagină să existe. Setați o proprietate de conformitate, atașați structurile pe care standardul le cere, iar biblioteca refuză la momentul salvării configurațiile care contrazic profilul. Este un model mai bun decât generarea unui fișier și speranța că un post-procesor îl poate adapta ulterior, pentru că cea mai mare parte din ce cer aceste standarde nu poate fi adăugată după fapt

Trei standarde ISO, trei promisiuni diferite

PDF/A (ISO 19005) este despre timp. Promite că un fișier se va randa identic și peste decenii, așa că cere auto-suficiență completă: fiecare font înglobat, fiecare culoare cu sens independent de dispozitiv printr-un OutputIntent, metadate XMP complete și o interdicție asupra oricărui lucru al cărui comportament depinde de mediu. Criptarea și JavaScript-ul sunt excluse, pentru că nimeni nu poate garanta că decriptorul sau motorul de scripting vor mai exista în 2050

PDF/X (ISO 15930) este despre culoare pe hârtie. Există pentru ca un designer să poată preda un fișier unei tipografii fără ca vreunul dintre ei să trebuiască să discute despre el, ceea ce înseamnă condiții de tipărire caracterizate, o cheie /Trapped obligatorie, geometrie de tăiere și sângerare definită și, în varianta X-1a, nicio transparență live pe care un RIP să trebuiască să o ghicească. PDF/UA (ISO 14289) este despre cine poate citi rezultatul. Tehnologia asistivă are nevoie de un arbore de taguri complet, o ordine de citire rațională, o limbă de document declarată și alternative text pentru orice nu este text

Pentru că cele trei trag în direcții diferite, alegeți standardul dominant pentru fiecare canal de ieșire, în loc să urmăriți un singur fișier care să le satisfacă pe toate. Un master de tipărire doar CMYK este exact lucrul greșit de predat unui utilizator de cititor de ecran care nu vede niciodată culoarea, iar blocarea profilului arhivistic asupra comportamentului dinamic se ciocnește cu orice element interactiv. Generați câte un fișier pentru fiecare canal, din aceleași date sursă, și ocoliți întregul conflict

HotPDF generează fișiere PDF/A, PDF/X și PDF/UA per canal de ieșire dintr-un singur document sursă în Delphi, fiecare standard ISO păstrând o promisiune structurală diferită
PDF/A, PDF/X și PDF/UA trag în direcții diferite, deci HotPDF generează câte un fișier per canal de ieșire din aceeași sursă

PDF/A: OutputIntent este partea pe care toată lumea o uită

Dacă un fișier PDF/A eșuează la validare, OutputIntent este primul lucru de verificat. Este structura pe care generatoarele o omit cel mai des, exact pentru că nimic vizibil nu depinde de ea. ISO 19005 cere unul: un profil ICC înglobat care fixează ce înseamnă de fapt culorile de dispozitiv ale documentului. HotPDF face din acel profil o intrare explicită, nu o idee de ultim moment:

var
  Pdf: THotPDF;
  ICC: TFileStream;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := 'invoice-archival.pdf';
    Pdf.PDFACompliance := 'B';            // nivelul B: fidelitate vizuală
    Pdf.Lang := 'en-US';
    Pdf.StandardFontEmulation := False;   // înglobează fonturi reale, fără emulare Base-14
    ICC := TFileStream.Create('sRGB.icc', fmOpenRead);
    try
      Pdf.AddPDFAOutputIntent('sRGB IEC61966-2.1', '', ICC, 3, 'DeviceRGB');
    finally
      ICC.Free;
    end;
    Pdf.BeginDoc;
    Pdf.CurrentPage.SetFont('Arial', [], 11);
    Pdf.CurrentPage.TextOut(50, 760, 0, 'Archival invoice body');
    Pdf.EndDoc;
  finally
    Pdf.Free;
  end;
end;

Câteva detalii decid aici trecerea sau eșecul. StandardFontEmulation trebuie să fie dezactivat: fonturile Base-14 emulate nu sunt înglobate, iar înglobarea este nenegociabilă conform ISO 19005. Criptarea trebuie să rămână dezactivată, așa că nu combinați niciodată PDFACompliance cu ActivateProtection; un fișier arhivistic criptat este o contradicție pe care validatorul o prinde imediat. Numărul de componente din AddPDFAOutputIntent trebuie să corespundă profilului, care este 3 pentru un profil RGB precum sRGB IEC61966-2.1 și 4 pentru CMYK. HotPDF urmărește utilizarea DeviceRGB și DeviceCMYK față de intenția declarată pe măsură ce scrie, astfel încât o umplere CMYK rătăcită într-un document cu intenție RGB se transformă într-o problemă raportată, nu una silențioasă

Un lucru care merită spus despre profilul ICC: tratați-l ca pe un artefact de implementare cu versiune, nu ca pe un fișier pe care cineva l-a lăsat cândva pe serverul de build. Octeții lui sunt înglobați în fiecare document pe care îl generați, așa că un profil trunchiat sau corupt otrăvește pe tăcute un întreg lot, iar dumneavoastră aflați abia la momentul validării. Livrați-l împreună cu instalatorul dumneavoastră, înregistrați-i suma de control în jurnalul de rulare și încărcați-l prin modelul TFileStream prezentat mai sus, astfel încât un fișier lipsă să eșueze zgomotos în timpul generării, nu tăcut la poarta arhivei

PDF/X pentru tipărire: Trapped, CMYK și profilul de tipar

Masterele de tipărire inversează povestea culorii. Tiparul dorește CMYK caracterizat, iar standardul vă obligă să declarați dacă a fost aplicat trapping-ul, chiar și atunci când răspunsul cinstit este că nu aveți nicio idee. Cheia /Trapped este obligatorie indiferent de situație:

Pdf.PDFXCompliance := 'X-1a';
Pdf.Trapped := 'Unknown';        // cheie obligatorie conform ISO 15930
ICC := TFileStream.Create('FOGRA39.icc', fmOpenRead);
try
  Pdf.AddPDFXOutputIntent('FOGRA39 (ISO 12647-2:2004)', '', ICC, 4, 'DeviceCMYK');
finally
  ICC.Free;
end;
Pdf.BeginDoc;
// desenați cu culori sigure pentru CMYK, fără transparență, fără criptare
Pdf.EndDoc;

Numărul de componente este acum 4 pentru profilul de tipar CMYK. X-1a interzice de asemenea transparența live, așa că auditați orice cod de desenare care stratifică elemente translucide; orice compozitează un vizualizator pe ecran este exact ce va refuza să interpreteze un RIP. Când tipografia dumneavoastră trimite o altă caracterizare, schimbați octeții profilului și șirul de identificare, dar lăsați neatinsă structura din jur

PDF/UA: structura se generează, nu se adaugă ulterior

Accesibilitatea este standardul pe care echipele încearcă cel mai des să îl adauge forțat la final, și pedepsește această abordare mai aspru decât celelalte două. Arborele de taguri trebuie să reflecte ordinea în care conținutul a fost creat logic, iar aceasta este o informație pe care pur și simplu nu o mai aveți odată ce fișierul este scris. Setarea PDFUACompliance activează ieșirea cu taguri, iar API-ul de structură leagă fiecare apel de desenare de rolul său semantic pe măsură ce înaintați:

HotPDF construiește în timp real arborele de etichete PDF/UA pe măsură ce fiecare apel de desenare Delphi se execută, iar textul emis în afara BeginTaggedContent și EndTaggedContent rămâne invizibil cititoarelor de ecran
Arborele de tag-uri este scris în timp ce desenezi, iar textul din afara unei perechi tag-uite se randează bine, dar rămâne invizibil pentru cititoarele de ecran
Pdf.PDFUACompliance := True;     // activează automat PDF-ul cu taguri
Pdf.Lang := 'en-US';             // setați-o explicit; goală, revine la 'en'
Pdf.BeginDoc;

Root := Pdf.AddStructureElement(sstDocument, nil);
H1 := Pdf.EmitTaggedHeading(1, Root, 50, 700, 'Quarterly Report');
Para := Pdf.BeginTaggedContent('P', Root);
Pdf.CurrentPage.TextOut(50, 650, 0, 'Revenue grew in all regions.');
Pdf.EndTaggedContent;

Pdf.EndDoc;

Eșecul de urmărit este textul desenat în afara oricărei perechi BeginTaggedContent/EndTaggedContent. Se randează perfect și rămâne invizibil pentru un cititor de ecran, așa că niciun tester care vede nu îl prinde vreodată; bug-ul ajunge în producție și iese la suprafață doar atunci când un utilizator real de tehnologie asistivă lovește golul. Când șabloanele dumneavoastră poartă nume personalizate de rol de structură, mapați-le peste setul standard cu AddStructRoleMap('MyHead', 'H1'), astfel încât cititoarele conforme să știe ce înseamnă. ISO 14289 cere de asemenea o limbă declarată. HotPDF revine la 'en' atunci când Lang este gol, dar acesta este o plasă de siguranță, nu un motiv de a lăsa nesetată limba reală a documentului

Verificare: aveți încredere în validator, nu în vizualizator

Un vizualizator care deschide fișierul dumneavoastră nu dovedește nimic despre conformitate, așa că verificarea își are locul în fluxul de lansare, cu instrumente care verifică structura, nu randarea. Pentru PDF/A și PDF/UA, veraPDF este validatorul open-source de referință; raportează eșecurile pe clauze ISO, ceea ce se mapează direct înapoi la configurația de mai sus. Pentru PDF/X, profilurile Preflight din Adobe Acrobat rămân verificarea practică, pentru că conformitatea de tipar ține la fel de mult de intenția de culoare cât și de sintaxă

Generatorul își face propria parte din acest lucru. La momentul salvării, HotPDF reconciliază flagurile de funcții cu versiunea PDF configurată, retrogradând pe tăcute ceea ce versiunea nu poate exprima, cum ar fi AES-256 care coboară la AES-128 sub PDF 1.7. Porțile de conformitate din EndDoc merg mai departe și ridică direct o excepție la contradicții dure, cum ar fi cererea de PDFACompliance împreună cu criptarea. Niciuna dintre acestea nu înlocuiește validatorul extern. Ele doar opresc configurațiile imposibile să ajungă vreodată la el

Porțile de conformitate HotPDF din EndDoc prind configurațiile imposibile înainte ca veraPDF să valideze PDF/A și PDF/UA, iar Acrobat Preflight să valideze PDF/X într-o cale de lansare Delphi
HotPDF refuză configurațiile contradictorii la EndDoc, iar validatorii independenți decid conformitatea reală

Un obicei se dovedește repetat util: versionați întreaga configurație de conformitate ca pe o unitate. Versiunea HotPDF, revizia șablonului, suma de control a profilului ICC, versiunea validatorului care a aprobat. Conformitatea derivă în momentul în care oricare dintre acestea se schimbă sub celelalte, iar cele mai urâte audituri sunt cele în care nimeni nu poate reconstitui ce combinație a produs un fișier de arhivă vechi de cinci ani. O singură înregistrare de configurație per lot rezolvă asta definitiv

În sfârșit, rulați validatorul pe ieșiri reale de producție, niciodată pe un eșantion îngrijit, construit manual. Eșecurile care mușcă vin din date pe care nimeni nu le-a anticipat: un logo de client care sosește ca CMYK în timp ce intenția spune RGB, o ajustare de șablon care strecoară un font neînglobat, o nouă cale de cod care desenează text în afara arborelui de taguri. Păstrați câte un fișier cunoscut ca defect din fiecare incident trecut, ca intrare de regresie, iar poarta de conformitate rămâne onestă în timp. Pentru partea de randare a acestor fluxuri, vedeți articolul nostru despre randarea rapoartelor, fonturi și imagini cu HotPDF; pentru cablarea validatorilor într-un build, există o lucrare complementară despre automatizarea verificărilor preflight pentru PDF

Proprietățile de conformitate, output intents și API-ul de taguri folosite în aceste exemple vin incluse în HotPDF Delphi Component pentru Delphi și C++Builder; pagina de produs face legătura către referința completă pentru fiecare apel prezentat aici