Tekninen artikkeli

PDF/raster-skannattujen asiakirjojen validointi Delphissä

PDF/R, joka standardoitiin ISO 23504-1:nä, on PDF-profiili skannatuille asiakirjoille: jokainen sivu kantaa tasmalleen yhden kaistakuvan eikä mitään muuta. PDFium Component validoi sen Delphistä, Lazaruksesta ja C++Builderistä ValidatePdfRCompliance:n läpi, joka lukee virran ja palauttaa vaatimustason plus joukon konkreettisia ongelmia

Profiili on olemassa koska skannerit ja asiakirjankaappaust järjestelmät tarvitsivat kohteen joka oli kapeampi kuin PDF/A. Arkisto-PDF voi sisältää mitä osa sallii; rasteri-PDF on tahallaan köyhdytetty, jotta mikä tahansa vaatimustenvastainen lukija voi näyttää sen identtisesti ja mikä tahansa vaatimustenvastainen kirjoittaja voi tuottaa sen skannauksesta ilman luontimoottoria

Mitä PDF/R kieltää mitä PDF/A sallii?

Käytännössä tekstin. Rasterisivu kantaa skannatun kuvan eikä mitään muuta, joten fonttiresurssi sivulla on rikkominen — raportoitu nimellä pvriFontForbidden ISO 23504-1 §6.5.2:n alaisuudessa. Tuo yllättää ihmisiä jotka lisäävät näkymättömän OCR-tekstikerroksen hakua varten, mikä on normaali ja hyödyllinen asia PDF/A-työnkulussa ja yksinkertaisesti ei ole PDF/R

Sivun ja kuvan suhde on yhtä tiukka. §6.5.1 tekee jokaisesta sivusta tasmalleen yhden kaistakuvan, joten pvriPageImageMismatch syttyy kun kuvien määrä ei vastaa sivujen määrää — sivu ilman kuvaa ja sivu jolla kaksi ovat molemmat ei-vaatimustenvastaiset. Ja pvriBadMediaBox raportoi sivun jonka MediaBox ei ole muotoa [0 0 w h] (§6.5.3), koska skannauksella ei ole syytä istua siirrettyyn alkuperään

uses FPdfPdfr;

var
  Src: TFileStream;
  Res: TPdfRValidationResult;
begin
  Src := TFileStream.Create('scan-batch-0142.pdf', fmOpenRead or fmShareDenyWrite);
  try
    Res := ValidatePdfRCompliance(Src);
    if Res.IsCompliant then
      Memo1.Lines.Add('PDF/R-1 conformant')
    else
    begin
      if pvriFontForbidden in Res.Issues then
        Memo1.Lines.Add('A page names a font resource; a raster page carries no text');
      if pvriPageImageMismatch in Res.Issues then
        Memo1.Lines.Add('Image count does not match page count');
      if pvriForbiddenImageFilter in Res.Issues then
        Memo1.Lines.Add('A strip image uses an encoding outside the white list');
    end;
  finally
    Src.Free;
  end;
end;

Mitkä kuvakoodaukset ovat sallittuja

Neljä, ja sallittujen luettelo on lyhyt syystä. §6.6 hyväksyy /CCITTFaxDecode:n, /DCTDecode:n, /JPXDecode:n ja /FlateDecode:n — kaksitasoinen faksi, JPEG, JPEG 2000 ja häviötön deflate, jotka keskenään kattavat kaiken skanneritulosteen mitä merkitsee. Kaikki muut raportoidaan nimellä pvriForbiddenImageFilter, mukaanlukien /LZWDecode, /RunLengthDecode, /ASCII85Decode, /ASCIIHexDecode, /JBIG2Decode ja /Crypt

Kahden tuon hylkäämisen kohdalla kannattaa ymmärtää sen sijaan että ulkoa opettelisi. /JBIG2Decode pakkaa kaksitasoiset skannaukset äärimmäisen hyvin ja on täysin laillinen PDF/A:ssa, mutta sen symbolisanakirjan rekonstruktio voi korvata visuaalisesti samankaltaisia glyfejä — dokumentoitu vikatila skannatuille numeroille — ja profiili jonka koko tarkoitus on uskollinen rasterituotto ei voi hyväksyä tuota riskiä. ASCII-suodattimet on rajattu pois vastakkaisesta syystä: ne pullistavat tiedostoa tuomatta mitään mitä rasteriprofiili tarvitsee

Rakennesäännöt jotka syttyvät ennen kuin sivuakaan on luettu

