在WinForms中使用Graphics.DrawString旋转后,中文竖排文本显示不正确
在WinForms应用中使用 Graphics.DrawString 搭配 StringFormatFlags.DirectionVertical 来渲染中文文本,然后应用旋转变换,文本会以出人意料的方向和阅读顺序显示。
预期的行为是文本在逻辑上保持有序,并作为竖向字符串可读,同时整块文本作为一个整体旋转。相反,单个CJK字形会以被旋转和/或重新定位的方式出现,改变了原本的视觉呈现,甚至可能影响含义。
这似乎与 System.Drawing / GDI+的底层文本渲染行为有关,而不是某个特定的WinForms控件。
此问题在.NET Framework与 .NET Core / .NET下均存在。
屏幕截图:
实际输出:
预期输出:
字母输出:
简单示例:
示例已附在那个GitHub查询中:https://github.com/dotnet/winforms/issues/14698
代码片段:
private void Canvas_Paint(object sender, PaintEventArgs e)
{
if (!_showRotatedText)
return;
var g = e.Graphics;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
var text = _input.Text ?? string.Empty;
var sf = new StringFormat(StringFormat.GenericTypographic)
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center,
FormatFlags = StringFormatFlags.DirectionVertical
| StringFormatFlags.NoWrap,
Trimming = StringTrimming.EllipsisCharacter,
};
using (var font = new Font("Microsoft YaHei", 12, FontStyle.Bold))
using (var brush = new SolidBrush(Color.FromArgb(64, 64, 64)))
{
var r = _canvas.ClientRectangle;
float cx = r.X + r.Width / 2f;
float cy = r.Y + r.Height / 2f;
var old = g.Transform;
try
{
g.TranslateTransform(cx, cy);
g.RotateTransform(180f);
g.DrawString(text, font, brush,
new RectangleF(-r.Height / 2f, -r.Width / 2f,
r.Height, r.Width),
sf);
}
finally
{
g.Transform = old;
}
}
}
复现步骤:
步骤1:运行附带的示例应用程序。
步骤2:点击“旋转”按钮。
步骤3:观察旋转后中文文本的呈现方式。
实际行为:
-
中文字符以出人意料的方向显示。
-
旋转后文本流向发生变化。
-
渲染结果并非按预期可读。
预期行为:
-
旋转后文本应仍然可读。
-
整块文本应作为一个整体旋转。
-
中文字符应保持正确的方向和逻辑阅读顺序。
问题:
-
这是在渲染竖直CJK文本时,GDI+或
System.Drawing的已知限制吗? -
在这种情形下,这是
Graphics.DrawString的预期行为吗? -
是否有推荐的替代方案,用于正确呈现竖直中文文本?
环境:
框架:.NET Framework / .NET
操作系统:Windows 11
解决方案
移除 StringFormatFlags.DirectionVertical,并将旋转角度改为270度,以获得期望的输出。
DirectionVertical 会把文本竖直绘制出来,字符是否被旋转取决于具体语言。因此中文字符不会被旋转,但数字和拉丁文本会旋转。然后 g.RotateTransform(180f) 会对整段文本进行旋转,导致所有中文字符都颠倒过来。
使用 g.RotateTransform(270f),不带任何 DirectionVertical 标志,以原样绘制整段文本的同时进行旋转。


