Delen via


Tekstweergave met Direct2D en DirectWrite

In tegenstelling tot andere API's, zoals GDI, GDI+ of WPF, Direct2D samenwerken met een andere API, DirectWrite, om tekst te bewerken en weer te geven. In dit onderwerp worden de voordelen en interoperation van deze afzonderlijke onderdelen beschreven.

Dit onderwerp bevat de volgende secties.

Direct2D maakt incrementele acceptatie mogelijk

Het overzetten van een toepassing van de ene grafische API naar de andere kan moeilijk zijn of om verschillende redenen minder wenselijk. Dit kan zijn omdat u invoegtoepassingen moet ondersteunen die nog steeds de oudere interfaces gebruiken, omdat de toepassing zelf te groot is om over te zetten naar een nieuwe API in één release of omdat een deel van de nieuwere API wenselijk is, maar de oudere API goed genoeg werkt voor andere onderdelen van de toepassing.

Omdat Direct2D- en DirectWrite- zijn geïmplementeerd als afzonderlijke onderdelen, kunt u uw hele 2D-grafische systeem of alleen het tekstgedeelte ervan upgraden. U kunt bijvoorbeeld een toepassing bijwerken om DirectWrite te gebruiken voor tekst, maar nog steeds GDI- of GDI+ gebruiken voor rendering.

Text Services versus Text Rendering

Naarmate toepassingen zich hebben ontwikkeld, zijn hun vereisten voor tekstverwerking steeds complexer geworden. In eerste instantie was tekst over het algemeen beperkt tot statisch ingedeelde gebruikersinterface en werd de tekst weergegeven in een goed gedefinieerd vak, zoals een knop. Omdat toepassingen in een toenemend aantal talen beschikbaar waren, werd deze benadering moeilijker te ondersteunen omdat zowel de breedte als de hoogte van de vertaalde tekst aanzienlijk kan variëren tussen talen. Om zich aan te passen, zijn toepassingen gestart om hun gebruikersinterface dynamisch in te delen, zodat ze afhankelijk zijn van de werkelijke gerenderde grootte van de tekst, in plaats van andersom.

Om toepassingen te helpen deze taak te voltooien, biedt DirectWrite de interface IDWriteTextLayout. Met deze API kan een toepassing een stuk tekst met complexe kenmerken opgeven, zoals verschillende lettertypen en tekengrootten, onderstrepingen, doorhalen, bidirectionele tekst, effecten, beletseltekens en zelfs ingesloten niet-glyph-tekens (zoals een bitmap-emoticon of een pictogram). De toepassing kan vervolgens verschillende kenmerken van de tekst wijzigen, omdat deze de gebruikersinterface-indeling iteratief bepaalt. De DirectWrite Hello World Sample, dat wordt getoond in de volgende afbeelding en in het Zelfstudie: Aan de slag met DirectWrite onderdeel, toont veel van deze effecten.

schermafbeelding van het 'hallo wereld'-voorbeeld.

De indeling kan de glyphs idealiter positioneren op basis van hun breedte (zoals WPF doet), of de glyphs op de dichtstbijzijnde pixelposities uitlijnen (zoals GDI- wel).

Naast het verkrijgen van tekstmetingen, kan de toepassing verschillende delen van de tekst testen. Het zou bijvoorbeeld kunnen zijn dat er op een hyperlink in de tekst wordt geklikt. (Zie het onderwerp Hoe Hit Testing op een tekstlayout uit te voeren voor meer informatie over het testen van treffers.)

De interface voor de tekstindeling wordt losgekoppeld van de rendering-API die door de toepassing wordt gebruikt, zoals in het volgende diagram wordt weergegeven:

tekstindeling en grafische API-diagram.

Deze scheiding is mogelijk omdat DirectWrite een renderinginterface (IDWriteTextRenderer) biedt die toepassingen kunnen implementeren om tekst weer te geven met behulp van de gewenste graphics-API. De toepassing die is geïmplementeerd IDWriteTextRenderer::DrawGlyphRun callbackmethode wordt aangeroepen door DirectWrite bij het renderen van een tekstopmaak. Het is de verantwoordelijkheid van deze methode om de tekenbewerkingen uit te voeren of door te geven.

Voor het tekenen van glyphs, Direct2D- biedt ID2D1RenderTarget::D rawGlyphRun voor het tekenen naar een Direct2D-oppervlak en DirectWriteIDWriteBitmapRenderTarget::D rawGlyphRun voor tekenen naar een GDI-oppervlak dat vervolgens kan worden overgedragen naar een venster met GDI. Handig hebben DrawGlyphRun in zowel Direct2D als DirectWrite exact dezelfde compatibele parameters als de methode DrawGlyphRun die de toepassing implementeert op IDWriteTextRenderer.

