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

ขีดจำกัดการทำงานของ PDF/A และการตรวจสอบการเข้ารหัสแบบอักษร

PDFium Component ตรวจสอบขีดจำกัดการทำงานของ ISO 19005-1 Annex C — name token 127 ไบต์, อิลิเมนต์อาร์เรย์ 8191, entry dictionary 4095 และการซ้อนคอนเทนเนอร์ 28 ระดับ — และรายงานแบบอักษร TrueType symbolic ที่พก entry /Encoding การตรวจสอบทั้งสองรันบนเส้นทาง byte-scan ทำให้แอปพลิเคชัน Delphi หรือ Lazarus ได้คำตัดสินโดยไม่ต้องโหลด DLL ของ PDFium เลย

นี่คือความล้มเหลวที่ทำให้คนสับสนมากที่สุด เพราะเอกสารดูปกติ มันเรนเดอร์ได้ พิมพ์ได้ แบบอักษรทุกตัวฝังอยู่ output intent อยู่ที่นั่น แล้วตัวตรวจสอบปฏิเสธมันเพราะ dictionary ที่มี 4096 entry และไม่มีอะไรในเอกสารที่มองเห็นอธิบายเหตุผล

ขีดจำกัด Annex C ปกป้องอะไรจริง ๆ

การทำงานร่วมกันได้กับการทำงานที่เก่ากว่าตัวกำเนิดของคุณ Annex C สืบทอดขีดจำกัดการทำงานของ PDF Reference เข้าไปในทุก part ของ PDF/A และตัวเลขไม่ใช่ของตกแต่ง — พวกมันบรรยายสิ่งที่ตัวอ่านที่สอดคล้องถูกกำหนดให้รับมือเป็นประวัติศาสตร์ ไฟล์ที่เกินพวกมันอาจเปิดได้สมบูรณ์ในตัวอ่านสมัยใหม่และล้มเหลวในตัวอ่านเก็บถาวรที่ระบบเอกสารกำหนดมาตรฐานไว้เมื่อสิบห้าปีก่อน ซึ่งเป็นสถานการณ์ที่ PDF/A มีอยู่เพื่อป้องกันพอดี

สี่ขีดจำกัดเป็น inclusive name token ที่ยาว 127 ไบต์พอดีผ่านการตรวจสอบ 128 ไม่ผ่าน อาร์เรย์ที่มี 8191 อิลิเมนต์พอดีผ่าน 8192 ไม่ผ่าน PDFium Component ตรึงทั้งสองด้านของทุกขอบเขตในชุดทดสอบของมันด้วยเหตุผลนั้น เพราะ off-by-one ในการตรวจสอบขีดจำกัดผลิตตัวตรวจสอบที่เลวร้ายที่สุดประเภทหนึ่ง คือตัวที่ปฏิเสธไฟล์ที่สอดคล้องแล้วยังถูกเชื่อถืออยู่ดี

uses FPdfPdfa;

var
  Src: TFileStream;
  Res: TPdfAValidationResult;
begin
  Src := TFileStream.Create('archive.pdf', fmOpenRead or fmShareDenyWrite);
  try
    Res := ValidatePdfACompliance(Src);
    if pvaiArrayOverLimit in Res.Issues then
      Memo1.Lines.Add('An array carries more than 8191 elements');
    if pvaiDictOverLimit in Res.Issues then
      Memo1.Lines.Add('A dictionary carries more than 4095 entries');
    if pvaiNestingOverLimit in Res.Issues then
      Memo1.Lines.Add('Containers nest deeper than 28 levels');
    if pvaiNameOverLimit in Res.Issues then
      Memo1.Lines.Add('A name token is longer than 127 bytes');
  finally
    Src.Free;
  end;
end;

ตัวกำเนิดใดบ้างที่กระทบขีดจำกัดเหล่านี้จริง

ตัวที่สร้างโครงสร้างแบบโปรแกรม ซึ่งเป็นเอาต์พุต line-of-business ส่วนใหญ่ ฟอร์มที่มีฟิลด์หลายพันผลิตอาร์เรย์ /Annots หรืออาร์เรย์ AcroForm /Fields ที่โตเกิน 8191 หน้าที่ dictionary resource สะสมหนึ่ง entry ต่อรูปหรืออินสแตนซ์แบบอักษรที่สร้างขึ้นข้าม 4095 structure tree ที่สร้างลึก — เอกสาร tagged ที่สร้างด้วย recursion เหนือโมเดลข้อมูลที่ซ้อนกัน — เดินผ่าน 28 ระดับโดยไม่มีใครสังเกต เพราะไม่มีใคนดูความลึกการซ้อน

ชื่อยาวมาจากนิสัยที่ต่างกัน คือการเข้ารหัสข้อมูลเข้าไปใน name token ชื่อ colorant ที่สร้างจากตัวระบุลูกค้า optional-content group ที่ตั้งชื่อตามเส้นทางไฟล์เต็ม ฟิลด์ฟอร์มที่ชื่อเต็มของมันต่อลำดับชั้นหกระดับเข้าด้วยกัน ชื่อสร้างได้ถูกและทำให้ยาวได้ง่าย และ 127 ไบต์หายไปเร็วกว่าที่คุณคาดไว้เมื่อป้ายที่เข้ารหัส UTF-8 เกี่ยวข้อง

