Sıradan bir metin çağrısıyla, font olarak Segoe UI Emoji kullanılarak PDF'e yazılan sırıtan yüz emojisi düz siyah bir siluet çıkar: şekil doğru, sarı yok, gölgeleme yok. CBDT emoji fontuyla değiştirin ve aynı çağrı hiçbir şey çizmeyebilir; çünkü o font resimlerini PNG dosyaları olarak tutar ve çok az ya da hiç anahat verisi taşımaz. Siyah şekli görüntüleyiciden kopyalayın; panoda hâlâ U+1F600 vardır: karakter doğrudur, yalnızca renk tabloları hiç okunmamıştır
Renkli bir emoji PDF'te neden siyah bir siluet olarak basılır?
Çünkü bir PDF font programının renkli glif kavramı yoktur. ISO 32000-1 her glifi geçerli dolgu rengiyle boyanan bir şekil sayar ve OpenType'ın sonra eklediği renk tabloları (COLR/CPAL, SVG , CBDT/CBLC ve sbix) PDF görüntüleme modelinin parçası değildir; hiçbir görüntüleyicinin gömülü fonttan onları okumak için bir nedeni yoktur. Emojinin taşıdığı renk, PDF yazılırken — üreticinin hâlâ font baytlarını elinde tuttuğu ve tam olarak hangi glifi istediğini bildiği bir noktada — sayfa içeriğine dönüştürülmelidir. O çeviri her biçim için farklıdır ve gerçek emoji fontları dördünü de kullanır: istiflenmiş vektör katmanları, gradyan boya grafları, bütün SVG belgeleri ve PNG strike'ları
HotPDF o çeviriyi THotPDF.DrawRegisteredColorGlyph'de yapar. Bir glifin hangi biçime çözüldüğünü THPDFOpenTypeColorFormat olarak bildirir — değerleri otcfNone, otcfCOLRv0, otcfCOLRv1, otcfCBDT, otcfSVG ve otcfSBIX — ve fontu sabit bir sırada yoklar: önce COLR, sonra SVG, sonra CBDT, sonra sbix. Hem vektör hem bitmap taşıyan bir font bu yüzden vektör yolunu alır. Yakınlaştırılacak ya da basılacak her şey için doğru sıra budur
Tek bir kod noktasını çözmek ve çizmek
THotPDF.GetRegisteredColorGlyphInfo, bir kod noktasının hangi yolu izleyeceğini söyler; DrawRegisteredColorGlyph o yolu izler. İkisi de kod noktasını, en son RegisterUnicodeTTF'e geçirilen fontun karakter haritasında arar; dolayısıyla emoji fontu, çağrı anında kayıtlı Unicode font olmak zorundadır. Çizim işlevi, glifin renk verisi yoksa ya da hiçbir şey onu render edemediyse False döndürür ve o durumda sayfaya dokunulmaz
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';
// Palet girdisi 0xFFFF ("metin ön planı") bu renge çözülür
Pdf.ColorGlyphForegroundColor := clNavy;
Pdf.BeginDoc;
Pdf.RegisterUnicodeTTF('C:\Windows\Fonts\seguiemj.ttf');
// U+1F600, CPAL paleti 0, 300 ppem'e 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 yolu yok: tek renkli ana hatta 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;
PaletteIndex bir CPAL paleti seçer; koyu zemin paleti taşıyan bir font, glife dokunmadan değiştirilebilir. 0xFFFF palet girdisi OpenType belirtiminde özeldir: "metin rengi neyse o" demektir ve HotPDF onu ColorGlyphForegroundColor ile ColorGlyphForegroundAlpha'dan doldurur (varsayılan siyah ve 255). Emoji fontları o girdiyi nadiren kullanır. İkon fontları kullanır; sizinki glifleri onunla renklendiriyorsa çizimden önce özelliği metin renginize ayarlayın
TargetPixelsPerEm yalnızca bitmap fontlar için önemlidir ve varsayılanı, ezilmesine en çok değer parametredir. Sıfır bırakılırsa Round(FontSize * 96 / 72)'ye, bir ekran çözünürlüğüne dönüşür: 36 punto emoji için 48 piksel. sbix strike'larını 20, 32, 40, 48, 64, 96 ve 160 ppem'de bildiren bir font için bu varsayılan 48 piksellik strike'ı seçer ve 600 dpi'lık yazıcı sonra onu kabaca altı kat büyütmek zorunda kalır. 300 isteyin — 600 dpi'da 36 puncton gereksinimi budur — ve aynı çağrı, fontun en büyüğü olan 160 strike'ı alır
İmza ayrıca kapsamı sabitler. Tek bir kod noktası girer ve cmap üzerinden eşlenir. ZWJ aile dizileri, ten tonu değiştiricileri ve bölgesel göstergeli bayraklar GSUB ligatürleridir; önce bir glife şekillendirilmek zorundadırlar — OpenType GSUB alternatifleri makalesinin işlediği iş türü
COLR katmanları ve boyu grafları PDF vektörleri olarak
COLR v0 basit biçimdir. Her temel glif, her biri bir CPAL rengiyle, bir katman glifi yığını listeler ve HotPDF her katmanın ana hattını tablo sırasına göre doldurur. CPAL renginin alfası 255'in altında olan bir katman kendi /ca'sını alır; yarı saydam katmanlar, font tasarımcısının kastettiği gibi altlarındaki katmanlarla karışır. Sıradan bir belgede yığının tamamı sonra tek bir yalıtılmış saydamlık grubuna yakalanır (ISO 32000-1 §11.4). Grup, glifin dışında olanla ilgilidir: emojinin çevresine koyduğunuz bir opaklık, blend modu ya da soft mask, bitmiş glife bir kez uygulanır; her katmanda yinelenip katmanların örtüştü yerlerde ikilenmek yerine
COLR v1 başka bir hayvandır: gradyanlar, dönüşümler, iç içe glif kırpmaaları ve bileşik modlar taşıyan, düğümlerin PaintColrLayers ve PaintColrGlyph ile paylaşılabildiği yönlendirilmiş asiklik bir boya kaydı grafı. HotPDF onu önce sınırlı bir grafa ayrıştırır — 4096 boya düğümü, 96 derinlik düzeyi ve 1024 renk durağıyla sınırlı — ve her düğümü ziyaret edilirken izler; böylece geçerli yola geri dönen bir referans (düşmanca bir fontun katman yeniden kullanımıyla kurabileceği bir döngü) özyinelemeye girmez, reddedilir
Ofsetler, elle yazılan COLR v1 ayrıştırıcılarının genelde kırıldığı yerdir. BaseGlyphPaintRecord ofsetleri BaseGlyphList'in başına, LayerList boya ofsetleri LayerList'e ve boya tablosunun içindeki her Offset24 o boya tablosunun kendisine göredir. Üçünü de tek bir tabana göre çözün ve kuskusuz yasal glifler sınır kontrollerini geçemez; tam da bozuk bir fonta benzer. Graf kurulunca PDF'e eşleme çoğunlukla doğrudandır:
PaintGlyphglif ana hattını bir kırpma yoluna çevirir ve alt boyası kırpılan alanı doldurur- Doğrusal gradyanlar çok duraklı eksenel gölgelemelere, radyal gradyanlar radyal gölgelemelere dönüşür (§8.7.4.5)
- Sweep gradyanlarının PDF gölgeleme türü yoktur; merkez çevresinde, renk çizgisinden örneklenen 96 düz renkli kama olarak çizilirler
- Dönüşümler
cmoperatörlerine dönüşür; ötelemelerFontSize / UnitsPerEmile ölçeklenir PaintComposite13-27 modları, aynı adlı PDF blend modlarına —/Multiply,/Screen,/Luminosityve gerisi (§11.3.5) — bir ExtGState/BMgirdisi üzerinden eşlenir
Yarı saydam duraklı gradyanlar bir tuzağı daha saklar. COLR v1 renkleri alfa ile çarpılmış olarak enterpolasyon eder; PDF ise düz renk bekler ve alfa işlemini kendisi uygular. Çarpılmış değerleri PDF'e veren bir dönüştürücü, her yarı saydam bandı iki kez koyulaştırır. Renkler, enterpolasyondan sonra ve yazılmadan önce çarpımı geri alınarak düzeltilmelidir
COLR v1 bileşik modlarına PDF/A-1 ya da PDF/X-1a altında ne olur?
PaintComposite'deki Porter-Duff modları (5-12: src_in, dest_out, src_atop, xor, plus ve kardeşleri) aynı adlı bir PDF blend moduna sahip değildir ve PDF belirtiminin bariz okuması onların ifade edilemeyeceğini söyler. O okuma fazla güçlüdür. İn/out modları bir operand üzerinde alfa soft maskesidir; atop, xor ve plus, yalıtılmış biçimlerden, grup alfasından, parlaklık maskelerinden ve blend aritmetiğinden kurulabilir. HotPDF onları öyle kurar; bu glifler vektör kalır
Bedeli şu ki o kurulumların çoğu PDF saydamlığı ister ve PDF/A-1, PDF/X-1a ile PDF/X-3 bunu yasaklar. PDFACompliance bir PDF/A-1 değeri ya da PDFXCompliance 'X-1a' ya da 'X-3' olduğunda HotPDF glifi çizimden önce sınar ve saydamlık olmadan çizilemeyecek durumları raster olayına yönlendirir: atop, xor ve plus bileşimleri; maskelenen operandı basit bir opak boyadan daha fazlası olan in/out bileşimleri; kısmi alfalı düz boyalar; yarı saydam duraklı gradyanlar; ve alfası 255'in altında COLR v0 katmanları. İn ve out modları, maskelenen taraf düz bir renk ya da gradyan olduğunda — isteğe bağlı bir glif kırpması ya da dönüşümle sarılmış — vektör kalır; çünkü o durum yalnızca opak bir gri tonlama maskesi ister. StrictVersionLock dosyayı PDF 1.4'ün altına sabitlediğinde aynı şey COLR v0 için de geçerlidir
Pdf.PDFACompliance := 'B'; // PDF/A-1b: saydamlığa izin yok
Pdf.BeginDoc;
Pdf.RegisterUnicodeTTF(EmojiFontPath);
if not Pdf.DrawRegisteredColorGlyph(Pdf.CurrentPage, $1F308,
72, 200, EmojiFontName, 36, 0, 300) then
// OnColorGlyphRasterize işleyicisi olmadan, yarı saydam
// ya da bileşiklenmiş bir glif PDF/A-1 altında burada biter
LogMissingColorGlyph($1F308); // sizin kendi günlük rutininiz
Arşiv emojiyi renkli göstermek zorundaysa PDF/A-1b yerine PDF/A-2b'yi hedefleyin. Bölüm 2 saydamlığa izin verir; her COLR kurulumu vektör kalır ve yedek işleyici, her yarı saydam emoji için ana renderer olmaktan çıkıp güvenlik ağına döner. PDF/A-1'i adıyla zorunlu kılan iş akışlarında saklayın
Burada bir okuyucu tarafı ayarına daha yer var. HotPDF, COLR v1 gruplarını doğrusal ışık blend uzayında bileştirir; bazı render'lar bu gruplarda çok koyu kanalları kaybeder, bazıları grup blend uzaylarını büsbütün yok sayar. COLRv1DeviceSpaceGroupBlend (varsayılan False) grupların sıradan aygıt uzayında bileşenmesine izin verir. Takas, COLR v1 tekrar ve yansıma gradyanları makalesinde açıklanır; koyu yarı saydam tonlar kullanıcılarınızın gerçekten çalıştırdığı görüntüleyicide kayboluyorsa açın
SVG glyphleri ve bitmap strike'lar
SVG glifleri, HotPDF'in içe aktarılan SVG dosyaları için kullandığı güvenli kurucudan geçer ve sonuç bir Form XObject (§8.10) olarak kaydedilir; SVG'den Form XObject'e makalesinde anlatıldığı gibi. SVG tablosundaki belge gzip ile sıkıştırılmış olabilir. Sıkıştırılmış girdi 8 MB ile sınırlıdır, açma 8 KB'lık parçalarla yürür ve genişleyen boyut 32 MB'yi aşacaksa durur. Script'ler, foreignObject, javascript: URL'leri ve @import stil sayfaları kurucunun belgeyi büsbütün reddetmesine yol açar. Form, uzun kenarı font boyutuna eşit olacak şekilde ölçeklenir. Üretimden önce denemeye değer bir şey: bazı fontlar çok sayıda glifi tek bir paylaşılan SVG belgesine paketler ve kurucu o belgenin tamamını her glif için alır
Bitmap fontlar strike seçimi ve yerleşim meselesine indirgenir. CBDT için HotPDF, dikey ppem'i TargetPixelsPerEm'e 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 glifi gerçekten içeren en yakın strike kazanır; strike ofsetleri tabloya, glif ofsetleri strike'a göredir. Bir dupe kaydı başka bir glifin resmini yeniden kullanır ama kendi başlangıç ofsetlerini korur ve aramanın dıştaki başlangıcı ezmesine izin veren bir ayrıştırıcı resmi yana 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 (§11.6.5.3) ile yazılır. sbix'teki TIFF verileri olaya gider
Raster yedek işleyicisini yazmak
Hiçbir yerli yol işlemediğinde HotPDF OnColorGlyphRasterize fırlatır ve işleyicinizin döndürdüğü RGBA bitmap'i yerleştirir. İşleyici yokken ya da Handled False bırakılmışken DrawRegisteredColorGlyph False döndürür ve hiçbir şey çizilmez. İşleyici biçimi, font baytlarını, çıkarılan varlığı (SVG belgesi — belki hâlâ gzip'li — ya da bitmap baytları; COLR için boş), glif kimliğini, 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; HotPDF API'si değildir.
// Tam olarak Width * Height * 4 baytlık RGBA döndürmek zorundadır;
// alfa düz olmalı (çarpılmış değil)
Handled := RenderWithOwnEngine(Format, FontBytes, AssetData,
GlyphID, PaletteIndex, PixelSize, Width, Height, RGBA);
end;
// Bağlama
Pdf.OnColorGlyphRasterize := Fallback.Rasterize;
HotPDF sonucu, sayfa onu görmeden önce doğrular: sıfır boyutlar, uzunluğu tam olarak Width * Height * 4 olmayan bir tampon ya da taşacak kadar büyük boyutlar reddedilir ve çağrı False döndürür. Değişken renkli bir font için işleyici, kayıtlı eksen değerlerindeki statik örneği alır; bir ara özgün değişken fontu alırsa Sender üzerinde (THotPDF'e dönüştürerek) GetRegisteredVariableFontAxes çağrısı, render edilecek koordinatları verir. PixelSize, aynı TargetPixelsPerEm değeridir; yukarıdaki baskı çözünürlüğü öğüdü burada da geçerlidir
Rastgele kullanıcı metni basan bir hattın iki tür kaybı bilmesi gerekir: fontun hiç sahip olmadığı glifler ve renklerini yitiren glifler. İlkini eksik glif izleme makalesindeki çizim anı kapsama izleme bildirir; ikincisini DrawRegisteredColorGlyph'ten dönen bir False
COLR, SVG ve bitmap emoji render'ı, OpenType şekillendirme ve güvenli SVG kurucusu, Delphi ve C++Builder için HotPDF component'in parçalarının hepsidir