PDF/R, padronizado como ISO 23504-1, é o perfil PDF para documentos digitalizados: toda página carrega exatamente uma imagem de faixa e nada mais. O PDFium Component o valida a partir de Delphi, Lazarus e C++Builder por meio de ValidatePdfRCompliance, que lê um stream e devolve o nível de conformidade mais um conjunto de problemas concretos
O perfil existe porque scanners e sistemas de captura de documentos precisavam de um alvo mais estreito do que PDF/A. Um PDF arquivável pode conter qualquer coisa que a parte permite; um PDF raster é deliberadamente empobrecido, de modo que qualquer leitor compatível o exibe de forma idêntica e qualquer escritor compatível o produz a partir de uma digitalização sem um motor de autoria
O que o PDF/R proíbe que o PDF/A permite?
Texto, na prática. Uma página raster carrega a imagem digitalizada e nada mais, então um recurso de fonte numa página é uma violação — relatada como pvriFontForbidden sob ISO 23504-1 §6.5.2. Isso surpreende quem adiciona uma camada de texto OCR invisível para pesquisabilidade, que é uma coisa normal e útil de se fazer num fluxo PDF/A e simplesmente não é PDF/R
A relação página-imagem é igualmente estrita. A §6.5.1 faz toda página exatamente uma imagem de faixa, então pvriPageImageMismatch dispara quando a contagem de imagens não corresponde à contagem de páginas — uma página sem imagem e uma página com duas são ambas não compatíveis. E pvriBadMediaBox relata uma página cuja MediaBox não tem a forma [0 0 w h] (§6.5.3), porque uma digitalização não tem motivo para ficar numa origem deslocada
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;
Quais codificações de imagem são permitidas
Quatro, e a lista de permissões é curta por um motivo. A §6.6 admite /CCITTFaxDecode, /DCTDecode, /JPXDecode e /FlateDecode — fax bilevel, JPEG, JPEG 2000 e deflate sem perda, que entre eles cobrem toda saída de scanner que importa. Tudo o mais é relatado como pvriForbiddenImageFilter, incluindo /LZWDecode, /RunLengthDecode, /ASCII85Decode, /ASCIIHexDecode, /JBIG2Decode e /Crypt
DUas dessas rejeições valem entender em vez de memorizar. /JBIG2Decode comprime digitalizações bilevel extremamente bem e é perfeitamente legal em PDF/A, mas sua reconstrução de dicionário de símbolos pode substituir glifos visualmente semelhantes — um modo de falha documentado para dígitos digitalizados — e um perfil cujo propósito inteiro é reprodução raster fiel não pode admitir esse risco. Os filtros ASCII são excluídos pelo motivo oposto: eles inflam o arquivo sem adicionar nada que um perfil raster precise
Regras estruturais que disparam antes de qualquer página ser lida
PDF/R também constrange o contêiner. pvriObjStmPresent relata um stream /Type /ObjStm, que o perfil proíbe totalmente — object streams complicam a análise simples e sequencial que um leitor raster deve conseguir realizar. pvriBadHeader relata um cabeçalho fora de %PDF-1.4 a 1.7 e %PDF-2.0, e pvriEncryptVersionMismatch relata um arquivo criptografado cujo cabeçalho não é %PDF-2.0, conforme §6.2.3
O catálogo e o dicionário Info têm lista de permissões, não são apenas verificados. pvriProhibitedCatalogEntry e pvriProhibitedInfoEntry disparam para entradas fora do conjunto permitido, e pvriInfoXmpMismatch dispara quando uma entrada Info discorda de seu equivalente XMP. Um stream /Metadata de catálogo ausente, um /ID de trailer ausente e um marcador de rodapé %PDF-raster-1.0 ausente têm cada um o seu próprio problema também
Por que o registro de opções de salvamento omite Title e Author
TPdfRSaveOptions carrega Creator, Producer, CreationDate, ModDate, DocumentId e InstanceId, e deliberadamente não tem campo para Title, Author, Subject ou Keywords. Esses quatro são as entradas que a §6.4.3 proíbe, então um registro que os expusesse estaria convidando chamadores a escrever um arquivo não compatível por meio de uma API compatível
Duas opções booleanas controlam a limpeza ao converter um PDF existente. StripInfoOptionalEntries tem padrão True e remove Title, Author, Subject, Keywords e Trapped do dicionário Info de origem. StripCatalogOptionalEntries também tem padrão True e remove Names, Outlines, StructTreeRoot, OutputIntents, Lang e o restante, deixando apenas a lista de permissões da §6.3. Defina qualquer um como False e você mantém as entradas — e perde conformidade, que ocasionalmente é o que um chamador de fato quer para um arquivo 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;
Note o que a injeção de marcador não faz: ela adiciona metadados e identificação, e não consegue fornecer conteúdo de página. Uma página de origem que não carrega nenhuma imagem de faixa ainda vai falhar em pvriPageImageMismatch depois da injeção, porque a imagem ausente nunca foi um problema de metadados
Onde o PDF/R se encaixa num pipeline de captura
Use onde a entrega é a própria digitalização e fidelidade é o contrato inteiro — imagem evidenciária, captura de cheques e remessas, arquivos de desenho técnico de um scanner de formato largo. Use PDF/A em vez disso no momento em que o documento precise de texto pesquisável, marcação, anexos embutidos ou qualquer outra coisa que o perfil raster remova
Um arranjo comum e viável é produzir ambos: um original PDF/R que nunca muda, e um derivado PDF/A com uma camada OCR para recuperação. Os validadores são independentes, então o mesmo job em lote consegue conferir cada artefato contra o perfil que ele de fato reivindica. Para o lado arquivável desse par, veja as notas sobre conformidade arquivável de PDF/A e validação de preflight de PDF/A, e para saída orientada a impressão o guia sobre validação de documentos PDF/X prontos para impressão
O PDFium Component traz o motor PDFium para Delphi, C++Builder e Lazarus com uma API VCL e validadores de conformidade para PDF/A, PDF/X, PDF/E, PDF/UA e PDF/R — a página do produto PDFium Component lista os padrões e versões de IDE suportados