Tehnički članak

Automatizacija PDF preflight provjera u Delphiju uz HotPDF

Datoteka se čisto otvara na vašem računalu. Acrobat je prikazuje, pregled ispisa izgleda ispravno, svaka stranica je tu. Zatim odlazi u tiskaru ili u arhivski sustav koji preuzima vašu mjesečnu seriju i vraća se odbijena: RGB slike u CMYK zadatku, nema ključa /Trapped, namjera izlaza (output intent) koja ne odgovara tiskarskom stroju. Vizualno ništa nije bilo pogrešno s dokumentom. Bio je neispravan u odnosu na profil, a profil je provjeren negdje gdje vi niste imali pristup. Preflight je naziv u pripremi za tisak za tu provjeru, a pravo pitanje je gdje joj je mjesto kada PDF-ovi izlaze iz vašeg vlastitog Delphi koda, a ne s dizajnerske radne površine

HotPDF vam ne nudi preflight funkciju koju možete izravno pozvati. Komponenta sadrži prozor preflight izvješća u svojoj GUI demonstraciji, ali iza toga ne postoji API koji bi usluga ili skripta za izgradnju (build script) mogle pozvati, a pretvaranje da postoji samo bi vas navelo na traženje metode koje nema. To zvuči kao nedostatak sve dok ne shvatite da je za datoteke koje sami generirate pozivanje validatora na vlastiti izlaz ionako pogrešan pristup. Vi već kontrolirate svako svojstvo koje bi validator pregledavao. Koristan pristup je učiniti generator nesposobnim za izdavanje neispravne datoteke, a zatim to dokazati alatom koji niste sami napisali

Zašto svoj izlaz provjeravate drugačije

Tradicionalni preflight pretpostavlja datoteku nepoznatog podrijetla. Izradio ju je neki dizajner, neka druga aplikacija ili nepoznanica niz uređivanja, a vi je pregledavate jer nemate pojma što je unutra. Dokument koji je proizveo vaš kod nije nepoznanica. Ugradnja fonta, prostor boja, namjera izlaza, blok metapodataka: vaš je program odlučio o svemu tome nekoliko milisekundi prije nego što je datoteka zapisana na disk. Naknadni pregled radi otkrivanja odluka koje ste upravo donijeli je gubljenje vremena. Jeftinije je ograničiti te odluke tako da neusklađena datoteka nikada niti ne nastane

Postoji i razlog vjerodostojnosti za zadržavanje vanjske provjere. Knjižnica koja sama potvrđuje svoj izlaz zapravo ocjenjuje vlastiti test. Kada korisnički arhivski sustav ili RIP tiskare odbije vašu datoteku, tvrdnja \"naša komponenta kaže da je sve u redu\" nema nikakvu težinu. Presuda iz veraPDF-a ili Acrobata ima jer druga strana pokreće iste te alate

Učinite usklađenost postavkom, a ne kontrolnim popisom

Sloj prevencije je jednostavna konfiguracija. Postavite PDFACompliance ili PDFXCompliance prije BeginDoc i HotPDF će primjenjivati odgovarajuća pravila za cijeli proces generiranja: ugrađuje fontove, prati upotrebu DeviceRGB i DeviceCMYK u odnosu na namjeru izlaza koju ste deklarirali te odbija značajke koje profil zabranjuje. Kontradikcije izlaze na vidjelo pri EndDoc, gdje se provjere usklađenosti aktiviraju umjesto tihe isporuke nečega što će zakazati kasnije. Nakon što je datoteka spremljena, ista svojstva iščitavaju ono što je zapravo primijenjeno, što je ključna činjenica potrebna vašem dnevniku cjevovoda:

// After EndDoc: record the enforced profiles with the run metadata
if Pdf.PDFACompliance <> '' then
  Log('Generated as PDF/A level ' + Pdf.PDFACompliance);
if Pdf.PDFXCompliance <> '' then
  Log('Generated as PDF/X profile ' + Pdf.PDFXCompliance);

