Artikel Teknis

Menggabungkan banyak file PDF menjadi satu dokumen PDFium

PDFium Component mengekspos penggabungan PDF melalui satu metode: ImportPages. Polanya selalu sama: buat dokumen tujuan kosong, buka setiap file sumber, panggil ImportPages untuk menyalin halaman, tutup sumber, dan ulangi. Saat loop selesai, SaveAs menulis hasilnya ke disk. Tidak ada mode penggabungan khusus, tidak ada konfigurasi untuk dibalik. Kompleksitasnya hidup dalam kasus tepi, dan ada beberapa yang menggigit tanpa peringatan

Loop inti

Dua instans TPdf adalah semua yang Anda butuhkan. Satu memegang dokumen tujuan, dibuat kosong dengan CreateDocument. Yang lain membuka setiap file sumber secara bergiliran. Berikut prosedur yang mengambil daftar jalur file dan menulis output gabungan ke satu jalur:

procedure MergeFiles(const FileList: TStrings; const OutputPath: string);
var
  PdfDest, PdfSrc: TPdf;
  InsertAt, I: Integer;
begin
  PdfDest := TPdf.Create(nil);
  PdfSrc  := TPdf.Create(nil);
  try
    PdfDest.CreateDocument;
    InsertAt := 1;  // ImportPages menggunakan posisi tujuan 1-based

    for I := 0 to FileList.Count - 1 do
    begin
      PdfSrc.FileName := FileList[I];
      PdfSrc.Active   := True;

      if not PdfSrc.Active then
        raise Exception.CreateFmt('Cannot open: %s', [FileList[I]]);

      PdfDest.ImportPages(
        PdfSrc,
        '1-' + IntToStr(PdfSrc.PageCount),  // rentang dokumen penuh
        InsertAt);

      Inc(InsertAt, PdfSrc.PageCount);
      PdfSrc.Active := False;
    end;

    PdfDest.SaveAs(OutputPath);
  finally
    PdfSrc.Free;
    PdfDest.Free;
  end;
end;

Dua hal dalam kode itu mudah diabaikan pada bacaan pertama. Yang pertama adalah bagaimana PDFium melaporkan kegagalan muat. Active := True tidak pernah melempar pengecualian: jika file hilang, rusak, atau dilindungi kata sandi, PDFium menangkap kesalahan secara internal dan meninggalkan Active sebagai False. Tanpa pemeriksaan eksplisit di baris 10, file buruk akan diam-diam keluar dari penggabungan tanpa indikasi dalam output. PDF akhir akan memiliki lebih sedikit halaman dari yang diharapkan dan Anda tidak akan tahu file mana pelakunya

Yang kedua adalah penghitung InsertAt. Argumen ketiga ke ImportPages adalah posisi berbasis-1 dalam tujuan di mana halaman pertama yang diimpor mendarat. Memulai dari 1 menempatkan dokumen sumber pertama di awal file yang kalau tidak kosong. Setelah setiap sumber, penghitung maju sebesar PdfSrc.PageCount, sehingga batch halaman berikutnya menambahkan setelah yang terakhir. Lupa menambahkannya dan setiap sumber berikutnya menimpa halaman di posisi 1, memberi Anda dokumen terakhir dalam daftar dan tidak ada yang lain

Loop penggabungan Delphi dengan PDFium Component: setiap berkas sumber dibuka, disalin melalui ImportPages pada posisi InsertAt, dan dokumen tujuan ditulis sekali dengan SaveAs
ImportPages mendaratkan setiap sumber di posisi InsertAt, dan file yang hilang atau rusak gagal secara senyap kecuali Active diperiksa

Rentang halaman selektif

Anda tidak harus mengambil setiap halaman dari sumber. String rentang yang diteruskan sebagai argumen kedua mengikuti format koma-dan-tanda-hubung sederhana: "1-3" mengambil halaman 1 sampai 3, "2,4,6" memilih tiga halaman spesifik, dan "1-" berarti halaman 1 sampai akhir dokumen. Rentang bisa dikombinasikan dalam satu string, jadi "1-3,5,7-" melewati halaman 4 dan 6. Satu subtilitas penting di sini: angka selalu merujuk ke halaman dalam dokumen sumber, mulai dari 1, terlepas dari di mana halaman itu berakhir di tujuan. Jika Anda ingin halaman 40 sampai 50 dari katalog 200-halaman, string rentangnya adalah "40-50", bukan posisi relatif terhadap apa yang sudah ada di tujuan

// Ekstrak cover plus ringkasan eksekutif tiga halaman dari laporan panjang
PdfSrc.FileName := 'annual-report.pdf';
PdfSrc.Active   := True;
if PdfSrc.Active then
begin
  // Halaman 1 adalah cover; halaman 3-5 adalah ringkasan
  PdfDest.ImportPages(PdfSrc, '1,3-5', InsertAt);
  Inc(InsertAt, 4);  // 1 cover + 3 summary pages = 4 pages added
  PdfSrc.Active := False;
