Textkontur mit GraphicsPath.AddString

  • VB.NET
  • .NET (FX) 4.0

Es gibt 13 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    Textkontur mit GraphicsPath.AddString

    Ich möchte eine Kontur für eine Zeichenkette per GraphicsPath erzeugen. Aber der GraphicsPath entartet bei manchen Fonts (hier desyrel). Wenn ich die Kontur mir GraphicsPath.DrawString erzeuge, ergibt sich die im folgenden Bild gezeigte Entartung. Wenn ich die Kontur pixelweise erzeuge, sieht sie normal aus. Allerdings benötigt die pixelweise Erzeugung vergleichsweise viel Zeit.



    Ich gehe davon aus, dass die Entartung auf Besonderheiten des/der Fonts zurückzuführen ist. Nun suche ich nach Möglichkeiten, den GraphicsPath zu "desinfizieren". Mit GraphicsPath.Pathdata könnte man den Pfad vielleicht zerlegen und irgendwie analysieren. Aber wie dann wieder zusammensetzen?

    Gibt es dazu bereits Erfahrungen oder Wissen? Oder empfiehlt sich eine ganz andere Methode für die Kontur?
    Es hat zwar noch niemand reagiert. Aber ich habe die Lösung inzwischen gefunden. Es gibt im Internet dutzende Empfehlungen wie man eine Kontur zu einer Zeichenkette per GraphicsPath erzeugt. Allen Beispielen (!) fehlt ein entscheidender Schritt: Das Setzen der Eigenschaft

    Pen.LineJoin = LineJoin.Round

    Damit werden die Ecken zweier aufeinandertreffender Linien abgerundet. Sicher kommt die Notwendigkeit bei vielen Fonts nicht zum Tragen. Ich bin aber auf das Problem bei viel mehr als einem Font gestoßen.

    drschef schrieb:

    Es hat zwar noch niemand reagiert.

    Hättest Du einen Beispielcode gepostet, käme auch mehr Beteiligung.
    Ansonsten, danke für deine Erkenntnis! :)

    Da mich diese Kontur auch interessiert und vielleicht nicht nur mich, würde ich mich über ein Beispiel freuen.
    würde ich mich über ein Beispiel freuen ...


    Tut mir leid! Mein Thema betraf nicht die Frage, wie erzeuge ich eine Schriftkontur, sondern wie vermeide ich den dargestellten Fehler in der Erzeugung einer Schriftkontur. Und die Antwort darauf habe ich gegeben. Es war die einfache Anweisung

    Quellcode

    1. Pen.LineJoin = LineJoin.Round


    Falls es darum geht, wie man grundsätzlich eine Schriftkontur erzeugt, hätte das klar formuliert werden müssen. Für alle, die die Erzeugung einer Schriftkontur grundsätzlich interessiert, hier eine kurze prinzipielle Befehlsfolge. Mein Algorithmus eignet sich hier nicht, weil er zu komplex ist. Deshalb habe ich eine vereinfachte Befehlsfolge zusammen gestellt, die mit der Erstellung eines neuen Fensters beginnt, welches dann etwa mit dem folgenden Code versehen wird:

    Quellcode

    1. Imports System.Drawing.Drawing2D
    2. Imports System.Drawing.Imaging
    3. Public Class Test
    4. Private Sub Test_Load(sender As Object, e As System.EventArgs) Handles Me.Load
    5. Me.Width = 600
    6. Me.Height = 450
    7. Me.Left = 100
    8. Me.Top = 100
    9. End Sub
    10. Private Sub Me_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
    11. Dim B As Bitmap = New Bitmap(Me.ClientSize.Width, Me.ClientSize.Height, PixelFormat.Format32bppArgb)
    12. Dim G As Graphics = e.Graphics
    13. Dim R = New Drawing2D.GraphicsPath
    14. Dim Pt As Point = New Point(100, 100)
    15. R.AddString("Rijklm", New FontFamily("Arial"), CInt(FontStyle.Regular), 128, Pt, StringFormat.GenericDefault)
    16. Dim P As Pen = New Pen(Color.White, 10)
    17. P.LineJoin = LineJoin.Round
    18. G.DrawPath(P, R)
    19. P.Dispose()
    20. Dim Br As Brush = New SolidBrush(Color.Red)
    21. G.FillPath(Br, R)
    22. Br.Dispose()
    23. End Sub
    24. End Class

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „drschef“ ()

    drschef schrieb:

    etwa mit dem folgenden Code
    , den ich mal leicht beräumt habe:

    VB.NET-Quellcode

    1. Private Sub Me_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
    2. Dim g As Graphics = e.Graphics
    3. Dim gp = New Drawing2D.GraphicsPath
    4. gp.AddString("Rijklm", New FontFamily("Arial"), CInt(FontStyle.Regular), 128, New Point(100, 100), StringFormat.GenericDefault)
    5. Using p As Pen = New Pen(Color.White, 10)
    6. p.LineJoin = LineJoin.Round
    7. g.DrawPath(p, gp)
    8. End Using
    9. g.FillPath(Brushes.Red, gp)
    10. End Sub
    Bei diesem Beispiel sehe ich keinen Unterschied zwischen mit und ohne LineJoin.Round. :/
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „RodFromGermany“ ()

    Bei diesem Beispiel sehe ich keinen Unterschied zwischen mit und ohne


    Den wirst Du bei Arial auch nicht sehen, weil der Font vielleicht keine spitzen Ecken aufweist, die abgerundet werden müssen (auch wenn es so aussieht). Aufgetreten ist das eher bei Fonts, die scheinbar geglättet und abgerundet sind. Ich hatte extra oben von machen Fonts geschrieben. Es waren bei weitem nicht alle, aber auch nicht nur einer. Das war ja das Schlimme, woran ich verzweifelt bin.

    Übrigens hatte ich in meinem letzten Beitrag über das Beispiel geschrieben, ... Falls es darum geht, wie man grundsätzlich eine Schriftkontur erzeugt.... weil ich die Beiträge von dritter Seite so verstanden hatte.

    drschef schrieb:

    Aufgetreten ist das eher bei Fonts
    deren Name ich hier geheim halten möchte, sonst hätte ich ihn nämlich schon lange gepostet. :/
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    deren Name ich hier geheim halten möchte


    natürlich nicht, aber das klingt so, als hätte ich den Effekt erfunden. Außerdem war in meinem Eröffnungsbeitrag zum Thema bereits desyrel als Font genannt. Hatte also nichts mit Geheimhaltung zu tun. Hier mal ein paar weitere Beispiele: Algiers, ArSchatten7, Brush Script MT, Pennello, PlainGermanica, ShadowedGermanica. Es handelt sich also durchaus nicht um einen Ausrutscher bei einem einzelnen Font.

    Ausprobieren mit und ohne myPen.LineJoin = LineJoin.Round

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „drschef“ ()

    drschef schrieb:

    desyrel
    Sorry, den gibt es bei mir nicht.
    Allerdings bekomme ich in der Zeile R.AddString(...) immer eine Exception "Ungültiger Parameter", wenn da der Name eines vorhandenen "merkwürdigen" Fonts derin steht.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Exception "Ungültiger Parameter", wenn da der Name eines vorhandenen "merkwürdigen" Fonts derin steht


    Im ersten Moment würde ich sagen, dass da der Font im System nicht registriert ist, aber das scheidet ja aus. Nun wird es aber noch interessanter! Gibt es denn falsche und richtige oder gute und schlechte Fonts? Was hast Du für ein System, wenn die Frage erlaubt ist. Ich arbeite mit W7 und W81. Vielleicht hängt die Reaktion bei Dir auch mit der Fehlerbehandlung von VB zusammen.

    Für mich ist die Ursache des Fehlverhaltens (nicht Deiner Fehlermeldung) mittlerweile verständlich. Spitze Ecken in der Fontkontur führen durch Verlängerung der Tangenten zwangsläufig zu eben diesem Effekt. Erst das Abstumpfen mit LineJoin.Round lässt er sich verhindern. Ich kenne den Effekt von Corel Draw. Wenn man dort zwei Linien spitz aufeinandertreffen lässt, haut es auch so einen Spitzen Dorn raus, der beliebig entarten kann. Man muss dann auch die Option Ecken abrunden wählen, um das zu vermeiden. Aber am Ende ist das doch nicht 'Ehrenrühriges' und rechtfertigt nicht den Fehlerkommentar, der wenn überhaupt bei der Registrierung des Fonts angebracht wäre aber nicht bei der Anwendung.

    drschef schrieb:

    Fehlerbehandlung
    Ich hab jetzt mal folgenden Test gemacht, Form mit Combobox und Label:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Drawing.Drawing2D
    2. Imports System.Drawing.Imaging
    3. Public Class Form1
    4. Private FontName As String = "Courier new" ' "desyrel" '"Brush Script MT"
    5. Private Sub Test_Load(sender As Object, e As System.EventArgs) Handles Me.Load
    6. Me.Width = 600
    7. Me.Height = 450
    8. Me.Left = 100
    9. Me.Top = 100
    10. Dim fam() As System.Drawing.FontFamily = System.Drawing.FontFamily.Families()
    11. For Each fa In fam
    12. Me.ComboBox1.Items.Add(fa.Name)
    13. Next
    14. End Sub
    15. Private Sub Me_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
    16. Try
    17. Dim g As Graphics = e.Graphics
    18. Dim gp = New Drawing2D.GraphicsPath
    19. Dim pt As Point = New Point(50, 50)
    20. gp.AddString("Rijklm", New FontFamily(FontName), CInt(FontStyle.Regular), 128, pt, StringFormat.GenericDefault)
    21. Using p As Pen = New Pen(Color.White, 10)
    22. p.LineJoin = LineJoin.Round
    23. g.DrawPath(p, gp)
    24. End Using
    25. g.FillPath(Brushes.Red, gp)
    26. Dim m As New Matrix
    27. m.Translate(50, 150)
    28. gp.Transform(m)
    29. Using p As Pen = New Pen(Color.White, 10)
    30. g.DrawPath(p, gp)
    31. End Using
    32. g.FillPath(Brushes.Red, gp)
    33. Label1.Text = ""
    34. Catch ex As Exception
    35. Label1.Text = ex.Message
    36. End Try
    37. End Sub
    38. Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
    39. FontName = ComboBox1.SelectedItem.ToString
    40. Me.Invalidate()
    41. End Sub
    42. End Class
    Da ist zu sehen, was zu sehen sein soll. :thumbsup:
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Da ist zu sehen, was zu sehen sein soll.


    Das habe ich nicht ganz verstanden. In obigem Quelltext sollte bei Courier New und p.LineJoin = LineJoin.Round doch alles sauber kommen. Ich dachte, interessiert hätte der Fall, wo es nicht klappt, also Font ohne LineJoin und mit Effekt.

    drschef schrieb:

    nicht ganz verstanden
    Primär war für mich, die Fonts durchzuratern, ohne von einer Exception unterbrochen zu werden. Einige Fonts zeigen die Spitzen, einige nicht.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!