【问题标题】:Using C# to measure the width of a string in pixels in a cross platform way使用 C# 以跨平台方式测量字符串的宽度(以像素为单位)
【发布时间】:2021-12-22 17:20:27
【问题描述】:

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

但是,如您所见,我无法让 SkiaSharp 或 ImageSharp 产生相同的宽度,尽管它们产生相似的结果:

'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 相同的宽度测量值的任何想法?

谢谢。

【问题讨论】:

  • 你有没有渲染它们,看看它们的大小有多大不同?很可能不同的字体大小。
  • 渲染图像并进行比较。您发布的只是四舍五入错误,两个图像都是 251 像素宽。除非使用抗锯齿。 System.Drawing.Graphics 正在使用 Windows 默认值、算法、分辨率、字距调整、间距、边距等。它也可能受到用户设置的影响。如果不指定设备,将使用默认设备,这可能在库之间不同。
  • 此外,9 点不是 12 像素。实际像素大小取决于图像分辨率 (DPI)。点是实际的物理尺寸,类似于英寸或厘米。打印 9 个点需要多少像素取决于设备的分辨率 - 与 4K 屏幕相比,用于在非高清屏幕上绘制相同字符串的像素更少。打印机可以在更高的分辨率下工作
  • 查看Point (typography)The DTP point is defined as 1⁄72 of an international inch ( 1 / 72 × 25.4 mm ≈ 0.353 mm) and, as with earlier American point sizes, is considered to be 1⁄12 of a pica.上的维基百科文章

标签: skiasharp .net-6.0 imagesharp system.drawing.common


【解决方案1】:

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

这是对ImageSharp 和SkiaSharp 的反对,因为它们都默认为 72 DPI。 (我知道ImageSharp 肯定有,而且SkiaSharp 和ImageSharp 之间的数字在彼此的舍入误差内,它也必须使用72 的DPI。

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

【讨论】:

    猜你喜欢
    • 2011-06-28
    • 1970-01-01
    • 2011-06-21
    • 2013-06-17
    • 2018-06-14
    • 2019-09-22
    • 1970-01-01
    • 1970-01-01
    • 2013-08-22
    相关资源
    最近更新 更多