PDF/R rajoittaa myös säiliötä. pvriObjStmPresent raportoi /Type /ObjStm-virran, jonka profiili kieltää suoraan — objektivirrat monimutkaistavat yksinkertaista peräkkäistä jäsentämistä jonka rasterilukijan pitäisi pystyä suorittamaan. pvriBadHeader raportoi otsakkeen ulkona %PDF-1.4:stä 1.7:ään ja %PDF-2.0:sta, ja pvriEncryptVersionMismatch raportoi salatun tiedoston jonka otsake ei ole %PDF-2.0, §6.2.3:n mukaisesti

Katalogi ja Info-sanakirja on sallittujen luettelossa, eivät vain tarkistettu. pvriProhibitedCatalogEntry ja pvriProhibitedInfoEntry syttyvät merkinnöille sallitun joukon ulkopuolella, ja pvriInfoXmpMismatch syttyy kun Info-merkintä on eri mieltä XMP-vastineensa kanssa. Puuttuvalla katalogin /Metadata-virralla, puuttuvalla trailerin /ID:llä ja puuttuvalla %PDF-raster-1.0-loppumerkillä on kullakin oma ongelmansa

Miksi tallennusasetustietue jättää Title ja Author pois

TPdfRSaveOptions kantaa Creator:in, Producer:in, CreationDate:in, ModDate:in, DocumentId:n ja InstanceId:n, ja siinä ei tahallaan ole kenttää Titlelle, Authorille, Subjectille tai Keywordsille. Ne neljä ovat merkinnät jotka §6.4.3 kieltää, joten tietue joka paljastaisi ne kutsuisi kutsujia kirjoittamaan ei-vaatimustenvastaisen tiedoston vaatimustenvastaisen API:n läpi

Kaksi totuusarvo-asetusta hallitsee siivousta muunnettaessa olemassa olevaa PDF:ää. StripInfoOptionalEntries:n oletus on True ja se poistaa Titlen, Authorin, Subjectin, Keywordsin ja Trappedin lähde-Info-sanakirjasta. StripCatalogOptionalEntries:n oletus on myös True ja se poistaa Namesin, Outlinesin, StructTreeRootin, OutputIntentsin, Langin ja loput jättäen jäljelle vain §6.3:n sallittujen luettelon. Aseta jompikumpi False:ksi ja pidät merkinnät — ja menetät vaatimustenvastaisuuden, mikä silloin tällöin on sitä mitä kutsuja aidosti haluaa sisäiselle tiedostolle

var
  Opts: TPdfRSaveOptions;
  Src, Dest: TFileStream;
begin
  Opts := TPdfRSaveOptions.Default;
  Opts.Creator := 'Capture Station 4';
  Opts.Producer := 'PDFium Component';
  Src := TFileStream.Create('scan-in.pdf', fmOpenRead or fmShareDenyWrite);
  try
    Dest := TFileStream.Create('scan-pdfr.pdf', fmCreate);
    try
      InjectPdfRMarkers(Src, Dest, Opts);   // markers + metadata, not page content
    finally
      Dest.Free;
    end;
  finally
    Src.Free;
  end;
end;

Huomaa mitä merkki-injektio ei tee: se lisää metatietoja ja tunnistautumista, eikä se voi tarjota sivun sisältöä. Lähdesivu joka ei kanna kaistakuvaa epäonnistuu yhä pvriPageImageMismatch:ssä injektion jälkeen, koska puuttuva kuva ei koskaan ollut metatieto-ongelma

Mihin PDF/R sopii kaappausputkessa

Käytä sitä missä toimitettava on itse skannaus ja uskollisuus on koko sopimus — todistekuvaaaminen, shekki- ja suorituslaskukaappaus, insinööripiirustusten arkistot suurikokoiselta skannerilta. Käytä PDF/A:a sen sijaan heti kun asiakirja tarvitsee haettavaa tekstiä, tunnistusta, upotettuja liitteitä tai jotain muuta mitä rasteriprofiili riisuu

Yleinen ja toimiva järjestely on tuottaa molemmat: PDF/R-alkuperäinen joka ei koskaan muutu, ja PDF/A-johdannainen OCR-kerroksella hakua varten. Validaattorit ovat riippumattomia, joten sama erätyö voi tarkistaa kunkin artefaktin sen profiilia vastaan jonka se oikeasti vaatii. Tuon parin arkistointipuolta varten katso muistiinpanot PDF/A-arkistointivaatimustenvastaisuus ja PDF/A-eskelennusvalidointi, ja tulostussuuntautunutta tulostetta varten artikkeli tulostusvalmiiden PDF/X-asiakirjojen validointi

PDFium Component tuo PDFium-moottorin Delphille, C++Builderille ja Lazarukselle VCL-API:n ja vaatimustenvastaisuusvalidaattoreiden kanssa PDF/A:lle, PDF/X:lle, PDF/E:lle, PDF/UA:lle ja PDF/R:lle — PDFium Component -tuotesivulta löytyy tuetut standardit ja IDE-versiot