PDFiumPas, wrapper Delphi dan C++Builder di sekeliling mesin PDFium milik Google, menyimpan sebuah dokumen pada versi PDF eksak dari 1.3 hingga 1.7 lewat parameter PdfVersion milik metode TPdf.SaveAs. Pemanggilan FPDF_SaveWithVersion milik PDFium sendiri hanya menulis ulang header %PDF-M.m, tanpa memeriksa apakah konten sesungguhnya dokumen tersebut sah pada versi itu. PDFiumPas menutup celah itu dengan sebuah langkah pemeriksaan kesesuaian pasca-simpan yang menelusuri rantai revisi cross-reference aktif dan memeriksa deklarasi Adobe Extension Level sebelum file tersebut meninggalkan metode itu
Perbedaan itu paling penting dalam produksi cetak, di mana sebuah profil PDF/X menyebutkan versi PDF eksak dan sebuah tool preflight atau RIP menolak apa pun yang diam-diam tidak sepakat dengan headernya sendiri, sebuah skenario yang dibahas dari sisi output di memvalidasi dokumen PDF/X siap-cetak dengan PDFiumPas. SaveAs mengekspos target sebagai enum TPdfVersion, pv13 hingga pv17 berdampingan dengan nilai pv10 hingga pv12 yang lebih lama, plus sebuah TSaveOption independen untuk penulisan ulang inkremental atau penuh. Serahkan PdfVersion dan PDFiumPas melakukan dua pekerjaan dalam satu pemanggilan: ia meminta PDFium mencap header yang diminta, lalu membaca ulang byte yang baru ditulis dan menolak menyerahkan kembali sebuah file yang konten aktifnya tidak bisa secara sah ada pada versi itu
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;
Mengapa Definisi Objek Terakhir dalam File Adalah Hal yang Salah untuk Dipercaya?
Objek fisik terakhir dengan sebuah nomor tertentu dalam sebuah file PDF belum tentu objek yang akan diselesaikan sebuah reader yang sesuai standar untuk nomor itu hari ini. Sebuah PDF yang sudah melalui beberapa update inkremental tidak memiliki satu object graph, ia memiliki sebuah sejarah dari graph-graph itu berlapis di dalam satu file, dan setiap siklus append bisa membebaskan sebuah objek, mendefinisikan ulang di bawah sebuah nomor generasi baru, atau meninggalkan tubuh fisik lamanya duduk di antara dua marker endobj tanpa entri cross-reference apa pun yang lagi menunjuk padanya
PDFiumPas menabrak persis mode kegagalan itu sebelum ia melacak revisi xref secara eksplisit: sebuah anotasi Redact yang menjadi yatim piatu oleh sebuah penulisan-ulang objek-halaman belakangan, atau sebuah dictionary /MarkInfo yang ditinggalkan secara fisik hadir tanpa entri xref apa pun yang menunjuk padanya, masih bisa muncul dalam sebuah byte scan dan masih memicu sebuah pemeriksaan fitur-versi yang tidak lagi berlaku pada dokumen yang benar-benar akan dibuka sebuah reader. Arah kegagalannya adalah penolakan palsu, bukan penerimaan palsu: sebuah file yang benar-benar sudah melampaui sebuah fitur dalam revisi saat ininya masih bisa terhalang menyimpan pada versi yang lebih rendah karena konten yang tidak bisa dijangkau siapa pun lagi
Bagaimana PDFiumPas Menentukan Definisi Objek Mana yang Benar-Benar Aktif?
PDFiumPas menyelesaikan kumpulan objek aktif dengan cara yang sama seperti sebuah reader yang sesuai standar, dengan menelusuri rantai cross-reference alih-alih memindai byte untuk header objek. Resolver ini dimulai pada offset startxref terakhir dalam file dan mengikuti setiap link /Prev mundur lewat revisi yang lebih lama, mem-parse tabel cross-reference klasik, stream hybrid yang terhubung-/XRefStm, dan stream cross-reference murni sepanjang jalan. Penelusuran itu berjalan terbaru-ke-terlama dan menetapkan setiap nomor objek pada kali pertama ia terlihat, sehingga sebuah entri bebas dalam sebuah revisi belakangan dengan benar menaungi sebuah tubuh objek yang ditulis dalam sebuah revisi lebih awal, dan sebuah redefinisi di bawah sebuah offset atau generasi baru selalu menang atas apa yang digantikannya
Anggota object-stream mendapat sebuah pemeriksaan ekstra yang tidak bisa diberikan sebuah lookup offset polos dengan sendirinya, sebuah mekanisme yang dibahas lebih dalam di memvalidasi object dan cross-reference stream dengan PDFiumPas. Sebuah objek terkompresi yang dipulihkan dari sebuah /ObjStm harus memiliki stream induknya dikonfirmasi aktif dalam penelusuran yang sama, dan indeksnya harus sepakat dengan posisi anggota itu sendiri di dalam header stream tersebut sebelum PDFiumPas memperlakukannya sebagai konten hidup. ISO 32000-1 section 7.5.8.4 bahkan mendeskripsikan sebuah kasus referensi-hybrid di mana sebuah tabel kompatibilitas klasik menandai sebuah objek bebas sementara entri /XRefStm trailer secara bersamaan mendefinisikan objek yang sama itu sebagai sebuah anggota terkompresi di tempat lain; PDFiumPas menggabungkan stream xref suplemental ke dalam revisi yang sama sebelum entri klasik diterapkan, sehingga definisi terkompresi menang dengan cara yang dimaksudkan spesifikasi
Adobe Extension Level: Gerbang di Atas Nomor Versi
Sebuah header %PDF-1.7 hanya menjanjikan set fitur yang distandarkan ISO 32000-1 pada 2008, sementara beberapa kemampuan yang diandalkan produsen PDF hari ini dirilis belakangan sebagai suplemen khusus-Adobe yang dilapiskan di atas nomor versi yang sama itu. Adobe mendaftarkan setiap suplemen sebagai sepasang BaseVersion dan ExtensionLevel yang dicatat dalam dictionary /Extensions milik katalog dokumen di bawah sebuah prefix developer, ADBE untuk ekstensi Adobe sendiri, sehingga sebuah reader bisa membedakan sebuah file PDF 1.7 polos dari yang juga mengimplementasikan sebuah extension level bernomor. Menyimpan pada pv17 tanpa deklarasi itu bukan sebuah error dengan sendirinya; ia hanya menjadi satu begitu konten aktif memang bergantung pada sebuah fitur yang seharusnya dicakup deklarasi tersebut
Fitur Versi-Tinggi Mana yang Memicu Gerbang Versi-Eksplisit?
PDFiumPas memeriksa sebuah daftar spesifik yang digerakkan spesifikasi alih-alih menebak hanya dari nomor versi. Dictionary gambar yang membawa sebuah entri /SMaskInData eksplisit atau sebuah nilai /BitsPerComponent sebesar 16 keduanya membutuhkan PDF 1.5, dengan kasus enam-belas-bit mengikuti langsung aturan komponen-gambar PDF Reference 1.5 section 4.8. Anotasi RichMedia dan action RichMediaExecute membutuhkan /BaseVersion /1.7 dengan /ExtensionLevel 3 atau lebih tinggi. Stream 3D PRC, diidentifikasi oleh sebuah dictionary yang membawa baik /Type /3D maupun /Subtype /PRC, membutuhkan base version yang sama tetapi hanya /ExtensionLevel 1. Dictionary Geospatial Measure dan anotasi Projection membutuhkan /BaseVersion /1.7 dengan /ExtensionLevel 3, suplemen Adobe yang sama yang menjadi ketergantungan RichMedia
Pemeriksaan geospatial membawa sebuah detail pembacaan-spesifikasi yang layak diketahui jika Anda pernah membangun logika berpagar-versi Anda sendiri di atas PDFiumPas. ISO 32000-1 Table 254 menandai entri /Type milik dictionary Measure sebagai opsional, hanya mencatat bahwa "jika hadir, harus Measure," sementara Table 311 menjadikan /Type wajib untuk dictionary stream 3D tempat konten PRC hidup. Output GeoPDF dunia-nyata dari tool pemetaan secara rutin menghilangkan /Type pada dictionary Measure dan hanya menulis /Subtype /GEO, sehingga detektor geospatial PDFiumPas mencocokkan pada /Subtype saja alih-alih mewajibkan kedua key seperti yang bisa dilakukan detektor 3D PRC-nya dengan aman. Mewajibkan /Type pada kedua dictionary akan membiarkan konten GeoPDF yang sesuai standar lolos dari gerbang tanpa terdeteksi, mendarat dalam sebuah file PDF 1.7 polos tanpa deklarasi extension level yang mendukungnya
Apakah PDFiumPas Secara Otomatis Menurunkan Fitur yang Tidak Didukung?
Tidak sebagai sebuah kemampuan umum, dan mengasumsikan sebaliknya adalah kesalahan yang perlu dihindari di sini. SaveAs menyalurkan versi target lewat sebuah rutin internal, ValidatePdfVersionCompliance, dan ketika rutin itu menemukan sebuah fitur yang tidak bisa didukung versi target atau deklarasi extension level-nya, SaveAs memunculkan sebuah exception yang membawa teks error rutin itu alih-alih menulis file tersebut; pemanggil mendapatkan kembali sebuah alasan presisi bernama-fitur, tidak pernah sebuah dokumen yang diam-diam ditulis ulang. Satu tempat PDFiumPas memang menulis ulang konten secara otomatis adalah sebuah target PDF 1.3, di mana ia menghapus default transparansi /BM /Normal, /CA 1, dan /ca 1 yang secara semantik netral yang selalu ditulis PDFium ke dalam dictionary ExtGState terlepas dari versi target, karena nilai spesifik itu tidak membawa makna visual dan PDF 1.3 sepenuhnya mendahului key-key tersebut
// 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
Transparansi non-default sungguhan dan soft mask gambar tetap gagal secara langsung pada sebuah target PDF 1.3, karena menghapusnya akan mengubah bagaimana sebenarnya halaman itu terlihat, dan PDFiumPas tidak akan membuat keputusan itu atas nama Anda. Dua batas terkait layak direncanakan sebelum sebuah versi eksak masuk ke dalam sebuah pipeline batch. Output versi-eksplisit tidak pernah membawa sebuah dictionary /Encrypt; penyimpanan langsung gagal jika sumbernya terproteksi, yang kebetulan sejalan dengan profil PDF/X dan PDF/A yang melarang enkripsi bagaimanapun juga, tetapi itu berarti dekripsi adalah sebuah langkah terpisah dalam workflow Anda alih-alih sesuatu yang dilakukan SaveAs untuk Anda. PDFiumPas juga tidak memiliki metode publik untuk menulis sebuah deklarasi /Extensions /ADBE ke sebuah katalog, sehingga sebuah file sumber yang mengandung RichMedia, PRC 3D, atau konten geospatial tetapi tidak memiliki deklarasi itu tidak akan lolos gerbang tersebut tidak peduli PdfVersion apa yang Anda minta; deklarasi itu harus sudah ada di sumbernya, biasanya karena tool authoring yang menulisnya, atau fitur itu harus dikeluarkan sebelum penyimpanan. Properti read-only TPdf.PdfVersion layak diperiksa sebelum sebuah penyimpanan versi-eksak bahkan dicoba, karena ia menyelesaikan versi efektif yang sadar-katalog yang sama, header atau override /Version, mana pun yang berlaku saat ini, yang diandalkan validator waktu-simpan itu sendiri
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);
Perlakukan sebuah exception SaveAs pada sebuah target versi eksak sebagai sebuah laporan preflight alih-alih sebuah bug: pesan itu menyebutkan klausul persis yang dilanggar dokumen sumber, yang persis merupakan informasi yang dibutuhkan sebuah percetakan atau pipeline arsip sebelum sebuah file melangkah lebih jauh. Jalur penyimpanan versi-eksplisit, resolver revisi xref aktif, dan pemeriksaan Adobe Extension Level yang dijelaskan di sini disertakan sebagai bagian dari PDFiumPas Component standar untuk Delphi dan C++Builder; halaman produk membawa referensi TPdf.SaveAs lengkap berdampingan dengan sisa API kesesuaian dan form-nya