Dieser Artikel wurde maschinell übersetzt.

DirectX-Faktor

Wer hat Angst vor Glyph läuft?

Charles Petzold

Charles PetzoldIch habe zuerst das Konzept der Glyphen in Windows Presentation Foundation (WPF) einige Jahre zurück."Glyph" bezeichnet in der Typografie die grafische Darstellung eines Zeichens, anstatt seine Funktion in einer bestimmten schriftlichen Sprache, die durch das Zeichen Unicode-Wert angezeigt wird.Ich wusste, dass die WPF-Symbolelement und GlyphRun-Klasse repräsentiert eine alternative Möglichkeit zum Anzeigen von Text, aber sie schienen eine Ebene der unnötige Komplexität hinzufügen.Die größte Kuriosität beteiligt, verweisen auf eine gewünschte Schriftart nicht durch den Namen einer Schriftart-Familie, sondern durch den Dateipfad der eigentlichen Schriftart-Datei.Ich hatte Codierung für Windows seit Beta-Versionen von 1.0, und ich hatte noch nie brauchte, um eine Schriftart anhand des Dateinamens zu verweisen.Es war nicht einfach, wie es gemacht wird.

Schnell schloss ich, dass Glyphs und GlyphRun viel zu esoterisch für mainstream-Programmierer wie mich waren.Erst Jahre später, als ich zu arbeiten mit Microsoft XML Paper Specification (XPS begann) hat die Logik hinter Glyphen deutlich geworden.

Die grundlegende Unterscheidung

Normalerweise, wenn ein Programm eine Schriftart von Windows anfordert, tut sie dies mit den Namen einer Schriftart-Familie z. B. Century Schoolbook und Attribute wie kursiv oder Fett.Zur Laufzeit sucht Windows eine Font-Datei auf dem System des Benutzers mit einer Schriftart, die den Familiennamen entspricht.Kursiv und Fett kann entweder in dieser Schrift oder synthetisierte vom System.Um das Layout Text greift entweder Windows oder der Anwendung metrische Schriftartinformationen, die die Größe der Schrift-Zeichen beschreibt.

Was passiert, wenn zwei verschiedene Benutzer zwei unterschiedliche Font-Dateien auf ihrem System haben, die beide eine Schriftart mit den Familiennamen Century Schoolbook, aber mit etwas andere Schriftarteigenschaften enthalten?Das ist kein echtes Problem.Da Text formatiert ist und zur Laufzeit angelegt, das eigentliche Rendern dieser zwei Schriftarten könnte etwas anders sein, aber es würde nicht wirklich wichtig.Anwendungsprogramme sollen so flexibel sein.

XPS-Dokumente sind jedoch verschieden.Viel wie PDF beschreibt XPS ein Dokument mit festen Seiten.Der Text auf jeder Seite ist bereits angelegt und exakt positioniert.Wenn ein solches Dokument mit einer Schriftart, das ist etwas anders als die Schriftart verwendet dargestellt wird, um die Seite entwerfen, wird nicht es richtig aussehen.Dies ist deshalb XPS-Dokumente oft eingebettete Schriftart-Dateien enthalten, und deshalb die XPS-Seiten verwenden das Symbolelement verweisen diese Font-Dateien und den Text zu rendern.Jede Mehrdeutigkeit wird vollständig eliminiert.

Normalerweise verweisen wir auf Textzeichen Zeichencodes.Wir müssen in der Regel nicht Bescheid über die präzise Glyph, das geschieht als Folge der Verwendung dieser Zeichencode mit einer bestimmten Schriftart angezeigt werden.Aber manchmal ist es wichtig, mehr Kontrolle über die Symbole selbst zu haben.

