PDFiumPas, lớp bọc Delphi và C++Builder quanh engine PDFium của Google, lưu một tài liệu ở đúng phiên bản PDF từ 1.3 đến 1.7 thông qua tham số PdfVersion của phương thức TPdf.SaveAs. Lệnh gọi FPDF_SaveWithVersion riêng của PDFium chỉ viết lại header %PDF-M.m, mà không kiểm tra liệu nội dung thực tế của tài liệu có hợp lệ ở phiên bản đó hay không. PDFiumPas lấp khoảng trống đó bằng một lượt kiểm tra tuân thủ sau khi lưu, duyệt qua chuỗi bản sửa cross-reference đang hoạt động và kiểm tra các khai báo Adobe Extension Level trước khi file rời khỏi phương thức
Sự phân biệt đó quan trọng nhất trong sản xuất in ấn, nơi một hồ sơ PDF/X nêu tên một phiên bản PDF chính xác và một công cụ preflight hay RIP từ chối bất cứ thứ gì âm thầm bất đồng với header riêng của nó, một kịch bản được nói đến từ phía đầu ra trong xác thực tài liệu PDF/X sẵn sàng in với PDFiumPas. SaveAs phơi bày đích như enum TPdfVersion, pv13 đến pv17 cùng với các giá trị pv10 đến pv12 cũ hơn, cộng thêm một TSaveOption độc lập cho các lượt ghi lại gia tăng hoặc đầy đủ. Truyền PdfVersion và PDFiumPas làm hai việc trong một lệnh gọi: nó yêu cầu PDFium đóng dấu header được yêu cầu, sau đó đọc lại các byte vừa ghi và từ chối trả về một file mà nội dung đang hoạt động của nó không thể tồn tại hợp pháp ở phiên bản đó
var
Pdf: TPdf;
begin
Pdf:= TPdf.Create(nil);
try
Pdf.FileName:= 'source.pdf';
Pdf.Active:= True;
try
Pdf.SaveAs('press-ready.pdf', saNoIncremental, pv17);
except
on E: Exception do
// E.Message names the offending feature and the version or
// extension level it actually needs, for example:
// "RichMedia annotations and RichMediaExecute actions require
// /Extensions /ADBE with /BaseVersion /1.7 and /ExtensionLevel 3
// or newer."
raise;
end;
finally
Pdf.Free;
end;
end;
Vì sao định nghĩa đối tượng cuối cùng trong file lại là thứ sai để tin tưởng?
Đối tượng vật lý cuối cùng với một số cho trước trong một file PDF không nhất thiết là đối tượng mà một trình đọc tuân thủ chuẩn sẽ giải quyết cho số đó hôm nay. Một PDF đã trải qua nhiều lượt cập nhật gia tăng không có một đồ thị đối tượng, nó có một lịch sử các đồ thị xếp lớp bên trong một file duy nhất, và mỗi chu kỳ nối thêm có thể giải phóng một đối tượng, định nghĩa lại nó dưới một số thế hệ mới, hoặc để lại thân vật lý cũ của nó nằm giữa hai dấu endobj mà không còn mục cross-reference nào trỏ vào nó nữa
PDFiumPas từng gặp đúng chế độ lỗi đó trước khi nó theo dõi các bản sửa xref một cách tường minh: một chú thích Redact bị mồ côi bởi một lượt viết lại đối tượng trang sau đó, hay một từ điển /MarkInfo vẫn hiện diện về mặt vật lý mà không có mục xref nào trỏ vào nó, vẫn có thể xuất hiện trong một lượt quét byte và vẫn có thể kích hoạt một kiểm tra tính năng theo phiên bản không còn áp dụng cho tài liệu mà một trình đọc thực sự sẽ mở. Hướng lỗi là từ chối sai, không phải chấp nhận sai: một file đã thực sự vượt qua một tính năng trong bản sửa hiện tại của nó vẫn có thể bị chặn lưu ở một phiên bản thấp hơn vì nội dung mà không ai còn có thể chạm tới nữa
PDFiumPas xác định đối tượng định nghĩa nào thực sự đang hoạt động như thế nào?
PDFiumPas giải quyết tập hợp đối tượng đang hoạt động theo đúng cách một trình đọc tuân thủ chuẩn làm, bằng cách duyệt chuỗi cross-reference thay vì quét byte tìm header đối tượng. Bộ giải quyết bắt đầu tại offset startxref cuối cùng trong file và theo mỗi liên kết /Prev ngược lại qua các bản sửa cũ hơn, phân tích các bảng cross-reference cổ điển, các luồng liên kết /XRefStm lai, và các luồng cross-reference thuần túy dọc đường. Lượt duyệt chạy từ mới-nhất-đến-cũ-nhất và chốt mỗi số đối tượng lần đầu tiên nó được thấy, nên một mục tự do trong một bản sửa sau đúng đắn che khuất một thân đối tượng được viết trong một bản sửa trước, và một lần định nghĩa lại dưới một offset hay thế hệ mới luôn thắng thứ nó thay thế
Các thành viên object-stream nhận được một kiểm tra bổ sung mà một lượt tra cứu offset thuần túy không thể tự cung cấp, một cơ chế được nói đến sâu hơn trong xác thực luồng object và cross-reference với PDFiumPas. Một đối tượng nén được khôi phục từ một /ObjStm phải có luồng cha của nó được xác nhận đang hoạt động trong cùng lượt duyệt, và chỉ số của nó phải khớp với vị trí riêng của thành viên đó bên trong header của luồng đó trước khi PDFiumPas coi nó là nội dung sống. ISO 32000-1 mục 7.5.8.4 thậm chí còn mô tả một trường hợp tham chiếu lai nơi một bảng tương thích cổ điển đánh dấu một đối tượng là tự do trong khi mục /XRefStm của trailer đồng thời định nghĩa chính đối tượng đó như một thành viên nén ở nơi khác; PDFiumPas gộp luồng xref bổ sung vào cùng bản sửa trước khi các mục cổ điển được áp dụng, nên định nghĩa nén thắng theo đúng ý định của đặc tả
Adobe Extension Level: cổng phía trên số phiên bản
Một header %PDF-1.7 chỉ hứa hẹn tập tính năng mà ISO 32000-1 chuẩn hóa vào năm 2008, trong khi một số khả năng mà các nhà sản xuất PDF ngày nay dựa vào lại phát hành sau đó như các bổ sung chỉ dành riêng cho Adobe xếp chồng lên trên cùng số phiên bản đó. Adobe đăng ký mỗi bổ sung như một cặp BaseVersion và ExtensionLevel được ghi lại trong từ điển /Extensions của document catalog dưới một tiền tố nhà phát triển, ADBE cho các phần mở rộng riêng của Adobe, để một trình đọc có thể phân biệt một file PDF 1.7 thuần túy với một file cũng triển khai một mức mở rộng có đánh số. Lưu ở pv17 mà không có khai báo đó tự nó không phải một lỗi; nó chỉ trở thành một lỗi ngay khi nội dung đang hoạt động thực sự phụ thuộc vào một tính năng mà khai báo đó vốn được cho là bao phủ
Những tính năng phiên bản cao nào kích hoạt cổng phiên bản tường minh?
PDFiumPas kiểm tra một danh sách cụ thể, dựa trên spec thay vì đoán mò từ mỗi số phiên bản. Các từ điển ảnh mang một mục /SMaskInData tường minh hay một giá trị /BitsPerComponent bằng 16 đều yêu cầu PDF 1.5, với trường hợp mười sáu-bit tuân theo trực tiếp các quy tắc thành phần ảnh của PDF Reference 1.5 mục 4.8. Các chú thích RichMedia và các hành động RichMediaExecute yêu cầu /BaseVersion /1.7 với /ExtensionLevel 3 trở lên. Các luồng 3D PRC, được nhận diện bằng một từ điển mang cả /Type /3D lẫn /Subtype /PRC, yêu cầu cùng base version nhưng chỉ /ExtensionLevel 1. Các từ điển Geospatial Measure và các chú thích Projection yêu cầu /BaseVersion /1.7 với /ExtensionLevel 3, cùng bổ sung Adobe mà RichMedia phụ thuộc vào
Kiểm tra geospatial mang theo một chi tiết đọc spec đáng biết nếu bạn từng xây dựng logic cổng-theo-phiên-bản của riêng mình trên nền PDFiumPas. ISO 32000-1 Bảng 254 đánh dấu mục /Type của từ điển Measure là tùy chọn, chỉ ghi chú rằng "nếu có mặt, phải là Measure," trong khi Bảng 311 làm cho /Type bắt buộc đối với từ điển luồng 3D nơi nội dung PRC sống. Đầu ra GeoPDF thực tế từ các công cụ bản đồ thường xuyên bỏ qua /Type trên từ điển Measure và chỉ viết /Subtype /GEO, nên bộ dò geospatial của PDFiumPas khớp chỉ trên /Subtype thay vì yêu cầu cả hai khóa theo cách bộ dò PRC 3D của nó có thể làm an toàn. Yêu cầu /Type trên cả hai từ điển sẽ để nội dung GeoPDF tuân thủ chuẩn lọt qua cổng mà không bị phát hiện, đáp xuống một file PDF 1.7 thuần túy không có khai báo mức mở rộng nào hậu thuẫn nó
PDFiumPas có tự động hạ cấp các tính năng không được hỗ trợ không?
Không như một khả năng tổng quát, và giả định ngược lại là sai lầm cần tránh ở đây. SaveAs dẫn phiên bản đích qua một routine nội bộ, ValidatePdfVersionCompliance, và khi routine đó tìm thấy một tính năng mà phiên bản đích hay khai báo mức mở rộng của nó không thể hỗ trợ, SaveAs ném ra một ngoại lệ mang theo văn bản lỗi của routine đó thay vì ghi file; caller nhận lại một lý do chính xác, nêu tên tính năng, không bao giờ là một tài liệu bị viết lại âm thầm. Nơi duy nhất PDFiumPas tự động viết lại nội dung là một đích PDF 1.3, nơi nó loại bỏ các mặc định trong suốt trung tính về ngữ nghĩa /BM /Normal, /CA 1, và /ca 1 mà PDFium luôn viết vào các từ điển ExtGState bất kể phiên bản đích, vì những giá trị cụ thể đó không mang ý nghĩa thị giác nào và PDF 1.3 hoàn toàn có trước các khóa đó
// PDF 1.3 targets rewrite the saved bytes to strip transparency
// defaults PDFium always emits, so incremental mode cannot apply
Pdf.SaveAs('legacy-archive.pdf', saIncremental, pv13);
// raises: PDF 1.3 normalization is incompatible with incremental
// save mode
Tính trong suốt và soft mask ảnh không-mặc-định thực sự vẫn thất bại hoàn toàn ở một đích PDF 1.3, vì việc loại bỏ chúng sẽ thay đổi cách trang thực sự trông như thế nào, và PDFiumPas sẽ không tự ý quyết định điều đó thay bạn. Có hai giới hạn liên quan đáng lên kế hoạch trước khi một phiên bản chính xác đi vào một pipeline hàng loạt. Đầu ra phiên bản tường minh không bao giờ mang một từ điển /Encrypt; lượt lưu thất bại ngay lập tức nếu nguồn được bảo vệ, điều này tình cờ khớp với các hồ sơ PDF/X và PDF/A vốn cấm mã hóa dù sao đi nữa, nhưng nó có nghĩa là việc giải mã là một bước riêng biệt trong luồng công việc của bạn thay vì thứ mà SaveAs làm cho bạn. PDFiumPas cũng không có phương thức công khai nào để viết một khai báo /Extensions /ADBE lên một catalog, nên một file nguồn chứa RichMedia, PRC 3D, hay nội dung geospatial nhưng thiếu khai báo đó sẽ không vượt qua cổng bất kể bạn yêu cầu PdfVersion nào; khai báo đó phải đã tồn tại trong nguồn, thường vì công cụ tạo dựng đã viết nó, hoặc tính năng đó phải được lấy ra trước khi lưu. Thuộc tính TPdf.PdfVersion chỉ đọc đáng kiểm tra trước cả khi một lượt lưu phiên bản chính xác được thử, vì nó giải quyết cùng phiên bản hiệu lực nhận biết catalog, header hoặc ghi đè /Version, bất cứ cái nào hiện hành, mà chính bộ xác thực lúc lưu dựa vào
Pdf.FileName:= 'incoming.pdf';
Pdf.Active:= True;
// PdfVersion resolves the same catalog-aware effective version the
// save-time validator uses, so a mismatch here is worth investigating
// before spending a full SaveAs attempt on it
LogSourceVersion('incoming.pdf', Pdf.PdfVersion);
Hãy coi một ngoại lệ SaveAs trên một đích phiên bản chính xác như một báo cáo preflight thay vì một bug: thông điệp nêu tên chính xác điều khoản mà tài liệu nguồn đang vi phạm, chính xác là thông tin mà một xưởng in hay pipeline lưu trữ cần trước khi một file đi xa hơn. Đường lưu phiên bản tường minh, bộ giải quyết bản sửa xref đang hoạt động, và các kiểm tra Adobe Extension Level được mô tả ở đây đi kèm sẵn trong PDFiumPas Component tiêu chuẩn dành cho Delphi và C++Builder; trang sản phẩm mang đầy đủ tài liệu tham khảo TPdf.SaveAs cùng với phần còn lại của API tuân thủ chuẩn và biểu mẫu