PDFium Component xác thực các giới hạn hiện thực ISO 19005-1 Annex C — token tên 127 byte, 8191 phần tử mảng, 4095 mục dictionary và 28 cấp lồng container — và báo cáo một font TrueType symbolic mang một mục /Encoding. Cả hai phép kiểm tra chạy trên đường quét byte, nên một ứng dụng Delphi hoặc Lazarus nhận được phán quyết mà không cần tải DLL PDFium gì cả
Đây là những thất bại khiến người ta bối rối nhất, vì tài liệu trông ổn. Nó render được, in được, mọi font đã nhúng, output intent hiện diện. Rồi một trình xác thực từ chối nó vì một dictionary có 4096 mục, và không gì trong tài liệu khả kiến giải thích vì sao
Các giới hạn Annex C thực sự đang bảo vệ điều gì?
Tính tương tác với các hiện thực ra đời trước bộ sinh của bạn. Annex C mang các giới hạn hiện thực PDF Reference vào mọi part PDF/A, và các con số không tùy tiện — chúng mô tả cái mà một trình đọc tuân thủ về mặt lịch sử được yêu cầu xử lý. Một file vượt chúng có thể mở hoàn hảo trong một trình xem hiện đại và thất bại trong trình đọc lưu trữ mà một hệ thống hồ sơ chuẩn hóa trên mười lăm năm trước, đó chính xác là kịch bản PDF/A tồn tại để ngăn chặn
Bốn giới hạn là bao hàm. Một token tên đúng 127 byte đạt xác thực; 128 thì không. Một mảng với đúng 8191 phần tử đạt; 8192 thì không. PDFium Component chốt cả hai phía của mọi biên giới trong bộ kiểm thử của nó vì lý do đó, vì một lỗi off-by-one trong kiểm tra giới hạn tạo ra loại trình xác thực tệ nhất: cái từ chối file tuân thủ mà vẫn bị tin tưởng
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;
Những bộ sinh nào thực sự chạm các giới hạn này?
Những cái dựng cấu trúc theo chương trình, đó là hầu hết đầu ra line-of-business. Một biểu mẫu với vài nghìn trường tạo ra một mảng /Annots hoặc mảng /Fields của AcroForm vượt 8191. Một trang mà dictionary resource tích lũy một mục cho mỗi hình hoặc mỗi instance font vượt 4095. Cây cấu trúc sinh sâu — một tài liệu tagged được dựng bằng đệ quy trên một mô hình dữ liệu lồng nhau — đi qua 28 cấp mà không ai để ý, vì không ai nhìn vào độ sâu lồng
Tên dài đến từ một thói quen khác: mã hóa dữ liệu vào các token tên. Một tên colorant dựng từ một định danh khách hàng, một nhóm optional-content đặt tên theo một đường dẫn file đầy đủ, một trường biểu mẫu mà tên đầy đủ đủ điều kiện nối sáu cấp hệ thống phân cấp. Tên rẻ khi sinh và dễ làm dài, và 127 byte biến mất nhanh hơn bạn trông đợi một khi một nhãn mã hóa UTF-8 có liên quan
Cách sửa là cấu trúc trong mọi trường hợp. Tách mảng, tách dictionary, san phẳng độ lồng, rút ngắn tên — khuyến nghị preflight cho từng vấn đề nêu tên giới hạn cụ thể thay vì nói rằng file không hợp lệ. Marker injection không giúp gì được ở đây: đây không phải là tuyên bố siêu dữ liệu, chúng là hình thái của đồ thị object
Vì sao một font TrueType symbolic không được mang /Encoding
Vì ISO 19005-1 §6.3.7 chỉ chấp nhận cmap tích hợp sẵn của font cho các font TrueType symbolic, và một mục /Encoding sẽ mâu thuẫn với nó. Một font symbolic ánh xạ code sang glyph theo điều kiện của riêng nó — đó là điều symbolic nghĩa. Thêm một bảng mã hóa và giờ có hai câu trả lời cho câu hỏi "byte 0x41 chọn glyph nào", mà không có quy tắc nào trong file nói cái nào thắng. Các trình đọc khác nhau giải quyết khác nhau, và một tài liệu render thành văn bản trong trình xem này lại render thành dingbat trong trình xem khác
PDFium Component đọc cờ symbolic từ /FontDescriptor, bất kể descriptor được ghi inline trong font dictionary hay tham chiếu gián tiếp. Một font TrueType không symbolic giữ /WinAnsiEncoding hoặc /MacRomanEncoding bắt buộc của nó mà không bị gắn cờ, vì đối với các font không symbolic thì encoding chính xác là thứ chuẩn yêu cầu. Phép kiểm tra kích hoạt trên sự mâu thuẫn, không phải trên sự hiện diện của một 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)');
Nguồn thực tế của khiếm khuyết này là subsetting font do một nhà sản xuất xử lý mọi font TrueType theo cùng cách. Symbol, Wingdings, font barcode và font icon là các vật mang thường thấy — chính xác là các font mà một tài liệu doanh nghiệp dùng cho checkbox, logo và barcode, và chính xác là những cái không ai xem lại khi một tài liệu thất bại xác thực vì "font"
Các vấn đề đến trong một báo cáo preflight như thế nào
Bốn giới hạn container được phân loại dưới structure; vấn đề encoding TrueType symbolic được phân loại dưới content. Sự phân tách đó quan trọng khi một báo cáo đi tới hai người khác nhau: phát hiện structure thường thuộc về ai đã viết bộ sinh, còn phát hiện content thường thuộc về ai đã cung cấp asset
Mỗi vấn đề mang một khuyến nghị nêu phương thuốc bằng thuật ngữ cụ thể — rút ngắn token tên xuống 127 byte hoặc ít hơn, tách mảng để không mảng nào mang quá 8191 phần tử, gỡ /Encoding khỏi font TrueType symbolic. Một báo cáo nói "không tuân thủ PDF/A" khởi đầu một cuộc điều tra. Một báo cáo nói giới hạn nào bị vượt và bởi cái gì thì kết thúc một cuộc điều tra
Xác thực không cần DLL, và vì sao điều đó quan trọng ở đây
Tất cả các phép kiểm tra trên chạy với byte file, nên chúng hoạt động trong một dịch vụ không triển khai binary PDFium, trong một bước build, hoặc trên một máy nơi việc tải một DLL bản địa là một vấn đề chính sách. Đó là một đường thiết kế có chủ đích trong PDFium Component: các phép kiểm tra có thể trả lời từ cấu trúc thì được trả lời từ cấu trúc, còn DLL dành cho những cái thực sự cần một engine render
Về quy trình xung quanh — chạy xác thực trên một thư mục, sinh báo cáo, và quyết định làm gì với các phát hiện — hãy xem các bài viết về xác thực preflight PDF/A trong Delphi và CLI báo cáo preflight hàng loạt. Về lựa chọn profile lưu trữ nằm trên tất cả các phép kiểm tra này, các ghi chú về tuân thủ lưu trữ PDF/A trình bày nên nhắm part và cấp nào trước khi bạn bắt đầu sửa các phát hiện
PDFium Component bọc engine PDFium cho Delphi, C++Builder và Lazarus với một API VCL cấp cao và một bộ xác thực tuân thủ chạy có hoặc không có DLL — xem trang sản phẩm PDFium Component để biết các chuẩn và nền tảng được hỗ trợ