PDFium Component validerer ISO 19005-1 Annex C-implementeringsgrænserne — 127-byte-navne-tokens, 8191 array-elementer, 4095 dictionary-poster og 28 niveauer af container-indlejring — og rapporterer en symbolsk TrueType-skrifttype, der bærer en /Encoding-post. Begge tjek kører på byte-scan-stien, så en Delphi- eller Lazarus-applikation får dommet uden at indlæse PDFium-DLL'en overhovedet
Dette er de fejl, der forvirrer folk mest, fordi dokumentet ser fint ud. Det renderer, det printer, hver skrifttype er indlejret, output-intent er til stede. Så afviser en validator det over en dictionary, der har 4096 poster, og intet i det synlige dokument forklarer hvorfor
Hvad beskytter Annex C-grænserne reelt?
Interoperabilitet med implementeringer, der gik forud for din generator. Annex C viderefører PDF Reference-implementeringsgrænserne ind i hver PDF/A-del, og tallene er ikke vilkårlige — de beskriver, hvad en overholdende læser historisk set var forpligtet til at håndtere. En fil, der overskrider dem, kan åbne perfekt i en moderne fremviser og fejle i den arkiv-læser, et registratur-system standardiserede på for femten år siden, hvilket netop er det scenarie, PDF/A eksisterer for at forhindre
De fire grænser er inklusive. Et navne-token på præcis 127 byte validerer; 128 gør ikke. Et array med præcis 8191 elementer validerer; 8192 gør ikke. PDFium Component fastlåser begge sider af hver grænse i sin test-suite af den grund, fordi en off-by-one i et grænse-tjek producerer den værste slags validator: én der afviser overholdende filer og alligevel tror på den
uses FPdfPdfa;
var
Src: TFileStream;
Res: TPdfAValidationResult;
begin
Src := TFileStream.Create('archive.pdf', fmOpenRead or fmShareDenyWrite);
try
Res := ValidatePdfACompliance(Src);
if pvaiArrayOverLimit in Res.Issues then
Memo1.Lines.Add('An array carries more than 8191 elements');
if pvaiDictOverLimit in Res.Issues then
Memo1.Lines.Add('A dictionary carries more than 4095 entries');
if pvaiNestingOverLimit in Res.Issues then
Memo1.Lines.Add('Containers nest deeper than 28 levels');
if pvaiNameOverLimit in Res.Issues then
Memo1.Lines.Add('A name token is longer than 127 bytes');
finally
Src.Free;
end;
end;
Hvilke generatorer rammer reelt disse grænser?
Sådanne der bygger struktur programmatisk, hvilket er det meste line-of-business-output. En formular med flere tusinde felter producerer et /Annots-array eller et AcroForm /Fields-array, der vokser forbi 8191. En side, hvis ressourcedictionary akkumulerer én post pr. genereret billede eller skrifttype-instans, krydser 4095. Dybt genererede strukturtræer — et tagget dokument bygget ved rekursion over en indlejret data-model — går forbi 28 niveauer uden at nogen lægger mærke til det, fordi ingen kigger på indlejrings-dybde
Lange navne kommer fra en anden vane: at indkode data i navne-tokens. Et farve-navn bygget fra en kunde-identifikator, en optional-content-gruppe navngivet efter en fuld fil-sti, et formularfelt, hvis fuldt kvalificerede navn konkatenerer seks niveauer af hierarki. Navne er billige at generere og lette at gøre lange, og 127 byte forsvinder hurtigere, end du ville forvente, når først en UTF-8-indkodet etiket er involveret
Løsningen er strukturel i hvert tilfælde. Split arrayet, split dictionary'en, flad indlejringerne ud, forkort navnet — preflight-anbefalingen for hvert issue navngiver den konkrete grænse frem for at sige dig, at filen er ugyldig. Markør-injektion kan ikke hjælpe her: det er ikke metadata-krav, det er formen af objekt-grafen
Hvorfor må en symbolsk TrueType-skrifttype ikke bære /Encoding?
Fordi ISO 19005-1 §6.3.7 kun admit-ter skrifttypens indbyggede cmap for symbolske TrueType-skrifttyper, og en /Encoding-post ville modsige den. En symbolsk skrifttype mapper koder til glyffer på sine egne vilkår — det er det, symbolsk betyder. Tilføj en kodnings-tabel, og der er nu to svar på spørgsmålet "hvilken glyph vælger byte 0x41", uden nogen regel i filen, der siger, hvilken der vinder. Forskellige læsere resolver det forskelligt, og et dokument, der renderer som tekst i én fremviser, renderer som dingbats i en anden
PDFium Component læser det symbolske flag fra /FontDescriptor, uanset om descriptoren skrives inline i skrifttype-dictionary'en eller refereres indirekte. En ikke-symbolsk TrueType-skrifttype bevarer sin krævede /WinAnsiEncoding eller /MacRomanEncoding uden at blive flagged, fordi for ikke-symbolske skrifttyper er kodningen præcis, hvad standarden beder om. Tjekket affyres på selvmodsigelsen, ikke på tilstedeværelsen af en kodning
if pvaiSymbolicTrueTypeEncoding in Res.Issues then
Memo1.Lines.Add(
'A symbolic TrueType font carries /Encoding; PDF/A admits only its ' +
'built-in cmap (ISO 19005-1 6.3.7)');
Den praktiske kilde til denne defekt er subsetting af skrifttyper udført af en producent, der behandler enhver TrueType-skrifttype ens. Symbol, Wingdings, stregkode-skrifttyper og ikon-skrifttyper er de sædvanlige bærere — præcis de skrifttyper, et forretningsdokument bruger til afkrydsningsfelder, logoer og stregkoder, og præcis de steder, ingen genundersøger, når et dokument fejler validering over "skrifttyper"
Hvordan issues ankommer i en preflight-rapport
De fire container-grænser klassificeres under struktur; det symbolske TrueType-kodnings-issue klassificeres under indhold. Den opsplitning betyder noget, når en rapport går til to forskellige personer: struktur-fund hører normalt til hvem end der skrev generatoren, og indholds-fund hører normalt til hvem end der leverede aktiverne
Hvert issue bærer en anbefaling, der navngiver middlet i konkrete termer — forkort navne-tokens til 127 byte eller færre, split arrays så intet bærer mere end 8191 elementer, fjern /Encoding fra symbolske TrueType-skrifttyper. En rapport der siger "ikke PDF/A-overholdende" starter en undersøgelse. En rapport der siger, hvilken grænse der blev overskredet og med hvad, afslutter én
Validering uden DLL, og hvorfor det betyder noget her
Alle tjekkene ovenfor kører mod fil-byte'ene, så de virker i en tjeneste, der ikke har nogen PDFium-binær udrullet, i et build-trin, eller på en maskine, hvor at indlæse en native DLL er et politik-problem. Det er en bevidst design-linje i PDFium Component: de tjek, der kan besvares fra struktur, besvares fra struktur, og DLL'en reserveres for dem, der reelt har brug for en render-motor
For den omgivende arbejdsgang — at køre validering over en mappe, producere rapporter og beslutte, hvad man skal gøre med fundene — se gennemgangene af PDF/A-preflight-validering i Delphi og batch-preflight-rapport-CLI'en. For det arkiv-profil-valg, der ligger over alle disse tjek, dækker noterne om PDF/A-arkiv-compliance, hvilken del og hvilket niveau der skal målrettes, før du begynder at fikse fund
PDFium Component indpakker PDFium-motoren til Delphi, C++Builder og Lazarus med en high-level VCL-API og et sæt conformance-validatorer, der kører med eller uden DLL — se PDFium Component-produktsiden for de understøttede standarder og platforme