Sie können davon ausgehen, es gibt eine 1: 1-Entsprechung zwischen Zeichencodes und Glyphen in einer bestimmten Schrift, und das ist in der Regel der Fall.Aber es gibt sehr wichtige Ausnahmen: Einige Font-Dateien enthalten Ligaturen, die einzelne Glyphen entspricht Zeichenpaare wie Fi oder fl.Einige nicht-lateinische Zeichensätze erfordern mehrere Symbole um ein einzelnes Zeichen zu rendern.Darüber hinaus enthalten einige Font-Dateien Alternative Glyphen für bestimmte Zeichen – z. B. eine NULL mit einem Schrägstrich durch es, kleine Großbuchstaben, Kleinbuchstaben oder Briefe mit stilistischen Schwungschrift-Zeichen verwendet.Diese stilistischen Alternativen sind charakteristisch für eine bestimmte Schriftart-Datei statt einer Schriftart.Deshalb ist die richtige Schriftart-Datei ist überaus wichtig.

Wenn Sie eine Anwendung Windows Store für Windows 8 schreiben, können Sie machen diese stilistische Alternativen über die Windows-Runtime-API verwenden.Kapitel 16 der "Programming Windows, 6th Edition" (O' Reilly Media, 2012) hat ein Programm namens TypographyDemo, das genau dies veranschaulicht.Aber die zugrunde liegende Unterstützung für Symbole in Windows 8 wird in DirectX implementiert, und die Macht der Glyphen selbst offenbart sich die meisten in dieser Umgebung.

Die Glyphe der DirectX-Unterstützung

Erkunden wie Glyphen in DirectX angezeigt umfasst die Ablaufverfolgung eines Pfads über mehrere Schnittstellen, Methoden und Strukturen.

Beginnen wir mit der ID2D1RenderTarget-Schnittstelle, die die grundlegenden Methoden zum Anzeigen von 2D Grafiken und Text enthält.Diese Schnittstelle definiert eine DrawGlyphRun-Methode.Diese Methode erfordert eine Struktur des Typs DWRITE_GLYPH_RUN, das beschreibt die Symbole angezeigt werden, und auch Referenzen ein Objekt der IDWriteFontFace geben.

Eine Möglichkeit zum Abrufen eines IDWriteFontFace-Objekts ist durch die CreateFontFace-Methode der IDWriteFactory.Diese Methode erfordert ein IDWriteFontFile-Objekt, das durch die CreateFontFileReference-Methode des IDWriteFactory abgerufen werden.

Die CreateFontFileReference-Methode verweist eine Font-Datei über einen Pfad und einen Dateinamen.Werden jedoch bei Verwendung von DirectX in einer Windows-Speicher-Anwendung Ihre app wahrscheinlich nicht vollen und kostenlosen Zugriff auf Festplatte des Benutzers, und Sie können nicht in der Regel Schriften in dieser Weise zugreifen.Jede Schriftartdatei, die Sie mit CreateFontFileReference verweisen wird wahrscheinlich als eine Ressource definiert werden und in das Anwendungspaket gebunden werden.

Sie können nicht jedoch irgendein Font-Datei im Paket Ihrer Anwendung einschließen.Wenn eine Schriftart Teil der Anwendung ist, muss eine Lizenz, um diese Schriftart zu verteilen.Glücklicherweise hat Microsoft einige Font-Dateien von Ascender Corp. lizenziert.zu dem ausdrücklichen Zweck der so dass Sie sie mit Ihrer Anwendung verteilen.Diese Font-Dateien wurden in erster Linie für XNA-Anwendungen verwendet, aber sie sind auch aus Sicht der Glyphen interessant.

Zum herunterladbaren Code für diese Spalte ist Grundlage ein Programm namens GlyphDump, die ich erstellt die DirectX App (XAML)-Vorlage im Visual Studio Express 2013 Vorschau.Diese Vorlage erstellt eine Anwendung, die DirectX-Grafiken auf eine SwapChainPanel rendert.

Ich einen neuen Filter (und entsprechenden Ordner) in das GlyphDump-Projekt mit dem Namen Schriftarten erstellt und hinzugefügt von Ascender Corporation lizenziert 10 Font-DateienEine ListBox in DirectXPage.xaml listet explizit die Familiennamen dieser Schriftarten mit Tageigenschaften verweisen auf die Dateinamen.Wenn man ausgewählt wird, erstellt das Programm den Pfad und den Namen der Schriftartdatei wie folgt:

Package::Current->InstalledLocation->Path +
  "\\Fonts\\" + filename;

Die GlyphDumpRenderer-Klasse wird dann dieser Pfad verwendet, um ein IDWriteFontFile-Objekt und ein IDWriteFontFace-Objekt zu erstellen.

Der Rest des Auftrags erfolgt in die Render-Methode, siehe Abbildung 1.

Abbildung 1 die Render-Methode in GlyphDump

bool GlyphDumpRenderer::Render()
{
  if (!m_needsRedraw)
      return false;
  ID2D1DeviceContext* context = m_deviceResources->GetD2DDeviceContext();
  context->SaveDrawingState(m_stateBlock.Get());
  context->BeginDraw();
  context->Clear(ColorF(ColorF::White));
  context->SetTransform(m_deviceResources->GetOrientationTransform2D());
  if (m_fontFace != nullptr)
  {
    Windows::Foundation::Size outputBounds = m_deviceResources->GetOutputBounds();
    uint16 glyphCount = m_fontFace->GetGlyphCount();
    int rows = (glyphCount + 16) / 16;
    float boxHeight = outputBounds.Height / (rows + 1);
    float boxWidth = outputBounds.Width / 17;
    // Define entire structure except glyphIndices
    DWRITE_GLYPH_RUN glyphRun;
    glyphRun.fontFace = m_fontFace.Get();
    glyphRun.fontEmSize = 0.75f * min(boxHeight, boxWidth);
    glyphRun.glyphCount = 1;
    glyphRun.glyphAdvances = nullptr;
    glyphRun.glyphOffsets = nullptr;
    glyphRun.isSideways = false;
    glyphRun.bidiLevel = 0;
    for (uint16 index = 0; index < glyphCount; index++)
    {
      glyphRun.glyphIndices = &index;
      context->DrawGlyphRun(Point2F(((index) % 16 + 0.5f) * boxWidth,
                                    ((index) / 16 + 1) * boxHeight),
                                    &glyphRun,
                                    m_blackBrush.Get());
    }
  }
  // We ignore D2DERR_RECREATE_TARGET here.
This error indicates
  // that the device is lost.
It will be handled during
  // the next call to Present.
HRESULT hr = context->EndDraw();
  if (hr != D2DERR_RECREATE_TARGET)
  {
    DX::ThrowIfFailed(hr);
  }
  context->RestoreDrawingState(m_stateBlock.Get());
  m_needsRedraw = false;
  return true;
}

Diese Render-Methode zeigt alle Glyphen in der ausgewählten Schriftart-Datei in Zeilen mit je 16 Zeichen, so dass versucht wird, einen FontEmSize-Wert ausreichend klein für diese Anzeige berechnen. (Für einige Schriftarten mit vielen Symbolen, das gut funktioniert nicht.) Normalerweise ist das GlyphIndices-Feld der DWRITE_GLYPH_RUN-Struktur ein Array von Symbolindizes. Hier bin ich zu einem Zeitpunkt nur eine Glyphe Darstellung.

Die DrawGlyphRun-Methode erfordert einen Koordinatenpunkt, die DWRITE_GLYPH_RUN-Struktur und einen Pinsel. Die Koordinate zeigt, wo am linke Rand der Glyphe Grundlinie positioniert werden soll. Beachten Sie, dass ich sagte "Grundlinie." Dies ist anders als die meisten Text-Display-Methoden, die erfordern, die linke obere Ecke des ersten Zeichens angibt.

Abbildung 2 zeigt vielleicht die interessanteste Schriftart dieser Partie, die ein Familienname von Pescadero und eine Schriftart-Dateiname des Pesca.ttf hat.

The GlyphDump Program Showing the Pescadero Font
Abbildung 2 zeigt die Schriftart Pescadero GlyphDump-Programm

Bevor Sie dieses Programm schreiben, hatte ich nie eine Anzeige wie hier gesehen. Es beginnt so etwas wie eine traditionelle ASCII-Tabelle zu suchen, aber dann gibt es eine Reihe von Glyphen für numerische hoch- und Tiefstellungsebenen und eine ganze Sammlung von Ligaturen von verschiedenen Arten, plus Großbuchstaben mit dekorativen Schwungschrift-Zeichen.

Offensichtlich ist das GlyphIndices-Feld des DWRITE_GLYPH_RUN nicht dasselbe als Zeichencode. Dies sind die Indizes, die die eigentlichen Symbole in der Schriftartdatei verweisen und diese Glyphen brauchen nicht einmal zu jeglicher Art der rationalen Ordnung vorliegen.

Text mit Glyphen

Sie könnte schon ein Dienstprogramm in der Lage, zum Anzeigen von Text mit einer bestimmten Schriftart-Datei mit Symbolindizes statt Zeichencodes sehen. Sie können angeben, genau welche Glyphen soll.

Das FancyTitle-Projekt veranschaulicht dies. Die Idee dahinter ist, dass Sie ein Programm, das vor allem XAML-basiert ist, aber Sie wollen einen Phantasie-Titel mit einigen Ligaturen und Schwungschrift-Zeichen aus der Schriftart Pescadero. Das Projekt umfasst die Pesca.ttf-Datei und die XAML-Datei definiert die SwapChainPanel haben eine Breite von 778 und einer Höhe von 54, Werte wählte ich empirisch anhand der Größe des gerenderten Textes.

Da die Display-Anforderungen dieses Projekts einfach sind, entfernt ich die FancyTitleMain-Klasse und die Rendering-Klassen verlassen die DirectXPage-Klasse die SwapChainPanel leisten. (Ich musste jedoch ändern DeviceResources leicht zu IDeviceNotify eine Klassenschnittstelle Ref DirectXPage IDevice Implementieren könnte­benachrichtigen und benachrichtigt werden, wenn das Ausgabegerät verloren und neu erstellt wird.)

Der Textausgabe angezeigt, die Abbildung 3 hat 24 Zeichen, aber nur 22 Glyphen. Sie erkennen die Ligaturen und Schwungschrift-Zeichen von Abbildung 2.

The FancyTitle Output
Abbildung 3 die FancyTitle-Ausgabe

Ich habe DirectX Hintergrund Alice blau gemacht, so Sie sehen können, dass die SwapChainPanel kaum größer als der Text ist. Natürlich ist es möglich, die Größe der Ausgabe zu antizipieren, gerade weil die Font-Datei Teil der Anwendung ist und die Symbole direkt zugegriffen wird sind.

Sie können Ligaturen und alternative Glyphen erhalten, ohne Verwendung von DrawGlyphRun. Sie erhalten sie auch mit geringerer Genauigkeit das TextBlock-Element in der Windows-Runtime, als die Typografie zu verwenden­Demo-Programm aus meinem Buch Windows 8 veranschaulicht. In DirectWrite können Sie die SetTypography-Methode des IDWriteTextLayout mit einem IDWriteTypography-Objekt, die letztlich ein Mitglied der umfangreichen DWRITE_FONT_FEATURE_TAG-Enumeration verweist. Aber diese Techniken sind nicht ganz so sicher wie die Symbole genau angeben.

Wie bekommen Sie kursiv und fett gedruckt mit DrawGlyphRun? In vielen Fällen enthalten andere Schriftart-Dateien kursive und Fett Variationen einer Schriftart. Zählen Sie die durch das GlyphDump-Programm enthaltenen Schriftarten ein paar Fett Schriftarten und eine helle Schrift. Jedoch haben Sie auch die Möglichkeit, Regular und bold Zeichen mit DWRITE_FONT_SIMULATIONS Flags in CreateFontFace zu simulieren.

Fortschritte und Offsets

GlyphDump und FancyTitle festgelegt zwei Feldern in DWRITE_GLYPH_RUN auf Nullptr. Diese beiden Felder sind GlyphAdvances und GlyphOffsets benannt.

Wenn Sie ein Array von Glyphen anzuzeigen, geben Sie den Ursprung der linken Grundlinie das erste Zeichen. Für jedes aufeinanderfolgende Zeichen ist die horizontale Koordinate des Ursprungs automatisch basierend auf der Breite des Zeichens erhöht. (Ein ähnlicher Prozess tritt seitwärts Text angezeigt werden soll.) Dieser Anstieg ist bekannt als "Vorschuss."

Hier erhalten Sie die Fortschritte, die DirectX für Abstand Zeichen verwendet, indem die GetDesignGlyphMetrics-Methode des IDWriteFontFace. Das Ergebnis ist ein Array von DWRITE_GLYPH_METRICS Strukturen, eine für jede Symbolindex, in denen Sie interessiert sind. Das AdvanceWidth-Feld der Struktur gibt den Fortschritt im Vergleich zu dem DesignUnitsPerEm Feld der DWRITE_FONT_METRICS-Struktur, die aus der GetMetrics-Methode des IDWriteFontFace gewonnen, und das auch vertikale Metriken für alle Glyphen innerhalb einer bestimmten Schriftart enthält.

Oder rufen Sie die GetDesignGlyphAdvances-Methode des IDWriteFontFace1, wonach auch Fortschritte im Vergleich zu den DesignUnitsPerEm-Wert. Teilen Sie die Werte durch DesignUnitsPerEm (die oft eine nette Runde Wert z. B. 2.048) und dann mit der Em-Größe angegeben in DWRITE_GLYPH_RUN multiplizieren.

Das GlyphAdvances-Array wird häufig zum Raum Zeichen näher zusammen oder weiter auseinander als die Design-Metriken geben. Wenn Sie es verwenden möchten, müssen Sie ein Array von Werten GlyphAdvances fest, die mindestens die Größe des Arrays von Symbolindizes, minus eins. Vorschuss wird nicht auf das letzte Symbol gebraucht, weil nichts darüber hinaus angezeigt wird.

Das GlyphOffsets-Feld ist ein Array von DWRITE_GLYPH_OFFSET Strukturen, eine für jedes Zeichen. Die beiden Felder sind AdvanceOffset und AscenderOffset, die einen gewünschten Offset angeben (auf der rechten Seite und oben, beziehungsweise) relativ normaler Speicherort des Charakters. Diese Einrichtung wird häufig in XPS-Dateien verwendet, um mehrere Glyphen einer bestimmten Schriftart überall auf der Seite zu positionieren.

Das CenteredGlyphDump-Programm veranschaulicht, wie das GlyphOffsets-Feld verwenden, um das gesamte Array von Symbolen aus einer bestimmten Schriftart-Datei mit einem einzelnen Aufruf von DrawGlyphRun anzuzeigen:

context->DrawGlyphRun(Point2F(), &m_glyphRun, m_blackBrush.Get());

Die Koordinate an DrawGlyphRun übergeben ist (0, 0), und GlyphAdvances auf ein Array von Nullwerten zu hemmen, Förderung der aufeinanderfolgende Glyphen festgelegt ist. Die Position der einzelnen Symbole wird vollständig durch GlyphOffsets geregelt. Diese Position basiert auf Glyph Metriken um jedes Zeichen in einer Spalte zu zentrieren. Abbildung 4 zeigt das Ergebnis.

The CenteredGlyphDump Program
Abbildung 4 das CenteredGlyphDump-Programm

Die eigene Font-Loader

Wenn eine Schriftartdatei ein Anwendungspaket gehört, ist es relativ einfach einen Dateipfad abgeleitet werden, die mit CreateFontReference verwendet werden können. Aber was ist, wenn Sie eine Schriftart, die in einem XPS oder EPUB-Paket befindet oder vielleicht in isoliertem Speicher oder in der Wolke?

So lange, wie Sie Code, die die Font-Datei zugreift schreiben können, können Sie von DirectX zugreifen. Du musst bieten zwei Klassen, die IDWriteFontFileLoader implementiert und andere, die IDWriteFontFileStream implementiert. Im Allgemeinen ist die Klasse, die IDWriteFontFileLoader implementiert ein Singleton, der alle Font-Dateien zugreift, die Ihrer Anwendung benötigen, die und weist jedem von ihnen einen Schlüssel. Die CreateStreamFromKey-Methode in der IDWriteFontFileLoader-Implementierung gibt eine Instanz der IDWriteFontStream für jede Schriftartdatei.

Diese zwei Klassen verwenden, Sie zuerst eine einzelne Instanz der Klasse, die implementiert IDWriteFontFileLoader instanziieren und an die RegisterFontFileLoader des IDWriteFactory-Objekts übergeben. Anschließend rufen Sie die CreateFontFileReference um ein IDWriteFontFile-Objekt zu erhalten, sondern rufen Sie CreateCustomFontFileReference mit dieser IDWriteFontFileLoader-Instanz und einem Schlüssel, die Identifizierung der gewünschten bestimmte Schriftart-Datei.

Diese Technik wird in das CenteredGlyphDump-Programm gezeigt. Das Projekt umfasst zwei Klassen — PrivateFontFileLoader und PrivateFontFileStream — die beiden Schnittstellen implementieren. Die Klassen Zugriff-Schriftart-Dateien im Anwendungspaket, aber sie könnte für andere Zwecke angepasst werden.

Es ist wahrscheinlich die IDWriteFontFileLoader-Implementierung müssen Datei I/O telefonieren, und in einer Windows-Speicher-Anwendung müssen diese Aufrufe asynchron sein. Es macht sehr viel Sinn für die IDWriteFontFileLoader-Klasse, um eine asynchrone Methode zu definieren, die alle Schriftarten in den Speicher geladen und die IDWriteFontFileStream um diese Speicherblöcke einfach Zeiger wieder. Dies ist der Ansatz habe ich mit PrivateFontFileLoader und PrivateFontFileStream, nach eng Untersuchung der Direct2D-Magazin-App-Probe unter den Microsoft-Beispielcode für Windows 8.1.

Der Schlüssel zu jeder Datei zu identifizieren habe ich den Dateinamen. Wenn die asynchrone Laden-Methode in PrivateFontFileLoader abgeschlossen ist, erhält das CenteredGlyphDump-Programm diese Dateinamen für die ListBox. Deshalb werden nur die Dateinamen angezeigt, Abbildung 4. Das Programm ist unwissend von der Familie-Schriftartnamen, die jede Datei zugeordnet.

Aus Zeichen, Symbole

Natürlich, Anzeigen von Text durch Verweisen auf Glyphen ist in Ordnung, wenn Sie genau welche Glyphen kennen, aber können Sie normale Unicode-Zeichen mit DrawGlyphRun anzeigen?

Sie können, da IDWriteFontFace eine GetGlyphIndices-Methode verfügt, die Zeichencodes zu Symbolindizes für die bestimmte Schriftart-Datei konvertiert. Dabei nimmt er das Standardsymbol für jeden Charakter-Code, damit Sie keines der raffinierte Alternativen erhalten.

Aber die Zeichencodes, die Sie an GetGlyphIndices übergeben sind in einer Form, die vielleicht einzigartig in allen Fenstern. Statt 16-Bit-Zeichen-codes (wie der Fall ist, wenn Sie normalerweise mit Unicode-Zeichenfolgen arbeiten), müssen Sie ein Array von 32-Bit-Zeichen-Codes zu erstellen. Wie Sie vielleicht wissen, Unicode ist eigentlich ein 21-Bit Zeichensatz, aber Zeichen werden häufig als 16-Bit-Werte (genannt UTF-16), was bedeutet, dass einige Zeichen umfassen zwei 16-Bit-Werte gespeichert. Aber GetGlyphIndices will 32-Bit-Werte. Sofern Ihre Zeichenkette Zeichen mit Codes über 0xFFFF verfügt, können Sie einfach Werte aus einem Array übertragen.

Wenn man mit normalen Zeichen des lateinischen Alphabets, können Sie auch davon ausgehen, daß es eine 1: 1-Entsprechung zwischen Zeichen und Glyphen. Andernfalls müssen Sie erstellen eine größere Ausgabearray um die Indizes zu erhalten.

Diese einfache Technik zeigt das HelloGlyphRun-Projekt. Abbildung 5 zeigt den Code, lädt eine Schriftartdatei und richtet eine DWRITE_GLYPH_RUN-Struktur. Die Update-Methode passt die Glyph-Offsets, um eine Art Plätschern Effekt des Texts zu erreichen.

Abbildung 5 definieren eine DWRITE_GLYPH_RUN aus einer Zeichenfolge

// Convert string to glyph indices
std::wstring str = L"Hello, Glyph Run!";
uint32 glyphCount = str.length();
std::vector<uint32> str32(glyphCount);
for (uint32 i = 0; i < glyphCount; i++)
     str32[i] = str[i];
m_glyphIndices = std::vector<uint16>(glyphCount);
m_fontFace->GetGlyphIndices(str32.data(), glyphCount, m_glyphIndices.data());
// Allocate array for offsets (set during Update)
m_glyphOffsets = std::vector<DWRITE_GLYPH_OFFSET>(glyphCount);
// Get output bounds
Windows::Foundation::Size outputBounds = m_deviceResources->GetOutputBounds();
// Define fields of DWRITE_GLYPH_RUN structure
m_glyphRun.fontFace = m_fontFace.Get();
m_glyphRun.fontEmSize = outputBounds.Width / 8; // Empirical
m_glyphRun.glyphCount = glyphCount;
m_glyphRun.glyphIndices = m_glyphIndices.data();
m_glyphRun.glyphAdvances = nullptr;
m_glyphRun.glyphOffsets = m_glyphOffsets.data();
m_glyphRun.isSideways = false;
m_glyphRun.bidiLevel = 0;

Obwohl Sie wahrscheinlich DrawGlyphRun nur mit Font-Dateien verwenden werden sind Sie vertraut mit, ist es möglich, festzustellen, welche Art von Glyphen befinden sich in einer bestimmten Schriftart-Datei zur Laufzeit. IDWriteFontFace definiert eine TryGetFontTable-Methode, die Tabellen in der OpenFont-Datei zugreift. Ein Tag der "Cmap" für die Charakter-Glyph Tabelle und "GSUB" für die Glyph-Ersetzungstabelle verwenden, aber bereit sein, viele quälende stundenlang mit der OpenType-Spezifikation, diese Tabellen erfolgreich zu lesen.

Glyph läuft mit System-Fonts

Ist DrawGlyphRun nur gut für Font-Dateien, die Sie selbst liefern? Zuerst scheint es so, aber können Sie es mit System-Fonts sowie. Hier ist der Prozess: Verwenden Sie die GetSystemFontCollection-Methode des IDWriteFactory, ein IDWriteFontCollection-Objekt ab. Dieses Objekt können Sie alle die Familiennamen, die auf dem System installierten Schriftarten zugeordnet zu suchen. Die GetFontFamily-Methode des IDWriteFontCollection gibt ein Objekt vom Typ IDWriteFontFamily. Ab rufen Sie GetMatchingFonts oder GetFirstMatchingFont um die Schriftfamilie mit kursiv, Fett und Stretch-Attribute zu kombinieren, um eine IDWriteFont zu erhalten.

Sobald Sie ein IDWriteFont-Objekt haben, rufen Sie CreateFontFace um ein IDWriteFontFace-Objekt zu erhalten. Das ist die gleiche Art von von CreateFontFace in den früheren Programmen abgerufenes! Aus diesem Objekt können Sie die Einrichtung einer DWRITE_GLYPH_RUN-Struktur für DrawGlyphRun beginnen.

Dies wird in das SystemFontGlyphs-Projekt veranschaulicht. Das Projekt verwendet die GetSystemFontCollection in seiner DirectXPage-Klasse, um ein Listenfeld mit den Systemnamen von Schriftfamilien zu füllen. Wenn ein Element ausgewählt ist, wird ein IDWriteFontFace-Objekt abgeleitet, die an dem Renderer übergeben wird.

Die SystemFontGlyphsRenderer-Klasse erstellt eine DWRITE_GLYPH_RUN-Struktur, basierend auf dem Text "Annoying vibrierende Texteffekt." Die Update-Methode ist dann verpflichtet, die Werte des Arrays Offsets Glyph auf Zufallszahlen zwischen-3 und 3, so dass es scheinen, als ob alle Zeichen der Zeichenfolge unabhängig vibrierende sind festgelegt.

Es scheint nicht viel von einen konzeptionellen Unterschied zwischen IDWriteFont und IDWriteFontFace werden, außer dass IDWriteFont immer eine Schriftart darstellt, die nicht Teil einer Schriftartenauflistung (z. B. der System Font Collection) während IDWriteFontFace Notwendigkeit ist. IDWriteFontCollection hat eine GetFontFromFontFace-Methode, die akzeptiert ein IDWriteFontFace und gibt die entsprechenden IDWriteFont, aber es funktioniert nur, wenn die Font-Datei mit der IDWriteFontFace verbundenen der Font Collection gehört.

Benutzerdefinierte Font-Kollektionen

Jetzt haben Sie gesehen, Verwendung von DrawGlyphRun mit Font-Dateien, die Ihre Anwendung lädt sowie Systemschriftarten. Ist es möglich, die regulären Textausgabe Methoden (DrawText und DrawTextLayout) mit Ihren eigenen Font-Dateien verwenden?

Ja. Sie werden sich erinnern, dass sowohl die DrawTextLayout als auch die DrawText ein IDWriteTextFormat-Objekt erfordern. Sie erstellen dies mithilfe der CreateTextFormat-Methode des IDWriteFactory durch die Angabe der Namen einer Schriftart-Familie und einer Schriftsammlung.

Normalerweise legen Sie dieses Schriften-Sammlung-Argument auf Nullptr Systemschriftarten anzugeben. Aber Sie können auch eine benutzerdefinierte Schriftart-Auflistung erstellen, indem die CreateCustomFontCollection-Methode des IDWriteFactory. Sie müssen eine eigene Klasse, die IDWriteFontCollectionLoader-Schnittstelle implementiert, und eine andere Klasse, die IDWriteFontFileEnumerator implementiert.

Das zeigt sich in dem ResourceFontLayout-Programm. Das Programm beinhaltet auch die Implementierungen der IDWriteFontFileLoader und IDWriteFontFileStream-Schnittstelle von zentriert­GlyphDump. Wenn Sie die Liste der Schriftfamilien aus dieser benutzerdefinierten Schriftart-Auflistung erhalten, beachten Sie, dass mehrere Schriften, die Dateien in eine einzelne Schriftart-Familie manchmal konsolidiert sind.

Der Preis am unteren Rand der Box

An diesem Punkt sollte die Bedeutung der IDWriteFontFace ganz offensichtlich. Sie können ein IDWriteFontFace-Objekt erstellen, aus zwei Richtungen: entweder direkt aus einer Datei, oder wählen Sie eine bestimmte Schriftart aus einer Schriftsammlung. Sie verweisen diese IDWriteFontFace in einer DWRITE_GLYPH_RUN-Struktur oder Glyph-Metriken zu erhalten bzw. Zugriff auf Tabellen in die Font-Datei.

IDWriteFontFace wird auch eine Methode namens GetGlyphRun­Gliederung. Die Argumente für diese Methode sind sehr ähnlich wie die Felder der DWRITE_GLYPH_RUN-Struktur, aber ein zusätzliches Argument ist ein IDWriteGeometrySink, das ist dasselbe wie ein ID2D1SimplifiedGeometrySink.

Das bedeutet, Sie können konvertieren eine Zeichenfolge in ein ID2D1PathGeometry und dann Rendern und bearbeiten diese Geometrie in welcher Weise auch immer Sie wollen. Abbildung 6 ist ein Screenshot aus dem OutlinedCharacters-Programm, das eine Zeichen-Geometrie das streichelte und gefüllt zeigt; die gleiche Geometrie, gerendert mit einem gepunkteten Stil (die animiert wird, um die Punkte, um die Zeichen zu reisen zu machen); und die Geometrie verbreitert und skizziert, im Endeffekt gliedern die Umrisse.

The OutlinedCharacters Program
Abbildung 6 das OutlinedCharacters-Programm

Und ich bin gerade erst angefangen.

Charles Petzold ist ein langjähriger Beitrag zum MSDN Magazine und Autor von "Programming Windows, 6th Edition" (O' Reilly Media, 2012), ein Buch über das Schreiben von Anwendungen für Windows 8. Seiner Website lautet charlespetzold.com.

Unser Dank gilt den folgenden technischen Experten von Microsoft für die Durchsicht dieses Artikels: Jim Galasyn und Justin Panian