Archive Browser
Download GetTextMetricsDemo.zip, last updated 09/07/2016 (10.51 KB)
Download- md5: 5716cc483e334071b2334c8ae92e076f
- sha1: 2c94d15164e3498d892843eaf8b78d77dd3ba8c7
- sha256: 3bf039f038a478d5f31aca3e1ca634739e4343a84de89ab73ff6c2f33653f9c2
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Text;
using System.Windows.Forms;
// Retrieving font and text metrics using C#
// http://www.cyotek.com/blog/retrieving-font-and-text-metrics-using-csharp
// Copyright © 2016 Cyotek Ltd. All Rights Reserved.
namespace GetTextMetricsDemo
{
internal partial class MainForm : Form
{
#region Constants
private const int _boxSize = _labelEdgeLength * 4;
private const TextFormatFlags _flags = TextFormatFlags.Left | TextFormatFlags.ExpandTabs | TextFormatFlags.NoPrefix | TextFormatFlags.NoPadding | TextFormatFlags.NoClipping;
private const int _labelEdgeLength = 6;
private const int _vaneLength = _labelEdgeLength >> 1;
#endregion
#region Constructors
public MainForm()
{
this.InitializeComponent();
}
#endregion
#region Methods
/// <summary>Raises the <see cref="E:System.Windows.Forms.Form.Shown" /> event.</summary>
/// <param name="e">A <see cref="T:System.EventArgs" /> that contains the event data. </param>
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
this.Font = SystemFonts.DialogFont;
this.SetFontTextBox();
this.UpdatePreview();
}
private void DrawHorizontalLabel(Graphics g, Color color, string label, int x, int y, int w)
{
Font font;
Size size;
string px;
using (Pen pen = new Pen(color))
{
g.DrawLine(pen, x, y - _vaneLength, x, y + _vaneLength);
g.DrawLine(pen, x, y, x + w, y);
g.DrawLine(pen, x + w, y - _vaneLength, x + w, y + _vaneLength);
}
font = this.Font;
px = w.ToString();
size = TextRenderer.MeasureText(g, px, font, Size.Empty, _flags);
TextRenderer.DrawText(g, label, font, new Rectangle(x, y + 3, w, 0), color, _flags | TextFormatFlags.HorizontalCenter | TextFormatFlags.WordBreak);
TextRenderer.DrawText(g, px, font, new Point(x + w + _labelEdgeLength, y - (size.Height >> 1)), color, _flags);
}
private void DrawMiddleLabel(Graphics g, Color color, string label, int x, int y)
{
Font font;
Size size;
font = this.Font;
size = TextRenderer.MeasureText(g, label, font, Size.Empty, _flags);
TextRenderer.DrawText(g, label, font, new Point(x, y - (size.Height >> 1)), color, _flags);
}
private int DrawValues(Graphics g, NativeMethods.TEXTMETRICW metrics)
{
List<Tuple<string, string>> values;
Font font;
int maxWidth;
int maxHeight;
int x;
int y;
int tableWidth;
font = this.Font;
maxWidth = 0;
maxHeight = 0;
tableWidth = 0;
values = new List<Tuple<string, string>>();
values.Add(Tuple.Create("Internal Leading", metrics.tmInternalLeading.ToString()));
values.Add(Tuple.Create("External Leading", metrics.tmExternalLeading.ToString()));
values.Add(Tuple.Create("Overhang", metrics.tmOverhang.ToString()));
values.Add(null);
values.Add(Tuple.Create("First Character", ((char)metrics.tmFirstChar).ToString()));
values.Add(Tuple.Create("Last Character", ((char)metrics.tmLastChar).ToString()));
values.Add(Tuple.Create("Default Character", ((char)metrics.tmDefaultChar).ToString()));
values.Add(Tuple.Create("Break Character", ((char)metrics.tmBreakChar).ToString()));
values.Add(null);
values.Add(Tuple.Create("Weight", metrics.tmWeight.ToString()));
values.Add(Tuple.Create("Italic", metrics.tmItalic.ToString()));
values.Add(Tuple.Create("Underline", metrics.tmUnderlined.ToString()));
values.Add(Tuple.Create("Strike Through", metrics.tmStruckOut.ToString()));
values.Add(null);
values.Add(Tuple.Create("Pitch and family", metrics.tmPitchAndFamily.ToString()));
values.Add(Tuple.Create("Character Set", metrics.tmCharSet.ToString()));
// ReSharper disable once LoopCanBePartlyConvertedToQuery
foreach (Tuple<string, string> tuple in values)
{
if (tuple != null)
{
Size size;
size = TextRenderer.MeasureText(tuple.Item1, font, Size.Empty, _flags);
maxWidth = Math.Max(maxWidth, size.Width);
maxHeight = Math.Max(maxHeight, size.Height);
}
}
x = _boxSize;
y = _boxSize;
foreach (Tuple<string, string> tuple in values)
{
if (tuple != null)
{
Size size;
string value;
value = ": " + tuple.Item2;
TextRenderer.DrawText(g, tuple.Item1, font, new Point(x, y), SystemColors.WindowText, _flags);
TextRenderer.DrawText(g, value, font, new Point(x + maxWidth, y), SystemColors.WindowText, _flags);
size = TextRenderer.MeasureText(value, font, Size.Empty, _flags);
tableWidth = Math.Max(tableWidth, maxWidth + size.Width);
}
y += maxHeight;
}
return tableWidth;
}
private void DrawVerticalLabel(Graphics g, Color color, string label, int x, int y, int h)
{
Font font;
Size size;
string px;
using (Pen pen = new Pen(color))
{
g.DrawLine(pen, x - _vaneLength, y, x + _vaneLength, y);
g.DrawLine(pen, x, y, x, y + h);
g.DrawLine(pen, x - _vaneLength, y + h, x + _vaneLength, y + h);
}
font = this.Font;
px = h.ToString();
size = TextRenderer.MeasureText(g, px, font, Size.Empty, _flags);
TextRenderer.DrawText(g, label, font, new Point(x + 3, y + 3), color, _flags);
TextRenderer.DrawText(g, px, font, new Point(x - (size.Width + 2), y + 3), color, _flags);
}
private void fontBrowseButton_Click(object sender, EventArgs e)
{
if (fontDialog.ShowDialog(this) == DialogResult.OK)
{
this.SetFontTextBox();
this.UpdatePreview();
}
}
private NativeMethods.TEXTMETRICW GetTextMetrics(IDeviceContext dc, Font font)
{
NativeMethods.TEXTMETRICW result;
IntPtr hDC;
IntPtr hFont;
IntPtr hFontDefault;
hDC = IntPtr.Zero;
hFont = IntPtr.Zero;
hFontDefault = IntPtr.Zero;
try
{
hDC = dc.GetHdc();
hFont = font.ToHfont();
hFontDefault = NativeMethods.SelectObject(hDC, hFont);
NativeMethods.GetTextMetrics(hDC, out result);
}
finally
{
if (hFontDefault != IntPtr.Zero)
{
NativeMethods.SelectObject(hDC, hFontDefault);
}
if (hFont != IntPtr.Zero)
{
NativeMethods.DeleteObject(hFont);
}
dc.ReleaseHdc();
}
return result;
}
private void previewPanel_Paint(object sender, PaintEventArgs e)
{
string text;
text = previewTextTextBox.Text;
if (!string.IsNullOrEmpty(text))
{
NativeMethods.TEXTMETRICW metrics;
Graphics g;
Font font;
Size size;
int x;
int y;
int w;
int h;
Rectangle bounds;
int ascent;
int descent;
int averageCharacterWidth;
int maxCharacterWidth;
int tableWidth;
g = e.Graphics;
font = fontDialog.Font;
metrics = this.GetTextMetrics(g, font);
size = TextRenderer.MeasureText(g, text, font, Size.Empty, _flags);
bounds = previewPanel.ClientRectangle;
// The average width of characters in the font (generally defined as the width of the letter x ).
// This value does not include the overhang required for bold or italic characters.
averageCharacterWidth = metrics.tmAveCharWidth;
// The width of the widest character in the font.
maxCharacterWidth = metrics.tmMaxCharWidth;
// The ascent (units above the base line) of characters.
ascent = metrics.tmAscent;
// The descent (units below the base line) of characters.
descent = metrics.tmDescent;
w = size.Width;
h = size.Height;
y = ((bounds.Height - h) >> 1) - _boxSize;
g.TextRenderingHint = TextRenderingHint.AntiAlias;
// draw any values which aren't part of the main diagram
tableWidth = this.DrawValues(g, metrics);
x = tableWidth + ((bounds.Width - (tableWidth + w)) >> 1);
// draw boxes which show the maximum and average character widths
using (Brush brush = new HatchBrush(HatchStyle.DiagonalCross, Color.Orange, SystemColors.Window))
{
int bx;
int by;
bx = (bounds.Width - (averageCharacterWidth + maxCharacterWidth + _boxSize)) >> 1;
by = y + h + _labelEdgeLength * 4;
g.FillRectangle(brush, bx, by, averageCharacterWidth, _boxSize);
g.DrawRectangle(Pens.Orange, bx, by, averageCharacterWidth, _boxSize);
this.DrawHorizontalLabel(g, Color.Orange, "Average Character Width", bx, by + _boxSize + _labelEdgeLength * 2, averageCharacterWidth);
bx += averageCharacterWidth + _boxSize;
g.FillRectangle(brush, bx, by, maxCharacterWidth, _boxSize);
g.DrawRectangle(Pens.Orange, bx, by, maxCharacterWidth, _boxSize);
this.DrawHorizontalLabel(g, Color.Orange, "Maximum Character Width", bx, by + _boxSize + _labelEdgeLength * 2, maxCharacterWidth);
}
// draw the text baseline
g.DrawLine(Pens.SeaGreen, x - _vaneLength, y + ascent, x + w + _labelEdgeLength, y + ascent);
// draw the preview text
TextRenderer.DrawText(g, text, font, new Point(x, y), previewPanel.ForeColor, _flags);
// labels
this.DrawVerticalLabel(g, Color.CornflowerBlue, "Ascent", x - _labelEdgeLength * 2, y, ascent);
this.DrawVerticalLabel(g, Color.CornflowerBlue, "Descent", x - _labelEdgeLength * 2, y + ascent, descent);
this.DrawVerticalLabel(g, Color.CornflowerBlue, "Height", x + w + _labelEdgeLength * 2, y, metrics.tmHeight);
this.DrawMiddleLabel(g, Color.SeaGreen, "Baseline", x + w + _labelEdgeLength * 3, y + ascent);
}
}
private void previewPanel_Resize(object sender, EventArgs e)
{
this.UpdatePreview();
}
private void previewTextTextBox_TextChanged(object sender, EventArgs e)
{
this.UpdatePreview();
}
private void SetFontTextBox()
{
Font font;
StringBuilder sb;
font = fontDialog.Font;
sb = new StringBuilder();
sb.Append(font.Name);
sb.Append(' ');
if ((font.Style & FontStyle.Bold) != 0)
{
sb.Append(' ');
sb.Append("Bold");
}
if ((font.Style & FontStyle.Italic) != 0)
{
sb.Append(' ');
sb.Append("Italic");
}
sb.Append(font.SizeInPoints);
sb.Append("pt");
fontTextBox.Text = sb.ToString();
}
private void UpdatePreview()
{
previewPanel.Invalidate();
}
#endregion
}
}
Donate
This software may be used free of charge, but as with all free software there are costs involved to develop and maintain.
If this site or its services have saved you time, please consider a donation to help with running costs and timely updates.
Donate