PDF/R, standardizzato come ISO 23504-1, è il profilo PDF per i documenti scansionati: ogni pagina porta esattamente una strip image e null'altro. PDFium Component lo convalida da Delphi, Lazarus e C++Builder attraverso ValidatePdfRCompliance, che legge uno stream e restituisce il livello di conformità più un insieme di problemi concreti
Il profilo esiste perché scanner e sistemi di acquisizione documentale avevano bisogno di un target più ristretto di PDF/A. Un PDF archivistico può contenere qualsiasi cosa la parte permette; un PDF raster è deliberatamente impoverito, così qualsiasi lettore conforme può visualizzarlo in modo identico e qualsiasi writer conforme può produrlo da una scansione senza un motore di authoring
Cosa vieta PDF/R che PDF/A permette?
Il testo, in pratica. Una pagina raster porta l'immagine scansionata e null'altro, così una risorsa font su una pagina è una violazione — riportata come pvriFontForbidden sotto ISO 23504-1 §6.5.2. Questo sorprende chi aggiunge un layer di testo OCR invisibile per ricercabilità, che è una cosa normale e utile in un flusso PDF/A e semplicemente non è PDF/R
La relazione pagina-immagine è altrettanto rigida. §6.5.1 fa di ogni pagina esattamente una strip image, così pvriPageImageMismatch scatta quando il conteggio immagini non corrisponde al conteggio pagine — una pagina senza immagine e una pagina con due sono entrambe non conformi. E pvriBadMediaBox riporta una pagina la cui MediaBox non ha la forma [0 0 w h] (§6.5.3), perché una scansione non ha motivo di stare a un offset di origine
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;
Quali codifiche di immagine sono ammesse
Quattro, e la white list è breve per un motivo. §6.6 ammette /CCITTFaxDecode, /DCTDecode, /JPXDecode e /FlateDecode — fax bilevel, JPEG, JPEG 2000 e deflate lossless, che tra loro coprono ogni output di scanner che conta. Tutto il resto viene riportato come pvriForbiddenImageFilter, inclusi /LZWDecode, /RunLengthDecode, /ASCII85Decode, /ASCIIHexDecode, /JBIG2Decode e /Crypt
Due di quei rifiuti valgono la pena di capire anziché memorizzare. /JBIG2Decode comprime le scansioni bilevel estremamente bene ed è perfettamente legale in PDF/A, ma la sua ricostruzione del dizionario di simboli può sostituire glifi visivamente simili — una modalità di fallimento documentata per cifre scansionate — e un profilo il cui scopo complessivo è la riproduzione raster fedele non può ammettere quel rischio. I filtri ASCII sono esclusi per il motivo opposto: gonfiano il file senza aggiungere nulla di cui un profilo raster abbia bisogno
Regole di struttura che scattano prima che qualsiasi pagina sia letta
PDF/R vincola anche il contenitore. pvriObjStmPresent riporta uno stream /Type /ObjStm, che il profilo vieta del tutto — gli object stream complicano il parsing semplice e sequenziale che un lettore raster dovrebbe essere in grado di eseguire. pvriBadHeader riporta un header fuori da %PDF-1.4 a 1.7 e %PDF-2.0, e pvriEncryptVersionMismatch riporta un file cifrato il cui header non è %PDF-2.0, secondo §6.2.3
Il dizionario Catalog e Info sono white-listati, non solo controllati. pvriProhibitedCatalogEntry e pvriProhibitedInfoEntry scattano per voci fuori dall'insieme permesso, e pvriInfoXmpMismatch scatta quando una voce Info non concorda con il proprio equivalente XMP. Uno stream /Metadata mancante nel Catalog, un /ID mancante nel trailer e un footer marker %PDF-raster-1.0 assente hanno ciascuno il proprio problema specifico
Perché il record delle opzioni di salvataggio omette Title e Author
TPdfRSaveOptions porta Creator, Producer, CreationDate, ModDate, DocumentId e InstanceId, e deliberatamente non ha campo per Title, Author, Subject o Keywords. Quei quattro sono le voci che §6.4.3 vieta, così un record che le esponesse inviterebbe i chiamanti a scrivere un file non conforme attraverso un'API conforme
Due opzioni booleane controllano la pulizia quando si converte un PDF esistente. StripInfoOptionalEntries vale predefinito True e rimuove Title, Author, Subject, Keywords e Trapped dal dizionario Info sorgente. StripCatalogOptionalEntries vale pure predefinito True e rimuove Names, Outlines, StructTreeRoot, OutputIntents, Lang e il resto, lasciando solo la white list di §6.3. Imposta uno dei due a False e tieni le voci — e perdi la conformità, il che è occasionalmente ciò che un chiamante vuole davvero per un file interno
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;
Nota cosa non fa l'iniezione di marker: aggiunge metadati e identificazione, e non può fornire contenuto di pagina. Una pagina sorgente che non porta alcuna strip image fallirà ancora pvriPageImageMismatch dopo l'iniezione, perché l'immagine mancante non è mai stata un problema di metadati
Dove si incastra PDF/R in una pipeline di acquisizione
Usalo dove il deliverable è la scansione stessa e la fedeltà è tutto il contratto — imaging probatorio, acquisizione di assegni e rimesse, archivi di disegni tecnici da scanner di grande formato. Usa invece PDF/A nel momento in cui il documento ha bisogno di testo ricercabile, tagging, allegati incorporati o qualsiasi altra cosa il profilo raster elimini
Un assetto comune e praticabile è produrre entrambi: un originale PDF/R che non cambia mai, e un derivato PDF/A con un layer OCR per il reperimento. I validatori sono indipendenti, così lo stesso job batch può controllare ciascun artefatto rispetto al profilo che rivendica davvero. Per il lato archivistico di quella coppia, vedi le note sulla conformità archivistica PDF/A e sulla validazione preflight PDF/A, e per output orientato alla stampa la guida sulla validazione di documenti PDF/X pronti per la stampa
PDFium Component porta il motore PDFium in Delphi, C++Builder e Lazarus con un'API VCL e validatori di conformità per PDF/A, PDF/X, PDF/E, PDF/UA e PDF/R — la pagina prodotto PDFium Component elenca gli standard supportati e le versioni di IDE