Odborný článok

Validácia PDF/raster skenovaných dokumentov v Delphi

PDF/R, štandardizovaný ako ISO 23504-1, je profil PDF pre skenované dokumenty: každá strana nesie presne jeden prúžkový obrázok a nič iné. PDFium Component ho validuje z Delphi, Lazarusu a C++Builder cez ValidatePdfRCompliance, ktorý číta stream a vracia úroveň zhody spolu so sadou konkrétnych problémov

Profil existuje, pretože skenery a systémy na zachytávanie dokumentov potrebovali cieľ užší než PDF/A. Archivačné PDF môže obsahovať čokoľvek, čo časť povoľuje; raster PDF je zámerne ochudobnený, takže ktorýkoľvek zodpovedajúci čítač ho zobrazí identicky a ktorýkoľvek zodpovedajúci zapisovateľ ho môže vyprodukovať zo skenu bez authoring enginu

Čo PDF/R zakazuje a PDF/A povoľuje?

V praxi text. Raster strana nesie skenovaný obrázok a nič iné, takže fontový zdroj na strane je porušenie — nahlásené ako pvriFontForbidden pod ISO 23504-1 §6.5.2. To prekvapí ľudí, ktorí pridávajú neviditeľnú OCR textovú vrstvu pre vyhľadáteľnosť, čo je v PDF/A workflow normálna a užitočná vec a jednoducho nie je PDF/R

Vzťah strany k obrázku je rovnako prísny. §6.5.1 robí každú stranu presne jedným prúžkovým obrázkom, takže pvriPageImageMismatch sa spustí, keď počet obrázkov nezodpovedá počtu strán — strana bez obrázku aj strana s dvoma sú obe nezodpovedajúce. A pvriBadMediaBox nahlási stranu, ktorej MediaBox nemá tvar [0 0 w h] (§6.5.3), pretože scan nemá dôvod sedieť na posunutom počiatku

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;

Ktoré kódovania obrázkov sú povolené

Štyri a biely zoznam je krátky z konkrétneho dôvodu. §6.6 pripúšťa /CCITTFaxDecode, /DCTDecode, /JPXDecode a /FlateDecode — obojúrovňový fax, JPEG, JPEG 2000 a bezstratový deflate, čo spolu pokrýva každý scanner výstup, na ktorom záleží. Všetko ostatné je nahlásené ako pvriForbiddenImageFilter, vrátane /LZWDecode, /RunLengthDecode, /ASCII85Decode, /ASCIIHexDecode, /JBIG2Decode a /Crypt

Dve z týchto odmietnutí sa oplatí pochopiť namiesto memorovania. /JBIG2Decode komprimuje obojúrovňové skeny extrémne dobre a je v PDF/A úplne legálny, no jeho rekonštrukcia slovníka symbolov môže nahradiť vizuálne podobné glyphy — zdokumentovaný režim zlyhania pri skenovaných čísliciach — a profil, ktorého celým účelom je verná raster reprodukcia, nemôže toto riziko pripustiť. ASCII filtre sú vylúčené z opačného dôvodu: nadýchnu súbor bez toho, aby pridali čokoľvek, čo raster profil potrebuje

Štrukturálne pravidlá, ktoré sa spúšťajú skôr než sa prečíta ktorákoľvek strana

PDF/R obmedzuje aj kontajner. pvriObjStmPresent nahlási stream /Type /ObjStm, ktorý profil outright zakazuje — objektové streamy komplikujú jednoduché, sekvenčné parsovanie, ktoré má byť raster čítač schopný vykonať. pvriBadHeader nahlási hlavičku mimo %PDF-1.4 až 1.7 a %PDF-2.0 a pvriEncryptVersionMismatch nahlási šifrovaný súbor, ktorého hlavička nie je %PDF-2.0, podľa §6.2.3

Katalóg a slovník Info sú na bielom zozname, nielen kontrolované. pvriProhibitedCatalogEntry a pvriProhibitedInfoEntry sa spúšťajú pre položky mimo povolenej množiny a pvriInfoXmpMismatch sa spustí, keď sa položka Info nezhoduje so svojím XMP ekvivalentom. Chýbajúci stream /Metadata v katalógu, chýbajúce /ID v traileri a chýbajúci zápatový marker %PDF-raster-1.0 majú každý svoj vlastný problém

Prečo záznam save options vynecháva Title a Author

TPdfRSaveOptions nesie Creator, Producer, CreationDate, ModDate, DocumentId a InstanceId a zámerne nemá žiadne pole pre Title, Author, Subject ani Keywords. Tieto štyri sú položky, ktoré §6.4.3 zakazuje, takže záznam, ktorý by ich vystavoval, by pozýval volajúcich zapísať nezodpovedajúci súbor cez zodpovedajúce API

Dve booleovske voľby riadia upratovanie pri konverzii existujúceho PDF. StripInfoOptionalEntries je predvolene True a odstraňuje Title, Author, Subject, Keywords a Trapped zo zdrojového slovníka Info. StripCatalogOptionalEntries je tiež predvolene True a odstraňuje Names, Outlines, StructTreeRoot, OutputIntents, Lang a zvyšok, pričom ponecháva iba biely zoznam §6.3. Nastavte jedno z nich na False a položky si ponecháte — a stratíte zhodu, čo je občas to, čo volajúci skutočne chce pre interný súbor

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;

Všimnite si, čo marker injection nerobí: pridáva metadáta a identifikáciu a nedokáže dodať obsah strany. Zdrojová strana, ktorá nenesie žiadny prúžkový obrázok, po injekcii stále zlyhá na pvriPageImageMismatch, pretože chýbajúci obrázok nebol nikdy metadatovým problémom

Kam PDF/R patrí v capture linke

Použite ho tam, kde je výstupom samotný scan a vernosť je celá zmluva — evidenné zobrazovanie, zachytávanie šekov a platieb, archívy inžinierskych výkresov z veľkoformátového skenera. Použite namiesto toho PDF/A v okamihu, keď dokument potrebuje vyhľadáteľný text, značenie, vložené prílohy alebo čokoľvek iné, čo raster profil odstraňuje

Bežné a fungujúce usporiadanie je produkovať obe: PDF/R originál, ktorý sa nikdy nezmení, a PDF/A derivát s OCR vrstvou pre vyhľadávanie. Validátory sú nezávislé, takže rovnaká dávková úloha môže skontrolovať každý artefakt proti profilu, ktorý skutočne nárokuje. Pre archivačnú stranu toho páru pozri poznámky k archivačnej zhode PDF/A a PDF/A preflight validácii a pre výstup orientovaný na tlač návod k validácii tlačou pripravených PDF/X dokumentov

PDFium Component prináša engine PDFium do Delphi, C++Builder a Lazarus s VCL API a validátormi zhody pre PDF/A, PDF/X, PDF/E, PDF/UA a PDF/R — produktovej stránka PDFium Component uvádza podporované štandardy a verzie IDE