Textrendering mit Direct2D und DirectWrite

Im Gegensatz zu anderen APIs wie GDI,GDI+ oder WPF interoperiert Direct2D mit einer anderen API,DirectWrite , um Text zu bearbeiten und zu rendern. In diesem Thema werden die Vorteile und die Interoperation dieser separaten Komponenten beschrieben.

Dieses Thema enthält folgende Abschnitte:

Direct2D ermöglicht die inkrementelle Einführung

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

Da Direct2D und DirectWrite als separate Komponenten implementiert werden, können Sie das gesamte 2D-Grafiksystem oder nur den Textteil davon aktualisieren. Beispielsweise können Sie eine Anwendung aktualisieren, um DirectWrite für Text zu verwenden, aber trotzdem GDI oder GDI+ Rendering verwenden.

Textdienste im Vergleich zum Textrendering

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

Um Anwendungen beim Abschließen dieser Aufgabe zu unterstützen, DirectWrite die IDWriteTextLayout-Schnittstelle bereit. Diese API ermöglicht es einer Anwendung, einen Textteil mit komplexen Merkmalen wie verschiedenen Schriftarten und Schriftgraden, Unterstreichungen, Durchgestrichenheiten, bidirektionalem Text, Effekten, Auslassungszeichen und sogar eingebetteten Nicht-Glyphenzeichen (z. B. Bitmap-Emoticon oder Symbol) anzugeben. Die Anwendung kann dann verschiedene Merkmale des Texts ändern, während sie iterativ das Layout der Benutzeroberfläche bestimmt. Das DirectWrite Hallo Welt-Beispiel,das in der folgenden Abbildung und im Thema Tutorial: Erste Schritte mit DirectWrite gezeigt wird, zeigt viele dieser Auswirkungen.

Screenshot des Beispiels "hello world".

Das Layout kann die Glyphen idealerweise 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 beispielsweise sein, dass sie wissen möchte, dass auf einen Link im Text geklickt wird. (Weitere Informationen zu Treffertests finden Sie im Thema How to Perform Hit Testing on a Text Layout .)

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)bietet, die Anwendungen implementieren können, um Text mithilfe der von Ihnen verwendeten Grafik-API zu rendern. Die von der Anwendung implementierte IDWriteTextRenderer::D rawGlyphRun-Rückrufmethode wird von DirectWrite beim Rendern eines Textlayouts aufgerufen. Es liegt in der Verantwortung dieser Methode, die Zeichnungsvorgänge durchzuführen oder zu übergeben.

Zum Zeichnen von Glyphen stellt Direct2D ID2D1RenderTarget::D rawGlyphRun für das Zeichnen auf eine Direct2D-Oberfläche und DirectWrite IDWriteBitmapRenderTarget::D rawGlyphRun zum Zeichnen auf eine GDI-Oberfläche zur Anwendung, die dann mithilfe von GDI in ein Fenster übertragen werden kann. Bequemerweise verfügen 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. Schriftartenumeration und -verwaltung, Glyphenanalyse und ähnliches) von DirectWrite direct2D behandelt. Die DirectWrite objekte werden direkt von Direct2D akzeptiert. Damit vorhandene GDI-Anwendungen die Vorteile von DirectWrite nutzen können, stellt sie die IDWriteGdiInterop-Methodenschnittstelle mit Methoden für folgende Aufgaben bereit:

Glyphen im Vergleich zu Text

Text ist ein Satz von Unicode-Codepunkten (Zeichen) mit verschiedenen stilischen Modifizierern (Schriftarten, Gewichtungen, Unterstreichungen, Durchgeknstreichungen und so weiter), die in einem Rechteck angeordnet sind. Ein Glyphen hingegen ist ein bestimmter Index in einer bestimmten Schriftartdatei. Ein Glyph definiert eine Reihe von Kurven, die gerendert werden können, hat aber keine textuelle Bedeutung. Möglicherweise gibt es eine n:n-Zuordnung zwischen Glyphen und Zeichen. Eine Sequenz von Glyphen, die aus demselben Schriftartengesicht stammen und sequenziell auf einer Baseline festgelegt werden, wird als GlyphRun bezeichnet. Sowohl DirectWrite als auch Direct2D rufen ihre präziseste Glyphenrendering-API DrawGlyphRun auf und haben sehr ähnliche Signaturen. Das folgende Beispiel wird von ID2D1RenderTarget in Direct2D verwendet:

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 ist von IDWriteBitmapRenderTarget inDirectWrite:

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 Baseline-Ursprung, den Messmodus und die Ausführungsparameter des Glyphen bei und enthält zusätzliche Parameter.

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 das folgende Codebeispiel zeigt.

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 How to Add Client Drawing Effects to a Text Layout.

