绘制倾斜/斜体文本字符串






4.73/5 (8投票s)
2007年4月19日
3分钟阅读

58448

580
本文展示了如何绘制倾斜/斜体文本字符串
引言
这里提供的函数可用于绘制具有倾斜或斜角的文本字符串。这种文本输出在等距或透视3D视图中非常有用,使文本字符串看起来像在它们的3D空间中一样。以下图片显示了一个例子
背景
Windows GDI 函数 TextOut()
不允许文本倾斜角。要绘制这种倾斜的字符串,我们需要使用 SetWorldTransform()
设置转换。然后,Windows 绘图函数将负责输出的剪切和旋转。此过程被整合到一个类似于 Windows TextOut()
函数的新函数中
void ObliqueTextOut( CDC *dc, int oblique, int x,int y,const CString &Text )
此函数具有与 Windows TextOut()
函数相同的参数,外加一个附加参数 oblique
,用于指定文本倾斜角。该函数可以放置在通常使用 TextOut()
的地方。
使用代码
将函数源代码插入到您的源代码文件中。在通常调用 Windows TextOut()
函数的地方调用该函数。请记住选择字体,设置文本背景模式、颜色和背景颜色等,就像在调用 TextOut()
之前通常所做的那样。
如果文本向前倾斜(向右),则角度 oblique
为正,如果文本向后倾斜(向左),则角度 oblique
为负。下图中的 oblique
角度 s
为正。角度以 1/10 度为单位。因此,如果文本向前倾斜 15 度,则 oblique=150。
关注点
问题的关键是在 DC 中设置转换。函数 SetWorldTransform()
需要一个 XFORM
结构来进行转换。因此,我们需要在调用 SetWorldTransform( )
之前准备 XFORM
结构。XFORM
具有 6 个成员数据。它们是 eM11
、eM21
、eM12
、eM22
、eDx
、eDx
。它们定义为
X = eM11 * x + eM21 * y + eDx
Y = eM12 * x + 2M22 * y + eDy
其中 (x,y)
是世界坐标,(X,Y)
是纸张空间坐标。
在下图中,x,y
是世界空间轴。字符串将始终在世界空间中的 (0,0)
处水平绘制。xs,ys
是剪切空间轴。从世界空间到剪切空间的变换是
xs = x - y * tan(s)
ys = y
其中 s
是倾斜或斜角。
纸张空间表示为 X,Y
。从剪切空间到纸张空间,变换是一个旋转(角度 r
)和平移 (Xo,Yo)
。
X = Xo + xs * cos(r) + ys * sin(r)
Y = Yo + ys * cos(r) - xs * sin(r)
其中 (Xo,Yo)
只是纸张空间中的文本插入点。将 (xs,ys)
代入以上公式,我们得到
X = cos(r) * x + (sin(r)-tan(s)*cos(r)) * y + Xo
Y = -sin(r) * x + (cos(r)+tan(s)*sin(r)) * y + Yo
将其与 XFORM
结构进行比较,很明显
eM11 = cos(r)
eM21 = sin(r) - tan(s) * cos(r)
eM12 = -sin(r)
eM22 = cos(r) + tan(s) * sin(r)
eDx = Xo
eDy = Yo
以上内容被翻译成函数代码(dc
是输入设备上下文)
XFORM xForm;
xForm.eDx = (float) x;
xForm.eDy = (float) y;
xForm.eM11 = (float) cos(txtRotate);
xForm.eM21 = (float) (sin(txtRotate) - tan(txtOblique)*cos(txtRotate));
xForm.eM12 = (float) -sin(txtRotate);
xForm.eM22 = (float) (cos(txtRotate) + tan(txtOblique)*sin(txtRotate));
SetGraphicsMode( dc->m_hDC, GM_ADVANCED );
SetWorldTransform( dc->m_hDC, &xForm );
需要调用 SetGraphicsMode()
。否则,函数 SetWorldTranform()
将不起作用。由于现在我们在世界空间中绘图,我们需要调整字体的旋转 (lfEscapement
) 以使其水平,并将字符方向 (lfOrintation
) 设置为从世界 X 轴开始。
LOGFONT lgf;
dc->GetCurrentFont()->GetLogFont( &lgf );
...
lgf.lfOrientation -= lgf.lfEscapement;
lgf.lfEscapement = 0;
CFont horFont;
horFont.CreateFontIndirect( &lgf );
CFont *OldFont = dc->SelectObject( &horFont );
现在,我们可以调用
dc->TextOut( 0,0, Text );
工作完成了。但在返回之前,我们需要恢复图形模式和字体
ModifyWorldTransform( dc->m_hDC, &xForm, MWT_IDENTITY );
SetGraphicsMode( dc->m_hDC, GM_COMPATIBLE );
dc->SelectObject( OldFont );
历史
- 2007 年 4 月 19 日:通过操作位图的版本 1
- 2007 年 4 月 25 日:版本 2 - 按照 Goran Mitrovics 的建议完全重写。它更简单,输出质量更好。非常感谢 Goran!