Tekninen artikkeli

PDF/X-validointi Delphissä PDFium Componentilla

PDFium Component for Delphi validoi painovalmiit PDF/X-dokumentit metodilla TPdf.ValidatePdfX, joka toteuttaa ISO 15930 -tarkistuksen kahdessa kerroksessa: kahdeksan tavutason sisältötarkistusta (kielletty LZW-pakkaus, JavaScript, lomakekentät, OPI-viittaukset, puuttuva TrimBox, asettamaton Trapped-avain ja muuta) sekä PDFiumin oliomallin läpikäynti, joka varmistaa FPDFFont_GetIsEmbedded-kutsulla fonttien upotuksen jokaisen sivun jokaisessa tekstiobjektissa. Tuloksena on TPdfXValidationResult-tietue, joka nimeää havaitun vaatimustason ja luettelee jokaisen rikkomuksen tyypitettynä luettelotyyppinä, joten Delphi-sovelluksesi voi kertoa asiakkaalle täsmälleen miksi tiedosto kimpoaa takaisin painosta ennen kuin kukaan polttaa levyä

Jos olet joskus lähettänyt työn kuriirilla kirjapainoon ja saanut sen takaisin yhden rivin hylkäyksellä — "ei TrimBoxia", "fontteja ei ole upotettu", "Trapped ei ole asetettu" — tiedät myöhään selviämisen hinnan. PDF/X on PDF/A:n painoteollinen vastine: siinä missä arkistoiva PDF/A takaa, että dokumentti piirtyy identtisesti vuosikymmenten päästä, PDF/X takaa, että dokumentti värierotellaan, kuvitetaan ja leikataan identtisesti jonkun toisen RIPissä huomisaamuna. Kaksi standardia jakavat koneistoa (XMP-tunnistus, OutputIntents, upotetut ICC-profiilit) mutta vastaavat eri kysymyksiin, ja siksi komponentti toimittaa kummallekin oman validaattorinsa — PDF/A-puoli käsitellään artikkelissa PDF/A-preflight-validointi PDFium Componentilla

Mitä ISO 15930 oikeastaan vaatii painovalmiilta PDF:ltä?

ISO 15930 on olemassa tehdäkseen sokean vaihdon mahdolliseksi: suunnittelija ojentaa tiedoston kirjapainolle, jonka kanssa hän ei ole koskaan puhunut, ja paino pystyy tuottamaan oikean lopputuloksen ilman puhelinsoittoa, ilman puuttuvan fontin sähköpostia ja ilman linkitettyä kuvaa, joka jäi suunnittelijan kannettavaan. Standardin jokainen sääntö palvelee tuota tavoitetta. Fontit on upotettava, koska vastaanottavan RIPin ei voi olettaa omistavan niitä. Ulkoiset viittaukset ovat kiellettyjä, koska tiedoston on oltava itsessään täydellinen. Interaktiiviset ominaisuudet ovat kiellettyjä, koska musteella ei ole onclick-käsittelijää

PDFium Component tunnistaa kolme vaatimusperhettä ja raportoi ne validointituloksen TPdfXConformance-luettelotyypin kautta: pxc1a vastaa PDF/X-1a:2001:tä (ISO 15930-1, tiukka CMYK-plus-spottiväri-perustaso PDF 1.3/1.4:n päällä), pxc3 vastaa PDF/X-3:2002:ta (ISO 15930-3, joka sallii RGB:n, Labin ja ICC-hallitun värin) ja pxc4 vastaa PDF/X-4:2010:tä (ISO 15930-7, joka viimein sallii elävän läpinäkyvyyden ja tasot PDF 1.6:n pohjalla). Tiedosto, joka ei kanna lainkaan PDF/X-tunnistusta, palautuu arvona pxcNone, mikä on itsessään hyödyllinen vastaus: dokumentti ei koskaan väittänytkään olevansa painovalmis, ja kaikki muu mitä validaattori raportoi selittää, mitä sinne pääsy vaatisi