Postavite te flagove u isti redak dnevnika u kojem se nalaze hash ulaznih podataka i verzija HotPDF-a. Na dan kada se validator i vaš generator ne slože oko datoteke, taj redak će vam reći koji je predložak proizveo datoteku i koja je verzija knjižnice učitana, pa rasprava koja bi inače trajala cijelo popodne postaje jednostavan grep. Namjere izlaza, ICC profili i označavanje koji stoje iza ovih flagova detaljno su opisani u vodiču za PDF/A, PDF/X i PDF/UA izlaz s HotPDF-om

Jeftina prva provjera za datoteke koje niste sami generirali

Nije svaki cjevovod isključivo generativan. Korisnici prenose PDF-ove, skeneri ih ispuštaju u mapu, partneri ih prilažu e-pošti. Slanje svakog od njih kroz potpuni strukturni validator troši dragocjeno vrijeme reda čekanja na datoteke koje se uopće neće ni otvoriti. HotPDF-ov Direct File API čita dovoljno strukture datoteke da odgovori na pitanje \"je li ovo uopće upotrebljiv PDF\" bez učitavanja cijelog stabla objekata, što ga čini izvrsnim mjestom za brzu eliminaciju neispravnih datoteka:

function TriagePdf(Pdf: THotPDF; const FileName: string): Boolean;
var
  Handle, Pages: Integer;
begin
  Result := False;
  Handle := Pdf.DAOpenFileReadOnly(FileName, '');
  if Handle <= 0 then
    Exit;  // structurally unreadable: quarantine, do not validate
  try
    Pages := Pdf.DAGetPageCount(Handle);
    Result := Pages > 0;
  finally
    Pdf.DACloseFile(Handle);
  end;
end;

Dvije činjenice o ovom API-ju određuju kako ćete ga omotati. Prečac sa stabilnom potrošnjom memorije vrijedi samo za nešifrirani unos; ako DAOpenFileReadOnly proslijedite lozinku, on se tiho vraća na potpuno parsiranje, pa bi datoteka za koju znate da je šifrirana trebala proći kroz DecryptFile u običnu radnu kopiju prije trijaže. Također, DAGetPageCount ne znači ništa na rukovatelju koji se nije čisto otvorio, pa provjera rukovatelja ostaje stroga i nepozitivan rezultat znači odbijanje, a ne ponovni pokušaj. Više ovakvih predložaka nalazi se u članku o Direct File API-ju za rad s velikim PDF-ovima

veraPDF, pokrenut kao dio procesa izgradnje

Za sve što deklarirate kao PDF/A ili PDF/UA, veraPDF je validator koji trebate povezati. Pokreće se bez grafičkog sučelja (headless), prema standardu prima serije datoteka, izvozi XML ili JSON te imenuje svaki neuspjeh prema ISO klauzuli, pa neispravnost pravila u odnosu na ISO 19005-1 klauzulu 6.2.2 upućuje izravno na postavku generatora umjesto da vas ostavi da nagađate. Pokretanje iz Delphija je uobičajena kontrola procesa:

function RunVeraPdf(const PdfFile, ReportFile: string): Cardinal;
var
  Cmd: string;
  SI: TStartupInfo;
  PI: TProcessInformation;
begin
  Cmd := Format('cmd /c verapdf.bat --format xml "%s" > "%s"',
    [PdfFile, ReportFile]);
  FillChar(SI, SizeOf(SI), 0);
  SI.cb := SizeOf(SI);
  if not CreateProcess(nil, PChar(Cmd), nil, nil, False,
      CREATE_NO_WINDOW, nil, nil, SI, PI) then
    RaiseLastOSError;
  try
    WaitForSingleObject(PI.hProcess, 120000);  // bound the wait per file
    GetExitCodeProcess(PI.hProcess, Result);
  finally
    CloseHandle(PI.hThread);
    CloseHandle(PI.hProcess);
  end;
end;

