It is used to store an array of integers (depending upon the number of a characters in the index) ranging 0 to 255 starting from a Dictionary of various font (if any font sent to the method does not exist). Testing proves it to take approximately 60ms. Other characters that are above 255 (unicode) are then measured as a fly and are then stored in the array as needed. All measurements are then called through a public static method named as MeasureStringWidth(). In the loop it will greatly enhance the processing speed by 30-40% if not more. Can measure italic and mono fonts. Just copy this free software project and enjoy.
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace dIRC7.Helpers
{
/* Faster (cached) MeasureStringWidth class
By: Jason James Newland & Ryan Alexander
©2012 KangaSoft Software – All Rights Reserved
*/
#region Fields
internal class FontData
{
public int[] NormalCharacterWidth { get; set; }
public int[] BoldCharacterWidth { get; set; }
public int[] ItalicCharacterWidth { get; set; }
}
#endregion
public sealed class IrcMeasureStringWidth
{
#region Fields
private const TextFormatFlags FormatFlags = TextFormatFlags.Left | TextFormatFlags.NoPrefix | TextFormatFlags.NoPadding | TextFormatFlags.NoClipping;
private static readonly Dictionary Fonts = new Dictionary();
#endregion
#region Public measure string width
public static int MeasureStringWidth(Graphics g, Font font, string text)
{
FontData data;
if (!Fonts.ContainsKey(font))
{
data = new FontData
{
NormalCharacterWidth = BuildLookupList(g, font),
BoldCharacterWidth = BuildLookupList(g, new Font(font, FontStyle.Bold)),
ItalicCharacterWidth = BuildLookupList(g, new Font(font, FontStyle.Italic))
};
Fonts.Add(font, data);
}
else { data = Fonts[font]; }
return MeasureStringWidth(g, text.ToCharArray(), font, data);
}
#endregion
#region Private methods
#region Measure string width overloads
private static int MeasureStringWidth(Graphics g, IList text, Font font, FontData data)
{
if (text == null || text.Count == 0) { return 0; }
return text.Count == 1 ? MeasureStringWidth(g, text[0], font, data) : text.Sum(chr => MeasureStringWidth(g, chr, font, data));
}
private static int MeasureStringWidth(IDeviceContext g, char chr, Font font, FontData data)
{
var chrValue = (int)chr;
if ((font.Bold && font.Italic) || font.Bold)
{
if (chrValue > 255 && data.BoldCharacterWidth[chrValue] == 0)
{
data.BoldCharacterWidth[chrValue] = MeasureString(g, font, chr.ToString());
}
return data.BoldCharacterWidth[chrValue];
}
if (font.Italic)
{
if (chrValue > 255 && data.ItalicCharacterWidth[chrValue] == 0)
{
data.ItalicCharacterWidth[chrValue] = MeasureString(g, font, chr.ToString());
}
return data.ItalicCharacterWidth[chrValue];
}
if (chrValue > 255 && data.NormalCharacterWidth[chrValue] == 0)
{
data.NormalCharacterWidth[chrValue] = MeasureString(g, font, chr.ToString());
}
return data.NormalCharacterWidth[chrValue];
}
#endregion
#region Build main character look-up list
private static int[] BuildLookupList(IDeviceContext g, Font font)
{
var lookUp = new int[char.MaxValue];
for (var i = (char)0; i < (char)256; i++)
{
lookUp[i] = MeasureString(g, font, i.ToString());
}
return lookUp;
}
#endregion
#region GDI measure text string
private static int MeasureString(IDeviceContext g, Font font, string text)
{
return string.IsNullOrEmpty(text) ? 0 : TextRenderer.MeasureText(g, text, font, Size.Empty, FormatFlags).Width;
}
#endregion
#endregion
}
}