Kiellot käyvät järkeen heti kun ajattelee kuten RIP-toimittaja. /LZWDecode on kielletty jokaisessa PDF/X-muunnelmassa, jottei vaatimuksia noudattava kuluttaja koskaan riipu suodattimesta, jolla on yhteensopivuus- ja lisensointihistoria; Flate tekee saman työn ilman painolastia. JavaScript, AcroForm-kentät ja /AA-lisätoimintosanakirjat ovat kiellettyjä, koska painotiedoston on oltava kiinteä kuvaus paperilla olevista merkeistä — mikä tahansa, joka voi muuttaa ulkoasua avaushetkellä, rikkoo takuun siitä että vedostettu on se mikä painuu. OPI-paikanpitäjät (Open Prepress Interface) ovat kiellettyjä, koska ne ovat suunnittelultaan viittauksia korkearesoluutioisiin kuviin, jotka on tallennettu jonnekin muualle, ja "jonnekin muualle" on juuri se, minkä sokea vaihto kieltää

Miksi kirjapainot hylkäävät PDF-tiedostot ilman TrimBoxia?

TrimBox on valmis sivu — se suorakulmio, joka jää jäljelle giljotiinin leikkausten jälkeen. MediaBox, joka on jokaisella PDF-sivulla, on pelkkä arkki: siihen kuuluvat leikkuuvara, leikkuumerkit, kohdistusmerkit ja väripalkit. Arkkiasemointiohjelmisto sijoittaa sivut painoarkille niiden TrimBoxien mukaan; ilman sitä operaattorin on arvattava, mihin käyntikorttisi oikeasti päättyy, ja väärä arvaus leikkaa leikkuuvaran pois tai jättää valkoisen siivun toiseen reunaan. Siksi ISO 15930 vaatii TrimBoxin (tai ArtBoxin) jokaiselle sivulle, ja siksi ValidatePdfX nostaa arvon pvxiMissingTrimBox, kun yhdeltäkään dokumentin sivulta ei löydy /TrimBox-avainta

PDFium Componentin kaavio painovalmiista PDF-sivusta, jossa MediaBox-arkki leikkuuvaroineen, leikkuumerkkeineen, väripalkkeineen ja kohdistusmerkkeineen ympäröi ISO 15930:n vaatimaa TrimBox-suorakulmiota, ja pvxiMissingTrimBox nousee kun avain puuttuu
MediaBox on koko arkki leikkuuvaroineen, leikkuumerkkeineen ja väripalkkeineen, kun taas TrimBox on valmis sivu, joka giljotiinin on löydettävä; ISO 15930 vaatii sen jokaiselle sivulle

/Trapped-avain vastaa toiseen tuotannolliseen kysymykseen. Ylitäyttö on painoa edeltävä tekniikka, jossa vierekkäisiä värejä limitetään hieman, jottei painokoneen pienoinen kohdistusvirhe avaa niiden väliin valkoisia rakoja. Painon on tiedettävä, onko tuo työ jo tehty: jo ylitäytetyn tiedoston ylitäyttö kaksinkertaistaa limitykset, ja ylitäyttämättömän tiedoston ohittaminen uhkaa jättää näkyviä rakoja. Siksi PDF/X vaatii, että Info-sanakirja ilmoittaa /Trapped /True tai /Trapped /False nimenomaisesti — puuttuva avain tai /Unknown pakottaa ihmisen tarkastamaan tiedoston, mikä on juuri se keskustelu, jonka sokean vaihdon oli määrä poistaa. Komponentti merkitsee tämän arvolla pvxiTrappedNotSet

Kaavio PDFium Componentin TPdf.ValidatePdfX-metodista Delphissä: tavutason merkkiselaus kahdeksalla sisältötarkistuksella ja PDFiumin oliomallin fonttiupotusläpikäynti, jotka yhdistyvät yhdeksi TPdfXValidationResult-tietueeksi
ValidatePdfX haarauttaa yhden ladatun dokumentin tavutason sisältötarkistusten ja PDFiumin oliomallin fonttiläpikäynnin läpi ja yhdistää sitten molemmat kerrokset yhdeksi tyypitetyksi tulostietueeksi

Kaksikerroksisen validoinnin ajaminen metodilla TPdf.ValidatePdfX

