The simplest way to get graphical information in Blazor is to use the DOM.
Measure the text using javascript by creating a temporary svg element.
In your javascript, create the following function:
window.measureString = function(textParams) {
const svg = `
<svg style="position:absolute">
<text
font-family="${textParams.Font}"
font-size="${textParams.Size}">
${textParams.Text}
</text>
</svg>`;
const el = document.createElement("div");
el.innerHTML = svg;
document.body.appendChild(el);
const svgText = el.querySelector('text').getBBox();
el.remove();
return { Height: svgText.height, Width: svgText.width };
}
...and interop to that function.
In your .blazor file:
@inject IJsInterop js;
@code {
public class Measurement { public decimal Width { get;set; } public decimal Height { get;set; }}
Task MeasureString(string text, string font, int size) {
var measurement = await js.InvokeAsync<Measurement>("measureString",
new {
Text = text,
Font = font,
Size = size
});
Console.WriteLine($"Width: {measurement.Width} Height: {measurement.Height}";
}
}
The code above averages at 2ms per call.
Out of curiosity, I also found a way of doing (more or less) the same measurement with native c# using the library SixLabors.Fonts.
The following code gets you a measurement. The font itself must be provided first as a Stream, so quite a bit of work. Also, the measurement does not yield the same result as the js code above, so probably not compatible with SVG measurements. I used C:\Windows\Fonts\Arial.ttf as a source in a MemoryStream.
using SixLabors.Fonts;
var fontStream = GetFontAsMemoryStream();
var fonts = new FontCollection();
var font = fonts.Install(fontStream);
var renderOption = new RendererOptions(font.CreateFont(size));
var measurement = TextMeasurer.Measure(text, renderOption);
The above code averages at 2500ms, so a bit more than 1000 times slower than js interop. Might be possible to cache the result of fonts.Install() somehow, but I did not immediately succeed to re-use the font instance without exceptions.