Jede Glyphen-Ausführung beginnt an einem Ursprung und wird in einer Zeile ab diesem Ursprung ausgeführt. Die Glyphen werden durch die aktuelle Welttransformation und die ausgewählten Textrenderingeinstellungen auf dem zugeordneten Renderziel geändert. Diese API wird im Allgemeinen nur direkt von Anwendungen aufgerufen, die über ein eigenes Layout (z. B. einen Textprozessor) oder durch eine Anwendung, die die IDWriteTextRenderer-Schnittstelle implementiert hat.

DirectWrite und Direct2D

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

Daher bietet Direct2D APIs, 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. Diese Methode erfordert jedoch, dass ein benutzerdefinierter Textrenderer von der Anwendung implementiert wird. (Weitere Informationen finden Sie im Thema Rendern auf einer GDI-Oberfläche.)

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

Aus diesem Grund bietet Direct2D mehrschichtige APIs, die es einer Anwendung ermöglichen, einfach zu starten und komplexer zu werden, ohne ihren Arbeitscode zurückver nachverfolgen oder verdringen zu müssen. Eine vereinfachte Ansicht ist im folgenden Diagramm dargestellt:

directwrite- und direct2d-Anwendungsdiagramm.

Drawtext

DrawText ist die einfachste der zu verwendenden APIs. Dabei werden eine Unicode-Zeichenfolge, ein Vordergrundpinsel, ein einzelnes Formatobjekt und ein Zielrechteck verwendet. Es wird die gesamte Zeichenfolge innerhalb des Layoutrechtecks angeordnet und gerendert und optional abgeschnitten. Dies ist nützlich, wenn Sie einen einfachen Text in einer Benutzeroberfläche mit festem Layout hinzufügen.

DrawTextLayout

Durch das Erstellen eines IDWriteTextLayout-Objekts kann eine Anwendung mit dem Messen und Anordnen des Texts und anderer Benutzeroberflächenelemente beginnen und mehrere Schriftarten, Stile, Unterstreichungen und Durchstreichungen unterstützen. Direct2D stellt die DrawTextLayout-API bereit, die dieses Objekt direkt akzeptiert und den Text an einem bestimmten Punkt rendert. (Breite und Höhe werden vom Layoutobjekt bereitgestellt.) Zusätzlich zur Implementierung aller erwarteten Textlayoutfeatures interpretiert Direct2D jedes Effektobjekt als Pinsel und wenden diesen Pinsel auf den ausgewählten Bereich von Glyphen an. Außerdem werden alle Inlineobjekte aufruft. Eine Anwendung kann dann bei Wunsch Nichtsymbolzeichen (Symbole) in den Text einfügen. Ein weiterer Vorteil der Verwendung eines Textlayoutobjekts besteht in der Zwischenspeicherung der Glyphenpositionen. Daher ist ein großer Leistungsgewinn möglich, indem dasselbe Layoutobjekt für mehrere Zeichnen-Aufrufe wiederverwendbar ist und vermieden wird, dass die Glyphenpositionen für jeden Aufruf neu berechnet werden. 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. Alle vorhandenen Interaktionen mit dem Textlayoutobjekt bleiben unverändert.

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

Glyphenrendering

Durch 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 Volltonfarbe auf einem Speicherdomänencontroller gerendert, ohne dass zusätzliche APIs wie Direct2Derforderlich sind.

Dadurch kann die Anwendung erweiterte Textrenderingfeatures wie die folgenden abrufen:

  • MitHilfe von Subpixel-ClearType kann eine Anwendung Glyphen an Subpixelpositionen setzen, um das Rendern von spitzen Glyphen und das Layout von Glyphen zu ermöglichen.
  • Antialiasing in Y-Richtung ermöglicht ein reibungsloseres Rendern von Kurven auf größeren Glyphen.

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

  • Hardwarebeschleunigung.
  • Die Fähigkeit, Text mit einem beliebigen Direct2D-Pinsel zu füllen, z. B. radiale Farbverläufe, lineare Farbverläufe und Bitmaps.
  • Weitere Unterstützung für Das Layering und Clipping über die APIs PushAxisAlignedClip, PushLayer und CreateCompatibleRenderTarget.
  • Die Möglichkeit zur Unterstützung des Graustufentextrenderings. Dadurch wird der Ziel-Alphakanal entsprechend der Deckkraft des Textpinsels 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. Hierfür ist direct2D nicht erforderlich, um das Renderzielfarbpixel beim Rendern von Text zu überprüfen.

Zusammenfassung

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