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);
}
}
下面我们来试验一下:新建一个窗体,在 onpaint 事件里加入如下代码:
protected override void onpaint(painteventargs e)
{
base.onpaint(e);
graphics g = e.graphics;
g.textrenderinghint = system.drawing.text.textrenderinghint.antialias;
brush brush = new solidbrush(color.red);
font font = new font("宋体", 12.0f);
string s = "test中文オンエア版";
sizef size = g.measurestring(s, font, int.maxvalue);
pointf[] positions = new pointf[s.length];
for (int i = 0; i < s.length; i++)
positions[i] = new pointf(i * 40 + 20, size.height);
gdiplusmethods.drawdriverstring(g, s, font, brush, positions);
}
在这里,我们使用 pointf[] positions 这个数组来控制字符的输出位置。需要注意的是坐标指的是字符的左下角,而不是左上角(计算机科学家和数学家使用不同的坐标系)。
有趣的是,如果我们把字体从“宋体”改为英文字体,如“arial”,那么非英文字母将显示成一个框。这是因为 gdipdrawdriverstring 就像它的名字暗示的那样,它直接使用指定字体绘制文本而不做其他处理。而 gdipdrawstring 则会对文本进行分析,例如如果我们使用一个英文字体绘制中文字,则 gdipdrawstring 会在内部创建一个中文字体(通常是宋体)然后使用这个字体进行绘制(这个分析和匹配过程是相当复杂的,并且没有任何文档记载)。