Your strings overlap because you have one drawing area (rectangles[0]) and all strings are drawn in this area, without any further indication in relation to their position.
Since StringFormat.LineAlignment is set to StringAlignment.Center, all Text is drawn in the center of the area defined by rectangles[0].
To center a series of strings inside a drawing area, you can imagine your sequence of strings, plus the space that divides them, as a Rectangle.
To center this Rectangle (Drawing Area) inside a Container object, you can define the relation between this parts as:
Drawing Area Height = (Text Height * Number of Strings) + (Interline * (Number of Strings - 1))
Blank Area Height = (Container Height - Drawing Area Height)
The centered position of the imaginary Drawing Area inside its Container is then:
Container Top + (Blank Area Height / 2)
Now we know where to start to draw our Text lines. All other string positions are relative to the already calculated Drawing Area (since they are all part of this measure).
This way, you don't need to manually position the strings inside a Container.
To define the different strings and their related properties (Text, Font, Font Style, Text Height, Text Color) I have used a class object, DrawingString.
The Text lines are separated by an interline.
You can modify this value and specify a different line spacing:
float interline = 12.0f;
The Text position inside the Container rectangle (rectangles[0]) is calculated automatically.
Thus, you can add more strings to the list and they'll be positioned accordingly.
DrawingString class:
internal class DrawingString
{
public DrawingString() { }
public DrawingString(string text, string fontName, FontStyle style, float fontSize, Brush brush)
{
Text = text;
FontName = fontName;
FontStyle = style;
FontSize = fontSize;
Brush = brush;
}
public string Text { get; set; }
public string FontName { get; set; }
public FontStyle FontStyle { get; set; }
public float FontSize { get; set; }
public Brush Brush { get; set; }
}
List<DrawingString> drawingStrings = new List<DrawingString>() {
new DrawingString("A Graphics", "Arial", FontStyle.Regular, 20f, Brushes.LightGreen),
new DrawingString("String Drawing", "Segoe UI", FontStyle.Regular, 17f, Brushes.Orange),
new DrawingString("Example", "Calibri", FontStyle.Regular, 22f, Brushes.SteelBlue),
new DrawingString("One more Line", "Microsoft Sans Serif", FontStyle.Regular, 17f, Brushes.MediumPurple)
};
List<RectangleF> rectangles = new List<RectangleF>() {
new RectangleF(5.8188976377953F, 5.48031496062993F, 170.59055118110234F, 170.6456692913386F)
};
You can now choose a canvas to draw these strings to. It could be the surface of a Control or an Image.
If it's a Control, use the Graphics object provided by the Paint event handler to draw the strings, otherwise, derive a Graphics object from the Bitmap, using the Graphics.FromImage() method.
If the same StringFormat is used to draw all strings and/or if it needs to be redefined by the User or the application, declare a StringFormat object as a Field and modify it as required (it could also be part of the DrawingString class):
StringFormat format = new StringFormat() {
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center,
FormatFlags = StringFormatFlags.NoClip,
Trimming = StringTrimming.EllipsisWord
};
Assuming these string are drawn on the surface of, e.g., a PictureBox Control, hence using the PaintEventArgs of its Paint event handler:
private void somePictureBox_Paint(object sender, PaintEventArgs e)
{
e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
float interline = 12.0f;
float textHeigh = drawingStrings.Select(ds => ds.FontSize + interline).Sum() - interline;
float textPosition = (rectangles[0].Height - textHeigh + interline) / 2;
foreach (var item in drawingStrings) {
rectangles.Add(new RectangleF(
new PointF(rectangles[0].X, textPosition),
new SizeF(rectangles[0].Width, item.FontSize)));
textPosition += item.FontSize + interline;
}
// Uncomment to draw the bounding Rectangles border
// e.Graphics.DrawRectangles(Pens.White, rectangles.ToArray());
int rectArea = 0;
foreach (var item in drawingStrings) {
rectArea += 1;
using (Font font = new Font(item.FontName, item.FontSize, item.FontStyle, GraphicsUnit.Pixel)) {
e.Graphics.DrawString(item.Text, font, item.Brush, rectangles[rectArea], format);
}
}
}
This is the result with the List<DrawingString> you see in the code and what happens if you add another line of Text:

If you uncomment this line: e.Graphics.DrawRectangles(Pens.White, rectangles.ToArray());,
you can see how the rectangles are sized with different interline values:

Interline 12.0F Interline 16.0F