分享
 
 
 

使用 GDI+ 绘制有间距的文本

王朝c#·作者佚名  2006-12-17
窄屏简体版  字體: |||超大  

在 .NET Framework 中 Graphics.DrawString 方法提供了基本的文本绘制功能。然而,这个方法本身缺乏对字符格式的控制能力,例如不支持多数文本处理器支持的字符间距(大概微软认为不会有人编写基于 .NET 的文本处理器)。这个问题最简单的解决方法是将整个字符串“化整为零”,一个字符一个字符的按照指定间距画出来。然而这样做会产生大量的临时字符串,而且有巨大的 PInvoke 代价。那有没有其他的方法呢?答案是肯定的——GDI+ 底层提供了 GdipDrawDriverString 方法,允许我们对单个字符的输出位置进行控制。遗憾的是也许因为这个方法太底层了,所以在 .NET Framework 中并没有针对它的封装。(顺便说一下,Office 从 Office XP 开始就使用 GDI+ 作为绘图引擎,象 Visio 中的文本绘制就使用了 GdipDrawDriverString)

下面是对 GdipDrawDriverString 的简单封装(GdiplusMethods.cs):

using System;

using System.Drawing.Drawing2D;

using System.Reflection;

using System.Runtime.InteropServices;

namespace System.Drawing

{

/// <summary>

/// Summary description for GdiplusMethods.

/// </summary>

public class GdiplusMethods

{

private GdiplusMethods() { }

private enum DriverStringOptions

{

CmapLookup = 1,

Vertical = 2,

Advance = 4,

LimitSubpixel = 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);

}

}

下面我们来试验一下:新建一个窗体,在 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 会在内部创建一个中文字体(通常是宋体)然后使用这个字体进行绘制(这个分析和匹配过程是相当复杂的,并且没有任何文档记载)。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有