使用Canvas.TextOut有什么含义? [英] What are the implications of using Canvas.TextOut?
问题描述
简介
我的问题来自我过去几天一直在处理的一个相当有趣的问题。我最近问了一个有关
图.1 Canvas.TextOut
图2 DrawText
您可能需要o使用屏幕放大镜看得更近一些,但是在SomeText行中, Some
和 Text $ c之间的间距更引人注目$ c>以及
和文本
T e
之间>稍有不同。
示例2
A略有不同更好的例子也许是在 Canvas.TextOut
和 DrawText
与就地编辑器(TEdit)文本之间进行比较:
图3比较
您可以看到这里的区别更加明显。当使用 Canvas.TextOut
时,字符串 True
明显显示出文本字符之间更大的间距,其中 DrawText
和就地编辑器
完全相同地呈现文本。
使用 Canvas.TextOut
,我在调整检查器分隔符的大小以及显示和隐藏就地编辑器之间遇到各种可怕的文本不匹配的情况。如果我没有尝试过尝试其他的文本绘制方法,我想我永远也不会意识到这种差异并找到解决方案。重要的是要知道在将文本绘制到画布上时,我使用的字体设置与为原位编辑器定义的字体完全相同。
现在,我我使用的是 DrawText
而不是 Canvas.TextOut
一切都与就地编辑器以及我想要的方式一致。
问题
我的问题是 Canvas.TextOut
呈现文本与 DrawText
有何不同?从我的示例并处理我当前的问题,很明显, Canvas.TextOut
不会以与具有相同字体设置的TEdit相同的方式呈现文本,但是 DrawText
确实呈现了看似正确的文本。
这使我质疑的用法Canvas.TextOut
,如果它不能正确呈现文本,我是否应该总是使用 DrawText
代替?
测试演示
您可以使用以下代码对其进行测试:
type
TForm1 = class(TForm)
Edit1:TEdit;
过程FormCreate(Sender:TObject);
过程FormDestroy(Sender:TObject);
过程FormPaint(Sender:TObject);
私人
Font:TFont;
FRect:TRect;
public
{公开声明}
结尾;
var
Form1:TForm1;
实现
{$ R * .dfm}
过程TForm1.FormCreate(Sender:TObject);
开始
FFont:= TFont.Create;
FFont.Color:= clNavy;
FFont.Name:=Segoe UI;
FFont.Size:= 9;
FFont.Style:= [];
FRect:= Rect(10,30,100,100);
Canvas.Font.Assign(FFont);
Edit1.Font.Assign(FFont);
结尾;
过程TForm1.FormDestroy(Sender:TObject);
开始
Font。免费;
结尾;
过程TForm1.FormPaint(Sender:TObject);
开始
Canvas.TextOut(10,10,‘Canvas.TextOut:[真]’);
DrawText(Canvas.Handle,PChar('DrawText:[True]'),Length('DrawText:[True]'),FRect,DT_LEFT);
结尾;
通过以上操作在全新的VCL项目上运行,我得到的结果如下:
图4测试演示
再次注意使用 Canvas.TextOut <时字符串
True
的间距/ code>,从我的角度来看,它明显不同于 DrawText
和 TEdit
绘制方式
下图与图4相同,但放大了400%
图5测试演示放大了400%
在 Text <中,在
T
和 e
之间看到了显着差异/ code>以及 True
中的 T
和 r
。
图6文本使用指南放大了400%
您可以看到 T
与 e
使用 DrawText
比使用 Canvas.TextOut
(使用 ExtTextOut
。)
图7单词 True
根据准则放大了700%
您可以看到 T
和 r
之间的字距更近了一个像素与 Canvas.T相比,使用
(使用 DrawText
和就地编辑器(TEdit) extOut ExtTextOut
。)
我测试了几种不同的字体,这是我的发现:
好:
Arial,Cambria,Candara,Comic Sans MS,Consolas,Courier,Courier New,
Fixedsys,乔治亚州,Lucida Console,Lucida Sans Unicode,Microsoft Sans
Serif,Tahoma,Terminal和Times New罗马。
坏:
Calibri ,Corbel,Myriad Pro,Segoe UI,Trebuchet MS和Verdana。
好的字体是看起来可以使文本呈现相同字体的字体就像 DrawText
一样,Inpace编辑器(TEdit)控件也使用 Canvas.TextOut
进行操作。不好的结果表明 Canvas.TextOut
呈现的文本与其他方法略有不同。
虽然我不太确定,但这里还是有一些线索,不过我还是添加了它,以防万一。
可观察到的差异是由于使用了不同的WinAPI文本呈现功能及其行为。具体字符字距
在排版中,字距调整(不太常用的插值)是
调整比例字体中字符之间的间距的过程,通常
会获得视觉上令人愉悦的结果。字距调整会调整各个字母形式之间的
间距,而跟踪(字母间距)
会在一系列字符范围内统一调整间距。
DrawText函数绘制格式化的文本。
它将根据指定的方法(扩展标签,
对齐字符,换行等)来格式化文本。
- ExtTextOut (由
Canvas.TextOut
使用)
ExtTextOut
声明:
BOOL ExtTextOut(
_In_ HDC hdc,
_In_ int X,
_In_ int Y,
_In_ UINT fuOptions,
_In_ const RECT * lprc,
_In_ LPCTSTR lpString,
_In_ UINT cbCount,
_In_ const INT * lpDx
);
如果lpDx参数为NULL,则ExtTextOut函数使用
字符之间的默认间距。字符单元格起源和lpDx参数指向的数组的
内容以逻辑单位
指定。字符单元格的原点定义为字符单元格的左上
角。
基本上 DrawText
将自动绘制格式化的文本,其中包括调整字符之间的间距(字距调整),而 ExtTextOut
默认情况下将使用字符之间的默认间距(无字距调整)。如果要调整字符之间的间距,则必须计算并提供字距调整数组( lpDx
)参数。
这些差异在某些字符组合中尤其明显,例如 T
和在 T
或 AV
,其中一个 V
可以容纳 A
。不同的字体也具有不同的默认字距,这就是为什么某些字体使用这两种功能在外观上呈现相同效果的原因,而有些字体则没有。字距调整还取决于字体大小。例如,以 9 pt
用 Arial
渲染的字符 AV
两个函数具有相同的输出,而 12 pt
的 Arial
将导致不同的输出。
下图的第一行使用 ExtTextOut
进行无字距绘制,第二行使用 DrawText
。
< img src = https://i.stack.imgur.com/wF1oM.png alt =在此处输入图片描述>
Introduction
My question comes from a rather interesting problem I have been dealing with for the past few days. I recently asked a question regarding Writing a custom property inspector - How to handle inplace editor focus when validating values?
I have since made some nice progress with my control such as adding a divider in the middle to separate between Name and Value rows, and importantly the divider can be used to resize the two columns.
Here is where my problems started, having the inplace editor visible whilst resizing the divider caused a slight slow down on my control. So I further changed the code to only show the inplace editor if the divider is not been resized. So essentially, I used Canvas.TextOut
to draw my values as strings, if a row is selected then the Inplace editor is shown above. The inplace editor becomes hidden if the divider is been resized, once the resize operation has complete the inplace editor becomes visible again.
Whilst this solved the slight slowdown issue I mentioned, I was faced with a new problem in that the text from the inplace editor (which is basically a TEdit) differed slightly to the text that I was drawing using Canvas.TextOut
Example 1
The difference is quite subtle but if you look close enough you can just see it:
fig.1 Canvas.TextOut
fig.2 DrawText
You may need to use a screen magnifier to look more closer, but with the SomeText row it is more noticeable in that the spacing between Some
and Text
and also between the T
and e
in Text
is slightly different.
Example 2
A slightly better example is perhaps comparing between Canvas.TextOut
and DrawText
to the inplace editor (TEdit) text:
fig.3 Comparison
As you can see the difference here is much more prominent. The string True
clearly shows much larger spacing between the text characters when using Canvas.TextOut
, where as the DrawText
and inplace editor
render text exactly alike.
When I was using Canvas.TextOut
I was getting all kinds of horrible text mismatches between resizing my inspector divider and showing and hiding the inplace editor. Had I not experimented and tried alternative text drawing methods I don't think I would have ever realised the difference and found a solution. It is important to know that I was using the exact same Font settings when drawing my text to the canvas as the Font I had defined for the inplace editor.
Now that I am using DrawText
instead of Canvas.TextOut
everything is working in unison with the inplace editor and exactly how I want it to.
Question
My question is what makes Canvas.TextOut
render text so differently to DrawText
? From my example and dealing with my current problem, it is clear that Canvas.TextOut
does not render the text in the same way that a TEdit with the same Font settings does, but DrawText
does render text seemingly the correct way.
This makes me question the use of Canvas.TextOut
, if it does not render text correctly should I always look to use DrawText
instead?
Test Demo
You can test this for yourself with the following code:
type
TForm1 = class(TForm)
Edit1: TEdit;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormPaint(Sender: TObject);
private
FFont: TFont;
FRect: TRect;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
FFont := TFont.Create;
FFont.Color := clNavy;
FFont.Name := 'Segoe UI';
FFont.Size := 9;
FFont.Style := [];
FRect := Rect(10, 30, 100, 100);
Canvas.Font.Assign(FFont);
Edit1.Font.Assign(FFont);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FFont.Free;
end;
procedure TForm1.FormPaint(Sender: TObject);
begin
Canvas.TextOut(10, 10, 'Canvas.TextOut: [True]');
DrawText(Canvas.Handle, PChar('DrawText: [True]'), Length('DrawText: [True]'), FRect, DT_LEFT);
end;
With the above running on a completely new VCL Project, the result I get is as follows:
fig.4 Test Demo
Again notice the spacing in the string True
when using Canvas.TextOut
, from my end it is clearly different to DrawText
and the way that the TEdit
draws its text.
The below is the same image as fig.4 but zoomed in at 400%
fig.5 Test Demo zoomed at 400%
Noticeable differences are seen between the T
and e
in Text
and also T
and r
in True
.
fig.6 The word 'Text' zoomed in at 400% with guidelines
You can see the kerning between the T
and e
is one pixel closer with DrawText
than with Canvas.TextOut
(which uses ExtTextOut
.)
fig.7 The word True
zoomed in at 700% with guidelines
You can see the kerning between the T
and r
is one pixel closer with DrawText
and the Inplace Editor (TEdit) than with Canvas.TextOut
(which uses ExtTextOut
.)
I have tested several different fonts and here are my findings:
Good:
Arial, Cambria, Candara, Comic Sans MS, Consolas, Courier, Courier New, Fixedsys, Georgia, Lucida Console, Lucida Sans Unicode, Microsoft Sans Serif, Tahoma, Terminal and Times New Roman.
Bad:
Calibri, Corbel, Myriad Pro, Segoe UI, Trebuchet MS and Verdana.
The good fonts are the ones that appear to render text the same way as DrawText
and the Inpace Editor (TEdit) controls do using Canvas.TextOut
. The bad ones show that Canvas.TextOut
renders text slightly different to the other methods.
There may some clue here although I am not too sure, but I am adding it anyway just in case.
Observed difference is due to using different WinAPI text rendering functions and their behavior. Specifically character kerning
In typography, kerning (less commonly mortising) is the process of adjusting the spacing between characters in a proportional font, usually to achieve a visually pleasing result. Kerning adjusts the space between individual letter forms, while tracking (letter-spacing) adjusts spacing uniformly over a range of characters.
The DrawText function draws formatted text in the specified rectangle. It formats the text according to the specified method (expanding tabs, justifying characters, breaking lines, and so forth).
- ExtTextOut (used by
Canvas.TextOut
)
ExtTextOut
declaration:
BOOL ExtTextOut(
_In_ HDC hdc,
_In_ int X,
_In_ int Y,
_In_ UINT fuOptions,
_In_ const RECT *lprc,
_In_ LPCTSTR lpString,
_In_ UINT cbCount,
_In_ const INT *lpDx
);
If the lpDx parameter is NULL, the ExtTextOut function uses the default spacing between characters. The character-cell origins and the contents of the array pointed to by the lpDx parameter are specified in logical units. A character-cell origin is defined as the upper-left corner of the character cell.
Basically DrawText
will automatically draw formatted text and that includes adjusting spacing between characters (kerning), while ExtTextOut
will by default use default spacing between characters (no-kerning). If you want to adjust spacing between characters you will have to calculate and provide kerning array (lpDx
) parameter.
Those differences are especially visible with some character combinations like T
and small letters that visually fit under T
, or AV
where one V
fits over A
. Different fonts also have different default kernings and that is reason why some fonts have visually same rendering using both functions and some not. Kerning also depends on font size. For instance characters AV
rendered with Arial
at 9 pt
will have same output with both functions, while Arial
at 12 pt
will result in different outputs.
First line in following image is drawn with no-kerning using ExtTextOut
and second line with automatic kerning using DrawText
.
这篇关于使用Canvas.TextOut有什么含义?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!