以公制单位准确计算文本宽度
Posted
技术标签:
【中文标题】以公制单位准确计算文本宽度【英文标题】:Accurately compute text widths in metric units 【发布时间】:2012-03-08 18:14:10 【问题描述】:我想计算给定字符串的公制单位的确切文本宽度。我的伪代码如下所示:
Bitmap.Canvas.Assign(Font);
PixelWidth := Bitmap.Canvas.TextWidth(Font)
MetricWidth := PtToMM * (PixelWidth * 72.0 / GetScreenDPI);
PtToMM
是一个常量,定义为0.352777778
。这对于某些字体和字体大小来说非常准确,但对于其他字体和字体大小来说,它要么太小要么太大。我尝试了很多其他可能性,例如GetCharWidth32
和GetCharABCWidths
,还有映射模式MM_LOMETRIC
,但我就是无法让它工作。这个问题困扰着我,所以请任何人都可以帮助并告诉我我错在哪里。非常感谢!
编辑我检查了一个字符串:公制宽度计算为 4.17 厘米,实际打印输出的宽度(在纸上测量)为 4.4 厘米(字体 Times New Roman,大小 12)。
【问题讨论】:
一些问题:你怎么知道计算出的文本宽度不是它应该是的?您是否使用正确的 DC 获取文本宽度? (即:你有没有机会在屏幕画布上阅读,然后在印刷画布上使用结果?)。我从未使用过这种计算来获得实际的 METRIC 值,但 PIXEL 值一直是准确的。我使用类似的代码在连续纸上使用点阵打印机打印 1 米长的表格,其中列的宽度是根据文本内容计算的。 @Comsin:不确定我是否明白你的问题。我将它用于打印预览和打印,因此它既可以在屏幕上使用,也可以在打印机上使用。 这听起来像你想比 Windows 更聪明。你不应该自己计算这个,你应该让你的打印机设备上下文告诉你纸上的宽度是多少? 像素是逻辑单位,所以metric这个词应该换成physical。几年前我做了一些类似的实验,发现什么显示设备永远不准确。 @CosminPrund 询问的是您是否尝试使用屏幕的 DC 与打印机的 DC 来计算这些尺寸。如果您使用屏幕的 DC,它的分辨率可能不够高,无法确保非常准确的物理测量。此外,打印机可能会用略有不同的指标替换其自己的 Times 版本。最后,您的计算似乎是从像素 -> 英寸 -> 点 -> 毫米开始的。积累错误的地方很多。 【参考方案1】:我没有对它进行广泛的测试,但它似乎给出了正确的结果。结果是文本的宽度,以千分之一毫米为单位。此函数不支持自动换行和其他特殊注意事项。
另外,请注意,在使用打印机时,不正确的打印配准会“拉伸”文本。
另外,请注意对于打印机,例如,将打印分辨率从 300 ppp 更改为 1200 ppp 也会改变结果。
uses
ConvUtils, stdConvs ;
function CalcRequiredTextWidth(aDC : HDC; aFont : TFont; const asText: string): Double;
var vCanvas : TCanvas;
iPixelsWidth : Integer;
dInchWidth : Double;
iFontSize : Integer;
begin
vCanvas := TCanvas.Create;
try
vCanvas.Handle := aDC;
vCanvas.Font.Assign(aFont);
iFontSize := vCanvas.Font.Size;
vCanvas.Font.PixelsPerInch := GetDeviceCaps(aDC, LOGPIXELSY);
vCanvas.Font.Size := iFontSize;
iPixelsWidth := vCanvas.TextExtent(asText).cx;
dInchWidth := iPixelsWidth / GetDeviceCaps(vCanvas.Handle, LOGPIXELSX);
Result := Convert(dInchWidth, duInches, duMicrons);
finally
vCanvas.Free;
end;
end;
【讨论】:
以上是关于以公制单位准确计算文本宽度的主要内容,如果未能解决你的问题,请参考以下文章