PDFium Component valideert de ISO 19005-1 Annex C-implementatielimieten — naam-tokens van 127 bytes, 8191 array-elementen, 4095 dictionary-entries en 28 niveaus van container-nesting — en rapporteert een symbolisch TrueType-font dat een /Encoding-entry meedraagt. Beide controles draaien op het byte-scan-pad, zodat een Delphi- of Lazarus-applicatie het verdict krijgt zonder de PDFium-DLL überhaupt te laden
Dit zijn de falen die mensen het meest verwarren, want het document ziet er goed uit. Het rendert, het drukt, elk font is ingesloten, de output-intent is aanwezig. Dan wijst een validator het af over een dictionary dat 4096 entries heeft, en niets in het zichtbare document verklaart waarom
Wat beschermen de Annex C-limieten werkelijk?
Interoperabiliteit met implementaties die aan je generator voorafgaan. Annex C voert de PDF Reference-implementatielimieten door in elk PDF/A-deel, en de getallen zijn niet willekeurig — ze beschrijven wat een conformerende reader historisch moest kunnen verwerken. Een bestand dat ze overschrijdt opent mogelijk perfect in een moderne viewer en faalt in de archiefreader waarop een recordsysteem vijftien jaar geleden is gestandaardiseerd, wat precies het scenario is dat PDF/A bestaat om te voorkomen
De vier limieten zijn inclusief. Een naam-token van precies 127 bytes valideert; 128 niet. Een array met precies 8191 elementen valideert; 8192 niet. PDFium Component pinnt beide kanten van elke grens in zijn testsuite om die reden, want een off-by-one in een limietcontrole produceert het ergste soort validator: een die conformerende bestanden afwijst en toch wordt geloofd
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;
Welke generators raken deze limieten daadwerkelijk?
Generators die structuur programmatisch opbouwen, wat de meeste line-of-business-uitvoer is. Een formulier met enige duizenden velden produceert een /Annots-array of een AcroForm /Fields-array die voorbij 8191 groeit. Een pagina waarvan de resources-dictionary één entry per gegenereerde afbeelding of font-instance accumuleert, overschrijdt 4095. Diep gegenereerde structuurbomen — een getagd document gebouwd door recursie over een genest gegevensmodel — lopen voorbij 28 niveaus zonder dat iemand het merkt, want niemand kijkt naar nestingsdiepte
Lange namen komen voort uit een andere gewoonte: gegevens in naam-tokens coderen. Een kleurnaam gebouwd uit een klantidentificator, een optional-content-group vernoemd naar een volledig bestandspad, een formulierveld waarvan de volledig-gekwalificeerde naam zes hiërarchieniveaus samenvoegt. Namen zijn goedkoop te genereren en gemakkelijk lang te maken, en 127 bytes is sneller weg dan je zou verwachten eens een UTF-8-gecodeerd label is betrokken
De reparatie is in elk geval structureel. Splits de array, splits het dictionary, maak de nesting plat, verkort de naam — de preflight-aanbeveling voor elke issue benoemt de concrete limiet in plaats van je te vertellen dat het bestand ongeldig is. Merker-injectie kan hier niet helpen: dit zijn geen metagegevensclaims, het is de vorm van de objectgrafiek
Waarom een symbolisch TrueType-font geen /Encoding mag meedragen
Omdat ISO 19005-1 §6.3.7 voor symbolische TrueType-fonts alleen de ingebouwde cmap van het font admisseert, en een /Encoding-entry die tegenspreekt. Een symbolisch font mapt codes naar glyphs op eigen voorwaarden — dat is wat symbolisch betekent. Voeg een encoding-tabel toe en er zijn nu twee antwoorden op de vraag "welke glyph selecteert byte 0x41", zonder regel in het bestand die zegt welke wint. Verschillende readers lossen het verschillend op, en een document dat in de ene viewer als tekst rendert, rendert in een andere als dingbats
PDFium Component leest de symbolische vlag uit de /FontDescriptor, of de descriptor nu inline in het font-dictionary wordt geschreven of indirect wordt gerefereerd. Een niet-symbolisch TrueType-font behoudt zijn vereiste /WinAnsiEncoding of /MacRomanEncoding zonder te worden gevlagd, want voor niet-symbolische fonts is de encoding precies wat de standaard vraagt. De controle vuurt op de tegenspraak, niet op de aanwezigheid van een encoding
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)');
De praktische bron van dit defect is font-subsetting door een producent die elk TrueType-font dezelfde manier behandelt. Symbol-, Wingdings-, barcode- en icon-fonts zijn de dragers — precies de fonts die een bedrijfsdocument gebruikt voor checkboxes, logo's en barcodes, en precies de fonts die niemand heronderzoekt wanneer een document faalt bij validatie over "fonts"
Hoe de issues in een preflight-rapport verschijnen
De vier container-limieten worden geclassificeerd onder structuur; de symbolische-TrueType-encoding-issue wordt geclassificeerd onder content. Die splits talt wanneer een rapport naar twee verschillende mensen gaat: structuurbevindingen behoren meestal tot wie de generator schreef, en contentbevindingen meestal tot wie de assets leverde
Elke issue draagt een aanbeveling die het remedie in concrete termen benoemt — verkort naam-tokens tot 127 bytes of minder, splits arrays zodat er geen meer dan 8191 elementen draagt, verwijder /Encoding uit symbolische TrueType-fonts. Een rapport dat zegt "niet PDF/A-conform" start een onderzoek. Een rapport dat zegt welke limiet werd overschreden en waardoor beëindigt er een
Valideren zonder de DLL, en waarom dat hier er toe doet
Alle bovenstaande controles draaien tegen de bestandsbytes, dus ze werken in een service die geen PDFium-binary uitgerold heeft, in een build-stap, of op een machine waar het laden van een native DLL een beleidsprobleem is. Dat is een bewuste ontwerplijn in PDFium Component: de controles die vanuit structuur kunnen worden beantwoord, worden vanuit structuur beantwoord, en de DLL is gereserveerd voor de controles die werkelijk een rendering-engine nodig hebben
Voor de omringende workflow — validatie over een map draaien, rapporten produceren en beslissen wat met de bevindingen te doen — zie de doorlopen van PDF/A-preflight-validatie in Delphi en de batch-preflight-rapport-CLI. Voor de archiefprofielkeuze die boven al deze controles staat, behandelen de notities over PDF/A-archiefconformiteit welk deel en niveau te targeten vóór je begint met het repareren van bevindingen
PDFium Component wikkelt de PDFium-engine voor Delphi, C++Builder en Lazarus met een hoogwaardige VCL-API en een set conformiteitsvalidators die met of zonder de DLL draaien — zie de PDFium Component-productpagina voor de ondersteunde standaarden en platforms