您的位置:首页 > 产品设计 > UI/UE

Tcl/tk缩放Truetype字体时的精度问题

2017-02-11 19:21 561 查看
最近有国内新客户抱怨我们产品显示的原理图太不专业了,在原理图上使用宋体GB2312设计好中文图表,经过几次缩放时,表格内的文字居然会跑到表格外边,更要命的是打印出来的文档也存在同样的问题。我研究了一下,原来又是WindowsGDITextAPIs的一个大坑!

问题详细描述


用Tcl/tkscript可以很容易地重现这个问题。如下图,第一行文字使用的Arial字体renderingbyGDIAPIs,第二行文字使用的是OFHelvetica字体renderingbyFreetypeAPIs,两行文字都用和字体无关的方式加了边框。

刚运行脚本时,两行文字都是8pt,虽然显示效果不一样,但看着是一样大。 



放大几次后,第一行的GDI文字明显跑到框外了。 



再看一下这时的log: 
font:-familyArial -size20.118148965022 -weightnormal-slantroman-underline0-overstrike0-typetruetype 

font:-family{OFHelvetica} -size19.53125 -weightnormal-slantroman-underline0-overstrike0-typeoutline 

zoomfact:2.44140625

缩放比例2.44140625,outline字体的大小是19.53125ot,正好等于8*2.44140625,没有一点精度损失;而truetype字体的大小是20.118148965022pt,明显偏大了。

原因分析


Tcltk在Windows上使用GDIfontengine来渲染显示Truetype字体。GDITextAPIs的fontsize必须是int类型,在代码调用过程中,需要把界面指定的phsicialfontsize(pt)转换为logicalfontsize,从而导致了精度损失;作为对比,如果使用我们产品内置的Outline字体就没有类似的问题,因为Outline字体是我们过去为了支持跨平台,自己移植的Freetype字体,对应使用的是Freetypefontengine,Freetype
APIs的fontsize都是float类型的,从phsicialfontsize转换为logicalfontsize时不会产生精度损失。为了支持中文,用户只能使用基于GDIrender的truetype字体,因为Freetype字体库中还没有支持中文的字体,这次看来必须要对Tcl/tk的fontengine做个大手术,用DirectWritefloat-basedAPIs更换老旧的GDIAPIs了。

tcl/tk测试代码如下


proczoominit{c{zfact{1.1}}}{

#savezoomstateinaglobalvariablewiththesamenameasthecanvashandle

upvar#0$cdata

setdata(zdepth)1.0

}


proczoom{cfact}{

upvar#0$cdata

#zoomatthecurrentmouseposition

setx[$ccanvasx[expr{[winfopointerx$c]-[winforootx$c]}]]

sety[$ccanvasy[expr{[winfopointery$c]-[winforooty$c]}]]

$cscaleall$x$y$fact$fact

#savenewzoomdepth

setdata(zdepth)[expr{$data(zdepth)*$fact}]

#zoomtextsincethe"canvasscaleall"commanddoesn'taccountfortextitems

zoomtext$c

puts"zoomfact:$data(zdepth)"

}


proczoomtext{c}{

upvar#0$cdata

#adjustfonts

foreach{i}[$cfindall]{

if{![stringequal[$ctype$i]text]}{continue}

setfontsize0

#getoriginalfontsizeandtextfromtagsiftheywerepreviouslyrecorded

foreach{tag}[$cgettags$i]{

scan$tag{_f%f}fontsize

scan$tag"_t%\[^\0\]"text

}

#ifnot,thenrecordcurrentfontsizeandtextandusethem

setfont[$citemcget$i-font]

if{!$fontsize}{

settext[$citemcget$i-text]

setfontsize[fontactual$font-size]

$caddtag_f$fontsizewithtag$i

$caddtag_t$textwithtag$i

}

#scalefont

setnewsize[expr{$fontsize*$data(zdepth)}]

setindex[lsearch-exact$font-size]

incrindex

setfont[lreplace$font$index$index$newsize]

$citemconfigure$i-font$font-text$text-anchorw

puts"font:$font"

}


#updatecanvasscrollregion

setbbox[$cbboxall]

if{[llength$bbox]}{

$cconfigure-scrollregion$bbox

}{

$cconfigure-scrollregion[list-4-4\

[expr{[winfowidth$c]-4}]\

[expr{[winfoheight$c]-4}]]

}

#movesrollbartotoprightinordertoeasilyobservewhetherthezoomedtext

#goesoutsideoftherectangle

$cxviewmoveto[winfowidth$c]

$cyviewmoveto0

}



#testcode

setc[canvas.c-width600-height500\

-xscrollcommand".shorizset"\

-yscrollcommand".svertset"]

#addx/yscrollbarforthecanvas

scrollbar.svert-orientv-command"$cyview"

scrollbar.shoriz-orienth-command"$cxview"

grid.c-row0-column0-columnspan3-stickynews

grid.svert-row0-column3-columnspan1-stickyns

grid.shoriz-row1-column0-columnspan3-stickyew

gridcolumnconfigure.0-weight1

gridcolumnconfigure.1-weight1

gridcolumnconfigure.2-weight1

gridrowconfigure.0-weight1

zoominit.c

button.zoomin-text"ZoomIn"-command"zoom$c1.25"

button.zoomout-text"ZoomOut"-command"zoom$c0.8"

grid.zoomin.zoomout

settext"Hello,World!Here'sasimpleprocedurecalledzoomthatmighthelptogetyoustarted."

#tfontisatruetypefontrenderingbyWindowsGDIAPIs(GDIfontengine)

settfont[fontactual"-familyArial-size8"]

#ofontisaoutlinefontrenderingbyfreetypefontenginetransplantedbyourself

setofont[fontactual"-family{OFHelvetica}-size8"]

.ccreatetext450-text$text-font$tfont-anchorw-tagtfont

#createarectanglewiththesamesizeofthebboxofthetext.zoomin/outthecanvasandwe

#canobservewhetherthetextiszoomedinthesameproportionastherectangle

.ccreaterect[.cbboxtfont]

.ccreatetext4100-text$text-font$ofont-anchorw-tagofont

.ccreaterect[.cbboxofont]


代码参考资源链接: 
Canvaszoomingusingmousewheel
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  tcl-tk font 字体 gdi