TPdf.ValidatePdfX ei ota argumentteja ja palauttaa TPdfXValidationResult-tietueen, jossa on kolme jäsentä: Conformance (havaittu PDF/X-muunnelma), Issues (Pascal-joukko TPdfXValidationIssue-arvoja) ja IsCompliant-apufunktio. Sisäisesti se sarjallistaa ladatun dokumentin muistivirtaan, ajaa tavutason tarkastajan sen yli ja kulkee sitten PDFiumin oliomallin läpi fonttikohtaista upotustarkistusta varten. Minimaalinen preflight-portti näyttää tältä:

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;

Koska Issues on tavallinen Pascal-joukko, voit ositella sen juuri niin kuin työnkulkusi vaatii — käsittele rakenteelliset ongelmat kovina hylkäyksinä, käsittele pvxiMissingTitle (standardissa SHOULD eikä MUST) varoituksena ja lokita loput. Sama tietuetyyppi syöttää myös komponentin raporttigeneraattoria, joten jos haluat mieluummin tuottaa ihmisluettavan dokumentin kuin haarautua luettelotyypeillä, artikkelin erä-preflight-raportin CLI:n rakentaminen PDFium Componentilla kuvio pätee PDF/X:ään sellaisenaan

Mitä tavutason kerros nappaa — ja mitä siltä jää huomaamatta

Tavutason kerros on merkkiselaus dokumentin rakenteellisten tavujen yli niin että stream-rungot on tyhjennetty, joten JPEG, joka sattuu sisältämään tavukuvion /JavaScript, ei voi laukaista väärää positiivista. Merkkitarkistusten päälle (XMP pdfxid:GTS_PDFXVersion, OutputIntent upotetulla ICC-profiililla, trailerin /ID, salauskielto) sisältöläpikäynti lisää kahdeksan tarkistusta, kullakin oma luettelotyyppiarvonsa:

  • pvxiLzwForbidden — /LZWDecode-suodatin esiintyy jossain tiedostossa (kielletty kaikissa PDF/X-muunnelmissa)
  • pvxiJavaScriptForbidden — /JavaScript-toiminto tai nimipuu on läsnä
  • pvxiFormFieldsForbidden — /AcroForm-sanakirja tai /XFA-merkintä on olemassa
  • pvxiAdditionalActions — /AA-lisätoimintosanakirja on läsnä
  • pvxiEmbeddedFilesForbidden — /EmbeddedFiles tai /FileAttachment-merkintä on läsnä
  • pvxiOpiForbidden — /OPI- tai /Alternates-merkintä viittaa korvattavaan kuvasisältöön
  • pvxiMissingTrimBox — yhdeltäkään sivulta ei löydy /TrimBox-avainta
  • pvxiTrappedNotSet — /Trapped puuttuu tai on asetettu arvoon /Unknown

Tavuselaus on nopeaa eikä tarvitse piirtomoottoria, mutta siinä on synnynnäinen sokea piste fonttien suhteen: tuolla tasolla tarkastaja voi soveltaa vain karkeaa heuristiikkaa — se merkitsee dokumentin, kun se ei löydä lainkaan upotettua fonttiohjelmaa. Tiedosto, jossa on yhdeksän fonttia upotettuna ja yksi järjestelmäfontti livahtanut mukaan, näyttää tavuselaukselle moitteettomalta. Tuo yksi aukko on syy toisen kerroksen olemassaoloon

Fonttikohtainen upotus PDFiumin oliomallin kautta

PDFium Componentin oliomallikerros vastaa fonttikysymykseen täsmällisesti. Tavutason läpikäynnin jälkeen TPdf.ValidatePdfX käy läpi jokaisen sivun, kysyy objektiluetteloa FPDFPage_CountObjects-kutsulla ja ratkaisee jokaiselle tekstiobjektille fonttikahvan FPDFTextObj_GetFont-kutsulla sekä kyselee FPDFFont_GetIsEmbedded-arvon. Yksi upottamaton fontti missä tahansa dokumentissa lisää arvon pvxiPdfiumFontNotEmbedded ongelmajoukkoon. Läpikäynti oikosulkeutuu kahdella tasolla — se lopettaa sivun objektien selaamisen ja lopettaa lisäsivujen lataamisen heti kun ongelma on vahvistettu — joten rikkovassa 300-sivuisessa luettelossa tuomio saapuu usein ensimmäisen sivun jälkeen

