I have image with some area (rectangle) for text. Text can be with any length, one word or long string (that must be wrapped). I need to:
- Calculate font size (by string, font and rectangle)
- Draw text in this rectangle (with wrapping!)
The main requirement: get maximum of fontSize, the text should fill ALL rectangle.
What I done. I found nice 3rd party in NuGet: ImageProcessor. But, ImageFactory.Watermark gets only start point, not rectangle.
OK, I've implemented own solution:
- Try to draw text in rectangle with very big font size (use MeasureText, not real render).
- For example, my rectangle has height = 100, but MeasureString returns 200. Great, change fontSize from 50 to 25.
- With new fontSize every char became smaller, not only height, and width too! This is why I replace newFontSize = oldFontSize * (measuredHeight / requiredHeight) to newFontSize = oldFontSize * Math.Sqrt(measuredHeight / requiredHeight)
- Looks better. But I still have problems.
Prob 1: I use Graphics.MeasureString from GDI+ in WPF. This is not thread-safe, I have to use locks.
Prob 2: MeasureString returning wrong height, as if text has big margin. For example, I have 3 rectangles close to each other:
- RECTANGLE1
- RECTANGLE2
- RECTANGLE3
After render I see VERY big spaces between them.
I will happy get 3rd party with what I need! If no, to fix my code will be also great. Thanks!
Code:
private static void RenderText(string text, RectangleF rectangle,
string fontFamily, int maximumFontSize, Color textColor, Graphics graphics)
{
var font = new Font(fontFamily, maximumFontSize, FontStyle.Regular);
var stringFormat = new StringFormat
{
// LineAlignment = StringAlignment.Center,
FormatFlags = StringFormatFlags.NoClip | StringFormatFlags.FitBlackBox,
Trimming = StringTrimming.None
};
var previewSize = graphics.MeasureString(text, font,
new SizeF(rectangle.Width, rectangle.Height), stringFormat);
if (previewSize.Height > rectangle.Height)
{
var scale = Math.Sqrt(rectangle.Height / previewSize.Height);
font = new Font(fontFamily, (float) (maximumFontSize * scale), FontStyle.Regular);
}
graphics.DrawString(text, font, new SolidBrush(textColor), rectangle, stringFormat);
}
Additional note:
What I'm trying to get with this is to have both text-wrapping and font-scaling at the same time. Please see this sketch as an example.