„PDFium Component“, skirtas Delphi, patikrina spaudai paruoštus PDF/X dokumentus per TPdf.ValidatePdfX, kuris įgyvendina ISO 15930 patikrinimą dviem sluoksniais: aštuoniomis baitų lygio turinio patikromis (draudžiamas LZW suspaudimas, „JavaScript“, formos laukai, OPI nuorodos, trūkstamas „TrimBox“, nenustatytas „Trapped“ raktas ir kt.) plius „PDFium“ objektų modelio žingsniu, kuris naudoja FPDFFont_GetIsEmbedded, kad patikrintų šrifto įterpimą kiekviename teksto objekte kiekviename puslapyje. Rezultatas yra įrašas TPdfXValidationResult, kuris nurodo aptiktą suderinamumo lygį ir išvardija kiekvieną pažeidimą kaip tipo sąrašą (typed enum), todėl jūsų Delphi programa gali tiksliai pasakyti klientui, kodėl failas bus atmestas spaustuvėje dar prieš pradedant spausdinimo procesą
Jei kada nors siuntėte užsakymą komercinei spaustuvei ir gavote jį atgal su vienos eilutės atmetimu – „nėra TrimBox“, „šriftai neįterpti“, „Trapped nenustatytas“ – žinote, kiek kainuoja tai sužinoti per vėlai. PDF/X yra spaudos paruošimo (prepress) atitikmuo archyviniam PDF/A: kur archyvinis PDF/A garantuoja, kad dokumentas bus vizualizuojamas identiškai po kelių dešimtmečių, PDF/X garantuoja, kad dokumento spalvų atskyrimas, vaizdas ir apipjovimas bus identiškas kitoje RIP sistemoje rytoj ryte. Abu standartai dalijasi tam tikrais mechanizmais (XMP identifikavimu, „OutputIntents“, įterptais ICC profilais), tačiau atsako į skirtingus klausimus, todėl komponentas turi atskirus tikrintuvus kiekvienam iš jų – PDF/A dalis aprašyta straipsnyje apie PDF/A preflight patikrą su PDFium Component
Ko iš tikrųjų reikalauja ISO 15930 standartas iš spaudai paruošto PDF?
ISO 15930 egzistuoja tam, kad būtų įmanomi aklieji mainai (blind exchange): dizaineris perduoda failą spaustuvininkui, su kuriuo niekada nekalbėjo, o spaustuvininkas gali sukurti teisingą spaudinį be telefono skambučio, be elektroninio laiško apie trūkstamą šriftą ir be susietų paveikslėlių, kurie liko dizainerio nešiojamame kompiuteryje. Kiekviena standarto taisyklė tarnauja šiam tikslui. Šriftai turi būti įterpti, nes negalima daryti prielaidos, kad priimanti RIP sistema juos turi. Išorinės nuorodos yra draudžiamos, nes failas turi būti visiškai sukomplektuotas. Interaktyvios funkcijos yra draudžiamos, nes dažai neturi įvykių apdorojimo programų
„PDFium Component“ atpažįsta tris suderinamumo šeimas ir praneša apie jas per TPdfXConformance būsenų sąrašą patikros rezultate: pxc1a, skirtą PDF/X-1a:2001 (ISO 15930-1, griežta CMYK ir papildomų spalvų bazė PDF 1.3/1.4 pagrindu), pxc3, skirtą PDF/X-3:2002 (ISO 15930-3, leidžiantis RGB, Lab bei ICC valdomas spalvas), ir pxc4, skirtą PDF/X-4:2010 (ISO 15930-7, kuris leidžia tiesioginį permatomumą ir sluoksnius PDF 1.6 pagrindu). Failas, kuris išvis netui PDF/X identifikavimo, grąžinamas kaip pxcNone, kas savaime yra naudingas atsakymas: dokumentas niekada nedeklaravo esąs paruoštas spaudai, o visa kita, ką praneša tikrintuvas, paaiškina, ko reikėtų, kad jis toks taptų
Draudimai tampa suprantami, kai mąstote kaip RIP sistemų tiekėjas. /LZWDecode yra draudžiamas kiekviename PDF/X variante, kad suderinamas vartotojas niekada nepriklausytų nuo filtro su suderinamumo bei licencijavimo istorija; „Flate“ atlieka tą patį darbą be šio bagažo. „JavaScript“, „AcroForm“ laukai ir papildomų veiksmų /AA žodynai yra draudžiami, nes spaudos failas turi būti visiškai fiksuotas ženklų ant popieriaus aprašymas – bet kas, kas gali pakeisti išvaizdą atidarymo metu, pažeidžia garantiją, kad tai, kas buvo patikrinta, bus atspausdinta. OPI (Open Prepress Interface) vietos rezervavimo ženklai yra draudžiami, nes pagal dizainą jie yra nuorodos į didelės raiškos vaizdus, saugomus kažkur kitur, o „kažkur kitur“ yra būtent tai, ką aklieji mainai draudžia
Kodėl spaustuvės atmeta PDF failus be TrimBox?
TrimBox yra galutinis puslapis – stačiakampis, kuris lieka po apipjovimo giljotina. MediaBox, kurį turi kiekvienas PDF puslapis, yra tiesiog lapas: jis apima užlaidas (bleed), pjovimo žymes, registracijos taikinius ir spalvų juostas. Puslapių išdėstymo programinė įranga pozicionuoja puslapius spaudos lape pagal jų TrimBox; be jo operatoriui tenka spėlioti, kur iš tikrųjų baigiasi jūsų vizitinė kortelė, o neteisingas spėjimas nupjauna jūsų užlaidas arba palieka baltą juostelę viename krašte. Štai kodėl ISO 15930 reikalauja TrimBox (arba ArtBox) kiekviename puslapyje, ir kodėl ValidatePdfX sukelia pvxiMissingTrimBox klaidą, kai dokumente nerandamas /TrimBox raktas
Raktas /Trapped atsako į kitą gamybos klausimą. Gamybinis spalvų užleidimas (trapping) yra spaudos paruošimo technika, leidžianti šiek tiek perdengti gretimas spalvas, kad nedideli spaudos poslinkiai nesukurtų baltų tarpų tarp jų. Spaustuvei reikia žinoti, ar šis darbas jau buvo atliktas: užleidus jau užleistą failą, persidengimai padvigubėja, o praleidus užleidimą neužleistame faile kyla matomų tarpų rizika. Todėl PDF/X reikalauja, kad Info žodynas aiškiai nurodytų /Trapped /True arba /Trapped /False – trūkstamas raktas arba reikšmė /Unknown verčia žmogų tikrinti failą rankiniu būdu, o tai yra būtent tie pokalbiai, kuriuos aklieji mainai turėjo eliminuoti. Komponentas tai pažymi kaip pvxiTrappedNotSet
Dviejų sluoksnių patikros vykdymas su TPdf.ValidatePdfX
TPdf.ValidatePdfX nepriima jokių argumentų ir grąžina įrašą TPdfXValidationResult su trimis nariais: Conformance (aptiktas PDF/X tipas), Issues (Pascal aibė su TPdfXValidationIssue reikšmėmis) ir pagalbine IsCompliant reikšme. Viduje jis serijozuoja įkeltą dokumentą į atminties srautą, paleidžia baitų lygio tikrintuvą, o po to eina per „PDFium“ objektų modelį dėl šriftų įterpimo patikros. Minimalus preflight tikrinimas atrodo taip:
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;
Kadangi Issues is įprasta Pascal aibė, galite ją išskirstyti pagal savo darbo eigos poreikius – traktuoti struktūrines problemas kaip griežtus atmetimus, traktuoti pvxiMissingTitle (standarte rekomenduojama „SHOULD“, bet neprivaloma „MUST“) kaip įspėjimą ir registruoti likusius įvykius. Tas pats įrašo tipas taip pat maitina komponento ataskaitų generatorių, todėl jei norite sukurti žmogui skaitomą dokumentą, o ne šakotis pagal sąrašus, šablonas iš paketinių preflight ataskaitų kūrimo CLI su PDFium Component taikomas PDF/X formatui be pakeitimų
Ką baitų lygio sluoksnis sugauna – ir ką praleidžia
Baitų lygio sluoksnis yra žymų nuskaitymas per dokumento struktūrinius baitus, išvalant srautų turinius, todėl JPEG failas, kuriame atsitiktinai yra baitų seka /JavaScript, negali sukelti klaidingai teigiamo rezultato. Be žymų patikros (XMP pdfxid:GTS_PDFXVersion, „OutputIntent“ su įterptu ICC profiliu, trailer /ID, šifravimo draudimas), turinio praėjimas prideda aštuonias patikras, kurių kiekviena turi savo reikšmę:
pvxiLzwForbidden–/LZWDecodefiltras atsiranda bet kurioje failo vietoje (draudžiamas visuose PDF/X variantuose)pvxiJavaScriptForbidden– yra/JavaScriptveiksmas arba pavadinimų medispvxiFormFieldsForbidden– egzistuoja/AcroFormžodynas arba/XFAįrašaspvxiAdditionalActions– yra papildomų veiksmų/AAžodynaspvxiEmbeddedFilesForbidden– yra/EmbeddedFilesarba/FileAttachmentanotacijapvxiOpiForbidden–/OPIarba/Alternatesįrašas nurodo keičiamą vaizdo turinįpvxiMissingTrimBox– puslapiuose nerastas/TrimBoxpvxiTrappedNotSet– nėra/Trappedarba nustatyta reikšmė/Unknown
Baitų nuskaitymas yra greitas ir jam nereikia vaizdo vizualizavimo variklio, tačiau jis turi akląją zoną su šriftais: šiame lygmenyje tikrintuvas gali pritaikyti tik apytikslę heuristiką – jis pažymi dokumentą tik tada, kai išvis neranda jokios įterptos šrifto programos. Failas su devyniais įterptais šriftais ir vienu įterptu sisteminiu šriftu baitų nuskaitymui atrodo teisingas. Ši vėliava ir yra priežastis, kodėl egzistuoja antrasis sluoksnis
Šriftų įterpimo patikra per „PDFium“ objektų modelį
„PDFium Component“ objektų modelio sluoksnis tiksliai atsako į šrifto klausimą. Po baitų lygio patikros TPdf.ValidatePdfX pereina kiekvieną puslapį, paprašo FPDFPage_CountObjects objektų sąrašo ir kiekvienam teksto objektui nustato šrifto valdiklį per FPDFTextObj_GetFont bei užklausia FPDFFont_GetIsEmbedded. Vienas neįterptas šriftas bet kurioje dokumento vietoje prideda pvxiPdfiumFontNotEmbedded prie problemų aibės. Perėjimas sustabdomas dviejuose lygmenyse – jis nustoja skenuoti objektus puslapyje ir nustoja įkelti kitus puslapius, kai tik patvirtinama problema, todėl su pažeidimu esančio 300 puslapių katalogo nuosprendis dažnai priimamas jau po pirmojo puslapio
Verta žinoti dvi ribines pastabas. Pirma, šiam sluoksniui reikia, kad būtų įkelta „PDFium“ biblioteka, ir reikalaujama versijų, kurios eksportuoja FPDFFont_GetIsEmbedded; kai eksporto nėra, patikra yra praleidžiama, o ne pažymima kaip nepavykusi, todėl senesnė DLL biblioteka niekada nesukels netikrų atmetimų. Antra, patikra atsako tik į klausimą „įterptas ar ne“ ir nieko daugiau – ji neišskiria pilno įterpimo nuo dalinio (subsetting) ir netikrina simbolių (glyphs) aprėpties. Kai failas sugenda ir jums reikia sužinoti, kuris šriftas kuriame puslapyje sukėlė problemą, sąrašo sudarymo metodai iš straipsnio apie PDF šriftų savybių analizę su PDFium Delphi aplinkoje padeda tęsti darbą ten, kur baigiasi tikrintuvo rezultatas
Srautų tikrinimas neįkeliant dokumento – arba DLL bibliotekos
Baitų lygio tikrintuvas taip pat pateikiamas kaip savarankiška funkcija ValidatePdfXCompliance(Source: TStream) modulyje FPdfPdfx, ir tai yra grynas „Object Pascal“ kodas, nepriklausantis nuo „PDFium“ DLL. Tai leidžia jį naudoti ten, kur vaizdo generavimo variklis yra nepageidaujamas: lengvoje įkėlimo apsaugoje žiniatinklio serveryje, CI užduotyje, kuri tikrina sugeneruotus darbus, arba „Lazarus“ tarnyboje platformoje, kurioje nenorite platinti vietinių dvejetainių failų. Pateikite jam bet kokį srautą, palaikantį pozicijos keitimą (seekable stream):
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;
Kompromisas yra aiškus: atskiras kelias atlieka žymų patikrinimus bei visas aštuonias turinio patikras, tačiau neapima šrifto lygio „PDFium“ sluoksnio, todėl šrifto nuosprendis remiasi apytikslia heuristika. Protinga architektūra naudoja ValidatePdfXCompliance kaip pigų pirmąjį tikrinimą, o pilną TPdf.ValidatePdfX pasilieka failams, kurie jį praeina
Kur baigiasi šis tikrintuvas ir prasideda pilnas preflight
Sąžiningumas yra svarbus preflight įrankiuose, todėl štai riba. ValidatePdfX patikrina identifikavimo žymes, struktūrinius draudimus, puslapio geometrijos raktus, /Trapped deklaraciją ir šriftų įterpimą iki atskirų teksto objektų. Ji nematuoja bendro dažų padengimo (ink coverage), netikrina, ar kiekviena spalvų erdvė yra leistina deklaruotam variantui (pavyzdžiui, tik CMYK taisyklė PDF/X-1a variante), netikrina vaizdo raiškos pagal linijų rastrą ir nevertina viršutinio spaudinio (overprint) bei permatomumo suplokštinimo elgsenos – tam reikia spalvas valdančio preflight variklio, o pačio modulio dokumentacijoje rekomenduojama jį suporuoti su tokiu varikliu galutiniam sertifikavimui. Dviejų sluoksnių patikra suteikia 80 % atmetimų, kurie yra struktūriniai ir aptinkami anksti, per kelias milisekundes jūsų pačių Delphi kode, užuot gavus elektroninį laišką iš spaustuvės rytoj ryte
Abu patikros sluoksniai, PDF/X žymų įterpimo API, skirtos sukurti suderinamą išvestį, bei PDF/A, PDF/UA, PDF/E ir PDF/VT tikrintuvai, besidalijantys ta pačia architektūra, pateikiami „PDFium Component“, skirtoje Delphi ir C++Builder – vienas komponentas nuo vaizdo piešimo iki spaudos paruošimo priežiūros