Share via


Textrendering mit Direct2D und DirectWrite

Im Gegensatz zu anderen APIs, z. B. GDI, GDI+ oder WPF, interagiert Direct2D mit einer anderen API, DirectWrite, um Text zu bearbeiten und zu rendern. In diesem Thema werden die Vorteile und die Interoperabilität dieser separaten Komponenten beschrieben.

Dieses Thema enthält folgende Abschnitte:

Direct2D ermöglicht inkrementelle Einführung

Das Verschieben einer Anwendung von einer Grafik-API in eine andere kann aus verschiedenen Gründen schwierig oder nicht wie gewünscht sein. Dies kann daran sein, dass Sie Plug-Ins unterstützen müssen, die noch die älteren Schnittstellen verwenden, weil die Anwendung selbst zu groß ist, um in einem Release zu einer neuen API zu portieren, oder weil ein Teil der neueren API wünschenswert ist, aber die ältere API gut genug für andere Teile der Anwendung funktioniert.

Da Direct2D und DirectWrite als separate Komponenten implementiert sind, können Sie Ihr gesamtes 2D-Grafiksystem oder nur den Textteil aktualisieren. Sie können beispielsweise eine Anwendung aktualisieren, um DirectWrite für Text zu verwenden, aber weiterhin GDI oder GDI+ zum Rendern verwenden.

Textdienste im Vergleich zu Textrendering

Mit der Entwicklung der Anwendungen sind die Anforderungen an die Textverarbeitung immer komplexer geworden. Zunächst war Text in der Regel auf statisch angelegte Benutzeroberfläche beschränkt, und der Text wurde in einem klar definierten Feld wie einer Schaltfläche gerendert. Da Anwendungen in einer wachsenden Anzahl von Sprachen verfügbar waren, wurde dieser Ansatz schwieriger zu erhalten, da sowohl die Breite als auch die Höhe des übersetzten Texts in den einzelnen Sprachen erheblich variieren kann. Um sich anzupassen, begannen Anwendungen, ihre Benutzeroberfläche dynamisch so zu gestalten, dass sie von der tatsächlich gerenderten Größe des Texts abhängt, anstatt umgekehrt.

Um Anwendungen bei der Ausführung dieser Aufgabe zu unterstützen, stellt DirectWrite die IDWriteTextLayout-Schnittstelle bereit. Mit dieser API kann eine Anwendung einen Textabschnitt mit komplexen Merkmalen angeben, z. B. verschiedene Schriftarten und Schriftgrößen, Unterstrichen, Durchstreichungen, bidirektionalen Text, Effekte, Auslassungspunkte und sogar eingebettete Nicht-Glyphenzeichen (z. B. ein Bitmap-Emoticon oder ein Symbol). Die Anwendung kann dann verschiedene Merkmale des Texts ändern, da sie iterativ sein Ui-Layout bestimmt. Das DirectWrite Hallo Welt Beispiel, das in der folgenden Abbildung und im Thema Tutorial: Erste Schritte mit DirectWrite gezeigt wird, zeigt viele dieser Effekte.

Screenshot des Beispiels

Das Layout kann die Glyphen entweder ideal basierend auf ihrer Breite positionieren (wie WPF), oder es kann die Glyphen an den nächsten Pixelpositionen ausrichten (wie GDI ).

Zusätzlich zum Abrufen von Textmessungen kann die Anwendung verschiedene Teile des Texts testen. Es kann z. B. wissen, dass auf einen Link im Text geklickt wird. (Weitere Informationen zu Treffertests finden Sie im Thema Ausführen von Treffertests für ein Textlayout .)

Die Textlayoutschnittstelle ist von der Rendering-API entkoppelt, die die Anwendung verwendet, wie im folgenden Diagramm dargestellt:

Textlayout und Grafik-API-Diagramm.

Diese Trennung ist möglich, da DirectWrite eine Renderingschnittstelle (IDWriteTextRenderer) bereitstellt, die Anwendungen implementieren können, um Text mithilfe der gewünschten Grafik-API zu rendern. Die von der Anwendung implementierte IDWriteTextRenderer::D rawGlyphRun-Rückrufmethode wird vom DirectWrite beim Rendern eines Textlayouts aufgerufen. Es liegt in der Verantwortung dieser Methode, die Zeichnungsvorgänge auszuführen oder weiterzureichen.

Für Das Zeichnen von Glyphen stellt Direct2DID2D1RenderTarget::D rawGlyphRun zum Zeichnen auf einer Direct2D-Oberfläche bereit, und DirectWrite stellt IDWriteBitmapRenderTarget::D rawGlyphRun zum Zeichnen auf eine GDI-Oberfläche bereit, die dann mithilfe von GDI in ein Fenster übertragen werden kann. Praktischerweise verfügt DrawGlyphRun sowohl in Direct2D als auch DirectWrite über genau kompatible Parameter für die DrawGlyphRun-Methode, die die Anwendung in IDWriteTextRenderer implementiert.

