Bir tasarımcı başlıklar için tek katlı a içeren bir yazı tipi, tablolar için kesik sıfır ya da bir kapak için swash büyük harfler seçer. Bu glyphler zaten yazı tipinin içindedir. Yalnızca varsayılan değillerdir. Varsayılan a, karakterden cmap tablosu aracılığıyla bir glyph'e eşlenir; alternatif ise yalnızca bir ikame kuralıyla erişilebilen birkaç glyph kimliği uzağında oturur. Bu alternatifi bir PDF'de üretmek; kuralı okumak ve içerik akışında yedek glyph'i yaymak anlamına gelir. Bu makale, bu kuralları, tek-ikame türünü, altında yerel bir şekillendirme kütüphanesi olmaksızın Object Pascal'da okumakla ilgilidir
Kapsam kasıtlı olarak dardır. Stilistik setler ve alternatifler, tek-glyph-giriş, tek-glyph-çıkış ikamesidir. Bunlar, OpenType düzeninin küçük ve belirleyici bir tablo yürüyüşüyle çözebileceğiniz kısmıdır; bu da C bağımlılıklarından uzak kalmak isteyen bir Pascal motoru için iyi bir seçimdir
Neden HarfBuzz yerine saf Delphi
HarfBuzz, "bu metni şekillendir" sorusunun açık yanıtıdır ve tam çift yönlü, Hintçe veya Arapça şekillendirme için doğru yanıttır. Aynı zamanda bir C kütüphanesidir. Onu bir Delphi veya C++Builder ürününe bağlamak; her hedef platform ve mimari için yerel bir nesne göndermek, çağrı kuralını eşleştirmek, sürüm temposunu takip etmek ve kendi lisans koşullarınıza karşı lisans koşullarını okumak anlamına gelir. Bunların hiçbiri tek başına zor değildir. Tamamı asla gitmeyen bir sürtünmedir ve gerçek gereksinim "bu harfin ss01 formu" olduğunda hiçbir şey satın almaz
Tek ikame bir şekillendirme motoru gerektirmez. Bir avuç GSUB alt tablo formatı ve bir veya iki ikili arama için ayrıştırıcı gerektirir. Bunu Pascal'da yazmak araç zincirinin tamamını tek bir derleyici içinde tutar. Dürüst sınır, bu yaklaşımın yalnızca glyph ikamesi aramalarını yönetmesidir. Bu, çift yönlü çözümleme değildir; Hintçe yeniden sıralama değildir ve otomatik bağlamsal şekillendirme değildir. Bunlara ihtiyaç duyulduğu yerde ihtiyaç duyulur ve tek-ikame sorgusu onlar için geçmez
Üstten alta GSUB hiyerarşisi
Glyph Substitution tablosu bir yönlendirme zinciri olarak düzenlenmiştir ve bir ikame sorgusu zinciri üstten yürür. En üstte ScriptList bulunur. latn gibi bir betik etiketi bir girdiyi seçer ve özel etiket DFLT, daha belirli bir betik eşleşmediğinde geçerli olan varsayılan betiktir. Betik girdisi, ortak durum için varsayılan LangSys ve farklı davranış gerektiren diller için isteğe bağlı adlandırılmış olanlarla birlikte bir LangSys'e, dil sistemine işaret eder. Türkçe, noktalı ve noktasız i'nin kendi işlemlerini gerektirdiği olağan örnektir
LangSys bir dizi özellik dizini adlandırır. Her dizin, aralarında ss01 bulunan dört baytlık bir etiket ve bir arama dizini listesi taşıyan bir özellik kaydına sahip FeatureList'e işaret eder. Bu dizinler son olarak gerçek ikame alt tablolarının bulunduğu LookupList'e işaret eder. Dolayısıyla ss01'i çözmek demek: betiği bulun, LangSys'ini bulun, etiketi ss01 olan özelliği bulun, adlandırdığı aramaları toplayın ve uygulayın. HotPDF varsayılan olarak DFLT betiğini ve varsayılan LangSys'i kullanır; bu, Latin metin tasarımlarının büyük çoğunluğunun gönderdiği şeydir ve özelliklerini belirli bir betik altında bağlayan bir yazı tipi olduğunda betik etiketini geçersiz kılmak için bir yol sunar
Kapsam tabloları kimin katılacağına karar verir
Her ikame alt tablosu aynı soruyla başlar: bu giriş glyph bu kurala katılıyor mu ve katılıyorsa, kuralın kendi dizinlemesinde nerede oturuyor? Bu soruya bir Coverage tablosu yanıt verir ve yanıt, alt tablonun geri kalanının glyphin ne olacağını aramak için kullandığı küçük bir sıra olan kapsam dizinidir
Kapsam iki formatta gelir. Format 1, artan sıraya göre sıralanmış glyph kimliklerinin listesidir. İkili aramayla bir glyph bulursunuz ve listedeki konumu kapsam dizinidir. Format 2, her biri bir başlangıç glyph'i, bir bitiş glyph'i ve başlangıç glyph'inin eşlendiği kapsam dizininden oluşan aralık kayıtlarının listesidir. Bir aralık içindeki glyph, kapsam dizinini aralığın başından ofset ederek alır. Format 1, katılan glyphler dağılmış olduğunda kompakttır; Format 2 ise bitişik dizilere düştüklerinde. Her ikisi de sıralandığından her ikisi de logaritmik zamanda aranır ve her ikisi de motorun glyph'i yalnız bırakmasına izin veren temiz bir "kapsam dışı" veya bir kapsam dizini döndürür
Tek İkame, iki format
Tek İkame, LookupType 1'dir ve tam olarak bir yedekle bir glyph eşler. İki formatı da vardır ve bölme bir alan optimizasyonudur. Format 1 tek bir işaretli delta depolar. Çıkış glyph kimliği, giriş glyph kimliği artı bu delta, modulo 65536'dır. Bu, bir yazı tipinin her katılan glyphin kendi alternatifinden aynı sabit ofsette oturduğu bir ikameyi kodlama biçimidir; örneğin eşleşen oldstyle rakamlarından sabit bir mesafeye yerleştirilen lining rakamlar bloğu. Coverage tablosu hangi glyphlerin uygun olduğunu söyler ve tek delta hepsine hizmet eder
Format 2, açık yedek glyph kimliklerinin bir dizisini depolar. Coverage tablosundaki kapsam dizini, bu diziye dizindir; bu nedenle kapsam dizini 0'daki glyph ilk dizi girdisine dönüşür, kapsam dizini 1 ikincisine ve böyle devam eder. Format 2, alternatiflerin tekdüze bir ofsette olmadığı durumlarda kullanılır; bu, elle oluşturulmuş stilistik setler için yaygın durumdur. Sorgu, her iki durumda da çağrı tarafından aynıdır. Giriş glyphini alın, Coverage'dan geçirin ve kapsanıyorsa deltayı uygulayın veya dizi yuvasını okuyun
var
Pdf: THotPDF;
BaseGID, AltGID: Word;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.BeginDoc;
Pdf.RegisterUnicodeTTF('C:\Fonts\MyStylisticFace.ttf');
Pdf.SetFont('My Stylistic Face', 12, []);
// Default glyph for 'a' through the font's cmap.
BaseGID := Pdf.GetUnicodeGlyphForCodepoint(Ord('a'));
// Stylistic Set 1: resolve the alternate via GSUB LookupType 1.
AltGID := Pdf.GetSingleSubstituteGlyph(BaseGID, 'ss01');
// AltGID = BaseGID means the feature did not touch this glyph.
if AltGID <> BaseGID then
{ emit AltGID in the content stream };
finally
Pdf.Free;
end;
end;
Dikkat edilmesi gereken sözleşme, geçiş mekanizmasıdır. GetSingleSubstituteGlyph, her ıskada giriş glyph kimliğini değiştirmeden döndürür: yazı tipi yok, GSUB tablosu yok, eşleşen özellik yok, kapsam isabeti yok. Bu, çağrının koşulsuz yapılmasının güvenli olduğu anlamına gelir. Alternatifi sorun; yoksa tam olarak koyduğunuzu geri alırsınız; bu nedenle çağıran kod, özelliği olmayan bir yazı tipini hiçbir zaman özel durumlandırmak zorunda kalmaz
Stilistik özellik etiketleri ne anlama gelir
Özellik etiketi, hangi alternatifi istediğinizin tüm sözlüğüdür ve stilistik çalışmayla ilgili etiketler kısa bir listedir. Başlık çifti salt, stilistik alternatifler, bir glyphin alternatif formlarına kapsamlı erişim, ve ss01'den ss20'ye; bir yazı tipinin tanımlayabileceği yirmi numaralı stilistik set, her biri tasarımcının bir araya gruplandırdığı adlandırılmış ikame paketidir. Bir yazı tipi, örneğin tek katlı a ve düz bacaklı R'yi ss03 altına koyabilir; bu nedenle o seti etkinleştirmek her ikisini de yeniden biçimlendirir
Bunların etrafında birkaç tek-ikame etiketi daha bulunur. aalt, bir glyphin sahip olduğu her alternatifin birleşimi olan tüm-alternatifler-erişimi, genellikle glyph paleti özelliği olarak sunulur. titl, büyük boyutlar için kesilen başlık büyük harflerini seçer. subs ve sups, küçültülmüş varsayılanlar yerine gerçek alt simge ve üst simge rakamları takar. ordn sıra formları, 1. ve 2.'deki yükseltilmiş harfleri üretir. frac kesirleri oluşturur; ancak tam çapraz kesirler aynı zamanda düz tek ikame ötesine geçen bağlaçsal ve bağlamsal mantığa da yaslanır. Tek-glyph durumları için mekanizma ss01 ile aynıdır: etiketi ikame sorgusuna geçirin ve alternatif glyph'i geri okuyun
// Try a stylistic-set feature, then fall back to plain alternates.
function ResolveAlternate(Pdf: THotPDF; BaseGID: Word;
const PreferredTag: AnsiString): Word;
begin
Result := Pdf.GetSingleSubstituteGlyph(BaseGID, PreferredTag);
if Result = BaseGID then
Result := Pdf.GetSingleSubstituteGlyph(BaseGID, 'salt');
// Still BaseGID if neither feature covers this glyph.
end;
cmap format 12 ve tamamlayıcı düzlemler
Herhangi bir ikame çalışmadan önce bir karakterin glyph haline gelmesi gerekir ve bu cmap tablosunun işidir. İkame sorgusu bir glyph kimliğinden başlar; bu nedenle yol her zaman cmap aracılığıyla karakterden glyph'e, ardından GSUB aracılığıyla glyph'ten alternatife gider. cmap'in ilginç kısmı erişimidir. Format 4 alt tablosu Temel Çok Dilli Düzlemi; ilk 65536 kod noktasını kapsar ve bu çoğu Latin metni için yeterlidir. U+10000 ve sonrasındaki kod noktaları için yeterli değildir; matematiksel alfanümerikler, birçok simge ve birkaç yaşayan betiğin artık bulunduğu tamamlayıcı düzlemler
Format 12, tam U+0000'dan U+10FFFF aralığını kapsayan alt tablodur. Her grubu bir başlangıç kod noktası, bir bitiş kod noktası ve bir başlangıç glyph kimliğinden oluşan sıralanmış grup listesidir; bu nedenle bitişik bir kod noktası dizisi bitişik bir glyph dizisiyle eşlenir. HotPDF, verilerin şekillendirilme biçimiyle eşleşen karma bir stratejiyle kod noktalarını çözer. BMP'deki kod noktaları, tek bir aramayla kod noktasına göre dizinlenen doğrudan bir diziden sunulur. Tamamlayıcı düzlemlerdeki kod noktaları, kod noktasına göre sıralanan ve ikili aramayla aranan seyrek bir tablodan sunulur. Sonuç olarak GetUnicodeGlyphForCodepoint, tam bir Cardinal alır ve tüm aralıkta doğru şekilde yanıt verir; yazı tipinin eşlemediği herhangi bir kod noktası için glyph kimliği 0 olan .notdef glyph'ini döndürür
var
Pdf: THotPDF;
Cp: Cardinal;
GID, StyledGID: Word;
begin
// A supplementary-plane code point: U+1D49C MATHEMATICAL SCRIPT CAPITAL A.
Cp := $1D49C;
GID := Pdf.GetUnicodeGlyphForCodepoint(Cp); // format 12 lookup
if GID <> 0 then
StyledGID := Pdf.GetSingleSubstituteGlyph(GID, 'ss01')
else
StyledGID := 0; // font has no glyph for this code point
end;
Bu sorguların sona erdiği yer
Tek-ikame API'leri bir soru şeklini yanıtlar ve yanıtlamadıklarının net olması önemlidir. LookupType 1, sekiz ikame türünden biridir. Sorgu, bir glyphin birden fazla glyph'e dönüştüğü LookupType 2 çoklu ikameyi işlemez; birkaç glyphin tek bir glyph'e dönüştüğü LookupType 4 bağlaç ikamesini de işlemez. Yalnızca belirli bir komşulukta bir glyph göründüğünde tetiklenen bağlamsal ve zincirleme-bağlamsal türleri, LookupTypes 5 ve 6'yı veya uzantı ve ters-zincirleme türlerini işlemez. Çapraz bir kesir, Devanagari bileşik harf veya Arapça başlangıç-orta-son kaskadı bir sıra sorunudur ve glyph başına tek-ikame araması onu ifade edemez
Ayrıca otomatik şekillendirme yapmaz. Buradaki hiçbir şey bir metin dizisini incelemez, hangi özelliklerin açılacağına karar vermez ve bunları betiğin gerektirdiği sırayla uygulamaz. Çağrı, özellik etiketini seçer ve onu glyph glyph uygular. Bu, seçime bağlı ve yerel olan stilistik setler ve alternatifler için tam doğru araçtır; yeniden sıralamaya ihtiyaç duyan bir betik için tam yanlış araçtır. Sınırı keskin tutmak, ikame yolunun küçük ve öngörülebilir kalmasını sağlayan şeydir
Dizi düzeyinde çalışmayı gerektiren durumlar için karmaşık-betik hikayesi Delphi'de karmaşık-betik metin şekillendirme hakkındaki makalemizde ele alınmaktadır. İkameleriniz sayfaya görüntüler ve diğer yazı tipleri de yerleştiren daha büyük bir raporlama işinin parçasıysa yazı tipleri ve görüntülerle rapor çıktısı kılavuzu bu parçaların nasıl bir araya geldiğini kapsar. Bunların tümü aynı motor üzerinde, GSUB ikame sorgularını bu blogda başka yerlerde ele alınan yazı tipi gömme, alt kümeleme ve metin API'leriyle birlikte taşıyan Delphi ve C++Builder için HotPDF Component'te çalışır