پاسخ کوتاه به آن تیکت پشتیبانی بله است، با چند محدودیت. HotPDF 2.730.0 روی Free Pascal 3.2.2 و Lazarus 4.6 برای Win64 بیلد میشود و مسیرهای اصلی ساخت و لود و ذخیره کار میکنند. آنچه دنبالش نمیآید هر چیزی است که روی یک آبجکت کدک نیتیو لینکشده ایستا یا روی متدهای بینام Delphi تکیه کند
این پرسش معمولاً به یک شکل میرسد: تیمی برای یک ابزار چندسکویی روی Lazarus استاندارد میشود، یا یک کدبیس Free Pascal به ارث میبرد، و همان کامپوننت PDFای را میخواهد که از قبل برای Delphi لایسنس کرده. پورت کردن یک کتابخانه بالغ Delphi بهندرت مسئله سینتکس است. بخش جالب این است که پورت کجا لو میدهد کتابخانه بیسروصدا به یک زنجیره ابزار چسبیده بوده؛ و در این مورد چسبیدگی در دو جای خیلی خاص نشسته: ABI فایلهای آبجکت کدکهای همراه، و قابلیتهای کامپایلری که پشت یک سیمبل نسخه پنهان شدهاند
آنچه Free Pascal 3.2.2 پیش از کامپایل HPDFDoc لازم دارد
HotPDF زیر Free Pascal فقط در حالت Delphi کامپایل میشود و فقط وقتی که شاخههای یونیت LCL لازاروس روی مسیر جستجو باشند. هیچکدام قابل مذاکره نیست. HotPDF.inc داخل بلاک {$IFDEF FPC} خودش کامپایلر را با {$MODE DELPHI} و {$H+} سوییچ میکند و با یک {$FATAL} هر چیز قدیمیتر را رد میکند وقتی FPC_FULLVERSION زیر 30202 است، پس نصب 3.0.x با سر و صدا شکست میخورد بهجای اینکه یونیت خراب تولید کند. پکیج رانتایم لازاروس HotPDFLaz.lpk باقی را کدگذاری میکند: LCL بهعنوان پکیج الزامی و -Mdelphi بهعنوان یک آپشن سفارشی
الزام LCL کسانی را غافلگیر میکند که فقط خروجی کنسول میخواهند، اما این الزام ساختاری است. HPDFFPCCompat تایپهای VCL دلفی را که Free Pascal معادلی برایشان ندارد تأمین میکند؛ TMetafile و TMetafileCanvas را روی کلاسهای بیتمپ و کنوس LCL نگاشت میکند و TRichEdit را به TMemo مستعاری میکند، و HPDFDoc هم TPNGObject را به Graphics.TPortableNetworkGraphic مستعاری میکند. اینها را شیمهای زمان کامپایل ببینید، نه برابری قابلیت: یک کلاس متافایل با پشتوانه بیتمپ یونیت را در حال کامپایل نگه میدارد، اما رفتار مسیرهای متافایل را مثل Delphi نمیکند. حتی اسموکتست غیر گرافیکی هم Interfaces را درگیر میکند و اسکریپت بیلد -Fu را برای lcl\units\x86_64-win64 و شاخه خروجی lazutils پاس میدهد
چرا D2009+ نمیتواند نقش گیت نسخه را هم بازی کند
وسوسهکننده است که بیلد Free Pascal را یک کامپایلر مدرن بگیرید و سیمبل جدیدترین قابلیت دلفی را ساده تعریف کنید. HotPDF این کار را نمیکند و دلیلش ارزش گفتن صریح دارد: D2009+ فقط یعنی رشتههای یونیکد نیست، گیت یونیتهایی هم هست که API عمومیشان با متدهای بینام بیان شده. Free Pascal 3.2.2 نه متدهای بینام دلفی را پشتیبانی میکند نه آن APIها را، پس قرض گرفتن سیمبل کدی را وارد میکند که اصلاً کامپایل نمیشود. بنابراین بند uses در HPDFDoc دو دنباله شرطی جداگانه حمل میکند و همپوشانی میان آنها عمدی است نه تصادفی
uses
// ...
HPDFJavaScript,
HPDFFormCalcGraph
{$IFDEF FPC}
, HPDFFPCCodecStubs,
HPDFCMS,
HPDFWinCertSigner
{$ENDIF}
{$IFDEF D2009+}
, HPDFXFARuntime,
HPDFCMS,
HPDFWinCertSigner,
HPDFSignVerify,
HPDFSignatureBatch
{$ENDIF};
چرا کدکهای نیتیو در لینکر متوقف میشوند؟
چون آنها آبجکتهای COFF ویندوز ۶۴ بیتی هستند که توسط یک زنجیره ابزار خاص تولید شدهاند و هیچکدام از دو لینکر Free Pascal روی Win64 حاضر به خوردنشان نیست: نه لینکر داخلی، نه مسیر GNU ld خارجی. این یک مشکل ABI فایل آبجکت است نه یک مشکل پاسکال، و هیچ مقدار سورس شرطی آن را درست نمیکند. کتابخانه تنها مسیر صادقانه موجود را برمیدارد. هر دایرکتیو {$L} که یک آبجکت کدک ایستا را وارد میکند در {$IFNDEF FPC} پیچیده شده، پس بیلد Free Pascal آنها را ساده حذف میکند و HPDFFPCCodecStubs بعداً هر سیمبل خارجی گمشده را بهشکل استابی فراهم میکند که بهجای برگشتن استثنا پرتاب میکند
// 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;
آن جدول استاب طولانی است و خواندنش دقیقاً به شما میگوید امروز کدام قابلیتها فقط مخصوص Delphi هستند: نقطههای ورود deflate با zlib-ng و zopfli، فشردهسازی و ازفشردهسازی libjpeg، کدک JPEG 2000 در OpenJPEG، libtiff و مقداردهیهای اولیه به ازای هر فشردهسازیش، انکد و دیکد JBIG2، نقطههای ورود تبدیل رنگ Little-CMS و پریمیتیوهای AES. انتخاب طراحی پشت استابها از خود فهرست مهمتر است. یک سیمبل گمشده در زمان لینک دیواری از ارجاعهای تعریفنشده از یونیتی میدهد که هرگز به آن دست نزدهاید؛ اما استابی که ENotSupportedException پرتاب کند بیلدی میدهد که اجرا میشود، پیامی که دلیل را نام میبرد و استکتریسی که به محل فراخوانی اشاره میکند. یعنی بیلد Free Pascal هرگز جایی که بیلد Delphi بایتهای درست تولید میکرد، بیسروصدا بایت اشتباه تولید نمیکند. اثر مرتبه دوم را هم ببینید: اجرای کدکهای تصویر غیرقابلاعتماد در یک پروسس جدا تصمیمی است که فقط در بیلد Delphi پیش میآید، چون بیلد Free Pascal اصلاً دیکدر نیتیو درونپروسسی برای سندباکس کردن ندارد
فشردهسازی: اولین خطی که باید عوض شود cmNone است
پیش از پورت هر چیز دیگری، Compression را روی cmNone بگذارید. THPDFCompressionMethod دقیقاً دو مقدار دارد، cmNone و cmFlateDecode، و مورد دوم مستقیم به نقطههای ورود deflate میرود که در بیلد Free Pascal استاباند. اول مدل آبجکت اصلی را با فشردهسازی خاموش راستیآزمایی کنید، بعد تصمیم بگیرید چه چیز دیگری لازم دارید. ترتیب کار در اسموکتست همراه محصول همین است: یک سند تکصفحهای فشردهنشده بسازید، دوباره لودش کنید و تأیید کنید شمار صفحهها یک برگشته. خروجی فشردهنشده بزرگتر است و همچنان یک 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 به یک سیمبل استابشده میرسد
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.
با رندر موازی صفحهها چه میشود؟
هنوز کامپایل میشود، هنوز بیتمپهای درست برمیگرداند و دیگر موازی نیست. THotPDF.RenderLoadedPagesParallel و THotPDF.RenderLoadedPagesParallelOrdered روی TThread.CreateAnonymousThread با یک کلوژر procedure درونخطی بنا شدهاند که Free Pascal 3.2.2 نمیتواند بیانش کند، پس شاخه Free Pascal یک فالبک سریال قطعی اجرا میکند: ایندکس صفحهها را به ترتیب میرود، برای هرکدام RenderLoadedPageToBitmap را صدا میزند و موفقیتها را میشمارد. شکل API، مقدار برگشتی و آرایه خروجی تغییری نکردهاند و همین است که اجازه میدهد یک کدبیس واحد هر دو جور بیلد شود
var
Bitmaps: THPDFBitmapArray;
Info: THPDFParallelRenderPipelineInfo;
Rendered: Integer;
begin
Rendered := Pdf.RenderLoadedPagesParallel([0, 1, 2, 3], 150, 4,
Bitmaps, Info);
// Delphi: Info.WorkerCount هر چیزی است که بودجه حافظه اجازه میداد
// Free Pascal: Info.WorkerCount همیشه 1 است، صفحهها به ترتیب ایندکس
if Info.WorkerCount = 1 then
LogSerialFallback(Rendered, Info.RequestedWorkerCount);
فالبک بیسروصدا نیست و همین بخش ارزش طراحی حولش را دارد. THPDFParallelRenderPipelineInfo را صادقانه پر میکند: PageCount از درخواست، RequestedWorkerCount بازتاب همان که خواستهاید، WorkerCount روی 1، و شمارهای completed و delivered همخوان با آنچه واقعاً برگشته. کدی که از قبل Info را برای اندازه گرفتن نوار پیشرفت یا بودجه حافظه بازرسی میکند سر جایش کار میکند و حقیقت را میخواند نه یک فرض را. اگر برنامه توانعبوری شما به پایپلاین رندر موازی و مدل backpressure آن وابسته است، آن برنامه یک برنامه Delphi است؛ روی Free Pascal بودجهتان را برای هزینه تکنخی رندر یک صفحه به بیتمپ ضربدر شمار صفحهها ببندید
عملاً کدام بیلد را عرضه میکنید؟
بر اساس قابلیت انتخاب کنید، نه بر اساس سلیقه. اگر گردش کار شما سرهمبندی سند، متن و رسم برداری، پر کردن فرم، لود و ذخیره است، بیلد Free Pascal روی Win64 آن را پوشش میدهد و بهتر است با فشردهسازی خاموش راستیآزمایی کنید پیش از روشن کردن هر چیز. اگر کارتان تصویر JPEG یا JPEG 2000 یا TIFF یا JBIG2 دارد، تبدیلهای رنگ ICC، خروجی فشرده یا توانعبوری وابسته به هستههای زیاد، فعلاً روی Delphi یا C++Builder بمانید. مرز را یک ABI فایل آبجکت و یک قابلیت زبانی غایب کشیدهاند؛ هر دو در سورس قابل دیدناند تا مدفون در یک ماتریس پشتیبانی، و هر دو با یک خطای نامدار شکست میخورند نه با یک نتیجه غلط
پکیج Free Pascal و Lazarus در همان توزیع یونیتهای Delphi و C++Builder عرضه میشود، پس یک لایسنس هر دو را پوشش میدهد و میتوانید مسیر لازاروس را روی اسناد خودتان آزمایش کنید پیش از متعهد شدن به آن؛ صفحه محصول HotPDF Delphi PDF Component ماتریس پشتیبانی کامپایلر بهروز و مرجع کامل API را دارد