Skip to content

Instantly share code, notes, and snippets.

@JanWichelmann
Created July 9, 2020 19:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JanWichelmann/5d1b8210a9bd5c3c25c0703ac2af6540 to your computer and use it in GitHub Desktop.
Save JanWichelmann/5d1b8210a9bd5c3c25c0703ac2af6540 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Drawing;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
string fontFamilyName = "Arial";
int minFontSize = 10;
int maxFontSize = 200;
var fm = new FontMeasure(fontFamilyName, minFontSize, maxFontSize);
// Create test images for many width/height combinations
for(int width = 100; width < 300; width += 20)
{
for(int height = 100; height < 300; height += 20)
{
// Test input
string input = "1188yyyiiiii_Š_?!mmmm";
// Allocate image, add light background to better highlight image size
using var img = new Bitmap(width, height);
using var g = Graphics.FromImage(img);
g.Clear(Color.LightYellow);
// Get correctly sized font
var font = fm.GetFont(input, g, width, height);
// Render
g.DrawString(input, font, Brushes.Black, 0, 0);
//img.Save($"img_{width}_{height}.png");
}
}
}
}
class FontMeasure
{
int _minFontSize;
int _maxFontSize;
Dictionary<int, Font> _fontCache = new Dictionary<int, Font>();
public FontMeasure(string fontFamily, int minFontSize, int maxFontSize)
{
_minFontSize = minFontSize;
_maxFontSize = maxFontSize;
// Cache all potentially needed font sizes
for(int i = minFontSize; i <= maxFontSize; ++i)
_fontCache.Add(i, new Font(fontFamily, i));
}
public Font GetFont(string str, Graphics g, int imgWidth, int imgHeight)
{
int counter = 0;
// Measure with maximum sized font
var baseSize = g.MeasureString(str, _fontCache[_maxFontSize]);
++counter;
// Downsample to actual image size
float widthRatio = imgWidth / baseSize.Width;
float heightRatio = imgHeight / baseSize.Height;
float minRatio = Math.Min(widthRatio, heightRatio);
int estimatedFontSize = (int)(_maxFontSize * minRatio);
// Make sure the precomputed font list is always hit
if(estimatedFontSize > _maxFontSize)
estimatedFontSize = _maxFontSize;
else if(estimatedFontSize < _minFontSize)
estimatedFontSize = _minFontSize;
// Make sure the estimated size is not too large
var estimatedSize = g.MeasureString(str, _fontCache[estimatedFontSize]);
++counter;
bool estimatedSizeWasReduced = false;
while(estimatedSize.Width > imgWidth || estimatedSize.Height > imgHeight)
{
if(estimatedFontSize == _minFontSize)
break;
--estimatedFontSize;
estimatedSizeWasReduced = true;
estimatedSize = g.MeasureString(str, _fontCache[estimatedFontSize]);
++counter;
}
// Can we increase the size a bit?
if(!estimatedSizeWasReduced)
{
while(estimatedSize.Width < imgWidth && estimatedSize.Height < imgHeight)
{
if(estimatedFontSize == _maxFontSize)
break;
++estimatedFontSize;
estimatedSize = g.MeasureString(str, _fontCache[estimatedFontSize]);
++counter;
}
// We increase the size until it is larger than the image, so we need to go back one step afterwards
if(estimatedFontSize > _minFontSize)
--estimatedFontSize;
}
Console.WriteLine("Calls to g.MeasureString(): " + counter);
return _fontCache[estimatedFontSize];
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment