PDF/R eli standardi ISO 23504-1 on skannatuille asiakirjoille tarkoitettu PDF-profiili: jokaisella sivulla on täsmälleen yksi kaistakuva eikä yhtään mitään muuta. PDFium Component validoi sen Delphistä, Lazaruksesta ja C++Builderistä funktiolla ValidatePdfRCompliance, joka lukee streamin ja palauttaa vaatimustenmukaisuustason sekä joukon konkreettisia ongelmia
Profiili syntyi siksi, että skannerit ja dokumenttien kaappausjärjestelmät tarvitsivat PDF/A:ta kapeamman maalin. Arkistoitava PDF saa sisältää mitä tahansa, minkä standardin osa sallii; rasteri-PDF on tarkoituksella riisuttu, jotta mikä tahansa vaatimukset täyttävä lukija näyttää sen samalla tavalla ja mikä tahansa vaatimukset täyttävä kirjoitin saa sen ulos suoraan skannauksesta ilman taitto-ohjelmaa
Mitä PDF/R kieltää, minkä PDF/A sallii?
Käytännössä tekstin. Rasterisivulla on skannattu kuva eikä mitään muuta, joten sivulla oleva fonttiresurssi on rikkomus — se raportoidaan koodilla pvriFontForbidden, ISO 23504-1 §6.5.2. Se yllättää ne, jotka lisäävät näkymättömän OCR-tekstikerroksen haettavuuden vuoksi: PDF/A-työnkulussa se on aivan normaali ja hyödyllinen temppu, mutta PDF/R:ää siitä ei tule
Sivun ja kuvan suhde on yhtä tiukka. §6.5.1 vaatii jokaiselta sivulta täsmälleen yhden kaistakuvan, joten pvriPageImageMismatch nousee heti kun kuvien määrä ei täsmää sivujen määrään — sivu ilman kuvaa ja sivu jolla niitä on kaksi ovat kumpikin vaatimustenvastaisia. pvriBadMediaBox puolestaan raportoi sivun, jonka MediaBox ei ole muotoa [0 0 w h] (§6.5.3), koska skannauksella ei ole mitään syytä alkaa muualta kuin origosta
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 lista on lyhyt hyvästä syystä. §6.6 hyväksyy suodattimet /CCITTFaxDecode, /DCTDecode, /JPXDecode ja /FlateDecode — kaksitasoinen faksi, JPEG, JPEG 2000 ja häviötön deflate, jotka yhdessä kattavat jokaisen skanneriulostulon jolla on merkitystä. Kaikesta muusta nousee pvriForbiddenImageFilter, mukaan lukien /LZWDecode, /RunLengthDecode, /ASCII85Decode, /ASCIIHexDecode, /JBIG2Decode ja /Crypt
Kaksi noista hylkäyksistä kannattaa ymmärtää eikä vain opetella ulkoa. /JBIG2Decode pakkaa kaksitasoiset skannaukset poikkeuksellisen tiiviisti ja on PDF/A:ssa täysin laillinen, mutta sen symbolisanakirjan rekonstruktio voi vaihtaa tilalle silmämääräisesti samannäköisen glyfin — skannattujen numeroiden kohdalla tämä on dokumentoitu vikatila — eikä profiili, jonka koko idea on uskollinen rasteritoisto, voi ottaa sitä riskiä. ASCII-suodattimet on jätetty pois päinvastaisesta syystä: ne vain kasvattavat tiedostoa antamatta rasteriprofiilille mitään
Rakennesäännöt, jotka laukeavat ennen yhtäkään sivua
PDF/R kurittaa myös säiliötä. pvriObjStmPresent raportoi /Type /ObjStm -streamin, jonka profiili kieltää suoralta kädeltä — objektistreamit mutkistavat sitä yksinkertaista peräkkäistä jäsennystä, johon rasterilukijan pitäisi pystyä. pvriBadHeader raportoi otsakkeen, joka on jotain muuta kuin %PDF-1.4–1.7 tai %PDF-2.0, ja pvriEncryptVersionMismatch salatun tiedoston, jonka otsake ei ole %PDF-2.0 (§6.2.3)
Katalogi ja Info-sanakirja eivät ole pelkästään tarkistuksen alla vaan sallittujen listalla. pvriProhibitedCatalogEntry ja pvriProhibitedInfoEntry nousevat sallitun joukon ulkopuolisista merkinnöistä, ja pvriInfoXmpMismatch silloin kun Info-merkintä ja sen XMP-vastine ovat eri mieltä. Puuttuvalle katalogin /Metadata-streamille, puuttuvalle trailerin /ID:lle ja puuttuvalle %PDF-raster-1.0-loppumerkille on kullekin oma koodinsa
Miksi tallennusasetuksista puuttuvat Title ja Author
TPdfRSaveOptions kantaa kentät Creator, Producer, CreationDate, ModDate, DocumentId ja InstanceId, eikä siinä ole tarkoituksella kenttää Titlelle, Authorille, Subjectille tai Keywordsille. Juuri ne neljä §6.4.3 kieltää, joten tietue joka tarjoaisi ne houkuttelisi kutsujan kirjoittamaan vaatimustenvastaisen tiedoston vaatimukset täyttävän rajapinnan läpi
Kaksi totuusarvoista asetusta hoitaa siivouksen, kun olemassa oleva PDF muunnetaan. StripInfoOptionalEntries on oletuksena True ja poistaa lähteen Info-sanakirjasta Titlen, Authorin, Subjectin, Keywordsin ja Trappedin. StripCatalogOptionalEntries on niin ikään oletuksena True ja poistaa Namesin, Outlinesin, StructTreeRootin, OutputIntentsin, Langin ja loput, jolloin jäljelle jää vain §6.3:n sallittujen lista. Jos kumman tahansa asettaa Falseksi, merkinnät jäävät — ja vaatimustenmukaisuus menee, mikä on silloin tällöin juuri se mitä kutsuja sisäiseltä tiedostolta haluaakin
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); // merkinnät ja metatiedot, ei sivun sisältöä
finally
Dest.Free;
end;
finally
Src.Free;
end;
end;
Huomaa mitä merkintöjen injektointi ei tee: se lisää metatiedot ja tunnisteet, mutta sivun sisältöä se ei voi loihtia. Lähdesivu jolla ei ole kaistakuvaa kaatuu injektion jälkeenkin virheeseen pvriPageImageMismatch, koska puuttuva kuva ei ollut koskaan metatieto-ongelma
Mihin PDF/R sopii kaappausputkessa
Käytä sitä silloin kun toimitettava tuote on itse skannaus ja uskollisuus on koko sopimus — todistusaineiston kuvantaminen, shekkien ja maksusuoritusten kaappaus, suurkuvaskannerilla tehdyt insinööripiirustusten arkistot. Ota PDF/A käyttöön heti kun asiakirja tarvitsee haettavaa tekstiä, tagitusta, upotettuja liitteitä tai mitä tahansa muuta minkä rasteriprofiili riisuu pois
Yleinen ja toimiva järjestely on tuottaa molemmat: PDF/R-alkuperäinen joka ei muutu koskaan, ja PDF/A-johdannainen OCR-kerroksineen hakua varten. Validaattorit ovat toisistaan riippumattomia, joten sama eräajo voi tarkistaa kummankin artefaktin sitä profiilia vasten jota se oikeasti väittää noudattavansa. Parin arkistopuolelta kannattaa lukea muistiinpanot aiheista PDF/A-arkistointiyhteensopivuus ja PDF/A-esitarkistus, ja tulostuspuolelta läpikäynti aiheesta painovalmiiden PDF/X-asiakirjojen validointi
PDFium Component tuo PDFium-moottorin Delphille, C++Builderille ja Lazarukselle VCL-rajapinnan sekä PDF/A-, PDF/X-, PDF/E-, PDF/UA- ja PDF/R-validaattoreiden kanssa — PDFium Component -tuotesivulta löytyvät tuetut standardit ja IDE-versiot