使用 C# 以跨平台方式测量字符串的宽度(以像素为单位)

Jon*_*ara 7 skiasharp imagesharp system.drawing.common .net-6.0

我有一些现有的 C# 代码,用于System.Drawing.Common测量字符串的近似宽度(以像素为单位):

var text = "abc123 this is some long text my dog's name is fido.";

using (var bitmap = new Bitmap(500, 50))
using (var graphics = Graphics.FromImage(bitmap))
{
    // Size: 9 Points
    using var font = new System.Drawing.Font(familyName: "Times New Roman", emSize: 9f);
    
    var ms = graphics.MeasureString(text, font);
    
    // Output: 'abc123 this is some long text my dog's name is fido.' via System.Drawing: 394.00195 x 22.183594
    Console.WriteLine($"'{text}' via System.Drawing: {ms.Width} x {ms.Height}");
}
Run Code Online (Sandbox Code Playgroud)

升级到 后.NET 6.0,我收到一堆警告消息,告诉我这些图形基元仅在 Windows 上受支持。我希望这种测量能够在其他平台上工作,所以我尝试对这两个平台执行类似的操作SkiaSharp

var text = "abc123 this is some long text my dog's name is fido.";

using (var paint = new SKPaint())
{
    paint.Typeface = SKTypeface.FromFamilyName("Times New Roman");
    
    // Size: 12px
    paint.TextSize = 12f;
    
    var skBounds = SKRect.Empty;
    var textWidth = paint.MeasureText(text.AsSpan(), ref skBounds);
    
    // Output: 'abc123 this is some long text my dog's name is fido.' via SkiaSharp: 251.13867 x 12
    Console.WriteLine($"'{text}' via SkiaSharp: {skBounds.Width} x {skBounds.Height}");
}
Run Code Online (Sandbox Code Playgroud)

ImageSharp

var text = "abc123 this is some long text my dog's name is fido.";

// Size: 12px
var imgSharpFont = SixLabors.Fonts.SystemFonts.CreateFont("Times New Roman", 12f);
var imgSharpMeasurement = TextMeasurer.Measure(text, new RendererOptions(imgSharpFont));

// Output: 'abc123 this is some long text my dog's name is fido.' via ImageSharp: 251.13869 x 14.589844
Console.WriteLine($"'{text}' via ImageSharp: {imgSharpMeasurement.Width} x {imgSharpMeasurement.Height}");
Run Code Online (Sandbox Code Playgroud)

然而,正如您所看到的,我无法获得SkiaSharpImageSharp产生相同的宽度,尽管它们产生相似的结果:

'abc123 this is some long text my dog's name is fido.' via System.Drawing: 394.00195
'abc123 this is some long text my dog's name is fido.' via SkiaSharp: 251.13867
'abc123 this is some long text my dog's name is fido.' via ImageSharp: 251.13869
Run Code Online (Sandbox Code Playgroud)

我对图形编程的了解不够,不知道我错过了什么。它可能是点和像素之间的单位转换,或者也许我没有设置正确的属性。关于如何制作SkiaSharp和/或ImageSharp返回与 相同的宽度测量值有什么想法吗System.Drawing.Common

谢谢。

toc*_*oft 5

基本上这个问题是由于默认情况下System.Drawing.Graphics将使用机器的 DPI (原因是因为System.Drawing它是围绕 GDI 构建的,GDI 是一个用于将图像绘制到屏幕和打印机的 Windows 子系统)。

这是反对的ImageSharpSkiaSharp因为两者都默认为72 DPI。(我知道肯定是这样,并且由于和ImageSharp之间的数字彼此之间存在舍入误差,因此也必须使用 72 的 DPI)。SkiaSharpImageSharp

根据您提供的数字,我猜您正在运行 112 DPI 显示器?