Artikel Teknis

HotPDF di Free Pascal dan Lazarus: Batas Win64

Jawaban singkat untuk tiket dukungan itu adalah ya, dengan batasan. HotPDF 2.730.0 terbangun di Free Pascal 3.2.2 dan Lazarus 4.6 untuk Win64, dan jalur inti create, load, serta save bekerja. Yang tidak mengikuti adalah apa pun yang bertumpu pada objek codec native yang statis terlink atau pada anonymous method Delphi

Pertanyaannya biasanya datang dengan cara yang sama: sebuah tim menstandarkan diri pada Lazarus untuk alat lintas platform, atau mewarisi kode basis Free Pascal, lalu menginginkan komponen PDF yang sama yang sudah mereka lisensikan untuk Delphi. Mem-port pustaka Delphi yang matang jarang sekadar soal sintaks. Bagian menariknya adalah apa yang dibongkar oleh port tentang di mana pustaka itu diam-diam terikat pada satu toolchain, dan dalam kasus ini ikatannya duduk di dua tempat yang sangat spesifik: ABI berkas objek dari codec yang dibundel, dan fitur kompiler yang bersembunyi di balik sebuah simbol versi

Matriks kemampuan yang membandingkan build Delphi HotPDF dengan build Win64 Free Pascal 3.2.2 dan Lazarus 4.6, memperlihatkan jalur dokumen mana yang dibagi dan API codec, kompresi, rendering paralel, serta anonymous method mana yang bermuara ke stub yang melempar exception
Jalur inti create, load, dan save identik di kedua build, dan jurangnya seluruhnya ada pada codec statis terlink dan API anonymous method

Apa yang dibutuhkan Free Pascal 3.2.2 sebelum HPDFDoc terkompilasi

HotPDF terkompilasi di Free Pascal hanya dalam mode Delphi, dan hanya saat direktori unit LCL Lazarus berada di jalur pencarian. Keduanya tidak bisa ditawar. HotPDF.inc mengalihkan kompiler dengan {$MODE DELPHI} dan {$H+} di dalam blok {$IFDEF FPC} serta menolak apa pun yang lebih tua dengan {$FATAL} saat FPC_FULLVERSION di bawah 30202, jadi instalasi 3.0.x gagal dengan nyaring alih-alih menghasilkan unit rusak. Paket runtime Lazarus HotPDFLaz.lpk mengodekan sisanya: LCL sebagai paket wajib dan -Mdelphi sebagai opsi kustom

Persyaratan LCL mengejutkan orang yang hanya ingin output konsol, tetapi ia struktural. HPDFFPCCompat menyediakan tipe VCL Delphi yang tak punya padanan di Free Pascal, memetakan TMetafile dan TMetafileCanvas ke kelas bitmap dan canvas LCL serta meng-alias TRichEdit ke TMemo, sementara HPDFDoc meng-alias TPNGObject ke Graphics.TPortableNetworkGraphic. Perlakukan itu sebagai shim waktu-kompilasi, bukan paritas fitur: kelas metafile yang ditopang bitmap menjaga unit tetap terkompilasi, ia tidak membuat jalur metafile berperilaku seperti di Delphi. Bahkan smoke test non-GUI pun menarik Interfaces, dan skrip build meneruskan -Fu untuk lcl\units\x86_64-win64 serta direktori output lazutils

Mengapa D2009+ tidak bisa menjadi gerbang versi

Menggoda untuk memperlakukan build Free Pascal sebagai kompiler modern dan sekadar mendefinisikan simbol fitur Delphi terbaru. HotPDF tidak, dan alasannya layak dinyatakan terus terang: D2009+ tidak berarti string Unicode saja, ia juga menggerbangi unit yang API publiknya diekspresikan dengan anonymous method. Free Pascal 3.2.2 tidak mendukung anonymous method Delphi maupun API-API itu, jadi meminjam simbol tersebut akan menyeret kode yang tidak mungkin terkompilasi. Klausa uses HPDFDoc karena itu membawa dua ekor kondisional terpisah, dan tumpang tindih di antara keduanya disengaja, bukan kebetulan

