PDF مفهومی به نام فونت متغیر ندارد. فونتی که در یک فایل PDF تعبیه شده، مجموعهای ثابت از طرحکلیها با متریکهای ثابت است، بنابراین یک فونت متغیر باید پیش از قرارگرفتن در سند، به یک نمونه ایستا (static instance) کاهش یابد. HotPDF این نمونهسازی را بهصورت درونی انجام میدهد: شما محورهای یک فونت متغیر را بررسی میکنید، مختصاتی مانند وزن ۶۲۰ یا عرض ۸۷.۵ را انتخاب میکنید، و کتابخانه آن مقادیر را در یک برنامه فونت کامل و خودکفا جای میدهد که هر خواننده PDF منطبق با استاندارد میتواند آن را رندر کند
دلیل اهمیت این موضوع عملی است نه نظری. ریختهگریهای فونت (type foundries) بهطور فزاینده بهجای دهها وزن ایستا، یک فایل متغیر واحد عرضه میکنند، و تیمهای طراحی مقادیری را انتخاب میکنند که هیچ نمونه نامگذاریشدهای آنها را ارائه نمیدهد. بدون نمونهسازی، یک موتور تولید گزارش یا به نمونه پیشفرض بازمیگردد، که تصمیم طراحی را دور میریزد، یا کل فونت متغیر را تعبیه میکند و امیدوار است نمایشگر مختصات محوریای را که هیچ راهی برای دانستن آنها ندارد رعایت کند، کاری که هیچ خوانندهای ملزم به انجام آن نیست
نمونهسازی واقعاً چه چیزی را باید بازسازی کند؟
یک فونت متغیر OpenType به ازای هر گلیف یک طرحکلی پیشفرض بهعلاوه مجموعهای از دلتاها که بر اساس موقعیت در فضای طراحی نمایهگذاری شدهاند، ذخیره میکند. اعمال یک مختصات محوری صرفاً نوشتن یک عدد در یک سربرگ نیست؛ بهمعنای پیمایش جدول gvar، درونیابی دلتاها برای موقعیت درخواستی، جابهجایی نقاط، و سپس محاسبه دوباره هر چیزی است که از آن نقاط استخراج شده بود. HotPDF طرحکلی گلیفها، جدول بلند loca، متریکهای کامل افقی و عمودی، کادر مرزی سراسری فونت و تعدیل جمعبررسی (checksum) sfnt را بازسازی میکند
به همان اندازه، آنچه حذف میشود اهمیت دارد. یک نمونه ایستا نباید fvar، avar، gvar، HVAR، VVAR، MVAR، STAT یا cvar را نگه دارد، و یک DSIG منسوخ نیز باید حذف شود، زیرا بایتهای امضاشده دیگر وجود ندارند. باقیگذاشتن هر یک از اینها فونتی تولید میکند که ادعا میکند متغیر است درحالیکه طرحکلیهایی را حمل میکند که از قبل جابهجا شدهاند، و خوانندههایی که تنوعات را واقعاً اعمال میکنند، آنها را برای بار دوم اعمال خواهند کرد
نقاط شبح (phantom points) و دام اعمال دوباره
ظریفترین قاعده در کل این فرایند مربوط به متریکهاست. در gvar، تعداد نقاط برای یک گلیف شامل نقاط طرحکلی، یا نقاط مؤلفه برای یک گلیف ترکیبی، بهعلاوه چهار نقطه شبح است که فاصله سمت چپ (left side bearing)، عرض پیشروی (advance width) و معادلهای عمودی آنها را رمزگذاری میکنند. این نقاط شبح خودشان نیز مشمول دلتا هستند
بنابراین وقتی فونتی جدول gvar دارد، HotPDF متریکهای افقی و عمودی را از نقاط شبح درونیابیشده استخراج میکند و HVAR یا VVAR را اضافهتر اعمال نمیکند. اعمال هر دو خطای کلاسیک است: همان تنوع دو بار اعمال میشود و هر عرض پیشروی کمی بیش از حد پهن درمیآید، که بهصورت متنی که بهتدریج در طول یک خط تراز-شده به راست منحرف میشود، ظاهر میشود. فقط هنگامی که فونتی gvar ندارد، کتابخانه مخزن تنوع متریک را مستقیماً در hmtx یا vmtx جای میدهد
دو جزئیات دیگر هندسه را درست نگه میدارند. نقاط شبح هرگز در درونیابی کانتور شرکت نمیکنند، بنابراین نقاطی که برای یک گلیف ساده صراحتاً فهرست نشدهاند با IUP به ازای هر کانتور استنتاج میشوند، درحالیکه نقاط شبح از آن مستثنا هستند. و گلیفهای ترکیبی دلتاهای خود را روی افستهای مؤلفهای که از پارامترهای XY استفاده میکنند اعمال میکنند، که پس از آن کرانهای فرزند بهصورت بازگشتی دوباره محاسبه میشوند. این بازگشت از نظر عمق محدود است و از نظر چرخه بررسی میشود، زیرا در غیر این صورت یک گراف مؤلفه خصمانه یا صرفاً خراب میتواند بیپایان بازگشت کند
بازرسی فضای طراحی پیش از انتخاب
اولین فراخوانی در هر جریانکار نمونهسازی، InspectVariableFont است، که محورها و نمونههای نامگذاریشدهای را که ریختهگری تعریف کرده گزارش میدهد. رکوردهای محور برچسب چهاربایتی، مقادیر کمینه، پیشفرض و بیشینه، پرچمها و یک شناسه نام را حمل میکنند؛ نمونههای نامگذاریشده یک شناسه نام زیرخانواده، پرچمها، یک شناسه نام PostScript اختیاری و یک مختصات به ازای هر محور را حمل میکنند:
var
Pdf: THotPDF;
Axes: THPDFVariableFontAxisArray;
Instances: THPDFVariableFontNamedInstanceArray;
I: Integer;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.InspectVariableFont('C:\Fonts\Inter.ttf', Axes, Instances) then
begin
for I := 0 to High(Axes) do
Writeln(Format('%s min=%.1f default=%.1f max=%.1f',
[string(Axes[I].Tag), Axes[I].MinimumValue,
Axes[I].DefaultValue, Axes[I].MaximumValue]));
Writeln(Format('%d named instance(s) defined', [Length(Instances)]));
end
else
Writeln('not a variable font - embed it as an ordinary TrueType face');
finally
Pdf.Free;
end;
end;
گزارشکردن دامنه محور اهمیت دارد زیرا مقادیر محور به دامنهای که فونت اعلام میکند محدود میشوند، نه به دامنهای که رابط کاربری شما ارائه میدهد. لغزندهای (slider) که به کاربر اجازه میدهد وزن ۱۰۰۰ را روی فونتی درخواست کند که محور wght آن در ۹۰۰ متوقف میشود، باید در رابط کاربری اصلاح شود، نه بهطور خاموش در لایه فونت، وگرنه خروجی چاپشده با پیشنمایش مغایرت خواهد داشت
انتخاب مختصات و تولید سند
انتخاب محور حالتمند (stateful) است و روی فونتهایی که پس از آن ثبت میشوند اعمال میشود. SetVariableFontAxis یک برچسب ASCII چاپپذیر چهاربایتی و یک مقدار متناهی میگیرد، و هر چیز دیگری را بهجای نادیدهگرفتن خاموش، با یک استثنا رد میکند. ClearVariableFontAxes انتخاب را بازنشانی میکند، و GetVariableFontAxisSelections آنچه را که در حال حاضر معلق است گزارش میدهد، که ثبت آن در موتورهای گزارشسازی که چندین مسیر کد ممکن است به یک شیء سند واحد دست زده باشند، ارزشمند است. خودِ خانواده فونت از طریق SetFont با نام انتخاب میشود، دقیقاً همانطور که هر چهره TrueType تعبیهشده دیگری انتخاب میشود:
begin
Pdf := THotPDF.Create(nil);
try
Pdf.BeginDoc;
Pdf.SetVariableFontAxis('wght', 620); // نیمهضخیم، نه یک نمونه نامگذاریشده
Pdf.SetVariableFontAxis('wdth', 87.5); // اندکی فشرده
Pdf.CurrentPage.SetFont('Inter', [], 11);
Pdf.CurrentPage.TextOut(72, 720, 0, 'Quarterly results');
Pdf.ClearVariableFontAxes; // بازگشت به نمونه پیشفرض
Pdf.CurrentPage.SetFont('Inter', [], 10);
Pdf.CurrentPage.TextOut(72, 700, 0, 'Prepared by the finance team');
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
رویداد OnVariableFontInstance هنگام تولید هر نمونه فعال میشود و مقادیر محوری را که استفاده شدهاند گزارش میدهد، که ارزانترین راه برای اثبات در یک لاگ است که یک PDF مشخص واقعاً چه چیزی دارد. از آنجا که هر مجموعه مختصات متمایز، یک برنامه فونت متمایز تولید میکند، انتخابهای محور را بخشی از کلید کش فونت خود در نظر بگیرید؛ مکانیزمهای کشکردن در کش پایدار زیرمجموعه فونت شرح داده شدهاند
نمونهسازی چگونه با زیرمجموعهسازی و شکلدهی تعامل میکند؟
نمونهسازی پیش از زیرمجموعهسازی اجرا میشود، و این ترتیب درست است. فونت نمونهسازیشده یک چهره TrueType ایستای معمولی است، بنابراین زیرمجموعهساز عادی آن را مانند هر چهره دیگری در نظر میگیرد: بستار گلیف (glyph closure) را محاسبه میکند، گلیفهایی را که سند واقعاً استفاده میکند نگه میدارد و بقیه را کنار میگذارد. نکتهای که باید مراقب آن بود این است که دو انتخاب محوری متفاوت از یک خانواده، دو برنامه فونت متفاوت هستند، بنابراین سندی که وزن ۴۰۰ و وزن ۶۲۰ را ترکیب میکند، دو زیرمجموعه تعبیه میکند، نه یک چهره مشترک با دو نمونه
شکلدهی از نظر اصولی تحتتأثیر قرار نمیگیرد اما در عمل ارزش بررسی دارد. ویژگیهای چیدمان در GSUB و GPOS قرار دارند، که نمونهسازی آنها را حفظ میکند، بنابراین لیگاچرها و جایگزینهای سبکی همچنان همانطور که در جایگزینهای سبکی OpenType GSUB شرح داده شده کار میکنند. آنچه تغییر میکند چیدمان است: یک نمونه فشرده پیشرویهای باریکتری نسبت به نمونه پیشفرض دارد، بنابراین هر چیدمانی که متن را پیش از نمونهسازی اندازهگیری کرده باشد، عرضهای نادرستی را اندازهگیری کرده است. با همان انتخاب محوری که با آن رندر خواهید کرد اندازهگیری کنید، و مغایرت از بین میرود
یک نکته دفاعی آخر از پیادهسازی، که برای هرکسی که این مسیر را گسترش میدهد مفید است. فونتهایی که متریک عمودی ندارند همچنان آرگومانهای آرایه پویا را در محل فراخوانی دلفی ارزیابی میکنند، بنابراین آرایههای زمان تجزیه (parse-time) همیشه تخصیص مییابند، بهجای تکیهکردن بر یک بررسی HasVerticalMetrics برای عبور کوتاه از یک اندیس خالی. این نوع جزئیات در سطح زبان است که یک شاخه ظاهراً محافظتشده را دقیقاً روی همان فونتهایی که با آنها آزمایش نکردهاید، به یک نقض دسترسی (access violation) تبدیل میکند
پشتیبانی از فونت متغیر در همان خطلوله فونتی جای میگیرد که تعبیه، زیرمجموعهسازی و بستار گلیف در آن قرار دارند، که با جزئیات بیشتر در بستار زیرمجموعه فونت و گلیفهای شکلیافته شرح داده شده. مجموعه کامل ویژگیهای تایپوگرافی برای دلفی و C++Builder در صفحه مؤلفه HotPDF PDF برای دلفی فهرست شده