HotPDF riše barvne emoji v PDF prek THotPDF.DrawRegisteredColorGlyph, ki prebere barvne podatke pisave, registrirane s RegisterUnicodeTTF, in jih odda kot izvorno grafiko PDF: plasti COLR v0 kot zapolnjene glifne orise, grafe risanja COLR v1 kot odreze, senčenja in načine zlivanja, glife SVG kot Form XObjects, bitne slike CBDT ali sbix pa kot slike. Česar ne more preslikati izvorno, gre namesto tega na dogodek OnColorGlyphRasterize in se ne spremeni tiho v črno obliko
Zadnji stavek je celoten razlog, da ta koda sploh obstaja. Vgradite pisavo emoji na običajen način in pregledovalnik dobi oris iz glyf ali CFF, zapolnjen s tem, kar trenutna barva polnjenja slučajno je. Nasmehnjen obraz pride kot črna gmota, zastava kot pravokotnik in nič v cevovodu se ne pritoži
Zakaj se barvni emoji natisne kot črna silhueta v PDF?
Program pisave PDF nima pojma o barvnih glifih. ISO 32000-1 obravnava glifo kot obliko, pobarvano s trenutno barvo, barvne tabele, ki jih je OpenType dodal pozneje, torej COLR/CPAL, SVG , CBDT/CBLC in sbix, pa niso del modela slikanja PDF, zato noben pregledovalnik ni dolžan brati jih iz vgrajene pisave. Barvo je treba prevesti v vsebino strani ob ustvarjanju, ko producent še ima bajte pisave in ve, katero glifo želi. Ta prevod se razlikuje po formatu, pisave emoji v divjini pa uporabljajo vse: plastene vektorje, grafe risanja s prelivami, vgrajene dokumente SVG in bitne velikosti PNG. HotPDF poroča rezultat kot THPDFOpenTypeColorFormat, z vrednostmi otcfNone, otcfCOLRv0, otcfCOLRv1, otcfCBDT, otcfSVG in otcfSBIX, pisavo pa preizkusi v fiksnem prednostnem vrstnem redu: najprej COLR, nato SVG, nato CBDT, nato sbix. Vektorski podatki zmagajo nad bitnimi slikami, kadar pisava nosi oboje, kar je točno tisto, kar hočete v dokumentu, ki ga je mogoče povečati ali natisniti
En klic, pet formatov: razreševanje in risanje barvne glife
THotPDF.GetRegisteredColorGlyphInfo odgovori, katero pot bo vzela kodna točka, DrawRegisteredColorGlyph pa jo vzame. Oba poiščeta kodno točko v znakovnem zemljevidu pisave, ki je bila nazadnje podana RegisterUnicodeTTF, zato mora biti barvna pisava registrirana pisava Unicode v času klica. Funkcija risanja vrne False, ko glifa nima barvnih podatkov ali je nobena pot ne more upodobiti, rezervo pa prepusti vam
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, paleta CPAL 0, bitna velikost najbližja 300 ppem
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
// Brez barvnih podatkov: padite nazaj na enobarvni oris
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;
Dva parametra zaslužita pozornost. PaletteIndex izbere paleto CPAL, zato se pisava, ki dobavlja paleto za temno ozadje, lahko zamenja, brez da bi se dotaknili glife. TargetPixelsPerEm je pomemben le za bitne pisave; puščen na nič privzame Round(FontSize * 96 / 72), ločljivost zaslona, zato primer zahteva 300 za tiskovni izhod. Iskrena meja sedi v podpisu: klic vzame eno kodno točko in jo preslika skozi cmap samega. Zaporedja ZWJ, modifikatorji odtenka kože in zastave regionalnih kazalcev so ligature GSUB, zato je njihovo sestavljanje problem oblikovanja, take vrste, kot ga pokriva članek o alternativah OpenType GSUB, in ne nekaj, kar bi ta vstopna točka naredila za vas
COLR v0: naložene plasti glif z barvami palete
COLR v0 je preprost primer in HotPDF ga upodobi neposredno: vsaka osnovna glifa našteje plasti glif z barvnim vnosom CPAL, vsaka plast pa postane ena navadna operacija prikaza besedila z lastno barvo polnjenja, naložena v vrstnem redu tabele. Plast z alfo pod 255 dobi slovar parametrov grafičnega stanja z ujemajočima /ca in /CA (ISO 32000-1 §8.4.5), vsaka glifa plasti pa je označena kot uporabljena, tako da subsetter obdrži njen oris, čeprav se nanjo neposredno ne preslika nobena kodna točka. Ena podrobnost preseneča: kazalo vnosa palete 0xFFFF pomeni »uporabi barvo ospredja besedila« v specifikaciji OpenType, HotPDF pa jo razreši v črno in ne v trenutno barvo polnjenja strani. Za pisave emoji to redko pomaga; za ikonske pisave, ki se zanašajo na vnos ospredja, da obarvajo glifo, preverite izhod, preden domnevate, da bo sledil vaši barvi besedila
Kako HotPDF pretvori graf risanja COLR v1 v operatorje PDF?
Z razčlenjevanjem tabel risanja najprej v raven, omejen graf in šele nato s preslikavo vsakega vozlišča v konstrukcijo PDF. Glifa COLR v1 ni seznam plasti, temveč usmerjen aciklični graf zapisov risanja, kjer si lahko vozlišča delijo prek PaintColrLayers in PaintColrGlyph. Razčlenjevalnik ga omeji na 4096 vozlišč risanja, 64 ravni globine in 1024 barvnih postankov ter sledi vsakemu vozlišču kot aktivnemu ali opravljenemu, tako da je sklic nazaj na aktivno vozlišče, cikel, ki ga lahko zlonamerna pisava zgradi iz ponovne uporabe plasti, zavrnjen in ne ponavljan. Osnovi odmikov so mesto, kjer se prva implementacija zmoti. Odmiki BaseGlyphPaintRecord so relativni na začetek BaseGlyphList, odmiki risanja LayerList so relativni na LayerList, vsak Offset24 znotraj tabele risanja pa je relativen na to tabelo risanja samo. Razrešite vse tri proti isti osnovi in povsem zakonite glife odpovejo preizkusu meja, kar izgleda točno kot pokvarjena pisava. Ko je graf zgrajen, je preslikava neposredna:
PaintGlyphnastavi glifni oris kot odrez z načinom upodabljanja besedila 7 (ISO 32000-1 §9.3.6) in nato pobarva svojega otroka znotraj njega- Enobarvna risanja zapolnijo odrezan pravokotnik; linearni prelivi postanejo večpostanek aksialna senčenja in radialni prelivi dvobarvna radialna senčenja (§8.7.4.5)
- Sweep prelivi nimajo ustreznika v PDF, zato jih HotPDF približa s 96 ravnimi barvnimi klini, vsak vzorčen iz barvne črte
- Transformacije se oddajo kot
cm, konjugirane okoli izhodišča glifne osnovne črte, s premiki, umerjenimi zFontSize / UnitsPerEm - Načini
PaintCompositeod 13 do 27 se preslikajo v ločljive in neločljive načine zlivanja PDF, kot so/Multiply,/Screenin/Luminosity(§11.3.5), nastavljene prek vnosa/BMExtGState
Meja je izrecna. Načini Porter-Duff od 5 do 12 (src_in, xor, plus in preostali) nimajo ustreznika med načini zlivanja PDF, razširitveni način ponovi in odbij na linearnih in radialnih prelivih ni oddan, prelivi, katerih postanki nosijo različne vrednosti alfe, pa niso ponarejeni z eno samo prosojnostjo. Radialni prelivi z več kot dvema postankoma obdržita le svoji prvi in zadnji barvi. HotPDF preveri celoten graf proti tej podprti podmnožici, preden zapiše en samega operatorja, zato nepodprta glifa pusti stran nedotaknjeno in nadaljuje na rastersko rezervo, namesto da bi za sabo pustila pol risbe
Glife SVG in bitne velikosti
Glife SVG gredo skozi isti omejen graditelj, ki ga HotPDF uporablja za uvožene datoteke SVG, rezultat pa je registriran kot Form XObject (§8.10), točno tako, kot je opisano v članku od SVG do Form XObject. Dokument v tabeli SVG je lahko stisnjen z gzip; dekompresija teče v koščkih po 8 KB in se ustavi, takoj ko bi razširjena velikost presegla 32 MB, namesto da bi najprej napihnili in šele potem preverili, stisnjeni vhod pa je sam omejen na 8 MB. Profil je omejen namenoma: skripti, vgrajene slike, zunanji URL-ji, URI-ji data: in nelokalne reference odpovejo zaprto. Forma se umeri tako, da njena daljša stran enača velikost pisave, in zasidra na osnovni črti, kar preslika koordinatni sistem SVG z y navzdol na tistega PDF z y navzgor. Vedite, da graditelj dobi celoten dokument SVG za glifo, brez izbire elementa glyphNNN, zato so pisave, ki spravijo veliko glif v en skupni dokument, vredne preizkusa, preden se nanje zanesete
Bitne pisave so vprašanje izbire velikosti in postavitve. Za CBDT HotPDF izbere velikost CBLC, katere navpični ppem je najbližje TargetPixelsPerEm, sprejme slikovne formate 17, 18 in 19 ter prebere meritve formata 19 iz indeksne podtabele CBLC, ker ta format ne shrani lastnih. Za sbix so odmiki velikosti relativni na tabelo in odmiki glif na velikost, zapis dupe pa ponovno uporabi grafiko druge glife, medtem ko obdrži svoje lastne odmike izhodišča; če pustite, da rekurzija prepiše zunanje izhodišče, se slika premakne. Paketi PNG in JPEG se dekodirajo interno, umerijo z FontSize / PixelsPerEmY, namesto da bi bili raztegnjeni na velikost pisave, in zapišejo z mehko masko (§11.6.5.3), kadarkoli kakšen piksel ni povsem moten. Paketi TIFF sbix se ne dekodirajo in gredo na dogodek
Kaj se zgodi, ko glife ni mogoče narisati izvorno?
HotPDF sproži OnColorGlyphRasterize in postavi katero koli bitno sliko RGBA, ki jo vrne vaš upravljalnik; če nič ni dodeljeno ali upravljalnik pusti Handled neresnično, DrawRegisteredColorGlyph vrne False in stran ostane nespremenjena. Dogodek se sproži za graf COLR v1 zunaj podprte podmnožice, za dokument SVG, ki ga varni graditelj odkloni, in za bitni paket, ki ga notranji dekoderji ne berejo. Upravljalnik dobi format, surove bajte pisave, izvlečeno sredstvo (dokument SVG, morda še vedno gzip, ali bitne bajte; prazno za COLR v1), ID glife, paleta in ciljno velikost pikslov
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 je vaš rasterizer, ni pa API HotPDF.
// Vrniti mora točno Width * Height * 4 bajtov RGBA.
Handled := RenderWithOwnEngine(Format, FontBytes, AssetData,
GlyphID, PaletteIndex, PixelSize, Width, Height, RGBA);
end;
// Povezava
Pdf.OnColorGlyphRasterize := Fallback.Rasterize;
HotPDF preveri izhod upravljalnika, preden se dotakne strani: ničelne velikosti, medpomnilnik, katerega dolžina ni točno Width * Height * 4, ali mere, dovolj velike za prelivanje, so zavrnjene in klic vrne False. Rasterska rezerva je še vedno raster, zato emoji, upodobljen na ta način, izgubi svojo vektorsko ostrost; zahtevajte PixelSize, ki se ujema z vašo izhodno ločljivostjo. Združite barvno pot s preizkusi pokritosti ob risanju iz članka o sledenju manjkajočih glif in cevovod, ki obravnava poljubno uporabniško besedilo, lahko poroča tako o manjkajočih glifah kot o glifah, ki so izgubile barvo
Upodobitelj barvnih glif, sklad oblikovanja OpenType in varni graditelj SVG vsi prihajajo v komponento HotPDF Delphi PDF, na voljo za Delphi in C++Builder