การแก้ไขเป็นเชิงโครงสร้างในทุกกรณี แบ่งอาร์เรย์ แบ่ง dictionary ทำให้การซ้อนแบน ย่อชื่อให้สั้นลง — คำแนะนำ preflight สำหรับแต่ละปัญหาระบุขีดจำกัดที่เป็นรูปธรรมแทนที่จะบอกว่าไฟล์ไม่ถูกต้อง การฉีด marker ช่วยไม่ได้ที่นี่ สิ่งเหล่านี้ไม่ใช่การอ้างเมตาดาต้า มันคือรูปร่างของกราฟออบเจกต์

ทำไมแบบอักษร TrueType symbolic จึงต้องไม่พก /Encoding

เพราะ ISO 19005-1 §6.3.7 ยอมรับเพียง cmap ในตัวของแบบอักษรสำหรับแบบอักษร TrueType symbolic และ entry /Encoding จะขัดแย้งกับมัน แบบอักษร symbolic แมปรหัสไปยัง glyph ตามเงื่อนไขของตัวเอง — นั่นคือสิ่งที่ symbolic หมายถึง เพิ่มตาราง encoding แล้วตอนนี้มีคำตอบสองคำตอบสำหรับคำถาม "glyph ใดที่ไบต์ 0x41 เลือก" โดยไม่มีกฎในไฟล์บอกว่าอันไหนชนะ ตัวอ่านต่างกันคลี่คลายมันต่างกัน และเอกสารที่เรนเดอร์เป็นข้อความในตัวอ่านหนึ่งเรนเดอร์เป็น dingbat ในอีกตัว

PDFium Component อ่านสถานะ symbolic จาก /FontDescriptor ไม่ว่า descriptor จะถูกเขียน inline ใน font dictionary หรืออ้าง indirect แบบอักษร TrueType ที่ไม่ใช่ symbolic ยังคง /WinAnsiEncoding หรือ /MacRomanEncoding ที่จำเป็นของมันโดยไม่ถูกตั้งสถานะ เพราะสำหรับแบบอักษรที่ไม่ใช่ symbolic encoding คือสิ่งที่มาตรฐานถามหาพอดี การตรวจสอบทำงานที่ความขัดแย้ง ไม่ใช่ที่การมีอยู่ของ encoding

if pvaiSymbolicTrueTypeEncoding in Res.Issues then
  Memo1.Lines.Add(
    'A symbolic TrueType font carries /Encoding; PDF/A admits only its ' +
    'built-in cmap (ISO 19005-1 6.3.7)');

แหล่งที่มาเชิงปฏิบัติของข้อบกพร่องนี้คือ font subsetting ที่ทำโดยตัวกำเนิดที่ปฏิบัติต่อแบบอักษร TrueType ทุกตัวเหมือนกัน Symbol, Wingdings, แบบอักษรบาร์โค้ด และแบบอักษรไอคอนเป็นพาหะตามปกติ — ซึ่งเป็นแบบอักษรที่เอกสารธุรกิจใช้สำหรับกล่องเช็ค โลโก้ และบาร์โค้ดพอดี และเป็นแบบอักษรที่ไม่มีใครตรวจสอบใหม่เมื่อเอกสารตก validation เรื่อง "แบบอักษร"

ปัญหาเหล่านี้เข้าสู่รายงาน preflight อย่างไร

ขีดจำกัดคอนเทนเนอร์ทั้งสี่จัดประเภทใต้ structure ปัญหา encoding ของ TrueType symbolic จัดประเภทใต้ content การแบ่งนั้นสำคัญเมื่อรายงานไปยังคนสองคนที่ต่างกัน ผลการตรวจ structure มักเป็นของใครก็ตามที่เขียนตัวกำเนิด และผลการตรวจ content มักเป็นของใครก็ตามที่จัดหาสินทรัพย์

ปัญหาแต่ละอันพกคำแนะนำที่ระบุวิธีแก้ในเงื่อนไขที่เป็นรูปธรรม — ย่อ name token ให้เหลือ 127 ไบต์หรือน้อยกว่า แบ่งอาร์เรย์เพื่อให้ไม่มีอันใดพกเกิน 8191 อิลิเมนต์ เอา /Encoding ออกจากแบบอักษร TrueType symbolic รายงานที่บอกว่า "ไม่สอดคล้อง PDF/A" เริ่มการสืบสวน รายงานที่บอกว่าขีดจำกัดใดเกินและด้วยอะไรยุติมัน

การตรวจสอบโดยไม่มี DLL และทำไมเรื่องนี้จึงสำคัญที่นี่

การตรวจสอบทั้งหมดข้างต้นรันกับไบต์ของไฟล์ จึงทำงานในบริการที่ไม่มี binary PDFium ปรับใช้ ในขั้นตอนบิลด์ หรือบนเครื่องที่การโหลด DLL พื้นเมืองเป็นปัญหานโยบาย นั่นคือเส้นการออกแบบที่ตั้งใจใน PDFium Component การตรวจสอบที่ตอบได้จากโครงสร้างถูกตอบจากโครงสร้าง และ DLL สงวนไว้สำหรับสิ่งที่ต้องการเอนจินเรนเดอร์จริง ๆ

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

PDFium Component หุ้มเอนจิน PDFium สำหรับ Delphi, C++Builder และ Lazarus ด้วย API VCL ระดับสูงและชุดตัวตรวจสอบการปฏิบัติตามมาตรฐานที่รันได้ทั้งมีและไม่มี DLL — ดู หน้าผลิตภัณฑ์ PDFium Component สำหรับมาตรฐานและแพลตฟอร์มที่รองรับ