The graphics.drawstring method in .NET Framework provides basic text drawing. However, this method itself lacks control capabilities on the character format, such as the character spacing supported by most text processors (probably Microsoft believes that there will be no .NET-based text processors). The simplest solution for this problem is to "finish zero" throughout the string, and draw a character in accordance with the specified interoperability. However, this will produce a large amount of temporary string, and there is a huge PINVOKE price. Is there any other way? The answer is a positive-GDI underlying provides the gdipdrawdriverstring method, allowing us to control the output of individual characters. Unfortunately, it may be because this method is too late, so there is no package in .NET Framework. (By the way, Office uses GDI from Office XP as a drawing engine, using gdipdrawdriverstring in Visio text.
Below is a simple package for gdipdrawdriverstring (GDIPLUSMETHODS.CS):
Using system.drawing.drawing2d; using system.Reflection; Using System.Runtime.InterOpServices;
Namespace system.drawing {///
Private enum driverstringoptions {cmaplookup = 1, vertical = 2, Advance = 4, limitedsubpixel = 8,}
Public Static Void DrawDriverstring (Graphics Graphics, String Text, Font Font, Brush Brush, Pointf [] positions) {DrawDriverstring (Graphics, Text, Font, Brush, Positions, NULL)
public static void DrawDriverString (Graphics graphics, string text, Font font, Brush brush, PointF [] positions, Matrix matrix) {if (graphics == null) throw new ArgumentNullException ( "graphics"); if (text == null) throw new ArgumentNullException ( "text"); if (font == null) throw new ArgumentNullException ( "font"); if (brush == null) throw new ArgumentNullException ( "brush"); if (positions == null) throw new ArgumentNullException ( "positions"); // Get hGraphics FieldInfo field = typeof (Graphics) .GetField ( "nativeGraphics", BindingFlags.Instance | BindingFlags.NonPublic); IntPtr hGraphics = (IntPtr) field.GetValue (graphics);
// Get HFONT FIELD = TypeOf (font) .Getfield ("NativeFont", BindingFlags.instance | BindingFlags.nonpublic); INTPTR HFONT = (INTPTR) Field.getValue (font);
// Get Hbrush Field = TypeOf (Brush) .Getfield ("Nativebrush", BindingFlags.instance | BindingFlags.nonpublic; INTPTR HBRUSH = (INTPTR) FIELD.GETVALUE (Brush);
// Get hMatrix IntPtr hMatrix = IntPtr.Zero; if (! Matrix = null) {field = typeof (Matrix) .GetField ( "nativeMatrix", BindingFlags.Instance | BindingFlags.NonPublic); hMatrix = (IntPtr) field.GetValue ( Matrix);
int result = GdipDrawDriverString (hGraphics, text, text.Length, hFont, hBrush, positions, (int) DriverStringOptions.CmapLookup, hMatrix);} [DllImport ( "Gdiplus.dll", CharSet = CharSet.Unicode)] internal extern static int GDIPMEASUREDRIVERSTRING (INTPTR Graphics, String Text, Int Length, INTPTR FONT, POINTF [] Positions, Int Flags, INTPTR MATRIX, REF Rectanglef Bounds;
[DllImport ( "Gdiplus.dll", CharSet = CharSet.Unicode)] internal extern static int GdipDrawDriverString (IntPtr graphics, string text, int length, IntPtr font, IntPtr brush, PointF [] positions, int flags, IntPtr matrix);} }
Let's take a look at: Create a form, add the following code in the onpaint event:
Protected Override Void onPaint (Painteventargs E) {base.onpaint (e);
Graphics g = E.Graphics; g.TextRenderingHint = system.drawing.text.textrenderingHint.ntialias; brush brush = new solidBrush (Color.red); font font = new font ("Song", 12.0F);
String s = "TEST" in Chinese オ エ エ 版 "; sizef size = g.measureString (s, font, int.maxvalue);
POINTF [] positions = new pointf [s.Length]; for (int i = 0; i GDIPLUSMETHODS.DRAWDRIVERSTRING (G, S, Font, Brush, Positions); Here, we use the PointF [] Positions to control the output location of the character. It should be noted that the coordinate refers to the lower left corner of the character, not the upper left corner (computer scientist and mathematician uses different coordinate systems).