Reputation: 895
I am using svg elements in our blazor applications. In that I am using text elements inside an Svg. Meanwhile I need text element's height and width in pixels. Based on that I am doing some dimension changes in SVG element. Unfortunately, I have no idea on how to get the text element's size.
In ASP.Net applications, there is a way like below,
using System.Drawing;
private float GetWidthOfString(string str)
{
Bitmap objBitmap = default(Bitmap);
Graphics objGraphics = default(Graphics);
objBitmap = new Bitmap(500, 200);
objGraphics = Graphics.FromImage(objBitmap);
SizeF stringSize = objGraphics.MeasureString(str, new Font("Arial", 12));
objBitmap.Dispose();
objGraphics.Dispose();
return stringSize.Width;
}
But I can't use this in blazor application. Is there any way find the text element's size in pixels?
Upvotes: 6
Views: 1871
Reputation: 3853
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.
Upvotes: 2