HotPDF piirtää värilliset emojit PDF:ään THotPDF.DrawRegisteredColorGlyph-kutsun kautta, joka lukee RegisterUnicodeTTFilla rekisteröidyn fontin väridatan ja tuo sen esiin natiivina PDF-grafiikkana: COLR v0 -kerrokset täytettyinä glyyfien ääriviivoina, COLR v1:n maalausgraafit clippeinä, varjostuksina ja sekoitustiloina, SVG-glyyfit Form XObjecteina ja CBDT- tai sbix-bittikartat kuvina. Kaikki, mitä se ei voi kuvata natiivisti, menee OnColorGlyphRasterize-tapahtumaan sen sijaan että muuttuisi hiljaa mustaksi muodoksi
Se viimeinen lause on koko syy sille, että tämä koodi on olemassa. Upota emoji-fontti tavallisella tavalla, niin katselin saa ääriviivan glyfistä tai CFFistä, täytettynä sillä, mikä nykyinen täyttöväri sattuu olemaan. Hymynaama saapuu mustana läiskänä, lippu suorakulmiona, eikä mikään putkessa valita
Miksi värillinen emoji tulostuu mustana siluettina PDF:ssä?
PDF-fonttiohjelmalla ei ole käsitystä väriglyyfeistä. ISO 32000-1 käsittelee glyyfin muotona, joka maalataan nykyisellä värillä, ja OpenType:n myöhemmin lisäämät väritaaulukot, nimittäin COLR/CPAL, SVG , CBDT/CBLC ja sbix, eivät kuulu PDF:n kuvausmalliin, joten mikään katselin ei ole velvollinen lukemaan niitä upotetusta fontista. Väri on käännettävä sivusisällöksi tuotantohetkellä, sillä silloin tuottajalla on vielä fontin tavut ja tieto siitä, mitä glyyfiä se haluaa. Käännös eroaa muotoa kohden, ja luonnonvaraiset emoji-fontit käyttävät niitä kaikkia: kerroksellisia vektoreita, liukuvärinmaalausgraafeja, upotettuja SVG-asiakirjoja ja PNG-strikeja. HotPDF raportoi tuloksen THPDFOpenTypeColorFormatina, arvoilla otcfNone, otcfCOLRv0, otcfCOLRv1, otcfCBDT, otcfSVG ja otcfSBIX, ja sondoi fontin kiinteässä tärkeysjärjestyksessä: ensin COLR, sitten SVG, sitten CBDT, sitten sbix. Vektordata voittaa bittikartat aina, kun fontti kantaa molempia, mikä on juuri se, mitä haluat asiakirjassa, jota saatetaan zoomata tai tulostaa
Yksi kutsu, viisi muotoa: väriglyyfin ratkaiseminen ja piirtäminen
THotPDF.GetRegisteredColorGlyphInfo vastaa siihen, minkä polun koodipiste tulee ottamaan, ja DrawRegisteredColorGlyph ottaa sen. Molemmat etsivät koodipisteen siihen fonttiin, joka viimeisimpänä välitettiin RegisterUnicodeTTFille, joten värifontin on oltava rekisteröity Unicode-fontti kutsun hetkellä. Piirtofunktio palauttaa Falsein, kun glyyfillä ei ole väridataa tai mikään polku ei pystynyt renderöimään sitä, ja jättää varamerkinnän sinun hoidettavaksesi
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-paletti 0, bittikartta-strike lähimpänä 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
// Ei väridataa: palataan yksivärisen ääriviivan varaan
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;
Kaksi parametria ansaitsee huomion. PaletteIndex valitsee CPAL-paletin, joten fontti, joka toimittaa tummataustaisen paletin, voidaan vaihtaa koskematta glyyfiin. TargetPixelsPerEm on merkitsevä vain bittikarttafonteille; nollaksi jätettynä se olettaa Round(FontSize * 96 / 72)in, näytön resoluution, minkä takia esimerkki pyytää 300:aa tulostustuotosta varten. Rehellinen raja istuu allekirjoituksessa: kutsu ottaa yhden koodipisteen ja kuvaa sen pelkän cmapin kautta. ZWJ-sekvenssit, ihonvärimuokkaimet ja alueellisten osoittimien liput ovat GSUB-ligatuureja, joten niiden kokoaminen on muotoiluongelma, jonka kaltaisia käsittelee artikkeli OpenType GSUB -vaihtoehtoisista muodoista, ei jotain, mitä tämä sisääntulopiste tekee puolestasi
COLR v0: päällekkäiset glyyfikerrokset palettiväreillä
COLR v0 on yksinkertainen tapaus, ja HotPDF renderöi sen suoraan: jokainen perusglyyfi luettelee kerrosglyyfit CPAL-värimerkinnällä, ja jokainen kerros muuttuu yhdeksi tavalliseksi tekstinäyttöoperaatioksi omalla täyttövärillään, pinottuna taulukkojärjestykseen. Kerros, jonka alfa on alle 255, saa grafiikkatilan parametrisanakirjan, jossa on vastaavat /ca ja /CA (ISO 32000-1 §8.4.5), ja jokainen kerrosglyyfi merkitään käytetyksi, jotta subsetoija pitää sen ääriviivan, vaikka mikään koodipiste ei kuvaisi siihen suoraan. Yksi yksityiskohta yllättää ihmiset: palettimerkinnän indeksi 0xFFFF tarkoittaa OpenType-spesifikaatiossa ”tekstin etualan värin käyttämistä”, ja HotPDF ratkaisee sen mustaksi eikä sivun nykyiseksi täyttöväriksi. Emoji-fonteilla tämä harvoin on merkitsevää; ikonifonteille, jotka nojaavat etualamerkintään glyyfin värjäämisessä, tarkista tuotos ennen kuin oletat sen seuraavan tekstiväriäsi
Miten HotPDF muuttaa COLR v1 -maalausgraafin PDF-operaattoreiksi?
Jäsentämällä maalaustaulukot ensin litteäksi, rajatuksi graafiksi ja vasta sitten kuvaamalla jokainen solmu PDF-rakenteeksi. COLR v1 -glyyfi ei ole kerrosten luettelo vaan maalaustietueiden suunnattu syklitön graafi, jossa solmuja voi jakaa PaintColrLayersilla ja PaintColrGlyphilla. Jäsennin kattoo sen 4096 maalaussolmuun, 64 syvyyteen ja 1024 väripysäkkiin, ja seuraa jokaista solmua aktiivisena tai valmiina, jolloin viittaus takaisin aktiiviseen solmuun — sykli, jonka pahantahtoinen fontti voi rakentaa kerrosten uudelleenkäytöstä — hylätään sen sijaan että siihen rekursioitaisiin. Siirtymäkohdat ovat se, jossa ensimmäinen toteutus menee pieleen. BaseGlyphPaintRecord-siirtymät ovat suhteessa BaseGlyphListin alkuun, LayerListin maalaussiirtymät ovat suhteessa LayerListin, ja jokainen maalaustaulukon sisäinen Offset24 on suhteessa kyseiseen maalaustaulukkoon itseensä. Ratkaise kaikki kolme samaa perustaa vasten, niin täysin lailliset glyyfit kaatuvat rajojen tarkistukseen, mikä näyttää täsmälleen rikkinäiseltä fontilta. Kun graafi on rakennettu, kuvaus on suoraviivainen:
PaintGlyphasettaa glyyfin ääriviivan clipiksi tekstirenderöintitilalla 7 (ISO 32000-1 §9.3.6) ja maalaa sitten lapsensa sen sisään- Yhtenäiset maalaukset täyttävät clipatun suorakulmion; lineaariset liukuvärit muuttuvat monipysäkkäisiksi aksiaalisiksi varjostuksiksi ja säteittäiset liukuvärit kaksivärisiksi säteittäisiksi varjostuksiksi (§8.7.4.5)
- Kiertoliukuväreillä ei ole PDF-vastinetta, joten HotPDF approksimoi ne 96 tasavärisellä kielolla, joista kukin näytteistetään värialalta
- Muunnokset tuotetaan
cminä, konjugoituna glyyfin perusviivan alkuperän ympärille, siirtymien skaalautuessa kaavallaFontSize / UnitsPerEm PaintComposite-tilat 13–27 kuvautuvat eroteltaviin ja ei-eroteltaviin PDF-sekoitustiloihin kuten/Multiply,/Screenja/Luminosity(§11.3.5), asetettuna ExtGState:n/BM-merkinnällä
Raja on eksplisiittinen. Porter-Duff-tiloilla 5–12 (src_in, xor, plus ja loput) ei ole PDF-sekoitustilavastinetta, toisto- ja heijastustilalaajennuksia ei tuoteta lineaarisille ja säteittäisille liukuväreille, eikä liukuvärejä, joiden pysäkit kantavat eri alfa-arvoja, väärennetään yhdellä läpinäkyvyydellä. Yli kahden pysäkin säteittäiset liukuvärit pitävät vain ensimmäisen ja viimeisen värinsä. HotPDF tarkistaa koko graafin tätä tuettua osajoukkoa vasten ennen kuin kirjoittaa yhtään operaattoria, joten tukematon glyyfi jättää sivun koskemattomaksi ja siirtyy rasterivaramerkintään sen sijaan että jättäisi puolet piirroksesta taakseen
SVG-glyyfit ja bittikartta-striket
SVG-glyyfit kulkevat saman rajatun rakentajan läpi, jota HotPDF käyttää tuoduille SVG-tiedostoille, ja tulos rekisteröidään Form XObjectina (§8.10), täsmälleen niin kuin artikkeli SVG:stä Form XObjectiksi kertoo. SVG -taulukon asiakirja voi olla gzip-pakattu; purku ajaa 8 kilotavun paloissa ja pysähtyy heti, kun laajentunut koko ylittäisi 32 Mt, sen sijaan että purkaisi ensin ja tarkistaisi jälkeenpäin, ja pakatun syötteen koko on kattoluku 8 Mt. Profiili on rajoittava tahallaan: skriptit, upotetut kuvat, ulkoiset URLit, data:-URIit ja ei-paikalliset viittaukset kaatuvat kiinni. Form skaalataan niin, että sen pidempi sivu on fontin kokoinen, ja ankkoroidaan perusviivaan, mikä kuvaa SVG:n y-alas koordinaatiston PDF:n y-ylös koordinaatistoon. Huomaa, että rakentaja vastaanottaa koko SVG-asiakirjan glyyfiä varten ilman glyphNNN-elementin valintaa, joten fontit, jotka pakkaavat monta glyyfiä yhteen jaettuun asiakirjaan, kannattaa testata ennen kuin nojaat niihin
Bittikarttafontit ovat strike-valinnan ja sijoittelun kysymys. CBDT:lle HotPDF valitsee CBLC-koon, jonka pystyppem on lähimpänä TargetPixelsPerEmia, hyväksyy kuvaformaatit 17, 18 ja 19 ja lukee formaatin 19 metriikat CBLC-indeksialitaulukosta, koska kyseinen formaatti ei tallenna niitä itse. sbixille strike-siirtymät ovat suhteessa taulukkoon ja glyyfisiirtymät strikeen, ja dupe-tietue käyttää uudelleen toisen glyyfin grafiikkaa pitäen omat alkuperäsiirtymänsä; antamalla rekursion ylikirjoittaa ulkoisen alkuperän siirtää kuvan. PNG- ja JPEG-hyötykuormat dekoodataan sisäisesti, skaalataan kertoimella FontSize / PixelsPerEmY sen sijaan että venytettäisiin fonttikokoon, ja kirjoitetaan pehmeällä maskilla (§11.6.5.3) aina, kun yksikin pikseli ei ole täysin peittävä. sbixin TIFF-hyötykuormia ei dekoodata, vaan ne menevät tapahtumaan
Mitä tapahtuu, kun glyyfiä ei voi piirtää natiivisti?
HotPDF nostaa OnColorGlyphRasterizein ja sijoittaa sen RGBA-bittikartan, jonka käsittelijäsi palauttaa; jos mitään ei ole sijoitettu tai käsittelijä jättää Handledin epätodeksi, DrawRegisteredColorGlyph palauttaa Falsein ja sivu pysyy muuttumattomana. Tapahtuma lauhtuu tuetun osajoukon ulkopuoliselle COLR v1 -graafille, turvallisen rakentajan hylkäämälle SVG-asiakirjalle ja bittikarttahyötykuormalle, jota sisäiset dekooderit eivät lue. Käsittelijä saa formaatin, fontin raakatavut, poimitun hyödykkeen (SVG-asiakirja, mahdollisesti yhä gzipattu, tai bittikarttatavut; tyhjä COLR v1:lle), glyyfi-ID:n, paletin ja kohdepikselikoon
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 on sinun rasteroijasi, ei HotPDF:n API.
// Sen on palautettava täsmälleen Width * Height * 4 tavua RGBA:ta.
Handled := RenderWithOwnEngine(Format, FontBytes, AssetData,
GlyphID, PaletteIndex, PixelSize, Width, Height, RGBA);
end;
// Kytkentä
Pdf.OnColorGlyphRasterize := Fallback.Rasterize;
HotPDF valido käsittelijän tuotoksen ennen kuin koskee sivuun: nollakoot, puskuri, jonka pituus ei ole täsmälleen Width * Height * 4, tai riittävän suuret ylivuottavat ulottuvuudet hylätään ja kutsu palauttaa Falsein. Rasterivaramerkintä on silti rasteria, joten tällä tavalla renderöityvä emoji menettää vektoriterävyytensä; pyydä PixelSizeia, joka vastaa tuotontarkuuttasi. Yhdistä väripolku piirtohetkellisiin kattavuustarkistuksiin artikkelista puuttuvien glyyfien seurannasta, niin mielivaltaista käyttäjätekstiä käsittelevä putki voi raportoida sekä puuttuvat glyyfit että värinsä menettäneet glyyfit
Väriglyyfirenderoija, OpenType-muotoilupino ja turvallinen SVG-rakentaja toimitetaan kaikki HotPDF Delphi PDF -komponentissa, saatavilla Delphille ja C++Builderille