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

Delphi 以公制单位精确计算文本宽度,delphi,fonts,gdi,delphi-xe,Delphi,Fonts,Gdi,Delphi Xe,我想计算给定字符串的精确文本宽度,单位为公制。我的伪代码如下所示: Bitmap.Canvas.Assign(Font); PixelWidth := Bitmap.Canvas.TextWidth(Font) MetricWidth := PtToMM * (PixelWidth * 72.0 / GetScreenDPI); PtToMM是一个常量,定义为0.3527778。对于某些字体和字体大小来说,这是非常准确的,但对于其他字体来说,它要么太小,要么太大。我尝试了很多其他的可能性,比如

我想计算给定字符串的精确文本宽度,单位为公制。我的伪代码如下所示:

Bitmap.Canvas.Assign(Font);
PixelWidth := Bitmap.Canvas.TextWidth(Font)
MetricWidth := PtToMM * (PixelWidth * 72.0 / GetScreenDPI);
PtToMM
是一个常量,定义为
0.3527778
。对于某些字体和字体大小来说,这是非常准确的,但对于其他字体来说,它要么太小,要么太大。我尝试了很多其他的可能性,比如
GetCharWidth32
GetCharABCWidths
,还有映射模式
MM_LOMETRIC
,但我就是无法让它工作。这个问题困扰着我,所以请任何人帮助我,告诉我哪里错了。多谢各位


编辑我检查了一个字符串:公制宽度计算为4.17厘米,实际打印输出的宽度(在纸上测量)为4.4厘米(字体乘以新罗马字体,大小12)。

我没有对其进行广泛测试,但似乎给出了正确的结果。结果是文本的宽度,单位为千分之一毫米。此函数不支持换行和其他特殊注意事项

另外,请注意,使用打印机时,不正确的打印注册可能会“拉伸”文本

另外,请注意,对于打印机,例如,将打印分辨率从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;

一些问题:您如何知道计算的文本宽度不是应该的宽度?您是否使用正确的DC测量文本宽度?(即:您是否有可能在屏幕画布上读取读数,然后在打印画布上使用结果?)。我从未使用过这种计算来获得实际的度量值,但像素值始终是精确的。我曾使用类似的代码在连续纸张上使用点阵打印机打印1米长的表格,其中列的宽度是根据文本内容计算的。@Comsin:我不确定我是否明白你的问题。我用它进行打印预览和打印,所以它可以在屏幕上和打印机上使用。这听起来像是你试图比Windows更聪明。你不应该自己计算,你应该让你的打印机设备上下文告诉你纸上的宽度是多少?像素是逻辑单位,所以公制术语应该用物理单位代替。几年前,我做了一些类似的实验,发现了哪些显示设备从来都不精确。@CosminPrund的问题是,你是否试图用屏幕的直流电和打印机的直流电来计算这些尺寸。如果您使用的是屏幕的DC,它的分辨率可能不够高,无法确保非常精确的物理测量。此外,打印机可能会使用稍有不同的度量替换其自己版本的Times。最后,您的计算似乎从像素->英寸->点->毫米开始。有很多地方会累积错误。