James Lavery
James Lavery

Reputation: 949

Fit text in a rectangle using SkiaSharp

I need to draw text to fill (i.e. be the largest sensible size which fits in) a rectangle. How can I do this? I can't see any methods to scale/fit the text - so I'm assuming (hopefully incorrectly) that I'm going to have to set a font size and measure to see if it fits, and adjust the font size accordingly.

Upvotes: 0

Views: 3272

Answers (3)

Waheed Bhatti
Waheed Bhatti

Reputation: 63

Draw the string at any font size, measure the width, and then use the ratio to determine the font size that would fit within your rect.

Font Size 20 = Text Width of 100

To fit in a width of 50 = 50/100 * 20 = Font size of 10

Upvotes: 0

Sherbet
Sherbet

Reputation: 71

I know this is a super old question, but I may as well answer it for anyone else wanting to know how to do this efficiently.

I recently had to do this for a project of mine. This is what I came up with.

To clarify:

Sector Size: The max length-ways size of the text.

Max Font: The max font size we want to test.

The comments explain how this works.

public float GetMaxFontSize(double sectorSize, SKTypeface typeface, string text, float degreeOfCertainty = 1f, float maxFont = 100f)
{
   var max = maxFont; // The upper bound. We know the font size is below this value
   var min = 0f; // The lower bound, We know the font size is equal to or above this value
   var last = -1f; // The last calculated value.
   float value;
   while (true)
   {
      value = min + ((max - min) / 2); // Find the half way point between Max and Min
      using (SKFont ft = new SKFont(typeface, value))
      using (SKPaint paint = new SKPaint(ft))
      {
         if (paint.MeasureText(text) > sectorSize) // Measure the string size at this font size
         {
            // The text size is too large
            // therefore the max possible size is below value
            last = value;
            max = value;
         }
         else
         {
            // The text fits within the area
            // therefore the min size is above or equal to value
            min = value;

            // Check if this value is within our degree of certainty
            if (Math.Abs(last - value) <= degreeOfCertainty)
            return last; // Value is within certainty range, we found the best font size!

            //This font difference is not within our degree of certainty
            last = value;
         }
      }
   }
}

In my use case, it takes 7 steps to calculate a font size of 54.68px, with an average execution duration over 10000 cycles of 250 ticks (0.025ms) with a degree of certainty of 1px.

Upvotes: 3

James Lavery
James Lavery

Reputation: 949

I came up with a slightly inefficient method for doing this starting with a small TextSize and increasing it and measuring until it doesn't fit in the rectangle - then taking the last size which fits.

To make this efficient, I then cache the TextSize for a given control size.

Not ideal, but it works well!

Upvotes: 1

Related Questions