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

问题描述

我有一些现有的 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}");
}

升级到 后.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}");
}

并且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}");

但是,如您所见,我无法获得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

我对图形编程的了解不足以知道我缺少什么。它可能是点和像素之间的单位转换,或者我没有设置正确的属性。关于如何进行SkiaSharp和/或ImageSharp返回与 相同的宽度测量的任何想法System.Drawing.Common

谢谢你。

标签: skiasharp.net-6.0imagesharpsystem.drawing.common

解决方案


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

这是反对ImageSharpSkiaSharp默认为72 DPI。(我知道ImageSharp肯定会,并且由于和之间的数字在SkiaSharp彼此ImageSharp的舍入误差内,它也必须使用 72 的 DPI)。

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


推荐阅读