HotPDF, renkli emojiyi bir PDF'e THotPDF.DrawRegisteredColorGlyph üzerinden çizer; bu, RegisterUnicodeTTF ile kaydedilmiş bir fontun renk verisini okur ve yerli PDF grafikleri olarak çıkarır: COLR v0 katmanları dolgulu glyph konturları olarak, COLR v1 paint grafları clipler, shadingler ve blend mode'lar olarak, SVG glyphleri Form XObjectleri olarak, CBDT ya da sbix bitmapleri ise görüntüler olarak. Yerli olarak eşleyemediği her şey, sessizce siyah bir şekle dönüşmek yerine OnColorGlyphRasterize olayına gider
Bu son cümle, bu kodun var olma sebebinin bütünüdür. Bir emoji fontunu sıradan yolla gömerseniz görüntüleyici konturu glyf ya da CFFden alır ve o anki dolgu rengiyle doldurur. Gülücük yüz siyah bir leke olarak gelir, bayrak bir dikdörtgen olarak gelir ve hattın hiçbir yerinden ses çıkmaz
Renkli bir emoji PDF'te neden siyah bir siluet olarak basılır?
Bir PDF font programının renkli glyph kavramı yoktur. ISO 32000-1 bir glyphi geçerli renkle boyanmış bir şekil sayar ve OpenType'ın sonradan eklediği renk tabloları — COLR/CPAL, SVG , CBDT/CBLC ve sbix — PDF görüntü modelinin parçası değildir; hiçbir görüntüleyici bunları gömülü bir fonttan okumak zorunda değildir. Renk, üreticinin hâlâ font baytlarına sahip olduğu ve hangi glyphi istediğini bildiği üretim anında sayfa içeriğine çevrilmek zorundadır. O çeviri biçime göre değişir ve sahada emoji fontları hepsini kullanır: katmanlı vektörler, gradient paint grafları, gömülü SVG belgeleri ve PNG strike'lar. HotPDF sonucu THPDFOpenTypeColorFormat olarak bildirir — otcfNone, otcfCOLRv0, otcfCOLRv1, otcfCBDT, otcfSVG ve otcfSBIX değerleriyle — ve fontu sabit bir öncelikle sınar: önce COLR, sonra SVG, sonra CBDT, sonra sbix. Vektör verisi, font ikisini de taşıdığında bitmapleri yener; yakınlaştırılabilir ya da basılabilir bir belgede istediğiniz de budur
Tek çağrı, beş biçim: renkli bir glyphi çözmek ve çizmek
THotPDF.GetRegisteredColorGlyphInfo, bir kod noktasının hangi yolu izleyeceğini yanıtlar ve DrawRegisteredColorGlyph o yolu izler. İkisi de kod noktasını, en son RegisterUnicodeTTFe geçirilen fontun karakter haritasında arar; dolayısıyla renk fontu, çağrı anında kayıtlı Unicode font olmak zorundadır. Çizim fonksiyonu, glyphin renk verisi yoksa ya da hiçbir yol onu render edemediyse False döndürür ve yedeği size bırakır
const
FormatNames: array[THPDFOpenTypeColorFormat] of string =
('none', 'COLR v0', 'COLR v1', 'CBDT', 'SVG', 'sbix');
var
Pdf: THotPDF;
Info: THPDFOpenTypeColorGlyphInfo;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.AutoLaunch := False;
Pdf.FileName := 'emoji.pdf';
Pdf.BeginDoc;
Pdf.RegisterUnicodeTTF('C:\Windows\Fonts\seguiemj.ttf');
// U+1F600, CPAL paleti 0, 300 ppeme en yakın bitmap strike
if Pdf.GetRegisteredColorGlyphInfo($1F600, 0, 300, Info) then
Writeln(Format('GID %d via %s',
[Info.GlyphID, FormatNames[Info.Format]]));
if not Pdf.DrawRegisteredColorGlyph(Pdf.CurrentPage, $1F600,
72, 144, 'Segoe UI Emoji', 36, 0, 300) then
begin
// Renk verisi yok: tek renkli kontura geri dön
Pdf.CurrentPage.SetFont('Segoe UI Emoji', [], 36, DEFAULT_CHARSET);
Pdf.CurrentPage.TextOut(72, 144, 0, WideString(#$D83D#$DE00));
end;
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
İki parametre ilgiyi hak ediyor. PaletteIndex bir CPAL paleti seçer; koyu arka plan paleti getiren bir font, glyphe dokunmadan değiştirilebilir. TargetPixelsPerEm yalnızca bitmap fontlar için önemli; sıfır bırakılırsa Round(FontSize * 96 / 72) varsayılanına döner, bu bir ekran çözünürlüğüdür ve örneğin baskı çıktısı için 300 istemesinin sebebi budur. Dürüst sınır imzadadır: çağrı tek bir kod noktası alır ve onu yalnızca cmap üzerinden eşler. ZWJ dizileri, ten tonu değiştiricileri ve bölgesel gösterge bayrakları GSUB ligatürleridir; onları birleştirmek, OpenType GSUB alternatifleri yazısının kapsadığı türden bir shaping problemidir, bu giriş noktasının sizin için yaptığı bir şey değil
COLR v0: palet renkleriyle istiflenmiş glyph katmanları
COLR v0 basit vakadır ve HotPDF onu doğrudan render eder: her base glyph, bir CPAL renk girdisiyle katman glyphleri listeler ve her katman, kendi dolgu rengiyle sıradan tek bir metin gösterme işlemine dönüşür, tablo sırasında istiflenir. Alfası 255in altında olan bir katman, eşleşen /ca ile /CA taşıyan bir graphics state parameter sözlüğü alır (ISO 32000-1 §8.4.5) ve her katman glyphi kullanılmış işaretlenir, böylece subsetter ona doğrudan kod noktası eşleşmese bile konturunu korur. İnsanları şaşırtan bir ayrıntı var: palet girdisi indeksi 0xFFFF, OpenType spesifikasyonunda "metin ön plan rengini kullan" demektir ve HotPDF bunu geçerli sayfa dolgu rengine değil siyaha çözer. Emoji fontları için bu nadiren önemli; bir glyphi renklendirmek için ön plan girdisine güvenen icon fontları için, metin renginizi izleyeceğini varsaymadan önce çıktıyı kontrol edin
HotPDF bir COLR v1 paint grafi nasıl PDF operatörlerine çevirir?
Paint tablolarını önce düz, sınırlı bir grafa ayrıştırıp sonra her düğümü bir PDF yapısına eşleyerek. Bir COLR v1 glyph, katman listesi değildir; paint kayıtlarından oluşan yönlendirilmiş döngüsüz bir grafdır ve düğümler PaintColrLayers ile PaintColrGlyph üzerinden paylaşılabilir. Parser onu 4096 paint düğümünde, 64 derinlik düzeyinde ve 1024 renk durağında sınırlar ve her düğümü aktif ya da bitmiş olarak izler; aktif bir düğüme geri referans — kötü niyetli bir fontun katman yeniden kullanımından kurabileceği bir döngü — içine özyinelemek yerine reddedilir. Offset tabanları, ilk uygulamanın yanıldığı yerdir. BaseGlyphPaintRecord offsetleri BaseGlyphListin başına göredir, LayerList paint offsetleri LayerListe göredir ve paint tablosu içindeki her Offset24 o paint tablosunun kendisine göredir. Üçünü de aynı tabana karşı çözerseniz tümüyle meşru glyphler sınır kontrolünden geçemez; bu da tam olarak bozuk font görünümü verir. Graf kurulduktan sonra eşleme doğrudandır:
PaintGlyph, glyph konturunu metin render modu 7 ile bir clip olarak set eder (ISO 32000-1 §9.3.6) ve çocuğunu onun içinde boyar- Düz boyalar kırpılmış bir dikdörtgeni doldurur; doğrusal gradientler çok duraklı axial shadinglere, radyal gradientler iki renkli radial shadinglere dönüşür (§8.7.4.5)
- Sweep gradientlerin PDF karşılığı yoktur; HotPDF onları renk çizgisinden örneklenmiş 96 düz renkli kama ile yaklaştırır
- Dönüşümler
cmolarak çıkar, glyph baseline başlangıcı çevresinde eşleniklenir ve ötelemelerFontSize / UnitsPerEmile ölçeklenir PaintCompositemodları 13 ile 27,/Multiply,/Screenve/Luminositygibi ayrıştırılabilir ve ayrıştırılamaz PDF blend mode'larına eşlenir (§11.3.5); bir ExtGState/BMgirdisi üzerinden set edilir
Sınır açıktır. Porter-Duff modları 5 ile 12 (src_in, xor, plus ve gerisi) PDF blend mode karşılığı bulamaz; doğrusal ve radyal gradientlerde repeat ile reflect extend modları çıkarılmaz ve durakları farklı alfa değerleri taşıyan gradientler tek bir opaklıkla taklit edilmez. İkiden fazla duraklı radyal gradientler yalnızca ilk ve son renklerini korur. HotPDF, tek bir operatör yazmadan önce tüm grafi bu desteklenen alt kümeye karşı sınar; desteklenmeyen bir glyph sayfayı dokunulmamış bırakır ve yarım bir çizim bırakmak yerine raster yedeğine geçer
SVG glyphleri ve bitmap strike'lar
SVG glyphleri, HotPDF'in içe aktarılan SVG dosyaları için kullandığı aynı sınırlı kurucudan geçer ve sonuç bir Form XObject olarak kaydedilir (§8.10); tam olarak SVG'den Form XObject'e yazısında anlatıldığı gibi. SVG tablosundaki belge gzip ile sıkıştırılmış olabilir; açma 8 KB'lik parçalarla yürür ve açılmış boyut 32 MB'ı geçecek gibi olur olmaz durur, önce açıp sonra bakmak yerine, ve sıkıştırılmış girdinin kendisi 8 MB ile sınırlıdır. Profil bilinçli olarak kısıtlayıcıdır: scriptler, gömülü görüntüler, harici URL'ler, data: URI'leri ve yerel olmayan referanslar kapalı kalmaya başarısız olur. Form, uzun kenarı font boyutuna eşit olacak şekilde ölçeklenir ve baseline'a sabitlenir; bu, y-aşağı SVG koordinat sistemini y-yukarı PDF sistemine eşler. Kurucunun glyph için tüm SVG belgesini aldığını, glyphNNN elemanının seçilmediğini bilin; bu yüzden çok sayıda glyphi tek bir paylaşılan belgeye paketleyen fontlara güvenmeden önce test etmeye değer
Bitmap fontlar strike seçimi ve yerleşim meselesidir. CBDT için HotPDF, dikey ppem'i TargetPixelsPerEme en yakın olan CBLC boyutunu seçer, 17, 18 ve 19 görüntü biçimlerini kabul eder ve 19. biçimin metriklerini CBLC index alt tablosundan okur, çünkü o biçim kendi metriklerini hiç saklamaz. sbix için strike offsetleri tabloya, glyph offsetleri strike'a göredir ve bir dupe kaydı, kendi başlangıç offsetlerini korurken başka bir glyphin grafiğini yeniden kullanır; özyinelemenin dıştaki başlangıcı ezmesine izin vermek görüntüyü kaydırır. PNG ve JPEG verileri içeride çözülür, font boyutuna gerilmek yerine FontSize / PixelsPerEmY ile ölçeklenir ve herhangi bir piksel tümüyle opak değilken bir soft mask ile yazılır (§11.6.5.3). sbix TIFF verileri çözülmez ve olaya gider
Bir glyph yerli olarak çizilemediğinde ne olur?
HotPDF OnColorGlyphRasterize tetikler ve handlerınızın döndürdüğü RGBA bitmapini yerleştirir; hiçbir şey atanmamışsa ya da handler Handledı false bırakırsa DrawRegisteredColorGlyph False döndürür ve sayfa değişmeden kalır. Olay, desteklenen alt kümenin dışında bir COLR v1 grafı için, güvenli kurucunun reddettiği bir SVG belgesi için ve iç decodların okumadığı bir bitmap verisi için tetiklenir. Handler; formatı, ham font baytlarını, çıkarılan varlığı (SVG belgesi, hâlâ gzip'li olabilir, ya da bitmap baytları; COLR v1 için boş), glyph IDyi, paleti ve hedef piksel boyutunu alır
type
TEmojiFallback = class
public
procedure Rasterize(Sender: TObject;
Format: THPDFOpenTypeColorFormat; const FontBytes: TBytes;
const AssetData: TBytes; GlyphID: Word;
PaletteIndex, PixelSize: Integer;
out Width, Height: Integer; out RGBA: TBytes;
out Handled: Boolean);
end;
procedure TEmojiFallback.Rasterize(Sender: TObject;
Format: THPDFOpenTypeColorFormat; const FontBytes: TBytes;
const AssetData: TBytes; GlyphID: Word;
PaletteIndex, PixelSize: Integer;
out Width, Height: Integer; out RGBA: TBytes;
out Handled: Boolean);
begin
Width := 0;
Height := 0;
RGBA := nil;
// RenderWithOwnEngine sizin rasterizer'ınızdır, bir HotPDF API'si değil.
// Tam olarak Width * Height * 4 bayt RGBA döndürmeli.
Handled := RenderWithOwnEngine(Format, FontBytes, AssetData,
GlyphID, PaletteIndex, PixelSize, Width, Height, RGBA);
end;
// Bağlantı
Pdf.OnColorGlyphRasterize := Fallback.Rasterize;
HotPDF, sayfaya dokunmadan önce handler çıktısını doğrular: sıfır boyutlar, uzunluğu tam olarak Width * Height * 4 olmayan bir tampon ya da taşmaya yetecek kadar büyük boyutlar reddedilir ve çağrı False döndürür. Raster yedeği yine de rasterdır; bu yolla render edilen bir emoji vektör keskinliğini kaybeder, çıktı çözünürlüğünüzle eşleşen bir PixelSize isteyin. Renk yolunu eksik glyph izleme yazısındaki çizim zamanı kapsam kontrolleriyle eşleştirin; keyfi kullanıcı metnini işleyen bir hat hem eksik glyphleri hem rengini kaybetmiş glyphleri bildirebilir
Renkli glyph renderer, OpenType shaping yığını ve güvenli SVG kurucusu, Delphi ve C++Builder için mevcut HotPDF Delphi PDF component ile gelir