Na een vergelijkbare scheiding worden tekstspecifieke functies (zoals lettertype-opsomming en -beheer, glyph-analyse enzovoort) verwerkt door DirectWrite- in plaats van Direct2D-. De DirectWrite-objecten worden rechtstreeks geaccepteerd door Direct2D. Om bestaande GDI-toepassingen te helpen om te profiteren van DirectWrite, biedt het de IDWriteGdiInterop methode-interface met methoden om het volgende te doen:

Glyphs versus Tekst

Tekst is een set Unicode-codepunten (tekens), met verschillende stijlaanpassingen (lettertypen, gewichten, onderstrepingen, doorhalen, enzovoort) die in een rechthoek zijn ingedeeld. Een symbool is daarentegen een bepaalde index in een bepaald lettertypebestand. Een glyph definieert een set curven die kan worden weergegeven, maar heeft geen tekstuele betekenis. Er is mogelijk een veel-op-veel-relatie tussen gliefen en tekens. Een reeks glyphs die afkomstig zijn van hetzelfde lettertype en die opeenvolgend op een basislijn zijn ingedeeld, wordt een GlyphRun-genoemd. Zowel DirectWrite als Direct2D roepen hun meest nauwkeurige glyph rendering API DrawGlyphRun aan, en ze hebben zeer vergelijkbare kenmerken. Het volgende is afkomstig uit ID2D1RenderTarget- in Direct2D:

STDMETHOD_(void, DrawGlyphRun)(
        D2D1_POINT_2F baselineOrigin,
        __in CONST DWRITE_GLYPH_RUN *glyphRun,
        __in ID2D1Brush *foregroundBrush,
        DWRITE_MEASURING_MODE measuringMode = DWRITE_MEASURING_MODE_NATURAL 
        ) PURE;

En deze methode is afkomstig uit IDWriteBitmapRenderTarget- in DirectWrite-:

STDMETHOD(DrawGlyphRun)(
        FLOAT baselineOriginX,
        FLOAT baselineOriginY,
        DWRITE_MEASURING_MODE measuringMode,
        __in DWRITE_GLYPH_RUN const* glyphRun,
        IDWriteRenderingParams* renderingParams,
        COLORREF textColor,
        __out_opt RECT* blackBoxRect = NULL
        ) PURE;

De DirectWrite versie houdt de oorsprong van de basislijn, de meetmodus en de glyph-runparameters, en bevat aanvullende parameters.

DirectWrite kunt u ook een aangepaste renderer gebruiken voor glyphs door de IDWriteTextRenderer-interface te implementeren. Deze interface heeft ook een methode DrawGlyphRun, zoals in het volgende codevoorbeeld wordt weergegeven.

STDMETHOD(DrawGlyphRun)(
        __maybenull void* clientDrawingContext,
        FLOAT baselineOriginX,
        FLOAT baselineOriginY,
        DWRITE_MEASURING_MODE measuringMode,
        __in DWRITE_GLYPH_RUN const* glyphRun,
        __in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
        __maybenull IUnknown* clientDrawingEffect
        ) PURE;

