Un archivio governativo una volta respinse un intero deposito di 1.400 fatture generate dal sistema di fatturazione Delphi di un cliente. Ogni file si apriva perfettamente in ogni viewer provato dal cliente; veraPDF li rifiutava tutti per lo stesso unico motivo: un OutputIntent mancante. L'episodio cattura la lezione centrale del lavoro su PDF conformi agli standard: la correttezza visiva non prova nulla, perché PDF/A, PDF/X e PDF/UA sono vincoli sulla struttura interna del file, non su come appare. HotPDF, libreria PDF VCL nativa di losLab, integra questi vincoli nella generazione del documento, così la conformità viene configurata prima che esista la prima pagina invece di essere rattoppata dopo.
Tre standard ISO, tre promesse diverse
PDF/A (ISO 19005) promette che un file verrà renderizzato identico anche tra decenni, ed è per questo che richiede autosufficienza completa: ogni font incorporato, ogni colore device-independent tramite OutputIntent, metadati XMP completi e divieto di qualunque cosa il cui comportamento dipenda dall'ambiente, inclusi crittografia e JavaScript. PDF/X (ISO 15930) promette scambio cieco tra designer e tipografia, quindi le sue regole riguardano colore e geometria: condizioni di stampa caratterizzate, chiave /Trapped obbligatoria, geometrie trim e bleed definite e, nella variante X-1a, niente trasparenza live. PDF/UA (ISO 14289) promette che la tecnologia assistiva possa leggere il documento, quindi impone requisiti sulla struttura logica: tag tree completo, ordine di lettura corretto, lingua documento dichiarata e alternative testuali per contenuto non testuale.
Queste promesse tirano in direzioni diverse. Un form interattivo va bene in PDF/UA ed è impossibile da combinare con le restrizioni del profilo archivistico sul comportamento dinamico; un master di stampa solo CMYK è esattamente sbagliato per utenti di screen reader che non vedono mai il colore. Decidi per ogni canale di output quale standard governa, invece di inseguire un unico file che soddisfi tutto.
PDF/A in HotPDF: l'OutputIntent è il punto decisivo
Il respingimento dell'archivio sopra dipendeva da una sola struttura mancante, ed è la struttura che la maggior parte dei generatori dimentica perché nulla di visibile dipende da essa. ISO 19005 richiede un OutputIntent: un profilo ICC incorporato che dia ai colori device un significato non ambiguo. HotPDF rende il profilo un input esplicito:
var
Pdf: THotPDF;
ICC: TFileStream;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'invoice-archival.pdf';
Pdf.PDFACompliance := 'B'; // level B: visual fidelity
Pdf.Lang := 'en-US';
Pdf.StandardFontEmulation := False; // embed real fonts, no Base-14 emulation
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;
Tre dettagli di configurazione decidono pass o fail. StandardFontEmulation deve essere disattivato, perché i font Base-14 emulati per definizione non sono incorporati, e l'embedding è non negoziabile sotto ISO 19005. La crittografia deve restare disabilitata; non combinare PDFACompliance con ActivateProtection, perché un file archivistico cifrato è una contraddizione che il validatore intercetterà. E il conteggio componenti passato a AddPDFAOutputIntent deve corrispondere al profilo, 3 per un profilo RGB come sRGB IEC61966-2.1. HotPDF traccia l'uso di DeviceRGB e DeviceCMYK durante la generazione rispetto all'intent dichiarato, così un riempimento CMYK in un documento con intent RGB emerge come problema di validazione invece che come incoerenza silenziosa.
Tratta il profilo ICC stesso come artefatto di deployment con una versione, non come file che qualcuno ha copiato una volta sul build server. I byte del profilo vengono incorporati in ogni documento generato, quindi un profilo corrotto o troncato avvelena un intero batch in una volta sola, e il fallimento appare solo in validazione. Distribuisci il profilo con l'installer, registra il suo checksum nel log di esecuzione e caricalo con il pattern TFileStream sopra, così un file mancante fallisce rumorosamente durante la generazione invece che in silenzio al gate di archivio.
PDF/X per la stampa: Trapped, CMYK e profilo di macchina
I master di stampa ribaltano la storia del colore: la macchina vuole CMYK caratterizzato, e lo standard insiste che tu dichiari se il trapping sia stato applicato. La chiave /Trapped è obbligatoria anche quando la risposta onesta è che non lo sai:
Pdf.PDFXCompliance := 'X-1a';
Pdf.Trapped := 'Unknown'; // mandatory key under 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;
// draw with CMYK-safe colors, no transparency, no encryption
Pdf.EndDoc;
Nota che il conteggio componenti è passato a 4 per il profilo di macchina CMYK. X-1a esclude inoltre la trasparenza live, quindi rivedi qualunque codice di disegno che stratifica elementi traslucidi; ciò che un viewer compone a schermo è precisamente ciò che un RIP rifiuta di indovinare. Se la tipografia ti consegna una caratterizzazione diversa, sostituisci profilo e identificatore ma mantieni identica la struttura.
PDF/UA: la struttura viene generata, non adattata dopo
L'accessibilità è lo standard che i team tentano più spesso di aggiungere alla fine, ed è quello in cui il retrofit fallisce di più, perché il tag tree deve rispecchiare l'ordine logico con cui il contenuto è stato creato. In HotPDF, impostare PDFUACompliance attiva l'output tagged, e l'API di struttura collega ogni chiamata di disegno al suo ruolo semantico:
Pdf.PDFUACompliance := True; // auto-enables tagged PDF
Pdf.Lang := 'en-US'; // set explicitly; empty falls back to '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;
Il pattern di errore da sorvegliare è contenuto disegnato fuori da qualunque coppia BeginTaggedContent/EndTaggedContent: renderizza normalmente ed è invisibile a uno screen reader, il peggior tipo di fallimento perché nessun tester vedente lo noterà. Se i tuoi template usano nomi di ruolo struttura personalizzati, mappali sul set standard con AddStructRoleMap('MyHead', 'H1') così i reader conformi sanno interpretarli. ISO 14289 richiede anche una lingua dichiarata; HotPDF sostituisce 'en' quando Lang è vuoto, che è una rete di sicurezza, non una scusa per saltare l'impostazione della lingua reale del documento.
Verifica: fidati del validatore, non del viewer
La storia della fattura ha una morale semplice: integra la verifica nel percorso di release con strumenti che controllano la struttura, non il rendering. Per PDF/A e PDF/UA, veraPDF è il validatore aperto di riferimento e riporta i fallimenti per clausola ISO, rendendo il suo output direttamente azionabile rispetto alla configurazione mostrata sopra. Per PDF/X, i profili Preflight di Adobe Acrobat restano il controllo pratico, perché le condizioni di stampa riguardano l'intento colore tanto quanto la sintassi. Dentro il generatore, HotPDF riconcilia i flag di funzionalità con la versione PDF configurata al momento del salvataggio — degradando in silenzio ciò che la versione non può esprimere, come AES-256 sotto PDF 1.7 — mentre i gate di conformità in EndDoc sollevano errori netti su contraddizioni dure come combinare PDFACompliance con crittografia. Nessun controllo sostituisce il validatore esterno; insieme impediscono alle configurazioni impossibili di arrivarci.
Versiona insieme l'intera configurazione di compliance: release HotPDF, revisione template, checksum del profilo ICC e versione del validatore che ha approvato. La conformità deriva quando uno qualsiasi di questi elementi cambia sotto gli altri, e gli audit più dolorosi che abbiamo visto erano quelli in cui nessuno sapeva dire quale combinazione avesse prodotto un file archivio di cinque anni prima. Un singolo record di configurazione per batch chiude la domanda in modo permanente.
Esegui il validatore su output reale di produzione, non su un campione costruito a mano. I fallimenti importanti vengono dai dati: un logo cliente che arriva in CMYK mentre l'intent dice RGB, una revisione template che introduce un font non incorporato, un nuovo percorso codice che disegna testo non tagged. Conserva un file noto-fallente per ogni incidente passato come input di regressione, e il gate di compliance resta onesto. Per il lato rendering di queste pipeline, vedi il nostro articolo su output report, font e immagini con HotPDF, e per collegare i validatori a una build, l'articolo collegato sull'automazione dei controlli PDF preflight.
FAQ
Un PDF può essere conforme a PDF/A e PDF/X allo stesso tempo?
A volte, ma raramente vale la ginnastica dei vincoli: il profilo archivistico vuole colore device-independent e metadati completi, quello di stampa vuole CMYK caratterizzato e dichiarazioni di trapping. Genera per canale a partire dagli stessi dati sorgente invece di forzare un file unico a servire entrambi.
Perché veraPDF rifiuta un file che si apre bene in ogni viewer?
I viewer sono deliberatamente permissivi; i validatori sono deliberatamente rigorosi. OutputIntent mancanti, font non incorporati e metadati XMP assenti non influenzano mai il rendering, quindi solo un validatore strutturale li segnalerà.
Le fatture dovrebbero usare PDF/A livello A o livello B?
Il livello B garantisce la riproduzione visiva ed è ciò che la maggior parte degli archivi richiede per documenti aziendali scansionati o generati. Il livello A aggiunge i requisiti di struttura tagged, incorporando di fatto il lavoro PDF/UA, ed è la scelta corretta quando gli obblighi di accessibilità si applicano all'archivio stesso.
Approfondimenti
Le proprietà di compliance, gli output intent e l'API di tagging in questo articolo fanno tutti parte di HotPDF Component per Delphi e C++Builder; la pagina prodotto collega il riferimento completo per ogni chiamata usata qui.