PDFium Component валидира лимитите за реализизация по ISO 19005-1 Annex C — токени за имена от 127 байта, 8191 елемента на масив, 4095 записа в речник и 28 нива на влагане на контейнери — и отчита символен TrueType шрифт, който носи запис /Encoding. И двете проверки тичат по пътя на байтово сканиране, така че Delphi или Lazarus приложение получава присъдата, без да зарежда PDFium DLL изобщо
Това са провалите, които озадачават хората най-много, защото документът изглежда фин. Рендерира се, печата се, всеки шрифт е вграден, output intent присъства. Тогава валидатор го отхвърля заради речник, който има 4096 записа, и нищо във видния документ не обяснява защо
Какво всъщност предпазват лимитите на Annex C?
Съвместимост с реализации, които предхождат вашия генератор. Annex C пренася лимитите за реализизация от PDF Reference във всяка PDF/A часть, а числата не са произволни — те описват това, което съответстващ четец е бил исторически задължен да обработва. Файл, който ги надвишава, може да се отваря перфектно в модерен четец и да се проваля в архивния четец, върху който система за записи е стандартизирала преди петнадесет години, което е точно сценарият, който PDF/A съществува, за да предотврати
Четирите лимита са включващи. Токен за име от точно 127 байта минава валидация; 128 не минава. Масив с точно 8191 елемента минава; 8192 не минава. PDFium Component заковава и двете страни на всяка граница в своя тестов набор по тази причина, защото грешка «с едно повече» в проверка за лимит произвежда най-лошия вид валидатор: такъв, който отхвърля съответстващи файлове, а му се вярва така или иначе
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;
Кои генератори реално удрят тези лимити?
Такива, които изграждат структура програмно, което е повечето бизнес изход. Формуляр с няколко хиляди полета произвежда масив /Annots или масив AcroForm /Fields, който расте покрай 8191. Страница, чийто речник на ресурси натрупва един запис на генерирано изображение или инстанция на шрифт, пресича 4095. Дълбоко генерирани дървета на структура — маркиран документ, изграден чрез рекурсия върху вложен модел на данни — преминават покрай 28 нива, без никой да забележи, защото никой не гледа дълбочината на влагане
Дългите имена идват от различен навик: кодиране на данни в токени за имена. Име на оцветител, изградено от идентификатор на клиент, optionally-content група, назована на пълен път до файл, поле на формуляр, чието напълно квалифицирано име конкатенира шест нива йерархия. Имената са евтини за генериране и лесни за правене дълги, а 127 байта изчезват по-бързо, отколкото бихте очаквали, след като е замесен UTF-8 кодиран етикет
Поправката е структурна във всеки случай. Разделете масива, разделете речника, изравнете влагането, съкратите името — препоръката за предполетна проверка за всеки проблем назовава конкретния лимит, вместо да ви казва, че файлът е невалиден. Инжектирането на маркери не може да помогне тук: това не са претенции за метаданни, те са формата на графа на обектите
Защо символен TrueType шрифт не трябва да носи /Encoding
Защото ISO 19005-1 §6.3.7 допуска само вградения cmap на шрифта за символни TrueType шрифтове, а запис /Encoding би му противоречил. Символен шрифт съпоставя кодове към глифове на собствени условия — това е точно това, което символно означава. Добавете таблица за кодиране и сега има два отговора на въпроса «кой глиф избира байт 0x41», без правило във файла, казващо кой печели. Различни читатели го разрешават различно, а документ, който се рендерира като текст в един четец, се рендерира като dingbats в друг
PDFium Component чете флага за символност от /FontDescriptor, независимо дали дескрипторът е записан вградено в речника на шрифта, или рефериран индиректно. Несимволен TrueType шрифт запазва своя изискван /WinAnsiEncoding или /MacRomanEncoding, без да бъде маркиран, защото за несимволни шрифтове кодирането е точно това, което стандартът иска. Проверката се задейства на противоречието, а не на присъствието на кодиране
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)');
Практическият източник на този дефект е подмножаване на шрифтове, извършено от продуцент, който третира всеки TrueType шрифт по същия начин. Symbol, Wingdings, баркод шрифтове и иконни шрифтове са обичайните носители — точно шрифтовете, които бизнес документ използва за отметки, лого и баркодове, и точно тези, които никой не преразглежда, когато документ не минава валидация заради «шрифтове»
Как проблемите пристигат в предполетен отчет
Четирите лимита за контейнери са класифицирани под структура; проблемът с кодирането на символен TrueType е класифициран под съдържание. Това разделяне има значение, когато отчет отива при двама различни хора: констатациите за структура обикновено принадлежат на този, който е написал генератора, а констатациите за съдържание — на този, който е доставил активите
Всеки проблем носи препоръка, която назовава лечението в конкретни термини — съкратете токените за имена до 127 байта или по-малко, разделете масивите така, че нито един да не носи повече от 8191 елемента, премахнете /Encoding от символни TrueType шрифтове. Отчет, който казва «не съответства на PDF/A», стартира разследване. Отчет, който казва кой лимит е бил надвишен и с колко, приключва такова
Валидиране без DLL и защо това има значение тук
Всички горепосочени проверки тичат срещу байтовете на файла, така че те работят в услуга, която няма разгърнат PDFium двоичен файл, в стъпка на изграждане, или на машина, където зареждането на нативна DLL е проблем на политика. Това е умишлена дизайн линия в PDFium Component: проверките, които могат да бъдат отговорени от структура, се отговарят от структура, а DLL се запазва за тези, които наистина се нуждаят от рендериращ двигател
За околния работен процес — пускане на валидация върху папка, произвеждане на отчети и решаване какво да се прави с констатациите — вижте ръководствата за PDF/A предполетна валидация в Delphi и CLI за партиден предполетен отчет. За избора на архивен профил, който седи над всички тези проверки, записките за архивно съответствие с PDF/A разглеждат коя част и ниво да целите, преди да започнете да поправяте констатации
PDFium Component обвива двигателя PDFium за Delphi, C++Builder и Lazarus с API от високо ниво VCL и набор валидатори за съответствие, които работят с или без DLL — вижте страницата на продукта PDFium Component за поддържаните стандарти и платформи