Kratak odgovor na taj support tiket je da, sa ograničenjima. HotPDF 2.730.0 se gradi na Free Pascal 3.2.2 i Lazarus 4.6 za Win64, i osnovni create, load i save putevi rade. Ono što ne sledi je sve što počiva na statički linkovanom nativnom codec objektu ili na Delphi anonimnim metodama
Pitanje obično stiže isto: tim se standardizuje na Lazarus za cross-platform alat, ili nasleđuje Free Pascal bazu koda, i želi istu PDF komponentu koju već licencira za Delphi. Portovanje zrele Delphi biblioteke retko je pitanje sintakse. Zanimljiv deo je ono što port otkriva o mestima gde je biblioteka tiho bila vezana za jedan toolchain, a u ovom slučaju vezanost sedi na dva vrlo specifična mesta: object-file ABI ugrađenih codec-ova i kompajlerske mogućnosti sakrivene iza verzionog simbola
Šta Free Pascal 3.2.2 traži pre nego što HPDFDoc kompajlira
HotPDF se kompajlira pod Free Pascal-om samo u Delphi mode-u, i samo kada su Lazarus LCL unit direktorijumi na search putanji. Ništa od toga nije pregovarljivo. HotPDF.inc prebacuje kompajler sa {$MODE DELPHI} i {$H+} unutar svog {$IFDEF FPC} bloka i odbija sve starije sa {$FATAL} kada je FPC_FULLVERSION ispod 30202, pa 3.0.x instalacija glasno pada umesto da proizvede pokvaren unit. Lazarus runtime paket HotPDFLaz.lpk kodira ostalo: LCL kao obavezan paket i -Mdelphi kao custom opciju
LCL zahtev iznenađuje one koji žele samo console izlaz, ali je strukturni. HPDFFPCCompat snabdeva Delphi VCL tipove za koje Free Pascal nema ekvivalent, mapirajući TMetafile i TMetafileCanvas na LCL bitmap i canvas klase i aliasujući TRichEdit na TMemo, dok HPDFDoc aliasuje TPNGObject na Graphics.TPortableNetworkGraphic. Tretirajte ih kao compile-time šimove, ne kao paritet mogućnosti: metafile klasa koju drži bitmapa drži unit u kompajliranju, ne čini da metafile putevi rade kao na Delphi-ju. Čak i non-GUI smoke test povlači Interfaces, a build skripta daje -Fu za lcl\units\x86_64-win64 i lazutils izlazni direktorijum
Zašto D2009+ ne može da služi i kao verziona kapija
Primamljivo je tretirati Free Pascal build kao moderan kompajler i jednostavno definisati najnoviji Delphi mogućnosni simbol. HotPDF to ne čini, i razlog vredi da se izrekne jasno: D2009+ ne znači samo Unicode stringove, on takođe kapijuje unit-e čiji je javni API izražen anonimnim metodama. Free Pascal 3.2.2 ne podržava ni Delphi anonimne metode ni te API-je, pa bi pozajmljivanje simbola povuklo kod koji ne može da se kompajlira. Uses klauzula HPDFDoc-a zato nosi dva odvojena uslovna repa, i preklapanje između njih namerno je, a ne slučajno
uses
// ...
HPDFJavaScript,
HPDFFormCalcGraph
{$IFDEF FPC}
, HPDFFPCCodecStubs,
HPDFCMS,
HPDFWinCertSigner
{$ENDIF}
{$IFDEF D2009+}
, HPDFXFARuntime,
HPDFCMS,
HPDFWinCertSigner,
HPDFSignVerify,
HPDFSignatureBatch
{$ENDIF};
Zašto se nativni codec-ovi zaustavljaju na linkeru?
Jer su Win64 COFF objekti koje je emitovao jedan konkretan toolchain, i nijedan Free Pascal linker na Win64 neće da ih konzumira: ni interni linker, ni eksterni GNU ld put. Ovo je object-file ABI problem, ne Pascal problem, i nijedna količina uslovnog izvornog koda to ne rešava. Biblioteka uzima jedini pošten dostupan put. Svaki {$L} direktiv koji povlači statički codec objekat umotan je u {$IFNDEF FPC}, pa Free Pascal build ih jednostavno izostavlja, a HPDFFPCCodecStubs zatim snabdeva svaki nedostajući eksterni simbol stubom koji baca umesto da vrati
// 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;
Ta stub tabela je dugačka, i čitanje je kaže tačno koje mogućnosti su danas Delphi-only: zlib-ng i zopfli deflate ulazne tačke, libjpeg kompresija i dekompresija, OpenJPEG JPEG 2000 codec, libtiff i njegovi inicijalizatori po kompresiji, JBIG2 kodiranje i dekodiranje, Little-CMS transformacija boja ulazne tačke, i AES primitivi. Dizajn odluka iza stubova važnija je od liste. Nedostajući simbol u link vremenu daje vam zid nedefinisanih referenci iz unit-a kojeg niste ni dirali; stub koji baca ENotSupportedException daje vam build koji radi, poruku koja imenuje razlog i stack trace koji pokazuje na mesto poziva. To takođe znači da Free Pascal build nikad tiho ne proizvodi pogrešne bajtove tamo gde bi Delphi build proizveo ispravne. Primetite i efekat drugog reda: pokretanje nepoverljivih image codec-ova u izolovanom procesu odluka je koja se javlja samo na Delphi buildu, jer Free Pascal build nema in-process nativni dekoder koji bi se sandboksovao
Kompresija: prva linija koju treba promeniti je cmNone
Pre nego što portujete išta drugo, postavite Compression na cmNone. THPDFCompressionMethod nudi tačno dve vrednosti, cmNone i cmFlateDecode, i druga ide pravo u deflate ulazne tačke koje su stubovi u Free Pascal buildu. Prvo proverite osnovni model objekata sa isključenom kompresijom, pa odlučite šta još trebate. To je redosled koji isporučeni smoke test koristi: napravi jednostranični nekompresovan dokument, ponovo ga učita i tvrdi da se broj stranica vratio kao jedan. Nekompresovan izlaz je veći, i i dalje je sasvim validan PDF
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 dospeva do stub-ovanog simbola
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.
Šta se dešava sa paralelnim renderovanjem stranica?
I dalje se kompajlira, i dalje vraća ispravne bitmape, i prestaje biti paralelno. THotPDF.RenderLoadedPagesParallel i THotPDF.RenderLoadedPagesParallelOrdered građeni su na TThread.CreateAnonymousThread sa inline procedure closure-om, koji Free Pascal 3.2.2 ne ume da izrazi, pa Free Pascal grana izvodi determinističku serial rezervu: prelazi indekse stranica redom, poziva RenderLoadedPageToBitmap za svaki i broji uspehe. Oblik API-ja, povratna vrednost i izlazni niz nepromenjeni su, što omogućava jednoj bazi koda da se gradi na oba načina
var
Bitmaps: THPDFBitmapArray;
Info: THPDFParallelRenderPipelineInfo;
Rendered: Integer;
begin
Rendered := Pdf.RenderLoadedPagesParallel([0, 1, 2, 3], 150, 4,
Bitmaps, Info);
// Delphi: Info.WorkerCount je šta god je memorijski budžet dozvolio
// Free Pascal: Info.WorkerCount je uvek 1, stranice po redu indeksa
if Info.WorkerCount = 1 then
LogSerialFallback(Rendered, Info.RequestedWorkerCount);
Rezerva nije tiha, i to je deo vredan dizajniranja oko nje. Ispunjava THPDFParallelRenderPipelineInfo pošteno: PageCount iz zahteva, RequestedWorkerCount odjekujući ono što ste tražili, WorkerCount postavljen na 1, i završeni i isporučeni brojači poklapaju se sa onim što je zaista stiglo. Kod koji već ispituje Info radi dimenzionisanja progresa trake ili memorijskog budžeta i dalje radi i čita istinu umesto pretpostavke. Ako vaš plan propusnosti zavisi od paralelnog render pipeline-a i njegovog backpressure modela, taj plan je Delphi plan; na Free Pascal-u, budžetirajte jednonitni trošak renderovanja stranice u bitmapu pomnožen brojem stranica
Koji biste build zaista isporučili?
Birajte po mogućnosti, ne po sklonosti. Ako je vaš tok rada skupljanje dokumenta, tekst i vektorsko crtanje, popunjavanje formulara, učitavanje i čuvanje, Free Pascal build na Win64 to pokriva, i trebalo bi da proverite sa isključenom kompresijom pre nego što bilo šta uključite. Ako uključuje JPEG ili JPEG 2000 ili TIFF ili JBIG2 slike, ICC transformacije boja, kompresovan izlaz, ili propusnost koja zavisi od mnogih jezgara, ostanite na Delphi ili C++Builder-u za sada. Granicu crtaju object-file ABI i nedostajuća jezička mogućnost, obe vidljive u izvornom kodu umesto zakopane u matrici podrške, i obe padaju sa imenovanom greškom umesto pogrešnim rezultatom
Free Pascal i Lazarus paket stiže u istoj distribuciji kao Delphi i C++Builder unit-i, pa jedna licenca pokriva oba i možete testirati Lazarus put protiv svojih dokumenata pre nego što mu se obavežete; HotPDF Delphi PDF Component stranica proizvoda nosi trenutnu matricu podrške kompajlera i kompletnu API referencu