PDF/E-1 là archival profile cho tài liệu kỹ thuật, và PDFlibPas triển khai nó như một author mode bạn bật bằng SetPDFEMode cộng với một bounded preflight đọc content stream từng operator một. Profile này không phải PDF/A đổi nhãn: nó có identification namespace riêng, yêu cầu lifecycle metadata riêng, và một quy tắc khiến validate content ngặt hơn bất kỳ archival profile nào bạn từng gặp
Sản phẩm bàn giao kỹ thuật là lý do profile này tồn tại. Một bộ bản vẽ phải đọc được và chứng minh được là không bị thay đổi sau hai mươi năm nữa, với lịch sử revision còn nguyên, và với màu sắc mang cùng một ý nghĩa trên plotter ở tòa nhà bên cạnh. Những yêu cầu đó tạo ra một specification mà phần lớn đòi hỏi nằm ngoài page content, trong metadata và color management — cũng chính là chỗ một PDF writer chung chung hay làm sai
Identification riêng, không phải biến thể của PDF/A
Điều cần nắm đầu tiên là identification PDF/E-1 không thể sinh ra bằng cách áp mẫu PDF/A hay PDF/X. Nó dùng một XMP namespace riêng, http://www.aim.org/pdfe/ns/id/, và version value phải xuất hiện ở hai nơi: như một document information entry và như XMP property có namespace đi kèm. Chỉ emit XMP property, hoặc chỉ emit information entry, sẽ cho ra file mang đúng ý đồ nhưng rớt validation
Output intent cũng có hình dạng dứt khoát không kém. PDF/E-1 đòi một embedded ICC profile mang subtype identifier ISO_PDFE1, và profile phải có số component khớp với họ màu device mà document thực sự dùng. Mệnh đề cuối là chỗ các bản triển khai lặng lẽ làm sai, vì nó có nghĩa là intent không thể chọn trước rồi bỏ quên
Vì sao device color cần một vòng quét toàn document?
Vì color space trốn trong các resource dictionary mà một vòng scan cấp page không bao giờ với tới. PDF/E-1 coi DeviceRGB và DeviceCMYK là hai họ loại trừ nhau ở cấp document, nên validate profile đồng nghĩa với việc biết mọi device color space mà bất cứ thứ gì trong file dùng. Một form XObject có resource riêng. Pattern cũng vậy, image cũng vậy. Một tiling pattern nằm trong form XObject nằm trong page là sâu ba tầng, và một validator chỉ check resource cấp đầu của page sẽ cho qua một document dùng cả hai họ
Vì vậy vòng quét register color space trong khi đi qua page, form, image và pattern như một lần duyệt duy nhất, rồi mới quyết định document có nhất quán không và output intent có khớp không. Cùng lý lẽ đó chi phối kiến trúc preflight nói chung: duyệt một phần cho ra false pass, và một false pass trên một phép kiểm tra conformance còn tệ hơn không check, vì nó được ghi lại như bằng chứng
var
Lib: TPDFlib;
Diag: WideString;
begin
Lib := TPDFlib.Create(nil);
try
Lib.LoadFromFile('assembly-drawings.pdf');
if Lib.SetPDFEMode(1) = 0 then
raise Exception.Create('PDF/E author mode was refused');
// Author mode giữ lifecycle metadata luôn khớp tại mọi lần save.
// Hỏi trước khi save xem document có qua nổi cổng của chính nó không
if not Lib.PDFEReadyForSave then
begin
Diag := Lib.GetPDFEDiagnostics;
Writeln('PDF/E blockers: ', Diag);
Exit;
end;
Lib.SaveToFile('assembly-drawings-pdfe.pdf');
finally
Lib.Free;
end;
end;
Lifecycle metadata là nghĩa vụ tính theo từng lần save
PDF/E-1 đòi nhiều hơn một document identifier. Bộ tối thiểu gồm media management document identifier, một version identifier, một rendition class, creation time, modification time, metadata time và một title. Đó là một bộ từ vựng theo dõi revision, và nó tồn tại vì một sản phẩm bàn giao kỹ thuật được kỳ vọng tái phát hành chứ không viết một lần rồi thôi
Hệ quả với bản triển khai là các field này không thể set lúc tạo document. Nếu modification time được ghi khi bạn bật mode mà document sau đó còn bị sửa, XMP snapshot và trạng thái thật của document đã trôi dạt, và validator so sánh chúng sẽ báo một sự không nhất quán mà chẳng ai chủ ý gây ra. Author mode vì thế đồng bộ các field ngay trước mỗi lần save, để metadata mô tả những byte sắp được ghi chứ không phải những byte tồn tại lúc mode vừa được bật
Đây là nguyên tắc chung cho conformance metadata và đáng nói riêng khỏi PDF/E: metadata dẫn xuất nằm trên save path, không nằm trên edit path. Bất kỳ field nào được tính từ trạng thái document đều phải tính lại đúng khoảnh khắc trạng thái bị đóng băng, nếu không nó là một cache không có invalidation
Quy tắc khiến validate content trở nên ngặt
PDF/E-1 không cho phép các operator của compatibility section hấp thụ content lạ. Trong PDF thường, BX và EX bao quanh một vùng mà consumer phải bỏ qua những operator mình không nhận ra — đó là lối thoát giúp producer emit các construct mới hơn mà không làm gãy reader cũ. Dưới PDF/E-1 lối thoát đó bị đóng, nên bất kỳ operator nào preflight không nhận ra đều được báo vô điều kiện, kể cả khi nó nằm trong compatibility section
Tác động lên validator là đáng kể. Nó không thể bỏ qua những vùng mình không hiểu, tức là operand parser phải parse thật sự mọi operator trong mọi content stream. Và đó là chỗ các giới hạn vào cuộc. Lần duyệt bị chặn ở 128 tầng nesting, một triệu object và 64 MiB content, và những con số đó không phải tinh chỉnh hiệu năng. Một file độc hại hay đơn giản là hỏng có thể trình ra một object graph có cycle hoặc độ sâu nesting đủ biến một validator đệ quy thành stack overflow, và các giới hạn là thứ giữ cho một vòng validate không trở thành denial-of-service vector. Tư thế phòng thủ tương tự được mô tả trong parse PDF không đáng tin một cách an toàn
// Validate standalone một file không phải do bạn sinh ra, không cần
// load nó vào một document instance
var
Issues: TStringList;
Stream: TFileStream;
I: Integer;
begin
Issues := TStringList.Create;
Stream := TFileStream.Create('incoming.pdf', fmOpenRead or fmShareDenyWrite);
try
if CheckCompliancePDFE(Stream, '', 0, Issues) = 0 then
for I := 0 to Issues.Count - 1 do
Writeln('PDF/E: ', Issues[I]);
finally
Stream.Free;
Issues.Free;
end;
end;
Cổng save sửa được gì và từ chối gì
Cổng chia công việc thành hai giai đoạn, và chính sự chia đó là một ý tưởng thiết kế dùng được. Trước tiên nó normalize những thứ sửa an toàn được: print flag của annotation, các no-zoom và no-rotate flag trên text annotation, và appearance-generation flag trên form dictionary. Đây là các setting chỉ có đúng một giá trị dưới profile và không mang thông tin gì, nên sửa lặng lẽ là đúng, còn từ chối vì chúng thì quá sách vở
Sau đó nó check các ràng buộc không thể sửa mà không đổi ý nghĩa document: version, identification, encryption, output intent, tính nhất quán device color và sự hiện diện của dynamic form content. Document rớt bất kỳ mục nào sẽ bị từ chối, vì tự bịa một output intent hay chọn giúp một họ màu sẽ cho ra file qua được validation nhưng diễn giải sai content
Đọc diagnostics lại qua GetPDFEDiagnostics trước khi save biến lời từ chối đó thành một danh sách hành động được thay vì một operation thất bại. Trong batch pipeline, gọi nó cho từng document, log blocker theo từng file, và chuyển các case rớt vào một queue cho người xem. Hữu ích hơn hẳn một lần save raise exception, vì blocker thường cụm lại: bốn mươi document rớt vì cùng thiếu một output intent là một cái fix, không phải bốn mươi
Chọn giữa các archival profile
PDF/E-1 là đích đúng khi sản phẩm bàn giao là tài liệu kỹ thuật có vòng đời revision, và cụ thể là khi tính nhất quán device color có tầm trọng vì đầu ra đi tới plotter và máy in khổ lớn. PDF/A là đích đúng khi mục tiêu là khả năng đọc lâu dài của document nói chung, và đây là profile có lượng validator hỗ trợ rộng nhất. Hai bên không thay thế được nhau, và một document có thể đạt cái này mà rớt cái kia
Nếu bạn đang chọn, hãy bắt đầu từ việc ai validate file ở đầu xa. Công cụ validate PDF/A có ở khắp nơi, và phần preflight tương ứng trong PDFlibPas được mô tả trong preflight PDF/A và PDF/UA. Validate PDF/E chuyên biệt hơn và thường là yêu cầu ghi trong hợp đồng chứ không phải mặc định. Khi một archive có sẵn phải được đưa lên một profile mà nó chưa từng được viết cho, metadata repair path trong convert sang PDF/A kèm metadata repair là pattern cần theo, và hình dạng ở đây y hệt: xác định, sửa những gì an toàn, từ chối phần còn lại kèm danh sách
Author mode, bounded content preflight và standalone compliance check đều đi kèm PDFlibPas Delphi PDF library, nên một document có thể được sản xuất dưới profile rồi được kiểm chứng độc lập sau đó qua một code path riêng — bố cục duy nhất đáng tin cho một lời tuyên bố conformance