Vremensko ograničenje (timeout) opravdava svoju svrhu. Oštećena datoteka može dovesti bilo koji parser u bezizlaznu situaciju, a beskonačno čekanje unutar radnog reda čekanja povlači cijeli ostatak reda za sobom. Ograničite čekanje, dodijelite vremenskom ograničenju vlastiti kod pogreške i odložite datoteku za ljudski pregled. Kada čitate rezultat, analizirajte XML tražeći identifikatore pravila, a ne tekst čitljiv ljudima. Identifikatori pravila preživljavaju nadogradnje validatora; formulacija poruka se mijenja, a stabilan kod je nešto po čemu inženjer podrške može pretraživati stare prijave problema

Način na koji pokrećete seriju važan je koliko i prolazak pojedine datoteke. Pokrenite jedan proces po datoteci, a ne po seriji, kako bi vas loš unos koštao samo tog jednog timeouta i ništa više. Ograničite broj validator procesa na broj jezgri jer je izgradnja XML izvješća CPU-zahtjevna, a prevelik broj paralelnih procesa samo usporava rad. Također postavite gornju granicu veličine na unosu jer će skenirana knjiga od dva gigabajta potpuno blokirati red čekanja bez obzira na to koliko je parser strpljiv. Ništa od toga nije preflight u strogom smislu riječi. To je razlika između provjere koja preživljava velike količine posla krajem mjeseca i one koja se ugasi prve noći kada zaustavi cjevovod u 2 sata ujutro

PDF/X je područje u kojem ovo ne uspijeva. veraPDF ga ne provjerava, tako da je funkcionalna provjera i dalje Acrobat Preflight s profilom ISO 15930 koji je vaša tiskara odredila. Acrobat zahtijeva čovjeka, što znači uzorkovanje umjesto potpune pokrivenosti: prva datoteka iz novog predloška, plus mali slučajni odabir iz svake serije, dok automatizirana provjera obrađuje sve što se može riješiti bez ljudske intervencije. Provjera uzorkovanjem koja se stvarno provodi bolja je od potpune automatizacije koja zauvijek ostane napola dovršena

Izvješće koje ćete željeti i za godinu dana

Preflight provjera se isplati dvostruko. Prvi put kada zaustavi neispravnu datoteku na vratima, i drugi put mnogo kasnije kada netko pita zašto je određena datoteka propuštena. Taj drugi trenutak je onaj koji bi trebao diktirati format izvješća jer je to trenutak u kojem vas oskudno izvješće ostavlja bez odgovora. Za svaku provjerenu datoteku sačuvajte hash unosa, generatorove flagove usklađenosti i verziju knjižnice iz gornjeg retka dnevnika, naziv i verziju validatora, profil prema kojem je provjeravana, prolaz or fail, te ID-ove neispravnih pravila s brojevima stranica gdje god ih validator nudi. Pohranite to izvješće pokraj datoteke koju opisuje. Ako ga stavite u zaseban sustav, taj će sustav vjerojatno biti ugašen prije nego što se ugasi arhiva koju dokumentira

Iznimke također moraju biti pismeno zabilježene. Kada kupac inzistira na slanju datoteke koju provjera odbija, rješenje nije ublažiti pravilo za sve. Zabilježite tko je odobrio ovu datoteku, na kojim temeljima i do kojeg datuma, a zatim priložite to izuzeće (waiver) njezinom izvješću. Izuzeće s imenom i rokom trajanja je odluka iza koje netko stoji. Provjera koja je komentirana "privremeno" samo je incident koji čeka svoj trenutak

Još jedna navika koja se isplati: kada datoteka ne prođe provjeru, kopirajte je u imenovanu mapu regresije prije nego što je itko dotakne. Gotovo svaki preflight problem vrijedan otklanjanja pogrešaka vodi do jednog određenog unosa, a timovi koji čuvaju te unose rješavaju problem ponovnog pojavljivanja za sat vremena umjesto da čekaju da se ponovno pojavi u produkciji. Svojstva usklađenosti i Direct File API prikazani ovdje dio su komponente HotPDF Component za Delphi i C++Builder, čija dokumentacija u potpunosti pokriva svaki poziv