uses
  // ...
  HPDFJavaScript,
  HPDFFormCalcGraph
{$IFDEF FPC}
  , HPDFFPCCodecStubs,
  HPDFCMS,
  HPDFWinCertSigner
{$ENDIF}
{$IFDEF D2009+}
  , HPDFXFARuntime,
  HPDFCMS,
  HPDFWinCertSigner,
  HPDFSignVerify,
  HPDFSignatureBatch
{$ENDIF};

Mengapa codec native berhenti di linker?

Karena mereka objek Win64 COFF yang dihasilkan oleh satu toolchain tertentu, dan tak ada linker Free Pascal di Win64 yang mau mengonsumsinya: bukan linker internal, bukan jalur GNU ld eksternal. Ini masalah ABI berkas objek, bukan masalah Pascal, dan seberapapun banyak sumber kondisional tak akan memperbaikinya. Pustaka mengambil satu-satunya jalan jujur yang tersedia. Setiap direktif {$L} yang menarik objek codec statis dibungkus {$IFNDEF FPC}, sehingga build Free Pascal sekadar melewatinya, dan HPDFFPCCodecStubs kemudian menyuplai setiap simbol eksternal yang hilang sebagai stub yang melempar alih-alih mengembalikan

// HPDFFPCCodecStubs.pas
function HPDFFPCNativeCodecUnavailable: PtrUInt;
begin
  raise ENotSupportedException.Create(
    'This native codec is not available in the Free Pascal build');
end;

function HPDFFPCStub_deflate: PtrUInt; cdecl;
  public name 'deflate';
begin
  Result := HPDFFPCNativeCodecUnavailable;
end;

Tabel stub itu panjang, dan membacanya memberi tahu Anda persis kemampuan mana yang hari ini hanya milik Delphi: titik masuk deflate zlib-ng dan zopfli, kompresi dan dekompresi libjpeg, codec OpenJPEG JPEG 2000, libtiff beserta inisialisasi per-kompresinya, encode dan decode JBIG2, titik masuk transformasi warna Little-CMS, serta primitif AES. Pilihan desain di balik stub lebih penting daripada daftarnya. Simbol yang hilang saat link memberi Anda tembok undefined references dari unit yang belum pernah Anda sentuh; stub yang melempar ENotSupportedException memberi Anda build yang jalan, pesan yang menyebut alasannya, dan stack trace yang menunjuk lokasi pemanggilan. Itu juga berarti build Free Pascal tak pernah diam-diam menghasilkan byte salah di tempat build Delphi menghasilkan byte benar. Perhatikan efek orde keduanya juga: menjalankan codec gambar tak terpercaya di proses terisolasi adalah keputusan yang hanya muncul di build Delphi, karena build Free Pascal tak punya dekoder native in-process untuk di-sandbox sejak awal

Di Delphi objek codec statis HotPDF terlink dan berjalan native, sementara build Win64 Free Pascal melewatkan direktif link dan mengarahkan setiap simbol eksternal yang hilang ke stub yang melempar exception bernama di lokasi pemanggilan
Melewatkan direktif link dan men-stub setiap simbol eksternal mengubah tembok undefined references menjadi build yang jalan dan menyebut batasnya sendiri

Kompresi: baris pertama yang diubah adalah cmNone

Sebelum mem-port apa pun lainnya, atur Compression ke cmNone. THPDFCompressionMethod menawarkan tepat dua nilai, cmNone dan cmFlateDecode, dan yang kedua bermuara langsung ke titik masuk deflate yang berupa stub di build Free Pascal. Verifikasi dulu model objek inti dengan kompresi mati, lalu putuskan apa lagi yang Anda butuhkan. Itulah urutan yang dipakai smoke test yang dikirim: buat dokumen satu halaman tanpa kompresi, muat ulang, dan asersi jumlah halaman kembali satu. Output tanpa kompresi lebih besar, dan tetap PDF yang sah sepenuhnya

program HotPDFLazarusSmoke;

{$mode delphi}
{$H+}

uses
  Interfaces, SysUtils, HPDFDoc;

var
  Pdf, Reloaded: THotPDF;
  OutputFile: string;
  PageCount: Integer;
