PDF/R, standardisé comme ISO 23504-1, est le profil PDF pour les documents scannés : chaque page porte exactement une image en bandes et rien d'autre. PDFium Component le valide depuis Delphi, Lazarus et C++Builder via ValidatePdfRCompliance, qui lit un flux et renvoie le niveau de conformité plus un ensemble de questions concrètes
Le profil existe car les scanners et les systèmes de capture de documents avaient besoin d'une cible plus étroite que PDF/A. Un PDF d'archivage peut contenir tout ce que la partie autorise ; un PDF raster est délibérément appauvri, afin qu'un lecteur conforme puisse l'afficher de façon identique et qu'un générateur conforme puisse le produire depuis un scan sans moteur de création
Que interdit PDF/R que PDF/A autorise ?
Le texte, en pratique. Une page raster porte l'image scannée et rien d'autre, donc une ressource de police sur une page est une violation — signalée comme pvriFontForbidden sous ISO 23504-1 §6.5.2. Cela surprend les gens qui ajoutent une couche de texte OCR invisible pour la recherche, ce qui est une chose normale et utile à faire dans un flux PDF/A et n'est tout simplement pas PDF/R
La relation page-image est également stricte. §6.5.1 fait de chaque page exactement une image en bandes, donc pvriPageImageMismatch se déclenche quand le compte d'images ne correspond pas au compte de pages — une page sans image et une page avec deux sont toutes deux non conformes. Et pvriBadMediaBox signale une page dont la MediaBox n'a pas la forme [0 0 w h] (§6.5.3), car un scan n'a aucune raison de se trouver à une origine décalée
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;
Quels encodages d'images sont autorisés
Quatre, et la liste blanche est courte pour une raison. §6.6 admet /CCITTFaxDecode, /DCTDecode, /JPXDecode et /FlateDecode — fax biniveau, JPEG, JPEG 2000 et deflate sans perte, qui entre eux couvrent toute sortie de scanner qui compte. Tout le reste est signalé comme pvriForbiddenImageFilter, y compris /LZWDecode, /RunLengthDecode, /ASCII85Decode, /ASCIIHexDecode, /JBIG2Decode et /Crypt
Deux de ces rejets valent la peine d'être compris plutôt que mémorisés. /JBIG2Decode comprime les scans biniveaux extrêmement bien et est parfaitement légal en PDF/A, mais sa reconstruction de dictionnaire de symboles peut substituer des glyphes visuellement similaires — un mode d'échec documenté pour les chiffres scannés — et un profil dont tout le propos est la reproduction raster fidèle ne peut pas admettre ce risque. Les filtres ASCII sont exclus pour la raison opposée : ils enflent le fichier sans rien ajouter qu'un profil raster ait besoin
Règles de structure qui se déclenchent avant qu'une page ne soit lue
PDF/R contraint aussi le conteneur. pvriObjStmPresent signale un flux /Type /ObjStm, que le profil interdit carrément — les flux d'objets compliquent l'analyse simple et séquentielle qu'un lecteur raster est censé pouvoir effectuer. pvriBadHeader signale un en-tête hors %PDF-1.4 à 1.7 et %PDF-2.0, et pvriEncryptVersionMismatch signale un fichier chiffré dont l'en-tête n'est pas %PDF-2.0, selon §6.2.3
Le dictionnaire Catalog et Info sont en liste blanche, pas simplement contrôlés. pvriProhibitedCatalogEntry et pvriProhibitedInfoEntry se déclenchent pour des entrées hors de l'ensemble permis, et pvriInfoXmpMismatch se déclenche quand une entrée Info n'est pas d'accord avec son équivalent XMP. Une flux /Metadata Catalog manquant, un /ID de trailer manquant et un marqueur de pied %PDF-raster-1.0 absent ont chacun leur propre question également
Pourquoi l'enregistrement d'options de sauvegarde omet Titre et Auteur
TPdfRSaveOptions porte Creator, Producer, CreationDate, ModDate, DocumentId et InstanceId, et n'a délibérément aucun champ pour Titre, Auteur, Sujet ou Mots-clés. Ces quatre sont les entrées que §6.4.3 interdit, donc un enregistrement qui les exposerait inviterait les appelants à écrire un fichier non conforme via une API conforme
Deux options booléennes contrôlent le nettoyage lors de la conversion d'un PDF existant. StripInfoOptionalEntries vaut True par défaut et retire Titre, Auteur, Sujet, Mots-clés et Trapped du dictionnaire Info source. StripCatalogOptionalEntries vaut aussi True par défaut et retire Names, Outlines, StructTreeRoot, OutputIntents, Lang et le reste, ne laissant que la liste blanche §6.3. Réglez l'un ou l'autre à False et vous gardez les entrées — et perdez la conformité, ce qui est occasionnellement ce qu'un appelant veut réellement pour un fichier interne
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;
Notez ce que l'injection de marqueurs ne fait pas : elle ajoute des métadonnées et de l'identification, et ne peut pas fournir de contenu de page. Une page source qui ne porte aucune image en bandes échouera encore à pvriPageImageMismatch après injection, car l'image manquante n'a jamais été un problème de métadonnées
Où PDF/R s'intègre dans un pipeline de capture
Utilisez-le là où le livrable est le scan lui-même et la fidélité est tout le contrat — imagerie probatoire, capture de chèques et remises, archives de plans d'ingénierie depuis un scanner grand format. Utilisez PDF/A à la place dès l'instant où le document a besoin de texte recherchable, de balisage, de pièces jointes incorporées ou de quoi que ce soit d'autre que le profil raster supprime
Un arrangement courant et viable est de produire les deux : un original PDF/R qui ne change jamais, et un dérivé PDF/A avec une couche OCR pour la recherche. Les validateurs sont indépendants, donc le même travail par lots peut vérifier chaque artefact contre le profil qu'il réclame effectivement. Pour le côté archivage de cette paire, voir les notes sur la conformité d'archivage PDF/A et la validation préflight PDF/A, et pour la sortie orientée impression la visite guidée de la validation de documents PDF/X prêts à imprimer
PDFium Component apporte le moteur PDFium à Delphi, C++Builder et Lazarus avec une API VCL et des validateurs de conformité pour PDF/A, PDF/X, PDF/E, PDF/UA et PDF/R — la page produit PDFium Component liste les normes et versions IDE prises en charge