บทความเทคนิค

การตรวจสอบเอกสารสแกน PDF/raster ใน Delphi

PDF/R ซึ่งกำหนดเป็นมาตรฐาน ISO 23504-1 คือโปรไฟล์ PDF สำหรับเอกสารที่สแกน ทุกหน้าพกภาพ strip เดียวพอดีและไม่มีอะไรอื่น PDFium Component ตรวจสอบมันจาก Delphi, Lazarus และ C++Builder ผ่าน ValidatePdfRCompliance ซึ่งอ่าน stream แล้วคืนระดับการปฏิบัติตามมาตรฐานพร้อมเซ็ตของปัญหาที่เป็นรูปธรรม

โปรไฟล์นี้มีอยู่เพราะเครื่องสแกนและระบบจับภาพเอกสารต้องการเป้าหมายที่แคบกว่า PDF/A PDF เก็บถาวรอาจมีอะไรก็ได้ที่ part อนุญาต PDF raster ถูกทำให้ยากจนโดยตั้งใจ เพื่อให้ตัวอ่านที่สอดคล้องใด ๆ แสดงมันเหมือนกันได้ และตัวเขียนที่สอดคล้องใด ๆ ผลิตมันจากการสแกนได้โดยไม่ต้องมีเอนจินการเขียน

PDF/R ห้ามอะไรที่ PDF/A อนุญาต

ข้อความในทางปฏิบัติ หน้า raster พกภาพสแกนและไม่มีอะไรอื่น ดังนั้น font resource บนหน้าจึงเป็นการละเมิด — รายงานเป็น pvriFontForbidden ภายใต้ ISO 23504-1 §6.5.2 นั่นทำให้คนที่เพิ่มเลเยอร์ข้อความ OCR ที่มองไม่เห็นเพื่อความสามารถในการค้นหาประหลาดใจ ซึ่งเป็นสิ่งปกติและมีประโยชน์ที่ทำในเวิร์กโฟลว์ PDF/A แต่ไม่ใช่ PDF/R

ความสัมพันธ์ระหว่างหน้ากับภาพเข้มงวดพอ ๆ §6.5.1 ทำให้ทุกหน้าเป็นภาพ strip เดียวพอดี ดังนั้น pvriPageImageMismatch จึงทำงานเมื่อจำนวนภาพไม่ตรงกับจำนวนหน้า — หน้าที่ไม่มีภาพและหน้าที่มีสองภาพทั้งคู่ไม่สอดคล้อง และ pvriBadMediaBox รายงานหน้าที่ MediaBox ไม่มีรูปแบบ [0 0 w h] (§6.5.3) เพราะการสแกนไม่มีเหตุผลที่จะนั่งที่จุดเริ่มต้นที่เลื่อนไป

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;

การเข้ารหัสภาพใดบ้างที่อนุญาต

สี่แบบ และ white list สั้นด้วยเหตุผล §6.6 ยอมรับ /CCITTFaxDecode, /DCTDecode, /JPXDecode และ /FlateDecode — แฟกซ์สองระดับ, JPEG, JPEG 2000 และ deflate แบบ lossless ซึ่งระหว่างพวกมันครอบคลุมเอาต์พุตเครื่องสแกนที่สำคัญทุกแบบ ทุกสิ่งอื่นถูกรายงานเป็น pvriForbiddenImageFilter รวมถึง /LZWDecode, /RunLengthDecode, /ASCII85Decode, /ASCIIHexDecode, /JBIG2Decode และ /Crypt

สองกรณีปฏิเสธในนั้นคุ้มค่าที่จะเข้าใจแทนที่จะท่องจำ /JBIG2Decode บีบอัดสแกนสองระดับได้ดีมากและถูกต้องตามกฎหมายอย่างสมบูรณ์ใน PDF/A แต่การสร้าง symbol-dictionary ใหม่ของมันสามารถแทนที่ glyph ที่คล้ายกันทางสายตา — ซึ่งเป็นรูปแบบความล้มเหลวที่บันทึกไว้สำหรับตัวเลขที่สแกน — และโปรไฟล์ที่จุดประสงค์ทั้งหมดคือการสืบทอด raster ที่ซื่อสัตย์จึงรับความเสี่ยงนั้นไม่ได้ ตัวกรอง ASCII ถูกแยกออกด้วยเหตุผลตรงกันข้าม มันพองไฟล์โดยไม่เพิ่มอะไรที่โปรไฟล์ raster ต้องการ

กฎโครงสร้างที่ทำงานก่อนที่หน้าใดจะถูกอ่าน

