Bir PDF bir fontu gömmediğinde HotPDF componenti o metni, HPDFMapBaseFontToSystemin seçtiği kurulu bir Windows fontuyla render eder: metot /BaseFont adını çözer, stil kısmını soyar, GDI ailenin kurulu olduğunu doğrulayana dek birkaç yazımı dener, eksik standart 14 genişliklerini metrik uyumlu fontlardan ölçer ve çizmeden önce tek baytlık kodları Unicodea çevirir. O adımların her biri, naif sürümün gerçek dosyalarda başarısız olması yüzünden var. RenderLoadedPageToBitmap sayfa rendererı gömülü programları iyi işler; bu, dosyada hiç olmayan fontların hikâyesidir
GDI gömülü olmayan bir font için yanlış yüzü neden sessizce çizer?
GDI asla eksik font bildirmez: CreateFontIndirecte tanımadığı bir aile adı verirseniz sessizce bir yedek seçer; çoğu zaman bold ağırlığı olmayan başka bir serif. İlk renderer PDF adını neredeyse aynen geçiriyordu; TimesNewRoman,Bold, TimesNewRomanPS-BoldMT ve SegoeUI-Semibold hiçbir şeyle eşleşmiyor ve GDInin seçtiği her ne ise öyle çıkıyordu. Adlar bundan da kötü olabilir. ISO 32000-1 §7.3.5 bir adın herhangi bir baytı #xx olarak yazmasına izin verir ve CJK üreticileri font adlarını rutin olarak kaçırılmış UTF-8 ya da eski kod sayfası baytlarıyla yazar; v2.766.69dan önce kaçış dizilerinin kendisi aile adı oluveriyordu. HPDFMapBaseFontToSystem artık önce kaçışları çözer, geçerli bir UTF-8 bayt dizisini karakterleri olarak döndürür ve kalan yüksek baytları sistem kod sayfasında okur
Stili kesmek, sezgisel kuralların sahaya indiği yerdir. Virgül her zaman aileyi bitirir (Arial,Bold Arial verir); tire ise yalnızca ardından gelen kelime bir stilse bitirir: Bold, Italic, Oblique, Regular, Roman, Medium, Light, Black, Heavy, Semi, Demi, Thin, Extra, Ultra ya da Condensed. O kural MS-Minchoyu bütün tutarken Calibri-Lightı Calibriye çevirir. HotPDF sonra ailenin yazımlarını dener; ardından PSMT, MT ya da PS eki soyulmuş yazımlarını dener. v2.768.18den beri o yazımlar, bir kelimenin başlayabileceği her noktadaki her boşluk seçeneğini kapsar: küçük harfi izleyen büyük harften önce (MyriadPro Myriad Pro olur), küçük harfin izlediği bir koşunun son büyük harfinde (UIGothic) ve baştaki bir MSden sonra (MSPGothic); tam boşluklu biçimden adın yazıldığı hâle kadar. Böyle dört noktadan sonra yalnızca tam boşluklu ve bitişik ad denenir. Boşluk körlemesine uygulanamaz, çünkü Windows bazı kelimeleri bitişik tutar: SimSun tam olarak o yazımla kuruludur; MicrosoftYaHei, MicrosoftJhengHei ve MSPGothic ise Microsoft YaHei, Microsoft JhengHei ve MS PGothica aittir. v2.768.18den önce mapper her iç büyük harften önce boşluk koyuyordu; MicrosoftYaHei Microsoft Ya Hei diye aranıyor ve hiç bulunamıyordu. Bir aday, CreateFontIndirectin ardından GetTextFacein istenen adı döndürmesiyle ya da — v2.768.18den beri — seçilen fontun name tablosunun onu herhangi bir dilde aile, tam aile ya da tipografik aile adı olarak listelemesiyle kurulu sayılır; cevap ad başına cache edilir, böylece kurulu olmayan çok fontlu belgeler artık her sayfada her ad için Windowsa sormuyor
Eşleme fonksiyonu HPDFRenderFontMetrics ünitesinde public olduğu için bir preflight raporu, her gömülü olmayan fontun hangi kurulu aileyle render edileceğini gösterebilir; THotPDFin yüklenmiş belgeler için çoktan açtığı font numaralandırmasını kullanarak:
uses
HPDFDoc, HPDFRenderFontMetrics;
procedure ListSystemFontMappings(Pdf: THotPDF; Log: TStrings);
var
Page, I: Integer;
Info: THPDFLoadedFontInfo;
begin
for Page := 0 to Pdf.LoadedPageCount - 1 do
for I := 0 to Pdf.GetLoadedFontCount(Page) - 1 do
if Pdf.GetLoadedFontInfo(Page, I, Info) and not Info.IsEmbedded then
Log.Add(Format('page %d /%s %s -> %s',
[Page + 1, string(Info.ResourceName), string(Info.FontName),
HPDFMapBaseFontToSystem(Info.FontName)]));
end;
HotPDF /Widthssi olmayan standart 14 fontlarını nasıl ölçer?
HotPDF eksik advanceleri aynı metrikli kurulu font üzerinde ölçer, çünkü ISO 32000-1 §9.6.2.2 standart 14 fontun /Widths atlamasına izin verir ve kütüphane AFM tablosu taşımaz. Arial Helvetica metriklerini taşır, Times New Roman Timesı, Courier New Courieri; HPDFMeasureBaseFontWidths eşleşen yüzü lfHeight = -1000de kurup GetCharWidth32W çağırır; o yükseklikte sonuç, PDF genişliklerinin kullandığı 1/1000 em birimlerindedir zaten. Renderer önce her kodu /Encoding, /BaseEncoding ve /Differences üzerinden, StandardEncoding varsayılanıyla Unicodea çevirir. SVG exportu ve metin çıkarması bir tuzağa daha çarpar: hiç /Encodingi olmayan standart bir Type 1 font, encoding bilgisi olmayan bir decoder üretiyordu; SVG export onu asla kaydetmiyor ve ölçülen her genişlik kullanılmıyordu. Kapalı StandardEncodingi sağlamak düzeltti, yeter ki önceden tanımlı encoding olarak işaretlensin; onu CMap-ad yoluna sokmak her kodu 0 olarak çözer ve her genişlik ona uyar
Bold, italic ve font descriptor bayraklarındaki bir kayma
Bir font descriptorın /Flags girdisi bitlerini 0dan değil 1den numaralar; yani ISO 32000-1 Tablo 123e göre ForceBold bit 19 ($40000), Italic bit 7 ($40)dir. Eski kod $20000yi test ediyordu; o bit 18, SmallCap. Hata v2.345.0dan v2.766.53e hayatta kaldı, çünkü /FontDescriptor neredeyse her zaman dolaylı bir referanstı ve font kurucusu yalnızca doğrudan objeleri okuyordu; bayrak kolunun tamamı hiç çalışmıyordu ve aynı körlük /Widths 12 0 Ri de yok sayıp metni 500 birimlik yedek advance ile diziyordu. v2.766.53 dolaylı referansları renderer üzerinden çözmeye başlayınca bit aynı değişiklikte düzeltilmek zorundaydı; yoksa her small-caps yüzü bir anda bold render olurdu:
const
// ISO 32000-1 Tablo 123 bit konumlarını 1den sayar
FD_ITALIC = $00040; // bit 7
FD_SMALLCAP = $20000; // bit 18, bir ağırlık değil
FD_FORCEBOLD = $40000; // bit 19
procedure ApplyDescriptorFlags(Flags: Integer; var LF: TLogFont);
begin
if (Flags and FD_FORCEBOLD) <> 0 then
LF.lfWeight := FW_BOLD;
if (Flags and FD_ITALIC) <> 0 then
LF.lfItalic := 1;
end;
UCS2 CMapli CJK fontları neden yanlış genişlikler alır?
Önceden tanımlı UCS2 CMapli CJK metni, bir renderer kodu CID olarak işlediğinde doğru glyphleri yanlış aralıklarla çizer, çünkü /W karakter koduna değil CIDe göre indekslenir. STSong-Light ve UniGB-UCS2-H ile kod tesadüfen Unicode değerine eşittir; GDI doğru karakterleri çizer ve hata advancelerde saklanır: küçük harfler 97 ve üzeri kodlar olarak gelir, [1 95 500] gibi bir /W girdisinin dışında kalır ve hepsi 1000lik varsayılan /DWyi alır. v2.766.56dan beri HotPDF rendererı kodları CMap codespace aralıkları üzerinden (ISO 32000-1 §9.7.6.2) okur ve genişliklere bakmadan önce CIDLere eşler. Yalnızca gömülü UCS2 ve UTF16 tabloları ile gömülü CMap streamleri kullanılır; GBK-EUC-H gibi bir şey için kimlik yaklaşıklığı destekleniyor gibi görünürken yanlış çıktı üretirdi, renderer da rol yapmaz
Aksanlı karakterler Çince Windowsta neden soru işaretine dönüşür?
Tek baytlık kodlar asla ANSI ("A") GDI fonksiyonlarına ulaşmamalı, çünkü GetGlyphOutlineA ve GetGlyphIndicesA baytları sistem kod sayfasında yorumlarken TextOutA seçili fontun karakter setini kullanır. Çince bir sistemde Arialın $A9 baytı (Windows-1252deki telif işareti) GBK lead baytı oldu ve "?" olarak render edildi; v2.766.83ün eklediği unhinted outline yolu düz içine yürüdü. v2.767.3, gerçekleşen fonta GetTextCharsetle karakter setini soruyor, onu TranslateCharsetInfo ile kod sayfasına çeviriyor, baytı MultiByteToWideChardan geçirip W fonksiyonlarını çağırıyor; symbol fontlar bunun yerine U+F000 artı kodu kullanıyor. Windows-1252yle anlaşamayan encodingler — /Differences, StandardEncoding, MacRomanEncoding — herhangi bir sistem fontu göremeden Unicodea eşlenir
Sistem fontlarıyla çizmenin sınırları nelerdir?
Sistem fontuyla render bir yaklaşımdır ve HotPDF componenti nerede durduğunu dürüstçe söyler. v2.768.18den önce kurulu kontrolü yalnızca GetTextFacein döndürdüğü adla karşılaştırıyordu; yerelleştirilmiş Windowsda o fonksiyon aile adını sistem dilinde bildirir, böylece Çince Windowsda Microsoft YaHei ya da Japonca Windowsda Yu Mincho eksik yargılanıp bir GDI yedeğiyle çiziliyordu; v2.768.18den beri başka adla geri gelen bir yüz de fontun name tablosunda aranır ve bu fontlar bulunur. Metrik uyumluluk yalnızca Helvetica, Times ve Courier aileleri için garanti edilir; Symbol Symbola, ZapfDingbats Wingdingsa eşlenir; bu bir eşleşme değil, geçici bir köprüdür. Yukarıdaki preflight ayrıca yalnızca her sayfanın /Resources sözlüğündeki fontları görür; form XObjectlerin içinden referans verilenleri görmez. Bir kod hâlâ çizilemiyorsa çizim zamanı çözülemeyen glyph takibi bildirir; thumbnail göz kararından iyidir
Kalıcı çözüm yazım tarafındadır. HotPDFin kendisi varsayılan olarak FontEmbedding True ile yazar; kod SetFontu Helvetica ile çağırsa bile gömülü bir Arial yedekler ve gömülü metin, yukarıdaki kumarın hiçbirinden geçmeden gömülü font glyph rendererından gider. Gelen dosyalar için ucuz bir koruma, eşlenen aile ekran fontu listesinde yoksa renderden önce uyarmaktır:
// VCL: Screen.Fonts kurulu aile adlarını listeler (Forms uniti)
function MissingSystemFamily(const BaseFont: AnsiString): Boolean;
begin
Result := Screen.Fonts.IndexOf(HPDFMapBaseFontToSystem(BaseFont)) < 0;
end;
Sayfa renderi, metin çıkarma ve yazım tarafında font subsetting dahil bütün component için HotPDF Delphi PDF component ürün sayfasına bakın