Bài viết kỹ thuật

Xác thực tài liệu quét PDF/raster trong Delphi

PDF/R, chuẩn hóa thành ISO 23504-1, là profile PDF cho tài liệu quét: mỗi trang mang đúng một strip image và không gì khác. PDFium Component xác thực nó từ Delphi, Lazarus và C++Builder thông qua ValidatePdfRCompliance, hàm này đọc một stream và trả về cấp tuân thủ cùng một tập hợp các vấn đề cụ thể

Profile tồn tại vì các máy quét và hệ thống capture tài liệu cần một đích hẹp hơn PDF/A. Một PDF lưu trữ có thể chứa bất cứ gì part cho phép; một PDF raster cố ý bị bần cùng hóa, để mọi trình đọc tuân thủ có thể hiển thị nó đồng nhất và mọi trình ghi tuân thủ có thể sản xuất nó từ một quét mà không cần engine tác giả

PDF/R cấm những gì mà PDF/A cho phép?

Văn bản, trên thực tế. Một trang raster mang ảnh quét và không gì khác, nên một tài nguyên font trên một trang là một vi phạm — báo cáo là pvriFontForbidden theo ISO 23504-1 §6.5.2. Điều đó gây bất ngờ cho những người thêm một lớp văn bản OCR vô hình để có thể tìm kiếm, một việc bình thường và hữu ích trong quy trình PDF/A và đơn giản là không phải PDF/R

Quan hệ trang-ảnh cũng nghiêm ngặt như nhau. §6.5.1 làm mỗi trang đúng một strip image, nên pvriPageImageMismatch kích hoạt khi số ảnh không khớp số trang — một trang không có ảnh và một trang có hai ảnh đều không tuân thủ. Và pvriBadMediaBox báo cáo một trang mà MediaBox không có dạng [0 0 w h] (§6.5.3), vì một quét không có lý do gì để ngồi ở một gốc offset

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;

Các encoding ảnh nào được phép

Bốn, và danh sách trắng ngắn vì một lý do. §6.6 chấp nhận /CCITTFaxDecode, /DCTDecode, /JPXDecode/FlateDecode — fax bilevel, JPEG, JPEG 2000 và deflate không mất dữ liệu, vốn giữa chúng bao phủ mọi đầu ra máy quét quan trọng. Mọi thứ khác được báo cáo là pvriForbiddenImageFilter, bao gồm /LZWDecode, /RunLengthDecode, /ASCII85Decode, /ASCIIHexDecode, /JBIG2Decode/Crypt

Hai trong số các lần từ chối đó đáng hiểu hơn là đáng nhớ. /JBIG2Decode nén các quét bilevel cực tốt và hoàn toàn hợp pháp trong PDF/A, nhưng phần dựng lại symbol-dictionary của nó có thể thay thế glyph trông giống nhau — một chế độ thất bại đã được ghi nhận cho các chữ số quét — và một profile mà toàn bộ mục đích là tái tạo raster trung thực không thể dung thứ rủi ro đó. Các filter ASCII bị loại vì lý do ngược lại: chúng phồng file mà không thêm gì mà một profile raster cần

Các quy tắc cấu trúc kích hoạt trước khi trang nào được đọc

PDF/R cũng ràng buộc container. pvriObjStmPresent báo cáo một stream /Type /ObjStm, vốn profile cấm hoàn toàn — object stream làm phức tạp phép phân tích tuần tự đơn giản mà một trình đọc raster được kỳ vọng để thực hiện. pvriBadHeader báo cáo một header ngoài %PDF-1.4 đến 1.7 và %PDF-2.0, còn pvriEncryptVersionMismatch báo cáo một file mã hóa mà header không phải %PDF-2.0, theo §6.2.3

Catalog và Info dictionary được liệt kê trắng, chứ không chỉ kiểm tra. pvriProhibitedCatalogEntrypvriProhibitedInfoEntry kích hoạt cho các mục ngoài tập hợp cho phép, còn pvriInfoXmpMismatch kích hoạt khi một mục Info bất đồng với phần XMP tương đương. Một stream /Metadata của catalog thiếu, một /ID của trailer thiếu và một marker chân trang %PDF-raster-1.0 vắng mặt mỗi cái có issue riêng

Vì sao bản ghi tùy chọn lưu bỏ Title và Author

TPdfRSaveOptions mang Creator, Producer, CreationDate, ModDate, DocumentIdInstanceId, và cố ý không có trường cho Title, Author, Subject hay Keywords. Bốn cái đó là các mục mà §6.4.3 cấm, nên một bản ghi phơi bày chúng sẽ mời gọi bên gọi ghi một file không tuân thủ qua một API tuân thủ

Hai tùy chọn boolean kiểm soát dọn dẹp khi chuyển một PDF sẵn có. StripInfoOptionalEntries mặc định True và gỡ Title, Author, Subject, Keywords và Trapped khỏi Info dictionary nguồn. StripCatalogOptionalEntries cũng mặc định True và gỡ Names, Outlines, StructTreeRoot, OutputIntents, Lang và phần còn lại, để lại chỉ danh sách trắng §6.3. Đặt một trong hai thành False và bạn giữ lại các mục — và mất tính tuân thủ, đôi khi đúng là điều một bên gọi thực sự muốn cho một file nội bộ

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;

Lưu ý điều marker injection không làm: nó thêm siêu dữ liệu và nhận diện, và không thể cung cấp nội dung trang. Một trang nguồn không mang strip image vẫn sẽ thất bại pvriPageImageMismatch sau khi inject, vì ảnh thiếu chưa bao giờ là vấn đề siêu dữ liệu

Nơi PDF/R phù hợp trong một pipeline capture

Hãy dùng nó khi sản phẩm bàn giao chính là bản quét và tính trung thành là toàn bộ hợp đồng — ảnh bằng chứng, capture séc và thanh toán, kho lưu trữ bản vẽ kỹ thuật từ một máy quét khổ lớn. Hãy dùng PDF/A thay vào đó ngay khi tài liệu cần văn bản tìm kiếm được, gắn thẻ, tệp đính kèm nhúng hoặc bất cứ thứ gì khác mà profile raster tước bỏ

Một sắp đặt phổ biến và khả thi là sản xuất cả hai: một bản gốc PDF/R không bao giờ thay đổi, và một bản phái sinh PDF/A với một lớp OCR cho việc truy xuất. Hai trình xác thực độc lập, nên cùng một tác vụ hàng loạt có thể kiểm tra từng artefact với profile mà nó thực sự cam kết. Về phía lưu trữ của cặp đó, xem các ghi chú về tuân thủ lưu trữ PDF/Axác thực preflight PDF/A, còn về đầu ra hướng in, bài viết về xác thực tài liệu PDF/X sẵn sàng in

PDFium Component mang engine PDFium tới Delphi, C++Builder và Lazarus với một API VCL và các trình xác thực tuân thủ cho PDF/A, PDF/X, PDF/E, PDF/UA và PDF/R — trang sản phẩm PDFium Component liệt kê các chuẩn và phiên bản IDE được hỗ trợ