Kaksi rajahuomiota kannattaa tietää. Ensinnäkin tämä kerros tarvitsee ladatun PDFium-kirjaston ja vaatii käännökset, jotka vievät ulos FPDFFont_GetIsEmbedded-funktion; kun vienti puuttuu, tarkistus ohitetaan eikä hylätä, joten vanhempi DLL ei koskaan tuota haamuhylkäyksiä. Toiseksi tarkistus vastaa vain kysymykseen "upotettu vai ei" eikä mihinkään muuhun — se ei erota täyttä upotusta osajoukotuksesta eikä tarkastele merkkien kattavuutta. Kun tiedosto hylkääntyy ja sinun on tiedettävä mikä fontti millä sivulla, artikkelin PDF:n fonttiominaisuuksien analysointi PDFiumilla Delphissä luettelointitekniikat jatkavat täsmälleen siitä mihin validaattorin totuusarvo loppuu

Virtojen validointi ilman dokumentin lataamista — tai DLL:ää

Tavutason tarkastaja on tarjolla myös itsenäisenä funktiona, ValidatePdfXCompliance(Source: TStream) FPdfPdfx-yksikössä, ja se on puhdasta Object Pascalia ilman riippuvuutta PDFium-DLL:ään. Se tekee siitä käyttökelpoisen paikoissa, joihin piirtomoottori ei ole tervetullut: kevyt latausportti verkkopalvelimella, CI-työ joka seuloo tuotettua kuvitusta, tai Lazarus-palvelu alustalla, jolle et mieluusti toimittaisi natiivibinäärejä. Syötä sille mikä tahansa siirrettävä virta:

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;

Vaihtokauppa on suora: itsenäinen polku ajaa merkkitarkistukset ja kaikki kahdeksan sisältötarkistusta, mutta ei fonttikohtaista PDFium-kerrosta, joten sen fonttituomio putoaa takaisin karkeaan heuristiikkaan. Järkevä arkkitehtuuri käyttää ValidatePdfXCompliance-funktiota halpana ensiporttina ja varaa täyden TPdf.ValidatePdfX-tarkistuksen niille tiedostoille, jotka pääsevät siitä läpi

Mihin tämä validaattori päättyy ja täysi preflight alkaa

Rehellisyydellä on merkitystä preflight-työkaluissa, joten tässä on raja. ValidatePdfX varmistaa tunnistusmerkinnät, rakenteelliset kiellot, sivugeometrian avaimet, Trapped-ilmoituksen ja fonttien upotuksen aina yksittäisiin tekstiobjekteihin asti. Se ei mittaa musteen kokonaispeittoa, ei validoi että jokainen väriavaruus on väitetylle muunnelmalle sallittu (esimerkiksi X-1a:n vain CMYK -sääntö), ei tarkista kuvien resoluutiota rasteritiheyttä vasten eikä arvioi päällepainatuksen ja läpinäkyvyyden litistyksen käyttäytymistä — ne vaativat värihallitun preflight-moottorin, ja yksikön oma dokumentaatio kehottaa parittamaan sen sellaisen kanssa lopullista sertifiointia varten. Kaksikerroksinen tarkistus antaa sinulle sen 80 prosenttia hylkäyksistä, jotka ovat rakenteellisia ja aikaisin havaittavia, napattuna millisekunneissa omassa Delphi-koodissasi eikä huomisessa sähköpostissa painosta

Molemmat validointikerrokset, PDF/X-merkintöjen syöttörajapinnat vaatimustenmukaisen tulosteen tuottamiseen sekä samaa arkkitehtuuria jakavat PDF/A-, PDF/UA-, PDF/E- ja PDF/VT-validaattorit toimitetaan tuotteessa PDFium Component Delphille ja C++Builderille — yksi komponentti, piirrosta painon porttivahtiin