Artikel Teknis

Memperbaiki Masalah Penggunaan Ulang Komponen HotPDF

Kesalahan "Please load the document before using BeginDoc" adalah tanda yang hampir pasti bahwa instans THotPDF yang sama sedang digunakan untuk menghasilkan lebih dari satu dokumen tanpa di-reset dengan benar di antaranya. Komponen memiliki mesin state internal yang melacak apakah sesi penulisan aktif, dan mesin itu tidak kembali ke keadaan awal secara otomatis hanya karena EndDoc dipanggil

THotPDF bukan service object yang dapat diputar terus seperti koneksi database. Satu instance memodelkan satu dokumen: BeginDoc membuka alur, EndDoc menserialisasikan hasil ke FileName, lalu instance harus dilepas. Memanggil BeginDoc lagi setelah dokumen selesai berarti meminta state machine masuk kembali ke jalur yang tidak didukung

Model lifecycle

Setiap instans THotPDF mengikuti urutan state ini:

  1. Create: objek dialokasikan, state internal diinisialisasi, tidak ada dokumen terbuka
  2. BeginDoc: sesi penulisan dimulai, file output dibuka atau stream dialokasikan, halaman pertama dibuat
  3. (menggambar halaman, menambahkan halaman)
  4. EndDoc: semua halaman difinalisasi, struktur PDF ditulis, file ditutup, state kembali ke idle
  5. Free: objek dibebaskan dari memori

Poin kritis: setelah EndDoc, komponen berada dalam keadaan idle tetapi siap untuk siklus BeginDoc lain jika dan hanya jika tidak ada file yang dimuat ke dalamnya. Jika sebelumnya Anda memanggil LoadFromFile, state internal berisi dokumen yang dimuat dan BeginDoc akan memunculkan kesalahan tersebut karena komponen mengharapkan Anda bekerja dengan dokumen yang ada, bukan membuat dokumen baru

Penyebab umum

Penggunaan ulang setelah LoadFromFile

Jika alur kerja Anda melibatkan pembacaan PDF yang ada dengan LoadFromFile, lalu kemudian mencoba menghasilkan PDF baru dengan BeginDoc pada komponen yang sama, komponen berada dalam state "dokumen dimuat" dan tidak menerima BeginDoc. Solusinya adalah membuat instans terpisah untuk membuat dan memuat, atau memanggil Free dan mengalokasikan ulang komponen sebelum menggunakannya untuk pembuatan

Memanggil BeginDoc dua kali tanpa EndDoc di antaranya

Memanggil BeginDoc saat sesi penulisan sudah aktif memunculkan kesalahan serupa. Ini biasanya terjadi ketika handler event dipanggil dua kali sebelum yang pertama selesai, atau ketika kode iterasi menjalankan ulang blok inisialisasi yang seharusnya berjalan sekali saja

Pola yang aman untuk pembuatan satu dokumen

Cara paling andal adalah mencakup komponen sepenuhnya dalam blok try/finally:

procedure GeneratePDF(const OutputPath: string);
var
  PDF: THotPDF;
begin
  PDF := THotPDF.Create(nil);
  try
    PDF.FileName := OutputPath;
    PDF.BeginDoc;
    // ... rendering ...
    PDF.EndDoc;
  finally
    PDF.Free;
  end;
end;

Dengan pola ini tidak ada ambiguitas tentang state. Komponen lahir, melakukan satu pekerjaan, dan dibebaskan. Tidak ada kemungkinan state residual dari panggilan sebelumnya

Penggunaan ulang yang aman untuk pembuatan batch

Jika Anda perlu menghasilkan beberapa dokumen dan ingin menghindari overhead alokasi objek berulang, komponen dapat digunakan kembali hanya jika tidak pernah menerima panggilan LoadFromFile dan setiap siklus BeginDoc/EndDoc selesai dengan bersih:

procedure GenerateBatch(const Files: TStringList);
var
  PDF: THotPDF;
  I: Integer;
begin
  PDF := THotPDF.Create(nil);
  try
    for I := 0 to Files.Count - 1 do
    begin
      PDF.FileName := Files[I];
      PDF.BeginDoc;
      // ... rendering untuk dokumen ke-I ...
      PDF.EndDoc;
    end;
  finally
    PDF.Free;
  end;
end;

Jika salah satu iterasi memunculkan exception sebelum EndDoc, loop berhenti dan blok finally hanya membebaskan komponen. Dokumen yang sebagian ditulis ditinggalkan di disk. Untuk kode produksi yang memerlukan perilaku atomic, bungkus setiap pasangan BeginDoc/EndDoc dalam blok try/except yang memutuskan apakah akan melanjutkan batch atau menginterupsinya

Masalah file lock setelah LoadFromFile

Satu jebakan terkait yang tidak menampilkan pesan kesalahan yang sama tetapi sering muncul bersamaan: ketika Anda memanggil LoadFromFile pada komponen HotPDF yang dijatuhkan ke form, file tetap terkunci selama instans komponen hidup. Jika Anda kemudian mencoba menulis ke file yang sama dengan instans kedua atau dengan alat eksternal saat form masih terbuka, Anda akan mendapatkan kesalahan akses file. Solusinya adalah memanggil SaveLoadedDocument terlebih dahulu jika Anda perlu mempertahankan modifikasi, lalu Free instans asli sebelum membuka koneksi baru ke file yang sama

Dokumentasi lengkap API tersedia di loslab.com

Contoh kode tambahan

var
  Pdf: THotPDF;
  PageCount: Integer;
begin
  Pdf := THotPDF.Create(nil);
  try
    PageCount := Pdf.LoadFromFile('contract.pdf');
    if PageCount > 0 then
    begin
      Pdf.CurrentPage.SetFont('Arial', [fsBold], 10);
      Pdf.CurrentPage.TextOut(40, 30, 0, 'REVIEWED');
      Pdf.SaveLoadedDocument('contract-reviewed.pdf');
    end;
  finally
    Pdf.Free;
  end;
end;