I have some existing C# code that uses System.Drawing.Common
to measure the approximate width of a string in pixels:
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}");
}
After upgrading to .NET 6.0
, I got a bunch of warning messages telling me that these graphics primitives are only supported on Windows. I want this measurement to work on other platforms, so I tried to do something similar with both 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}");
}
And 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}");
However, as you can see, I can't get SkiaSharp
or ImageSharp
to produce the same width, although they produce similar results:
'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
I don't understand graphics programming enough to know what I'm missing. It might be a unit conversion between Points and Pixels, or perhaps I'm not setting the correct properties. Any ideas on how to make SkiaSharp
and/or ImageSharp
return the same width measurement as System.Drawing.Common
?
Thank you.
System.Drawing.Graphics
is using Windows defaults, algorithms, resolution, kerning, spacing, margins etc. It's probably affected by the user settings too. Without specifying a device, a default one will be used which is probably different between libraries. – BicameralThe 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.
– Bicameral