我在Delphi中编写了一个Windows程序,它使用GetCharWidth和Em-Square非常精确地将文本放置到屏幕和打印机上。这适用于ANSI文本,您只需要检索和计算255个字符的宽度,但是当您使用65535个字符转到Unicode时,它太慢了。由于必须创建2个宽度数组,一个用于普通数组,一个用于粗体数组,因此问题变得更加严重。
//Setup a reference canvas for measuring purposes
RefDC := CreateCompatibleDC ( FCanvas.Handle ) ;
DPI := GetDeviceCaps ( RefDC , LOGPIXELSY ) ;
//find EmSquare
GetOutlineTextMetrics ( RefDC , sizeof(otm) , @otm[0] ) ;
EmSq := otm[0].otmEmSquare ;
//calc NORMAL char sizes
GetObject ( FCanvas.Font.Handle , SizeOf ( lf ) , @lf ) ;
lf.lfHeight := -EmSq ;
lf.lfWidth := 0 ;
lf.lfWeight := FW_NORMAL ;
hf := CreateFontIndirect ( lf ) ;
hold := SelectObject ( RefDC , hf ) ;
GetCharWidth ( RefDC , 0 , $FFFF , nCharWidth ) ;
for a := 0 to $FFFF do
fCharWidth[a] := nCharWidth[a]* PixelSize / EmSq ;
SelectObject ( RefDC , hold ) ;
DeleteObject ( hf ) ;
//calculate line height
PixelSize := abs ( fCanvas.Font.Size * DPI / 72 ) ;
GetOutlineTextMetrics ( RefDC , sizeof(otm) , @otm[0] ) ;
LineHt := round ( ( otm[0].otmTextMetrics.tmHeight +
otm[0].otmTextMetrics.tmExternalLeading ) *
PixelSize / EmSq ) ;
//calculate Bold char sizes
lf.lfWeight := FW_BOLD ;
hf := CreateFontIndirect ( lf ) ;
hold := SelectObject ( RefDC , hf ) ;
GetCharWidth ( RefDC , 0 , $FFFF , nCharWidth ) ;
for a := 0 to $FFFF do
fBoldWidth[a] := nCharWidth[a] * PixelSize / EmSq ;
SelectObject ( RefDC , hold ) ;
DeleteObject ( hf ) ;
DeleteDC ( RefDC ) ;`
答案 0 :(得分:8)
计算单个字符宽度并以Unicode格式添加它们不仅非常慢,而且它是错误的并且无法正常工作。 Unicode将字符标记组合在一起,有时以复杂的方式组合。
使用Unicode,正确的方法是将整个字符串传递给Windows API函数GetTextExtentExPoint以及行的宽度,它将确定行的宽度是多少你。
答案 1 :(得分:2)
我认为,在典型的会话中不太可能使用数千个字符。如果是这样,在第一轮中只计算前128个字符的宽度,并放入f.i.所有其余的-1。当进行查找时,测试宽度是否为-1,如果只是,则计算该字符的宽度,高度等。
答案 2 :(得分:1)
除了质疑问题本身的前提之外,你可以通过使用单独的数组和字体对象等获得两个nCharWidth数组并将它们一起处理,将你的两个0..65535循环减少到一个循环。
此外,您可以从循环中排除范围$ D800- $ DFFF,因为它们永远不能代表自己的字符(作为代理对中的第一个,您的代码似乎没有设计用来处理)。
答案 3 :(得分:0)
您是否使用过分析器实际查看瓶颈可能在哪里? 使用查找表时,一个常见的想法是,动态构建它们看起来成本太高,只需构建一次并将它们存储为资源...