It provide as Graphics extension methods.
with similar syntax as normal MeasureString and DrawString.
public static RectangleF[] MeasureString(this Graphics graphics, string s, Font font, Brush brush, TextPathAlign textPathAlign, TextPathPosition textPathPosition, int letterSpace,float rotateDegree, GraphicsPath graphicsPath);
public static void DrawString(this Graphics graphics, string s, Font font, Brush brush, TextPathAlign textPathAlign, TextPathPosition textPathPosition, int letterSpace,float rotateDegree, GraphicsPath graphicsPath)
sample code
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;<br />
Point[] myArray =<br />
{<br />
new Point(20, 100),<br />
new Point(40, 75),<br />
new Point(60, 125),<br />
new Point(80, 100),<br />
new Point(100, 50),<br />
new Point(120, 150),<br />
new Point(400, 400)<br />
};<br />
<br />
GraphicsPath myPath = new GraphicsPath();<br />
myPath.AddBeziers(myArray);<br />
<br />
Pen myPen = new Pen(Color.Black, 5);<br />
e.Graphics.DrawPath(myPen, myPath);<br />
<br />
System.Drawing.RectangleF[] regions = e.Graphics.MeasureString("Text on Path", new Font(FontFamily.GenericSerif, 24), new SolidBrush(Color.Red), TextPathAlign.Center, TextPathPosition.CenterPath, 100, 0, myPath);<br />
foreach (var region in regions)<br />
{<br />
e.Graphics.FillRectangle(new SolidBrush(Color.GreenYellow), region);<br />
}<br />
e.Graphics.DrawString("Text on Path", new Font(FontFamily.GenericSerif, 24), new SolidBrush(Color.Red), TextPathAlign.Center, TextPathPosition.CenterPath, 100, 0, myPath);<br />
<br />
GraphicsExtenstion class
using System;<br />
using System.Collections.Generic;<br />
using System.Drawing;<br />
using System.Drawing.Drawing2D;<br />
using System.Drawing.Text;<br />
<br />
namespace WindowsFormsApplication6<br />
{<br />
<br />
public enum TextPathAlign<br />
{<br />
Left = 0,<br />
Center = 1,<br />
Right = 2<br />
}<br />
<br />
public enum TextPathPosition<br />
{<br />
OverPath = 0,<br />
CenterPath = 1,<br />
UnderPath = 2<br />
}<br />
<br />
public static class GraphicsExtension<br />
{<br />
private static readonly TextOnPath TEXT_ON_PATH = new TextOnPath();<br />
<br />
public static RectangleF[] MeasureString(this Graphics graphics, string s, Font font, Brush brush, GraphicsPath graphicsPath)<br />
{<br />
return MeasureString(graphics, s, font, brush, TextPathAlign.Left, TextPathPosition.CenterPath, 100, graphicsPath);<br />
}<br />
<br />
public static RectangleF[] MeasureString(this Graphics graphics, string s, Font font, Brush brush, TextPathAlign textPathAlign, TextPathPosition textPathPosition, GraphicsPath graphicsPath)<br />
{<br />
return MeasureString(graphics, s, font, brush, textPathAlign, textPathPosition, 100, graphicsPath);<br />
}<br />
<br />
public static void DrawString(this Graphics graphics, string s, Font font, Brush brush, GraphicsPath graphicsPath)<br />
{<br />
DrawString(graphics, s, font, brush, TextPathAlign.Left, TextPathPosition.CenterPath, 100, graphicsPath);<br />
}<br />
<br />
public static void DrawString(this Graphics graphics, string s, Font font, Brush brush, TextPathAlign textPathAlign, TextPathPosition textPathPosition, GraphicsPath graphicsPath)<br />
{<br />
DrawString(graphics, s, font, brush, textPathAlign, textPathPosition, 100, graphicsPath);<br />
}<br />
<br />
public static RectangleF[] MeasureString(this Graphics graphics, string s, Font font, Brush brush, TextPathAlign textPathAlign, TextPathPosition textPathPosition, int letterSpace, GraphicsPath graphicsPath)<br />
{<br />
return MeasureString(graphics, s, font, brush, textPathAlign, textPathPosition, 100, 0,graphicsPath);<br />
}<br />
<br />
public static void DrawString(this Graphics graphics, string s, Font font, Brush brush, TextPathAlign textPathAlign, TextPathPosition textPathPosition, int letterSpace, GraphicsPath graphicsPath)<br />
{<br />
DrawString(graphics, s, font, brush, textPathAlign, textPathPosition, 100,0, graphicsPath);<br />
}<br />
<br />
public static RectangleF[] MeasureString(this Graphics graphics, string s, Font font, Brush brush, TextPathAlign textPathAlign, TextPathPosition textPathPosition, int letterSpace,float rotateDegree, GraphicsPath graphicsPath)<br />
{<br />
TEXT_ON_PATH.Text = s;<br />
TEXT_ON_PATH.Font = font;<br />
TEXT_ON_PATH.FillColorTop = brush;<br />
TEXT_ON_PATH.TextPathPathPosition = textPathPosition;<br />
TEXT_ON_PATH.TextPathAlignTop = textPathAlign;<br />
TEXT_ON_PATH.PathDataTop = graphicsPath.PathData;<br />
TEXT_ON_PATH.LetterSpacePercentage = letterSpace;<br />
TEXT_ON_PATH._graphics = graphics;<br />
TEXT_ON_PATH._graphicsPath = graphicsPath;<br />
TEXT_ON_PATH._measureString = true;<br />
TEXT_ON_PATH._rotateDegree = rotateDegree;<br />
TEXT_ON_PATH.DrawTextOnPath();<br />
return TEXT_ON_PATH._regionList.ToArray();<br />
}<br />
<br />
public static void DrawString(this Graphics graphics, string s, Font font, Brush brush, TextPathAlign textPathAlign, TextPathPosition textPathPosition, int letterSpace,float rotateDegree, GraphicsPath graphicsPath)<br />
{<br />
TEXT_ON_PATH.Text = s;<br />
TEXT_ON_PATH.Font = font;<br />
TEXT_ON_PATH.FillColorTop = brush;<br />
TEXT_ON_PATH.TextPathPathPosition = textPathPosition;<br />
TEXT_ON_PATH.TextPathAlignTop = textPathAlign;<br />
TEXT_ON_PATH.PathDataTop = graphicsPath.PathData;<br />
TEXT_ON_PATH.LetterSpacePercentage = letterSpace;<br />
TEXT_ON_PATH._graphics = graphics;<br />
TEXT_ON_PATH._graphicsPath = graphicsPath;<br />
TEXT_ON_PATH._measureString = false;<br />
TEXT_ON_PATH._rotateDegree = rotateDegree;<br />
TEXT_ON_PATH.DrawTextOnPath();<br />
<br />
}<br />
<br />
}<br />
<br />
<br />
internal class TextOnPath<br />
{<br />
private PathData _pathdata;<br />
private string _text;<br />
private Font _font;<br />
private Color _color = Color.Black;<br />
private Brush _fillBrush = new SolidBrush(Color.Black);<br />
private TextPathAlign _pathalign = TextPathAlign.Center;<br />
private int _letterspacepercentage = 100;<br />
private TextPathPosition _textPathPathPosition = TextPathPosition.CenterPath;<br />
public Exception LastError;<br />
internal Graphics _graphics;<br />
internal GraphicsPath _graphicsPath;<br />
internal bool _measureString;<br />
internal List<RectangleF> _regionList = new List<RectangleF>();<br />
internal float _rotateDegree;<br />
public TextPathPosition TextPathPathPosition<br />
{<br />
get { return _textPathPathPosition; }<br />
set { _textPathPathPosition = value; }<br />
}<br />
public PathData PathDataTop<br />
{<br />
get { return _pathdata; }<br />
set { _pathdata = value; }<br />
}<br />
<br />
public string Text<br />
{<br />
get { return _text; }<br />
set { _text = value; }<br />
}<br />
<br />
public Font Font<br />
{<br />
get { return _font; }<br />
set { _font = value; }<br />
}<br />
<br />
public Color Color<br />
{<br />
get { return _color; }<br />
set { _color = value; }<br />
}<br />
<br />
public Brush FillColorTop<br />
{<br />
get { return _fillBrush; }<br />
set { _fillBrush = value; }<br />
}<br />
<br />
public TextPathAlign TextPathAlignTop<br />
{<br />
get { return _pathalign; }<br />
set { _pathalign = value; }<br />
}<br />
<br />
public int LetterSpacePercentage<br />
{<br />
get { return _letterspacepercentage; }<br />
set { _letterspacepercentage = value; }<br />
}<br />
public void DrawTextOnPath(PathData pathdata, string text, Font font, Color color, Brush fillcolor, int letterspacepercentage)<br />
{<br />
<br />
_pathdata = pathdata;<br />
_text = text;<br />
_font = font;<br />
_color = color;<br />
_fillBrush = fillcolor;<br />
_letterspacepercentage = letterspacepercentage;<br />
<br />
DrawTextOnPath();<br />
}<br />
<br />
<br />
public void DrawTextOnPath()<br />
{<br />
PointF[] tmpPoints;<br />
PointF[] points = new PointF[25001];<br />
int count = 0;<br />
GraphicsPath gp = new GraphicsPath(_pathdata.Points, _pathdata.Types) { FillMode = FillMode.Winding };<br />
_regionList.Clear();<br />
gp.Flatten(null, 1);<br />
try<br />
{<br />
PointF tmpPoint = gp.PathPoints[0];<br />
int i;<br />
for (i = 0; i <= gp.PathPoints.Length - 2; i++)<br />
{<br />
if (gp.PathTypes[i + 1] == (byte)PathPointType.Start | (gp.PathTypes[i] & (byte)PathPointType.CloseSubpath) == (byte)PathPointType.CloseSubpath)<br />
{<br />
tmpPoints = GetLinePoints(gp.PathPoints[i], tmpPoint, 1);<br />
Array.ConstrainedCopy(tmpPoints, 0, points, count, tmpPoints.Length);<br />
count += 1;<br />
tmpPoint = gp.PathPoints[i + 1];<br />
}<br />
else<br />
{<br />
tmpPoints = GetLinePoints(gp.PathPoints[i], gp.PathPoints[i + 1], 1);<br />
Array.ConstrainedCopy(tmpPoints, 0, points, count, tmpPoints.Length);<br />
count += tmpPoints.Length - 1;<br />
<br />
}<br />
}<br />
tmpPoints = new PointF[count];<br />
Array.Copy(points, tmpPoints, count);<br />
points = CleanPoints(tmpPoints);<br />
<br />
count = points.Length - 1;<br />
DrawText(points, count);<br />
}<br />
catch (Exception ex)<br />
{<br />
LastError = ex;<br />
<br />
<br />
}<br />
}<br />
private static PointF[] CleanPoints(PointF[] points)<br />
{<br />
<br />
int i;<br />
PointF[] tmppoints = new PointF[points.Length + 1];<br />
PointF lastpoint = default(PointF);<br />
int count = 0;<br />
<br />
for (i = 0; i <= points.Length - 1; i++)<br />
{<br />
if (i == 0 | points[i].X != lastpoint.X | points[i].Y != lastpoint.Y)<br />
{<br />
tmppoints[count] = points[i];<br />
count += 1;<br />
}<br />
lastpoint = points[i];<br />
}<br />
<br />
<br />
points = new PointF[count];<br />
Array.Copy(tmppoints, points, count);<br />
<br />
return points;<br />
}<br />
<br />
private void DrawText(PointF[] points, int maxPoints)<br />
{<br />
<br />
GraphicsPath gp = new GraphicsPath(_pathdata.Points, _pathdata.Types) { FillMode = FillMode.Winding };<br />
gp.Flatten();<br />
gp.Dispose();<br />
Graphics g = _graphics;<br />
int count = 0;<br />
PointF point1 = default(PointF);<br />
int charStep = 0;<br />
double maxWidthText = default(double);<br />
int i;<br />
<br />
for (i = 0; i <= _text.Length - 1; i++)<br />
{<br />
maxWidthText += StringRegion(g, i);<br />
}<br />
<br />
switch (_pathalign)<br />
{<br />
case TextPathAlign.Left:<br />
point1 = points[0];<br />
count = 0;<br />
break;<br />
case TextPathAlign.Center:<br />
count = (int)((maxPoints - maxWidthText) / 2);<br />
if (count > 0)<br />
{<br />
point1 = points[count];<br />
}<br />
else<br />
{<br />
point1 = points[0];<br />
}<br />
<br />
break;<br />
case TextPathAlign.Right:<br />
count = (int)(maxPoints - maxWidthText - (double)StringRegion(g, _text.Length - 1) * LetterSpacePercentage / 100);<br />
if (count > 0)<br />
{<br />
point1 = points[count];<br />
}<br />
else<br />
{<br />
point1 = points[0];<br />
}<br />
<br />
break;<br />
}<br />
<br />
while (!(charStep > _text.Length - 1))<br />
{<br />
int lStrWidth = (int)(StringRegion(g, charStep) * LetterSpacePercentage / 100);<br />
if ((count + lStrWidth / 2) >= 0 & (count + lStrWidth) < maxPoints)<br />
{<br />
count += lStrWidth;<br />
PointF point2 = points[count];<br />
PointF point = points[count - lStrWidth / 2];<br />
double angle = GetAngle(point1, point2);<br />
DrawRotatedText(g, _text[charStep].ToString(), (float)angle, point);<br />
point1 = points[count];<br />
}<br />
else<br />
{<br />
count += lStrWidth;<br />
}<br />
charStep += 1;<br />
}<br />
<br />
}<br />
<br />
private RectangleF StringRegionValue(Graphics g, int textpos)<br />
{<br />
<br />
string measureString = _text.Substring(textpos, 1);<br />
int numChars = measureString.Length;<br />
CharacterRange[] characterRanges = new CharacterRange[numChars + 1];<br />
StringFormat stringFormat = new StringFormat<br />
{<br />
Trimming = StringTrimming.None,<br />
FormatFlags =<br />
StringFormatFlags.NoClip | StringFormatFlags.NoWrap |<br />
StringFormatFlags.LineLimit<br />
};<br />
SizeF size = g.MeasureString(_text, _font, 100);<br />
RectangleF layoutRect = new RectangleF(0f, 0f, size.Width, size.Height);<br />
characterRanges[0] = new CharacterRange(0, 1);<br />
stringFormat.FormatFlags = StringFormatFlags.NoClip;<br />
stringFormat.SetMeasurableCharacterRanges(characterRanges);<br />
stringFormat.Alignment = StringAlignment.Near;<br />
Region[] stringRegions = g.MeasureCharacterRanges(_text.Substring(textpos), _font, layoutRect, stringFormat);<br />
return stringRegions[0].GetBounds(g);<br />
}<br />
<br />
private float StringRegion(Graphics g, int textpos)<br />
{<br />
return StringRegionValue(g,textpos).Width;<br />
}<br />
<br />
private static double GetAngle(PointF point1, PointF point2)<br />
{<br />
double c = Math.Sqrt(Math.Pow((point2.X - point1.X), 2) + Math.Pow((point2.Y - point1.Y), 2));<br />
if (c == 0)<br />
{<br />
return 0;<br />
}<br />
if (point1.X > point2.X)<br />
{<br />
return Math.Asin((point1.Y - point2.Y) / c) * 180 / Math.PI - 180;<br />
}<br />
return Math.Asin((point2.Y - point1.Y) / c) * 180 / Math.PI;<br />
<br />
<br />
}<br />
private void DrawRotatedText(Graphics gr, string text, float angle, PointF pointCenter)<br />
{<br />
angle -= _rotateDegree;<br />
StringFormat stringFormat = new StringFormat { Alignment = StringAlignment.Center };<br />
<br />
gr.SmoothingMode = SmoothingMode.HighQuality;<br />
gr.CompositingQuality = CompositingQuality.HighQuality;<br />
gr.TextRenderingHint = TextRenderingHint.AntiAlias;<br />
GraphicsPath graphicsPath = new GraphicsPath(FillMode.Winding);<br />
int x = (int)pointCenter.X;<br />
int y = (int)pointCenter.Y;<br />
<br />
switch (TextPathPathPosition)<br />
{<br />
case TextPathPosition.OverPath:<br />
graphicsPath.AddString(text, _font.FontFamily, (int)_font.Style, _font.Size, new Point(x, (int)(y - _font.Size)), stringFormat);<br />
break;<br />
case TextPathPosition.CenterPath:<br />
graphicsPath.AddString(text, _font.FontFamily, (int)_font.Style, _font.Size, new Point(x, (int)(y - _font.Size / 2)), stringFormat);<br />
break;<br />
case TextPathPosition.UnderPath:<br />
graphicsPath.AddString(text, _font.FontFamily, (int)_font.Style, _font.Size, new Point(x, y), stringFormat);<br />
break;<br />
}<br />
<br />
<br />
Matrix rotationMatrix = new Matrix();<br />
rotationMatrix.RotateAt(angle, new PointF(x, y));<br />
graphicsPath.Transform(rotationMatrix);<br />
if (!_measureString)<br />
{<br />
gr.DrawPath(new Pen(_color), graphicsPath);<br />
gr.FillPath(_fillBrush, graphicsPath);<br />
}else<br />
{<br />
_regionList.Add(graphicsPath.GetBounds());<br />
}<br />
<br />
graphicsPath.Dispose();<br />
}<br />
<br />
<br />
<br />
public PointF[] GetLinePoints(PointF p1, PointF p2, int stepWitdth)<br />
{<br />
<br />
int lCount = 0;<br />
PointF[] tmpPoints = new PointF[10001];<br />
long ix;<br />
long iy;<br />
int dd;<br />
int id;<br />
int lStep = stepWitdth;<br />
<br />
p1.X = (int)p1.X;<br />
p1.Y = (int)p1.Y;<br />
p2.X = (int)p2.X;<br />
p2.Y = (int)p2.Y;<br />
long width = (long)(p2.X - p1.X);<br />
long height = (long)(p2.Y - p1.Y);<br />
long d = 0;<br />
<br />
if (width < 0)<br />
{<br />
width = -width;<br />
ix = -1;<br />
}<br />
else<br />
{<br />
ix = 1;<br />
}<br />
<br />
if (height < 0)<br />
{<br />
height = -height;<br />
iy = -1;<br />
}<br />
else<br />
{<br />
iy = 1;<br />
}<br />
<br />
if (width > height)<br />
{<br />
dd = (int)(width + width);<br />
id = (int)(height + height);<br />
<br />
do<br />
{<br />
if (lStep == stepWitdth)<br />
{<br />
tmpPoints[lCount].X = p1.X;<br />
tmpPoints[lCount].Y = p1.Y;<br />
lCount += 1;<br />
}<br />
else<br />
{<br />
lStep = lStep + stepWitdth;<br />
}<br />
if ((int)p1.X == (int)p2.X) break; <br />
<br />
p1.X = p1.X + ix;<br />
d = d + id;<br />
<br />
if (d > width)<br />
{<br />
p1.Y = p1.Y + iy;<br />
d = d - dd;<br />
}<br />
}<br />
<br />
while (true);<br />
}<br />
else<br />
{<br />
dd = (int)(height + height);<br />
id = (int)(width + width);<br />
<br />
do<br />
{<br />
if (lStep == stepWitdth)<br />
{<br />
tmpPoints[lCount].X = p1.X;<br />
tmpPoints[lCount].Y = p1.Y;<br />
lCount += 1;<br />
}<br />
else<br />
{<br />
lStep = lStep + stepWitdth;<br />
}<br />
if ((int)p1.Y == (int)p2.Y) break; <br />
<br />
p1.Y = p1.Y + iy;<br />
d = d + id;<br />
<br />
if (d > height)<br />
{<br />
p1.X = p1.X + ix;<br />
d = d - dd;<br />
}<br />
}<br />
while (true);<br />
}<br />
<br />
PointF[] tmpPoints2 = new PointF[lCount];<br />
<br />
Array.Copy(tmpPoints, tmpPoints2, lCount);<br />
<br />
return tmpPoints2;<br />
}<br />
<br />
}<br />
}<br />
|