Deze versie bevat meer parameters die handig zijn wanneer u een aangepaste tekstweergave implementeert. De laatste parameter wordt gebruikt voor door de toepassing geïmplementeerde aangepaste tekeneffecten. (Zie Clienttekeningseffecten toevoegen aan een tekstindelingvoor meer informatie over clienttekeningseffecten.

Elke glyphreeks begint bij een beginpunt en wordt vanaf dit punt op een lijn geplaatst. De glyphs worden gewijzigd door de huidige wereldtransformatie en de geselecteerde instellingen voor tekstweergave op het bijbehorende renderdoel. Deze API wordt over het algemeen alleen aangeroepen door toepassingen die hun eigen indeling uitvoeren (bijvoorbeeld een wordprocessor) of door een toepassing die de IDWriteTextRenderer interface heeft geïmplementeerd.

DirectWrite en Direct2D

Direct2D- biedt renderingservices op glyph-niveau via DrawGlyphRun-. Hiervoor moet de toepassing echter de details van rendering implementeren, waardoor de functionaliteit van de DrawText API van GDI zelfstandig wordt gereproduceerd.

Daarom biedt Direct2D- API's die tekst accepteren in plaats van glyphs: ID2D1RenderTarget::DrawTextLayout en ID2D1RenderTarget::DrawText. Beide methoden worden weergegeven op een Direct2D-oppervlak. Voor weergave op een GDI-oppervlak wordt IDWriteBitmapRenderTarget::DrawGlyphRun opgegeven. Voor deze methode moet echter een aangepaste tekstweergave worden geïmplementeerd door de toepassing. (Zie het onderwerp Render naar een GDI-oppervlak voor meer informatie.)

Het gebruik van tekst door een toepassing begint meestal eenvoudig: bijvoorbeeld OK of Annuleren op een knop met een vast formaat plaatsen. Na verloop van tijd wordt het echter complexer omdat internationalisatie en andere functies worden toegevoegd. Uiteindelijk moeten veel toepassingen DirectWrite's tekstindelingsobjecten gebruiken en de tekstweergave implementeren.

Daarom biedt Direct2D- gelaagde API's waarmee een toepassing eenvoudig kan starten en geavanceerder kan worden zonder dat ze hun werkcode hoeven te back-tracken of te verlaten. In het volgende diagram wordt een vereenvoudigde weergave weergegeven:

directwrite en direct2d toepassingsdiagram.

DrawText

DrawText is het eenvoudigst van de API's die moeten worden gebruikt. De functie vereist een Unicode-tekenreeks, een voorgrondborstel, een enkel opmaakobject en een doelrechthoek. Hiermee wordt de hele tekenreeks binnen de rechthoek van de indeling opgemaakt en weergegeven, en indien gewenst bijgesneden. Dit is handig wanneer u een eenvoudig stuk tekst in een stukje gebruikersinterface met vaste indeling plaatst.

DrawTextLayout

Door een IDWriteTextLayout--object te maken, kan een toepassing beginnen met het meten en rangschikken van de tekst en andere UI-elementen en ondersteuning bieden voor meerdere lettertypen, stijlen, onderstrepingen en doorhalen. Direct2D- biedt de DrawTextLayout-API die dit object rechtstreeks accepteert en de tekst op een bepaald punt weergeeft. (De breedte en hoogte worden geleverd door het indelingsobject). Naast het implementeren van alle verwachte functies voor de tekstindeling, interpreteert Direct2D elk effectobject als een penseel en past deze borstel toe op het geselecteerde bereik met glyphs. Inline-objecten worden ook aangeroepen. Een toepassing kan desgewenst niet-symbooltekens (pictogrammen) invoegen in de tekst. Een ander voordeel van het gebruik van een tekstindelingsobject is dat de glyph-posities erin in de cache worden opgeslagen. Daarom is een grote prestatiewinst mogelijk door hetzelfde indelingsobject opnieuw te gebruiken voor meerdere tekenoproepen en te voorkomen dat de glyph-posities voor elke aanroep opnieuw worden berekend. Deze mogelijkheid is niet aanwezig voor DrawTextvan GDI.

DrawGlyphRun

Ten slotte kan de toepassing de IDWriteTextRenderer interface zelf implementeren en DrawGlyphRun aanroepen en FillRectangle- zelf, of een andere rendering-API. Alle bestaande interactie met het object Tekstindeling blijft ongewijzigd.

Zie voor een voorbeeld van hoe u een aangepaste tekstweergave implementeert, het onderwerp Weergeven met een Aangepaste Tekstweergave.

Glyph Rendering

Door DirectWrite- toe te voegen aan een bestaande GDI-toepassing, kan de toepassing de IDWriteBitmapRenderTarget-API gebruiken om glyphs weer te geven. De methode IDWriteBitmapRenderTarget::DrawGlyphRun die DirectWrite biedt, zal in een effen kleur naar een geheugen DC renderen zonder dat hiervoor extra API's zoals Direct2Dnodig zijn.

Hierdoor kan de toepassing geavanceerde functies voor tekstweergave verkrijgen, zoals de volgende:

  • Met Sub-pixel ClearType kan een toepassing glyphs op sub-pixelposities plaatsen om zowel scherpe glyph-rendering als glyph-indeling mogelijk te maken.
  • Antialiasing in Y-richting zorgt voor een soepelere weergave van curven op grotere glyphs.

Een toepassing die overstapt naar Direct2D- krijgt ook de volgende functies:

  • Hardwareversnelling.
  • De mogelijkheid om tekst op te vullen met een willekeurige Direct2D kwast, zoals radiale kleurovergangen, lineaire kleurovergangen en bitmaps.
  • Meer ondersteuning voor lagen en knippen via de PushAxisAlignedClip, PushLayer en CreateCompatibleRenderTarget API's.
  • De mogelijkheid om tekstweergave in grijswaarden te ondersteunen. Hiermee wordt het alfakanaal van de bestemming correct gevuld op basis van zowel de dekking van het tekstpenseel als de antialiasing van de tekst.

Om hardwareversnelling efficiënt te ondersteunen, gebruikt Direct2D een iets andere benadering van gammacorrectie, alfacorrectiegenoemd. Hiervoor hoeft Direct2D de doelkleur pixel niet te inspecteren bij het weergeven van tekst.

Conclusie

In dit onderwerp worden de verschillen en overeenkomsten uitgelegd tussen Direct2D- en DirectWrite en de architecturale motivaties om ze als afzonderlijke, coöperatieve API's te bieden.