PDF/R จำกัดคอนเทนเนอร์ด้วย pvriObjStmPresent รายงาน stream /Type /ObjStm ซึ่งโปรไฟล์ห้ามโดยสิ้นเชิง — object stream ทำให้การ parse แบบเรียงอนุกรมง่าย ๆ ที่ตัวอ่าน raster ตั้งใจให้ทำได้ซับซ้อนขึ้น pvriBadHeader รายงาน header นอกเหนือจาก %PDF-1.4 ถึง 1.7 และ %PDF-2.0 และ pvriEncryptVersionMismatch รายงานไฟล์เข้ารหัสที่ header ไม่ใช่ %PDF-2.0 ตาม §6.2.3

catalog และ Info dictionary ถูก white-list ไม่ใช่แค่ตรวจสอบ pvriProhibitedCatalogEntry และ pvriProhibitedInfoEntry ทำงานสำหรับ entry นอกเซ็ตที่อนุญาต และ pvriInfoXmpMismatch ทำงานเมื่อ entry Info ไม่ลงรอยกับค่า XMP ที่เทียบเท่า catalog /Metadata stream ที่ขาดหายไป, trailer /ID ที่ขาดหายไป และเครื่องหมาย footer %PDF-raster-1.0 ที่ไม่อยู่ แต่ละอันมีปัญหาของตัวเอง

ทำไม record ตัวเลือกการบันทึกจึงละเว้น Title และ Author

TPdfRSaveOptions พก Creator, Producer, CreationDate, ModDate, DocumentId และ InstanceId และตั้งใจไม่มีฟิลด์สำหรับ Title, Author, Subject หรือ Keywords สี่อย่างนั้นคือ entry ที่ §6.4.3 ห้าม ดังนั้น record ที่เปิดเผยพวกมันจะเชิญผู้เรียกให้เขียนไฟล์ที่ไม่สอดคล้องผ่าน API ที่สอดคล้อง

ตัวเลือก boolean สองตัวควบคุมการทำความสะอาดเมื่อแปลง PDF ที่มีอยู่ StripInfoOptionalEntries มีค่าเริ่มต้น True และเอา Title, Author, Subject, Keywords และ Trapped ออกจาก source Info dictionary StripCatalogOptionalEntries ก็มีค่าเริ่มต้น True และเอา Names, Outlines, StructTreeRoot, OutputIntents, Lang และที่เหลือออก เหลือเพียง white list ของ §6.3 ตั้งอันใดอันหนึ่งเป็น False แล้วคุณเก็บ entry เอาไว้ — และเสียการสอดคล้อง ซึ่งบางครั้งเป็นสิ่งที่ผู้เรียกต้องการจริง ๆ สำหรับไฟล์ภายใน

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;

สังเกตสิ่งที่การฉีด marker ไม่ทำ มันเพิ่มเมตาดาต้าและการระบุ และไม่สามารถจัดหาเนื้อหาหน้าได้ หน้าต้นทางที่ไม่พก strip image จะยังคงตก pvriPageImageMismatch หลังการฉีด เพราะภาพที่ขาดหายไปไม่เคยเป็นปัญหาเมตาดาต้าตั้งแต่แรก

จุดที่ PDF/R สอดสนิทในไปป์ไลน์จับภาพ

ใช้มันเมื่อผลงานส่งมอบคือตัวสแกนเองและความซื่อสัตย์คือสัญญาทั้งหมด — การถ่ายภาพเพื่อหลักฐาน การจับเช็คและการชำระเงิน คลังแบบวิศวกรรมจากเครื่องสแกนขนาดใหญ่ ใช้ PDF/A แทนทันทีที่เอกสารต้องการข้อความที่ค้นหาได้ การติดแท็ก ไฟล์แนบฝัง หรือสิ่งอื่นใดที่โปรไฟล์ raster ปลดออก

การจัดเรียงที่พบได้และใช้งานได้คือผลิตทั้งสองแบบ ต้นฉบับ PDF/R ที่ไม่เปลี่ยนแปลง และสิ่งที่ได้จาก PDF/A พร้อมเลเยอร์ OCR สำหรับการค้นคืน ตัวตรวจสอบเป็นอิสระจากกัน ชุดงานเดียวกันจึงตรวจแต่ละอาร์ทิแฟกต์กับโปรไฟล์ที่มันอ้างจริง ๆ ได้ สำหรับฝั่งเก็บถาวรของคู่นั้น ดูบันทึกของ การปฏิบัติตามมาตรฐานเก็บถาวร PDF/A และ PDF/A preflight validation และสำหรับเอาต์พุตที่มุ่งเน้นการพิมพ์ คู่มือของ การตรวจสอบเอกสาร PDF/X ที่พร้อมพิมพ์

PDFium Component นำเอนจิน PDFium มาสู่ Delphi, C++Builder และ Lazarus ด้วย API VCL และตัวตรวจสอบการปฏิบัติตามมาตรฐานสำหรับ PDF/A, PDF/X, PDF/E, PDF/UA และ PDF/R — หน้าผลิตภัณฑ์ PDFium Component จัดประเภทมาตรฐานและเวอร์ชัน IDE ที่รองรับ