Nach einer ähnlichen Trennung werden textspezifische Features (z. B. Schriftartenenumeration und -verwaltung, Glyphenanalyse usw.) von DirectWrite anstelle von Direct2D behandelt. Die DirectWrite-Objekte werden direkt von Direct2D akzeptiert. Damit vorhandene GDI-Anwendungen DirectWrite nutzen können, stellt sie die IDWriteGdiInterop-Methodenschnittstelle mit Methoden für die folgenden Aktionen bereit:

Glyphen im Vergleich zu Text

Text ist ein Satz von Unicode-Codepunkten (Zeichen) mit verschiedenen stilistischen Modifizierern (Schriftarten, Gewichtungen, Unterstrichen, Durchstreichungen usw.), die in einem Rechteck angeordnet sind. Eine Glyphe ist im Gegensatz dazu ein bestimmter Index in einer bestimmten Schriftartdatei. Eine Glyphe definiert eine Reihe von Kurven, die gerendert werden können, aber sie hat keine textliche Bedeutung. Es gibt möglicherweise eine m:n-Zuordnung zwischen Glyphen und Zeichen. Eine Sequenz von Glyphen, die aus demselben Schriftzeichen stammen und sequenziell auf einer Basislinie angeordnet sind, wird als GlyphRun bezeichnet. Sowohl DirectWrite als auch Direct2D rufen ihre genaueste Glyphenrendering-API DrawGlyphRun auf, und sie haben sehr ähnliche Signaturen. Folgendes stammt aus 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;

Und diese Methode stammt von 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;

Die DirectWrite Version behält den Baselineursprung, den Messmodus und die Glyphenlaufparameter bei und enthält zusätzliche Parameter.

mit DirectWrite können Sie auch einen benutzerdefinierten Renderer für Glyphen verwenden, indem Sie die IDWriteTextRenderer-Schnittstelle implementieren. Diese Schnittstelle verfügt auch über eine DrawGlyphRun-Methode , wie im folgenden Codebeispiel gezeigt.

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;

