Компонентът PDFium за Delphi валидира готови за печат PDF/X документи чрез TPdf.ValidatePdfX, който имплементира проверка по ISO 15930 в два слоя: осем проверки на съдържанието на ниво байтове (забрана на LZW компресия, JavaScript, формулярни полета, OPI препратки, липсващ TrimBox, незададен Trapped ключ и др.) плюс преминаване през обективния модел на PDFium, което използва FPDFFont_GetIsEmbedded за проверка на вграждането на шрифтове за всеки текстов обект на всяка страница; Резултатът е запис TPdfXValidationResult, който посочва откритото ниво на съответствие и изброява всяко нарушение като типизирано изброяване (enum), така че вашето приложение на Delphi може да каже на клиента точно защо файлът ще бъде отхвърлен в печатницата, преди някой да е изложил пластините
Ако някога сте изпращали поръчка на търговска печатница и сте я получавали обратно с отказ от един ред — „няма TrimBox“, „шрифтовете не са вградени“, „Trapped не е зададен“ — знаете каква е цената да разберете твърде късно; PDF/X е съответствието за предпечатната подготовка на PDF/A: докато архивният PDF/A гарантира, че документът ще се рендерира идентично след десетилетия, PDF/X гарантира, че документът ще се раздели на цветове, ще се експонира и ще се обреже идентично на RIP на някой друг утре сутрин; Двата стандарта споделят сходни механизми (XMP идентификация, OutputIntents, вградени ICC профили), но отговарят на различни въпроси, поради което компонентът доставя отделни валидатори за всеки — страната на PDF/A е разгледана в PDF/A предварителна проверка с компонента PDFium
Какво всъщност изисква ISO 15930 от готов за печат PDF?
ISO 15930 съществува, за да направи възможен обмена на сляпо: дизайнерът предава файл на печатница, с която никога не е разговарял, и печатницата може да произведе правилен резултат без телефонно обаждане, без имейл за липсващ шрифт и без свързано изображение, останало на лаптопа на дизайнера; Всяко правило в стандарта служи на тази цел; Шрифтовете трябва да бъдат вградени, тъй като не може да се предполага, че получаващият RIP ги притежава; Външните препратки са забранени, тъй като файлът трябва да бъде напълно самостоятелен; Интерактивните функции са забранени, тъй като мастилото няма манипулатор за кликване
Компонентът PDFium разпознава три семейства съответствие и ги докладва чрез изброяването TPdfXConformance в резултата от валидирането: pxc1a за PDF/X-1a:2001 (ISO 15930-1, строгата CMYK-плюс-spot база върху PDF 1.3/1.4), pxc3 за PDF/X-3:2002 (ISO 15930-3, който допуска RGB, Lab и управлявани от ICC цветове) и pxc4 за PDF/X-4:2010 (ISO 15930-7, който най-накрая позволява прозрачност на живо и слоеве върху PDF 1.6 база); Файл, който изобщо не носи PDF/X идентификация, се връща като pxcNone, което само по себе си е полезен отговор: документът никога не е твърдял, че е готов за печат, а всичко останало, което валидаторът докладва, обяснява какво е необходимо, за да се стигне дотам
Забраните имат смисъл, след като започнете да мислите като доставчик на RIP; /LZWDecode е забранен във всички варианти на PDF/X, така че съвместимият потребител никога да не зависи от филтър с история на съвместимост и лицензиране; Flate върши същата работа без този товар; JavaScript, AcroForm полета и речници с допълнителни действия /AA са забранени, тъй като файлът за печат трябва да бъде фиксирано описание на маркировки върху хартия — всичко, което може да промени външния вид при отваряне, нарушава гаранцията, че това, което е одобрено, е това, което се печата; OPI (Open Prepress Interface) маркерите са забранени, тъй като по дизайн те са препратки към изображения с висока разделителна способност, съхранявани другаде, а „другаде“ е точно това, което обменът на сляпо забранява
Защо печатниците отхвърлят PDF файлове без TrimBox?
TrimBox е готовият за рязане лист — правоъгълникът, който остава след срязването на гилотината; MediaBox, който всяка PDF страница има, е просто листът: той включва наддаването за обрязване (bleed), маркировки за рязане, регистрационни мишени и цветни скали; Софтуерът за монтаж позиционира страниците върху печатния лист по техните TrimBoxes; без такъв оператор трябва да гадае къде всъщност свършва вашата визитка, а грешното предположение отрязва наддаването или оставя бяла ивица на единия ръб; Ето защо ISO 15930 изисква TrimBox (или ArtBox) на всяка страница и защо ValidatePdfX докладва pvxiMissingTrimBox, когато не е намерен ключ /TrimBox на нито една страница от документа
Ключът /Trapped отговаря на друг производствен въпрос; Трапингът (trapping) е предпечатна техника за леко застъпване на съседни цветове, така че минимално несъответствие при печат да не отваря бели празнини между тях; Печатницата трябва да знае дали тази работа вече е свършена: трапирането на вече трапиран файл удвоява застъпванията, а пропускането на трапинг при нетрапиран файл рискува видими празнини; Поради това PDF/X изисква речникът Info да декларира /Trapped /True или /Trapped /False изрично — липсващ ключ или /Unknown принуждава оператор да инспектира файла, което е точно разговорът, който обменът на сляпо трябваше да елиминира; Компонентът маркира това като pvxiTrappedNotSet
Изпълнение на двуслойната валидация с TPdf.ValidatePdfX
Методът TPdf.ValidatePdfX не приема аргументи и връща запис TPdfXValidationResult с три члена: Conformance (откритият PDF/X вариант), Issues (Pascal набор от стойности TPdfXValidationIssue) и помощна функция IsCompliant; Вътрешно той сериализира заредения документ в поток от паметта, изпълнява инспектора на ниво байтове над него и след това обхожда обективния модел на PDFium за проверка на вграждането на всеки шрифт; Една минимална проверка преди печат изглежда така:
uses PDFium, FPdfPdfx;
procedure CheckPrintReadiness(const FileName: string);
var
Pdf: TPdf;
Res: TPdfXValidationResult;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := FileName;
Pdf.Active := True;
Res := Pdf.ValidatePdfX;
Writeln('Detected conformance: ',
Ord(Res.Conformance)); // pxc1a, pxc3, pxc4, pxcNone...
if Res.IsCompliant then
Writeln('PDF/X checks passed')
else
begin
if pvxiMissingTrimBox in Res.Issues then
Writeln('REJECT: no /TrimBox on the pages');
if pvxiTrappedNotSet in Res.Issues then
Writeln('REJECT: /Trapped missing or /Unknown');
if pvxiPdfiumFontNotEmbedded in Res.Issues then
Writeln('REJECT: a page uses a non-embedded font');
if pvxiLzwForbidden in Res.Issues then
Writeln('REJECT: LZWDecode filter present');
end;
finally
Pdf.Free;
end;
end;
Тъй като Issues е обикновен Pascal набор, можете да го разделите според нуждите на вашия работен процес — третирайте структурните проблеми като твърди откази, третирайте pvxiMissingTitle (препоръка в стандарта, а не задължение) като предупреждение и записвайте останалото в лога; Същият тип запис захранва и генератора на отчети на компонента, така че ако предпочитате да издадете четим от човек документ, вместо да се разклонявате по enums, моделът в изграждането на CLI за пакетен отчет преди печат с компонента PDFium се прилага към PDF/X без промяна
Какво улавя слоят на ниво байтове и какво пропуска
Слоят на ниво байтове е сканиране на токени в структурните байтове на документа с празни тела на потоците, така че JPEG файл, който случайно съдържа байтовата последователност /JavaScript, не може да задейства фалшиво положителен резултат; В допълнение към проверките на маркери (XMP pdfxid:GTS_PDFXVersion, OutputIntent с вграден ICC профил, трейлър /ID, забрана на шифроване), преминаването през съдържанието добавя осем проверки, всяка със своя стойност на enum:
pvxiLzwForbidden— филтър/LZWDecodeсе появява някъде във файла (забранен във всички варианти на PDF/X)pvxiJavaScriptForbidden— налично е действие/JavaScriptили дърво с именаpvxiFormFieldsForbidden— съществува речник/AcroFormили запис/XFApvxiAdditionalActions— наличен е речник за допълнителни действия/AApvxiEmbeddedFilesForbidden— налично е/EmbeddedFilesили анотация/FileAttachmentpvxiOpiForbidden— запис/OPIили/Alternatesпрепраща към сменяемо съдържание на изображениеpvxiMissingTrimBox— няма намерен/TrimBoxна нито една страницаpvxiTrappedNotSet—/Trappedлипсва или е зададен на/Unknown
Сканирането на ниво байтове е бързо и не се нуждае от рендериращ двигател, но има вродено сляпо петно с шрифтовете: на това ниво инспекторът може да приложи само груба евристика — той маркира документа като грешен, когато не открие вградена програма за шрифт изобщо; Файл с девет вградени шрифта и един вмъкнат системен шрифт изглежда добре при сканиране по байтове; Тази единствена празнина е причината да съществува вторият слой
Вграждане на шрифтове чрез обективния модел на PDFium
Слоят на обективния модел на компонента PDFium отговаря точно на въпроса за шрифтовете; След преминаването на ниво байтове, TPdf.ValidatePdfX обхожда всяка страница, извиква FPDFPage_CountObjects за списъка с обекти и за всеки текстов обект извлича дескриптора на шрифта чрез FPDFTextObj_GetFont и прави запитване към FPDFFont_GetIsEmbedded; Един-единствен невграден шрифт някъде в документа добавя pvxiPdfiumFontNotEmbedded към набора от проблеми; Обхождането се прекратява на две нива — спира сканирането на обекти на дадена страница и спира зареждането на следващи страници в момента, в който проблемът бъде потвърден — така че за каталог с грешки от 300 страници присъдата често пристига още след страница първа
Две подробности, които си струва да знаете; Първо, този слой изисква заредената библиотека PDFium и се нуждае от компилации, които изнасят FPDFFont_GetIsEmbedded; когато този експорт липсва, проверката се пропуска, а не се счита за неуспешна, така че по-стара DLL никога не създава фалшиви откази; Второ, проверката отговаря на „вграден или не“ и нищо повече — тя не разграничава пълното вграждане от подмножествата (subsetting), нито проверява покритието на глифовете; Когато даден файл се провали и трябва да разберете кой шрифт на коя страница е виновен, техниките за изброяване в анализирането на свойствата на шрифтовете в PDF с PDFium в Delphi продължават точно оттам, където булевата стойност на валидатора спира
Валидиране на потоци без зареждане на документ — или на DLL
Инспекторът на ниво байтове също е изложен като самостоятелна функция, ValidatePdfXCompliance(Source: TStream) в модула FPdfPdfx, и е чист Object Pascal без зависимост от PDFium DLL; Това го прави лесен за внедряване на места, където рендериращ двигател не е желан: лека проверка при качване на уеб сървър, CI задача, която проверява генерирани графики, или Lazarus услуга на платформа, където предпочитате да не доставяте компилирани двоични файлове; Подайте му всеки поток с поддръжка на позициониране:
uses Classes, FPdfPdfx;
function QuickPdfXGate(const FileName: string): Boolean;
var
Fs: TFileStream;
Res: TPdfXValidationResult;
begin
Fs := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
Res := ValidatePdfXCompliance(Fs);
Result := Res.IsCompliant and (Res.Conformance <> pxcNone);
finally
Fs.Free;
end;
end;
Компромисът е ясен: самостоятелният път изпълнява проверките на маркерите и всичките осем проверки на съдържанието, но не и слоя на PDFium за всеки шрифт, така че неговата присъда за шрифтовете се връща към грубата евристика; Една разумна архитектура използва ValidatePdfXCompliance като бърза първа проверка и запазва пълния TPdf.ValidatePdfX за файлове, които я преминават успешно
Къде свършва този валидатор и къде започва пълната проверка
Честността е важна при предпечатните инструменти, така че ето я и границата; ValidatePdfX проверява маркери за идентификация, структурни забрани, ключове за геометрия на страниците, декларацията Trapped и вграждането на шрифтове до отделни текстови обекти; Той обаче не измерва общото покритие на мастилото (total ink coverage), не проверява дали всяко цветово пространство е законно за заявения вариант (например CMYK правилото на X-1a), не проверява разделителната способност на изображенията или поведението при надпечатване (overprint) и изглаждане на прозрачността — те се нуждаят от предпечатен двигател с управление на цветовете, а собствената документация на модула препоръчва сдвояването му с такъв за крайна сертификация; Това, че двуслойната проверка ви дава, са 80% от отказите, които са структурни и могат да бъдат открити рано, уловени за милисекунди в рамките на собствения ви Delphi код, вместо в утрешния имейл от печатницата
Двата слоя за валидация, приложните програмни интерфейсове (APIs) за вграждане на PDF/X маркери за генериране на съвместим изход, както и валидаторите за PDF/A, PDF/UA, PDF/E и PDF/VT, които споделят същата архитектура, се доставят в PDFium Component за Delphi и C++Builder — един компонент, от рендериране до предпечатни проверки