begin
  OutputFile := IncludeTrailingPathDelimiter(GetTempDir) +
    'HotPDF-FPC-Smoke.pdf';
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := OutputFile;
    Pdf.Compression := cmNone;   // cmFlateDecode reaches a stubbed symbol
    Pdf.BeginDoc;
    Pdf.CurrentPage.SetFont('Arial', [], 12);
    Pdf.CurrentPage.TextOut(72, 72, 0, 'HotPDF Free Pascal smoke test');
    Pdf.EndDoc;
  finally
    Pdf.Free;
  end;

  Reloaded := THotPDF.Create(nil);
  try
    PageCount := Reloaded.LoadFromFile(OutputFile);
    if PageCount <> 1 then
      raise Exception.CreateFmt('Expected one page, got %d', [PageCount]);
  finally
    Reloaded.Free;
  end;
end.

Apa yang terjadi pada rendering halaman paralel?

Ia tetap terkompilasi, tetap mengembalikan bitmap yang benar, dan berhenti menjadi paralel. THotPDF.RenderLoadedPagesParallel dan THotPDF.RenderLoadedPagesParallelOrdered dibangun di atas TThread.CreateAnonymousThread dengan closure procedure inline, yang tak bisa diekspresikan Free Pascal 3.2.2, sehingga cabang Free Pascal menjalankan fallback serial yang deterministik: ia menyusuri indeks halaman secara berurutan, memanggil RenderLoadedPageToBitmap untuk masing-masing, dan menghitung keberhasilannya. Bentuk API, nilai kembali, dan array output tak berubah, dan itulah yang memungkinkan satu basis kode terbangun dua arah

Panggilan render paralel HotPDF yang sama berjalan di thread pekerja yang tumpang tindih di bawah Delphi dan menyusuri indeks halaman secara serial di bawah Free Pascal, dengan record info pipeline melaporkan jumlah pekerja satu alih-alih menyembunyikan fallback
Cabang Free Pascal menjaga bentuk API dan array output sambil melaporkan jumlah pekerja satu, sehingga kode yang sudah membaca record info melihat kebenaran
var
  Bitmaps: THPDFBitmapArray;
  Info: THPDFParallelRenderPipelineInfo;
  Rendered: Integer;
begin
  Rendered := Pdf.RenderLoadedPagesParallel([0, 1, 2, 3], 150, 4,
    Bitmaps, Info);
  // Delphi: Info.WorkerCount is whatever the memory budget allowed
  // Free Pascal: Info.WorkerCount is always 1, pages in index order
  if Info.WorkerCount = 1 then
    LogSerialFallback(Rendered, Info.RequestedWorkerCount);

Fallback itu tidak diam, dan itulah bagian yang layak dirancang di sekelilingnya. Ia mengisi THPDFParallelRenderPipelineInfo dengan jujur: PageCount dari permintaan, RequestedWorkerCount yang menggemakan permintaan Anda, WorkerCount diatur 1, serta hitungan selesai dan tersampaikan yang cocok dengan yang benar-benar kembali. Kode yang sudah menginspeksi Info untuk mengukur progress bar atau anggaran memori tetap bekerja dan membaca kebenaran, bukan asumsi. Jika rencana throughput Anda bergantung pada pipeline render paralel dan model backpressure-nya, rencana itu adalah rencana Delphi; di Free Pascal, anggarkan biaya satu-thread merender halaman ke bitmap dikalikan jumlah halaman

Build mana yang benar-benar Anda kirim?

Pilih berdasarkan kemampuan, bukan preferensi. Jika alur kerja Anda adalah perakitan dokumen, teks dan gambar vektor, pengisian form, loading dan saving, build Free Pascal di Win64 menutupnya, dan Anda sebaiknya memvalidasi dengan kompresi mati sebelum menyalakan apa pun. Jika melibatkan gambar JPEG atau JPEG 2000 atau TIFF atau JBIG2, transformasi warna ICC, output terkompresi, atau throughput yang bergantung pada banyak core, tetaplah di Delphi atau C++Builder untuk sekarang. Batasnya digambar oleh ABI berkas objek dan satu fitur bahasa yang hilang, keduanya terlihat di sumber alih-alih terkubur di matriks dukungan, dan keduanya gagal dengan error bernama alih-alih hasil yang salah

Paket Free Pascal dan Lazarus dikirim dalam distribusi yang sama dengan unit Delphi dan C++Builder, jadi satu lisensi mencakup keduanya dan Anda bisa menguji jalur Lazarus terhadap dokumen Anda sendiri sebelum berkomitmen; halaman produk HotPDF Delphi PDF Component membawa matriks dukungan kompiler terkini dan referensi API lengkap