end;

Saat menghitung kenaikan ke InsertAt, hitung halaman yang benar-benar Anda impor, bukan jumlah halaman sumber. Jika Anda meneruskan '1,3-5' Anda mengimpor 4 halaman, jadi maju sebesar 4. Maju sebesar PdfSrc.PageCount akan meninggalkan celah posisi tujuan kosong dan menempatkan dokumen sumber berikutnya lebih jauh ke file dari yang dimaksudkan

Apa yang dipertahankan ImportPages dan apa yang tidak

Halaman yang disalin oleh ImportPages membawa konten visual mereka utuh. Teks, grafik vektor, gambar raster, font yang tersemat, dan form XObjects semua berpindah sebagai bagian dari aliran konten halaman. Anotasi tingkat-halaman, termasuk komentar, sorotan, dan goresan tinta, ikut juga, karena mereka disimpan di dalam kamus halaman alih-alih di tingkat dokumen

Metadata tingkat-dokumen adalah cerita yang berbeda. String judul, penulis, subjek, dan kata kunci dalam kamus Info sumber tertinggal. Dokumen tujuan dimulai dengan metadata kosong setelah CreateDocument, jadi jika output gabungan perlu field itu diisi Anda harus menugaskannya ke PdfDest secara langsung sebelum memanggil SaveAs. Properti Title, Author, Subject, Keywords, dan Creator pada TPdf mengambil string polos dan menulis ke dalam kamus Info saat simpan

Kolom formulir interaktif lebih rumit. Definisi field AcroForm hidup dalam kamus tingkat-dokumen alih-alih di dalam aliran halaman individu. Saat ImportPages menyalin halaman yang berisi kolom formulir, penampilan visual kolom itu berpindah karena dirender ke aliran konten halaman, tetapi widget field yang membuat mereka interaktif adalah bagian dari struktur AcroForm dan tidak mengikuti. Dalam penggabungan tipikal, kolom teks dari dokumen sumber akan menampilkan nilai yang dimilikinya pada saat impor, tetapi tidak akan dapat diedit dalam file gabungan. Jika Anda butuh field tetap dapat diisi, ratakkan mereka di setiap dokumen sumber sebelum mengimpor: itu memanggang nilai saat ini ke aliran konten dan menghapus overlay interaktif, memberi Anda hasil visual yang bersih tanpa widget rusak dalam output

PDFium ImportPages membawa konten halaman, font, dan anotasi ke PDF gabungan, sementara metadata Info, widget AcroForm, dan enkripsi tertinggal di setiap berkas sumber
ImportPages memindahkan segala yang tersimpan bersama halaman, sementara metadata level dokumen dan interaktivitas AcroForm tertinggal di belakang

File sumber terenkripsi

Dokumen sumber yang dilindungi kata sandi terbuka dengan cara yang sama seperti yang tidak terenkripsi, dengan satu properti tambahan untuk disetel lebih dulu. Tetapkan kata sandi ke PdfSrc.Password sebelum membalik Active := True, dan PDFium akan menggunakannya selama pembukaan:

PdfSrc.Password := 'user-password';
PdfSrc.FileName := 'protected.pdf';
PdfSrc.Active   := True;
if not PdfSrc.Active then
  raise Exception.Create('Wrong password or file cannot be opened');

PdfDest.ImportPages(PdfSrc, '1-' + IntToStr(PdfSrc.PageCount), InsertAt);
Inc(InsertAt, PdfSrc.PageCount);
PdfSrc.Active := False;

Kata sandi salah menyebabkan hasil Active = False yang diam seperti file hilang, jadi pemeriksaan eksplisit sama perluinya di sini. Enkripsi tidak berpindah ke tujuan: halaman yang diimpor dari sumber yang dilindungi mendarat di tujuan sebagai konten tidak terlindungi. Jika output gabungan juga butuh enkripsi, konfigurasikan di PdfDest sebelum memanggil SaveAs

Menyimpan hasil

SaveAs pada TPdf menerima baik jalur file atau TStream. Untuk sebagian besar penggabungan, overload file adalah yang Anda inginkan:

PdfDest.SaveAs('merged-output.pdf');

Argumen kedua opsional adalah TSaveOption yang mengontrol mode simpan. Default, saNone, menulis pembaruan inkremental jika dokumen dimuat dari file atau penulisan ulang lengkap jika dibuat segar. Karena tujuan yang dibangun dengan CreateDocument selalu segar, output akan menjadi file revisi-tunggal yang kompak. Argumen ketiga, TPdfVersion, memungkinkan Anda menyematkan header versi PDF ketika Anda memiliki konsumen downstream yang membutuhkan versi spesifik; membiarkannya di pvUnknown membiarkan PDFium memilih berdasarkan konten

Metode ImportPages dan SaveAs yang ditunjukkan di sini adalah bagian dari PDFium Component untuk Delphi dan C++Builder