PDF Library for Delphi menggabungkan dua dokumen AcroForm dengan kebijakan eksplisit untuk field yang berbagi nama. MergeDocumentEx menerima identifier dokumen sumber dan salah satu dari tiga strategi: dfsReject menolak penggabungan, dfsMerge mempertahankan nama bersama dan menyinkronkan value, dan dfsAutoNumber mengganti nama field yang masuk secara deterministik. Pemindaian nama terjadi sebelum nomor objek apa pun bergeser, sehingga penggabungan yang ditolak meninggalkan kedua dokumen tetap sepenuhnya dapat digunakan
Siapa pun yang pernah merakit sebuah paket aplikasi PDF pernah mengalami ini. Tiga form, masing-masing dengan field bernama Signature atau Date atau Total, digabungkan menjadi satu berkas. Dalam sebuah AcroForm, nama field yang sepenuhnya qualified adalah identitas field tersebut, sehingga dua field dengan nama yang sama sebenarnya bukan dua field sama sekali: mengisi satu mengisi yang lain, dan sebuah tanda tangan yang diterapkan pada satu mencakup scope yang tidak dimaksudkan siapa pun
Mengapa tabrakan nama diputuskan sebelum penggabungan?
MergeDocument yang lebih lama menggabungkan array field root AcroForm dari kedua dokumen dan tidak menawarkan pilihan apa pun. Lebih buruk lagi, ketika hasilnya tidak dapat digunakan, penemuan itu terjadi setelah nomor objek dinomori ulang dan pohon halaman dijahit, yang meninggalkan pemanggil memegang sebuah dokumen dalam keadaan yang tidak dimiliki oleh salah satu aslinya
MergeDocumentEx membalik urutan itu. Ia mengumpulkan nama field level atas dari kedua dokumen, membandingkannya, dan menerapkan strategi sebelum apa pun berpindah. Penolakan karena itu adalah no-op yang bersih: dokumen target tidak tersentuh, dokumen sumber tidak tersentuh, dan keduanya tetap terbuka dan dapat digunakan, yang diverifikasi pengujian penggabungan dengan membaca kembali sebuah value field dari dokumen sumber setelah penggabungan yang ditolak
Perbandingan ini menggunakan sebuah set nama yang terurut dan case-sensitive, sehingga biayanya proporsional terhadap jumlah field gabungan dikalikan sebuah faktor logaritmik alih-alih terhadap perkalian kedua jumlah tersebut. Case sensitivity adalah pilihan yang benar di sini karena nama field PDF bersifat case sensitive; melakukan folding padanya akan menggabungkan field yang oleh spesifikasi dianggap berbeda
Tiga strategi, dan kapan masing-masing tepat
dfsReject adalah strategi untuk pipeline otomatis yang tidak boleh menghasilkan dokumen ambigu. Penggabungan mengembalikan nol dan LastErrorCode melaporkan 705, sebuah kode khusus sehingga nama duplikat dapat dibedakan dari setiap kegagalan penggabungan lainnya dan dirutekan ke remedi tertentu, biasanya mengganti nama field di hulu
dfsMerge mempertahankan nama bersama secara sengaja dan menyinkronkan value target serta default value ke dalam field sumber, sehingga sebuah viewer yang conforming memperlakukan beberapa widget itu sebagai satu field yang bernama logis, yang merupakan perilaku AcroForm standar untuk sebuah field dengan beberapa widget annotation. Apa yang tidak dilakukannya adalah melipat dictionary field yang berbeda menjadi satu objek. Setiap field mempertahankan asosiasi halaman, appearance, dan action-nya sendiri, karena menggabungkannya akan diam-diam membuang pemformatan dan perilaku yang menjadi milik dokumen yang masuk
dfsAutoNumber mengganti nama duplikat yang masuk dengan menambahkan sufiks numerik dimulai dari _2 dan mengambil yang pertama bebas. Hasilnya reproducible: hanya bergantung pada nama yang ada, tidak pernah pada nomor objek field, sehingga menggabungkan pasangan dokumen yang sama dua kali menghasilkan nama yang sama kedua kalinya. Properti itu penting ketika kode di hilir, sebuah impor FDF atau pemetaan basis data, merujuk field berdasarkan nama
uses
PDFlibrary;
var
Lib: TPDFlib;
TargetDoc, SourceDoc: Integer;
begin
Lib := TPDFlib.Create;
try
TargetDoc := Lib.SelectedDocument;
Lib.LoadFromFile('application-part1.pdf', '');
SourceDoc := Lib.NewDocument;
Lib.LoadFromFile('application-part2.pdf', '');
Lib.SelectDocument(TargetDoc);
if Lib.MergeDocumentEx(SourceDoc, dfsReject) = 0 then
begin
if Lib.LastErrorCode = 705 then
begin
// Kedua dokumen masih utuh - coba lagi dengan sebuah policy
Log('duplicate field names; retrying with auto-numbering');
Lib.MergeDocumentEx(SourceDoc, dfsAutoNumber);
end;
end;
Lib.SaveToFile('application-complete.pdf');
finally
Lib.Free;
end;
end;
Perhatikan pola dua langkah dalam kode itu, yang hanya mungkin karena penolakan bersifat non-destruktif. Coba policy yang ketat terlebih dahulu, periksa errornya, lalu putuskan. Dengan sebuah penggabungan yang gagal di tengah jalan, fallback-nya harus dimulai ulang dengan memuat ulang kedua berkas
Seperti apa form yang tergabung sesudahnya
Di bawah dfsMerge, sebuah field target bernama Shared yang membawa "Target value" dan sebuah field sumber dengan nama yang sama menghasilkan dua field, keduanya bernama Shared, keduanya melaporkan target value, karena target value dan default value disinkronkan ke dalam field yang masuk. Itu adalah semantik yang dimaksudkan untuk nama bersama: satu field logis, beberapa widget, satu value
Di bawah dfsAutoNumber, input yang sama menghasilkan Shared dan Shared_2 sebagai field terpisah dengan value independen. Pilih antara keduanya dengan menanyakan satu pertanyaan: haruskah mengisi satu mengisi yang lain? Untuk nama penandatangan yang diulang di setiap bagian sebuah paket, ya, dan dfsMerge tepat. Untuk sebuah total yang bermakna berbeda pada masing-masing form, tidak, dan auto-numbering tepat
// Setelah penggabungan, enumerasi apa yang sebenarnya Anda dapatkan
for I := 1 to Lib.FormFieldCount do
Log(Format('%d: %s = %s',
[I, Lib.GetFormFieldTitle(I), Lib.GetFormFieldValue(I)]));
Catatan praktis untuk merakit paket form
Penggabungan yang berhasil mengonsumsi dokumen sumber: ia dihapus dari daftar dokumen library, itulah sebabnya DocumentCount turun dari dua menjadi satu. Jangan terus menggunakan identifier sumber sesudahnya. Versi dokumen dinaikkan ke yang lebih tinggi dari keduanya, sehingga menggabungkan form PDF 2.0 ke dalam dokumen 1.7 menghasilkan berkas 2.0
Urutan penting untuk nama. Menggabungkan A ke B dan menggabungkan B ke A menghasilkan hasil auto-numbered yang berbeda, karena dokumen yang melakukan penggabungan mempertahankan namanya tidak berubah. Ketika sebuah paket memiliki form utama kanonis, jadikan itu sebagai target
Field tanda tangan layak mendapat pertimbangan sendiri. Sebuah tanda tangan yang diterapkan sebelum penggabungan hanya mencakup revisi yang ditandatanganinya, sehingga penggabungan membatalkannya secara praktis karena berkasnya telah berubah sejak penandatanganan. Rakit terlebih dahulu dan tandatangani dokumen yang sudah dirakit, alih-alih menggabungkan bagian-bagian yang sudah ditandatangani. Ketika penggabungan menyangkut konten halaman alih-alih form, jalur yang lebih cepat dijelaskan dalam penggabungan PDF cepat dengan pergeseran referensi byte adalah alat yang lebih baik
Terakhir, rencanakan sisi data dari paket bersama-sama dengan penggabungan. Jika value field berasal dari sistem eksternal, putuskan apakah sistem itu mengalamatkan field berdasarkan nama sebelum memilih auto-numbering, karena Shared_2 tidak akan cocok dengan pemetaan yang mengharapkan Shared. Format impor dan ekspor dibahas dalam pertukaran data form FDF, XFDF, dan XFA, dan perilaku scripting level field yang juga dapat terpengaruh penggantian nama dibahas dalam action form interaktif dan JavaScript
Penggabungan form, pertukaran data, dan penandatanganan berjalan dalam library yang sama untuk Delphi, C++Builder, dan Free Pascal; daftar fitur lengkapnya ada di halaman PDF Library for Delphi