Diese Version enthält weitere Parameter, die nützlich sind, wenn Sie einen benutzerdefinierten Textrenderer implementieren. Der letzte Parameter wird für von der Anwendung implementierte benutzerdefinierte Zeichnungseffekte verwendet. (Weitere Informationen zu Clientzeichnungseffekten finden Sie unter Hinzufügen von Clientzeichnungseffekten zu einem Textlayout.

Jede Glyphenausführung beginnt an einem Ursprung und wird auf eine Zeile gesetzt, die von diesem Ursprung aus beginnt. Die Glyphen werden von der aktuellen Welttransformation und den ausgewählten Textrenderingeinstellungen auf dem zugeordneten Renderziel geändert. Diese API wird im Allgemeinen nur direkt von Anwendungen aufgerufen, die ihr eigenes Layout verwenden (z. B. ein Word Processor) oder von einer Anwendung, die die IDWriteTextRenderer-Schnittstelle implementiert hat.

DirectWrite und Direct2D

Direct2D stellt Renderingdienste auf Glyphenebene über DrawGlyphRun bereit. Dies erfordert jedoch, dass die Anwendung die Details des Renderings implementiert, wodurch die Funktionalität der DrawText-API von GDI selbst reproduziert wird.

Aus diesem Grund stellt Direct2D APIs bereit, die Text anstelle von Glyphen akzeptieren: ID2D1RenderTarget::D rawTextLayout und ID2D1RenderTarget::D rawText. Beide Methoden werden auf einer Direct2D-Oberfläche gerendert. Zum Rendern auf einer GDI-Oberfläche wird IDWriteBitmapRenderTarget::D rawGlyphRun bereitgestellt. Für diese Methode muss jedoch ein benutzerdefinierter Textrenderer von der Anwendung implementiert werden. (Weitere Informationen finden Sie im Thema Rendern auf einem GDI Surface .)

Die Verwendung von Text in einer Anwendung beginnt in der Regel einfach: Legen Sie z. B. OK oder Abbrechen auf eine Schaltfläche mit festem Layout. Im Laufe der Zeit wird es jedoch komplexer, wenn die Internationalisierung und andere Features hinzugefügt werden. Schließlich müssen viele Anwendungen die Textlayoutobjekte von DirectWrite verwenden und den Textrenderer implementieren.

Aus diesem Grund bietet Direct2D mehrstufige APIs, die es einer Anwendung ermöglichen, einfach zu starten und komplexer zu werden, ohne ihren funktionierenden Code zurückverfolgen oder aufgeben zu müssen. Im folgenden Diagramm ist eine vereinfachte Ansicht dargestellt:

Directwrite- und Direct2d-Anwendungsdiagramm.

Drawtext

DrawText ist die einfachste der zu verwendenden APIs. Es verwendet eine Unicode-Zeichenfolge, einen Vordergrundpinsel, ein einzelnes Formatobjekt und ein Zielrechteck. Es wird die gesamte Zeichenfolge innerhalb des Layoutrechtecks anlegt, gerendert und optional beschnitten. Dies ist nützlich, wenn Sie einen einfachen Textabschnitt in einem Teil der Benutzeroberfläche mit einem festen Layout einfügen.

DrawTextLayout

Durch das Erstellen eines IDWriteTextLayout-Objekts kann eine Anwendung mit dem Messen und Anordnen von Text und anderen UI-Elementen beginnen und mehrere Schriftarten, Stile, Unterstrichen und Durchstreichungen unterstützen. Direct2D stellt die DrawTextLayout-API bereit, die dieses Objekt direkt akzeptiert und den Text an einem bestimmten Punkt rendert. (Die Breite und Höhe wird vom Layoutobjekt angegeben.) Zusätzlich zur Implementierung aller erwarteten Textlayoutfeatures interpretiert Direct2D jedes Effektobjekt als Pinsel und wendet diesen Pinsel auf den ausgewählten Bereich von Glyphen an. Außerdem werden alle Inlineobjekte aufgerufen. Eine Anwendung kann dann bei Bedarf Nicht-Glyphenzeichen (Symbole) in den Text einfügen. Ein weiterer Vorteil der Verwendung eines Textlayoutobjekts ist, dass die Glyphenpositionen darin zwischengespeichert werden. Daher ist ein großer Leistungsgewinn möglich, indem dasselbe Layoutobjekt für mehrere Zeichnungsaufrufe wiederverwendet wird und eine Neuberechnung der Glyphenpositionen für jeden Aufruf vermieden wird. Diese Funktion ist für DrawText von GDI nicht vorhanden.

DrawGlyphRun

Schließlich kann die Anwendung die IDWriteTextRenderer-Schnittstelle selbst implementieren und DrawGlyphRun und FillRectangle selbst oder eine andere Rendering-API aufrufen. Die gesamte vorhandene Interaktion mit dem Textlayout-Objekt bleibt unverändert.

Ein Beispiel für die Implementierung eines benutzerdefinierten Textrenderers finden Sie im Thema Rendern mithilfe eines benutzerdefinierten Textrenderers .

Glyphenrendering

Durch das Hinzufügen von DirectWrite zu einer vorhandenen GDI-Anwendung kann die Anwendung die IDWriteBitmapRenderTarget-API zum Rendern von Glyphen verwenden. Die IDWriteBitmapRenderTarget::D rawGlyphRun-Methode, die DirectWrite bereitstellt, wird in vollfarbiger Farbe in einem Speicher-DC gerendert, ohne dass zusätzliche APIs wie Direct2D erforderlich sind.

Dadurch kann die Anwendung erweiterte Textrenderingfeatures wie die folgenden abrufen:

  • ClearType unter Pixel ermöglicht es einer Anwendung, Glyphen an Unterpixelpositionen zu platzieren, um sowohl ein scharfes Glyphenrendering als auch ein Glyphenlayout zu ermöglichen.
  • Y-Richtungs-Antialiasing ermöglicht ein glatteres Rendering von Kurven auf größeren Glyphen.

Eine Anwendung, die zu Direct2D wechselt, erhält auch die folgenden Features:

  • Hardwarebeschleunigung.
  • Die Möglichkeit, Text mit einem beliebigen Direct2D-Pinsel zu füllen, z. B. radiale Farbverläufe, lineare Farbverläufe und Bitmaps.
  • Mehr Unterstützung für Layering und Clipping über die APIs PushAxisAlignedClip, PushLayer und CreateCompatibleRenderTarget .
  • Die Möglichkeit, das Rendern von Text im Graustufenbereich zu unterstützen. Dadurch wird der Ziel-Alphakanal entsprechend der Textpinselopacity und der Antialiasierung des Texts ordnungsgemäß aufgefüllt.

Um die Hardwarebeschleunigung effizient zu unterstützen, verwendet Direct2D eine etwas andere Näherung zur Gammakorrektur, die als Alphakorrektur bezeichnet wird. Dies erfordert nicht, dass Direct2D das Renderzielfarbpixel beim Rendern von Text überprüfen kann.

Zusammenfassung

In diesem Thema werden die Unterschiede und Ähnlichkeiten zwischen Direct2D und DirectWrite sowie die architektonischen Beweggründe für die Bereitstellung als separate, kooperative APIs erläutert.