以公制单位准确计算文本宽度

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。这对于某些字体和字体大小来说非常准确,但对于其他字体和字体大小来说,它要么太小要么太大。我尝试了很多其他可能性,例如GetCharWidth32GetCharABCWidths,还有映射模式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;

【讨论】:

以上是关于以公制单位准确计算文本宽度的主要内容,如果未能解决你的问题,请参考以下文章

如何计算 JavaFX 中字符串的像素宽度?

如何计算边界矩形的宽度,以使文本包裹以适合特定比例?

计算文本宽度

如何编码公制前缀(千、兆、千兆等)并对其进行计算?

使用 PHP GD 计算文本宽度

移动端适配