2015-03-17 7 views
8

Ich möchte die exakte Höhe von Text in Windows gerendert finden. Ich habe versucht GetTextExtentPoint32 und Aufruf von DrawText mit dem DT_CALCRECT-Flag und beide geben das gleiche Ergebnis.So finden Sie die EXACT Pixel Höhe von Text in Windows gerendert mit DrawText

Es scheint, dass die zurückgegebene Höhe auf der vollen Zellenhöhe basiert, unabhängig vom tatsächlich zu zeichnenden Text.

Der folgende Code ist der WM_PAINT-Handler für ein Visual Studio 2013 Win32-Standardprojekt. Es erstellt eine (große) Schriftart und zeichnet den Beispieltext. Der größte Teil des Textes ist 98 Pixel, aber der Wert von GetTextExtentPoint32 zurückgekehrt ist 131.

Mir ist klar, dass einige Anwendungen könnte die vollständige Zellenhöhe wollen, aber auch einige Anwendungen (wie bei mir) will nur die tatsächlichen Höhe verwendet durch den Text.

Kann jemand diese Informationen finden?

Ja, ich kann in einem Speicher-DC rendern und nach dem ersten nicht-hintergrundfarbenen Pixel suchen - aber das wird super langsam.

Dank

case WM_PAINT: 
{ 
    hdc = BeginPaint (hWnd, &ps); 

    HFONT hfont = CreateFont (-99, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, VARIABLE_PITCH, L"Segoe UI Semibold"); 
    auto old_hfont = SelectObject (hdc, hfont); 

    wchar_t sample_text[] = L"123 Testing 123"; 
    size_t sample_text_length = wcslen (sample_text); 

    SIZE s; 
    GetTextExtentPoint32 (hdc, sample_text, sample_text_length, &s); 

    RECT r = {10, 10, 10 + s.cx, 10 + s.cy}; 

    SetBkColor (hdc, RGB (80, 120, 160)); 
    SetTextColor (hdc, RGB (220, 220, 220)); 

    DrawText (hdc, sample_text, sample_text_length, &r, DT_SINGLELINE | DT_NOPREFIX | DT_LEFT | DT_TOP); 

    SelectObject (hdc, old_hfont); 
    DeleteObject (hfont); 

    EndPaint (hWnd, &ps); 
    break; 
} 
+2

Auf einer Anti-Aliased-Schriftart, was wäre Ihre exakte Höhe? – RedX

+0

Die Gesamtanzahl der Rasterzeilen, in die die DrawText-Operation geschrieben wird? Was ich meine, ist die Höhe zwischen der ersten und der letzten Rasterzeile geschrieben an –

+0

Nur aus Neugier, können Sie weitere Details zum Anwendungsfall dafür angeben? [Mein Instinkt sagt, dass es vielleicht einen besseren Weg gibt, Ihr tatsächliches Problem zu lösen] (http://meta.stackexchange.com/q/66377/what-is-the-xy-problem). – Anthony

Antwort

3

Wenn Ihr Beispieltext nur ASCII-Buchstaben enthält, könnten Sie die Höhe eines aufsteigenden Brief wie b, einem absteigenden Brief wie g und einem mittleren Buchstaben wie x manuell auswerten. Sie würden das einmal im Voraus tun, wahrscheinlich sogar offline, also ist jede ineffiziente Methode völlig in Ordnung.

Dann ist (je nach Schriftart zu einer kleinen Fehlerspanne nach oben) der Gesamthöhe der Berechnung ist eine einfache Prüfung für Oberlängen (bdfhijklt und A-Z) und Unterlängen (gjpqy) in der Zeichenfolge.

+0

Aber das ist die Frage - wie "bemühe" Sie manuell die Höhe eines Buchstabens, wenn die Windows-API alle Zeichen als die gleiche Höhe behandelt? –

+1

@MarkRansom Durch ineffizientes Scannen genau wie im ursprünglichen Beitrag erwähnt. Die drei Höhen werden einmal vorausberechnet, möglicherweise sogar offline, so dass es ineffizient ist, überhaupt nicht zu schmerzen. – klimpergeist

7

Werfen Sie einen Blick auf GetGlyphOutline(GGO_METRICS) Die zurückgegebene GLYPHMETRICS-Struktur sollte alle Daten enthalten, die Sie zum Berechnen des Extents benötigen.

4

Ihr Text wird nicht direkt gezeichnet, zuerst wird er zu einem path, der die Umrisse Ihrer Geometrien/Glyphen beschreibt. Ein Pfad besteht aus Bewegungen, Linien und Kurven (und einer Schließen-Flagge zum Prior). Mit Ausnahme von Kurven sind andere Pfadsegmente extreme Punkte für die endgültige Füllung. Das Konvertieren von Kurven in Linien und das Iterieren durch alle Pfadsegmente, um das Minimum und Maximum in der horizontalen & vertikalen Bemaßung durch die Punkte zu finden, ergibt das am nächsten passende Rechteck zu Ihrem Text.

Sie können Ihren Text in einen Pfad konvertieren, indem Sie ihn mit dem Aufruf BeginPath vor und EndPath nach zeichnen. FlattenPath macht die Kurve-> Zeilenumwandlung. GetPath bietet Zugriff auf die Pfadpunkte im Kontext. AbortPath entfernt schließlich den Pfad aus dem Kontext.

Wenn Sie nicht set the background to transparent haben, kann der Pfad der Hintergrund um Ihren Text sein und bereits die ersten Pfadsegmente sind die Hintergrund/Extents Rechtecklinien - nicht was Sie wollen.

Um diese Methode zu vereinfachen, können Sie wiederholte Zeichen und Gruppenzeichen um 1) unter der Basislinie 2) über der Mittellinie 3) Pause ausschließen. Dies alles funktioniert sehr schnell im Vergleich zu Ihrem "Look Pixel" versuchen.

Weitere nützliche Quellen über Textgrößen sind font metrics (GetTextMetrics) und character widths (GetCharABCWidths)

2

Wenn dies eine Truetype-Schriftart ist, können Sie die Größe der Positionierung w.r.t. Glyphe finden der 'vorherige' Buchstabe und die Zeile in der fmtx-Tabelle, wie erklärt here. Es gibt auch similar information für OpenType-Schriftarten, aber es sieht umständlicher aus, etwas Sinnvolles abzuleiten.

Dies gibt Ihnen nicht die tatsächliche Pixelgröße der Glyphe, aber es gibt Ihnen eine genauere Idee, wo der True-Type-Schriftpfad für eine bestimmte Glyphe in Bezug auf die 'Basislinie' gezeichnet wird, und die Einheiten skalieren mit der Punktgröße und sind fontweit.

In Ihrem Fall würde ich einen Blick auf FreeType, eine 3rd-Party-Bibliothek, die schnell ist und unterstützt Raster-Schriftarten, TrueType und OpenType-Schriften. Es ist weit verbreitet und sehr well documented und unterstützt und kann genaue Metriken liefern.