Finding the bounding rectangle of text with alignment - c#

I'm trying to draw a box around a label which has been aligned using StringAlignment.Far for example. I can find the Size of text using g.MeasureString but I can't find a method to translate the origin point such that I can find a Rectangle which bounds the text.
Say I have a Point origin at which to draw from, and a StringFormat format with what alignment I wish my string to have. I can find the Size of the string using g.MeasureString(text, font). How do I translate this Point/Size pair into a rectangle which overlaps the g.DrawString(text, font, brush, origin, format) call.

It's difficult to convert c to managed code. You should use .Net code directly if it's available.
For MeasureString, see link Graphics.MeasureString Method
Example:
using System.Diagnostics;
...
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics g = e.Graphics;
Font font = new Font("Arial", 16);
SizeF sz = g.MeasureString("Text...", font);
Rectangle rc = new Rectangle(0,0, (int)sz.Width, (int)sz.Height);
Debug.WriteLine(rc.Width.ToString());
Debug.WriteLine(rc.Height.ToString());
//change top/left origin of rectangle
rc.X = 10;
rc.Y = 20;
}
You just need the width and height of text. You can change left/top corner of rectangle.
By the way, the C method gives a rectangle with top/left coordinates at zero, so it's the same information as Size
Edit
This will fit text with word-break flag in to a rectangle whose width is 100. The height of the rectangle is not known. TextRenderer.MeasureText will tell us the height of the rectangle. Top/left corner can be changed, alignment can be changed.
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Font font = new Font("Arial", 10);
string text = "I'm trying to draw a box around a label which has been aligned.";
Size layout = new Size(100, 0);
Size sz = TextRenderer.MeasureText(e.Graphics, text, font, layout,
TextFormatFlags.WordBreak);
Rectangle rc = new Rectangle(new Point(0,0), sz);
e.Graphics.DrawRectangle(Pens.Black, rc);
TextRenderer.DrawText(e.Graphics, text, font, rc,
SystemColors.ControlText, SystemColors.Control, TextFormatFlags.WordBreak);
}

My way is use SetMeasurableCharacterRanges to obtain the region of the whole text.
Consider into OnPaint:
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
Font font = new Font("Arial", 16);
string text = "Border of this text";
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
RectangleF area = new RectangleF(0, 0, 246, 84);
sf.SetMeasurableCharacterRanges(new CharacterRange[] { new CharacterRange(0, text.Length) });
Region[] r = g.MeasureCharacterRanges(text, font, area, sf);
Rectangle rf = new Rectangle((int)r[0].GetBounds(g).X, (int)r[0].GetBounds(g).Y, (int)r[0].GetBounds(g).Width, (int)r[0].GetBounds(g).Height);
g.DrawString(text, font, Brushes.Black, area, sf);
g.DrawRectangle(new Pen(Color.Red, 1), rf);
}

Related

How to connect .DrawEllipse with .DrawString

I'm trying to write text inside circle (not centered by rectangle) alignment must be from line to line inside circle.
I have successfully drawn the circle and text. I did research on Stack Overflow and Google without success about putting text inside this circle.
private void Button1_Click(object sender, EventArgs e)
{
System.Drawing.Graphics graphicsObj;
graphicsObj = this.CreateGraphics();
// Create font and brush.
Font drawFont = new Font("Arial", 5);
SolidBrush drawBrush = new SolidBrush(Color.Black);
// Create point for upper-left corner of drawing.
float x = 150.0F;
float y = 50.0F;
// Set format of string.
StringFormat drawFormat = new StringFormat();
drawFormat.FormatFlags = StringFormatFlags.FitBlackBox;
graphicsObj.DrawEllipse(Pens.Red, 20, 20, 350, 350);
graphicsObj.DrawString(richTextBox1.Text.ToString(), drawFont, drawBrush, x, y, drawFormat);
}
Looking for advise, not for exact code..
-> How to establish connection for text alignment based on rectangle.
Expected output like in this image : https://imge.to/i/miFif
exactly same but I need in C# Win.Form -> Wrap text inside a circular div
DrawString has an overload with format options:
...
DrawString(e.Cache, text, rect,
new StringFormat() {
LineAlignment = StringAlignment.Center,
Alignment = StringAlignment.Center
});

How can I use DrawString clearly?

I need to draw a string with Graphics class with DrawString method. But image has some black pixels, not the exact color. How can I draw it clearly?
public Image Ciz()
{
Color renk = Color.FromArgb(255, 133, 199);
Bitmap result = new Bitmap(KutuBoyutu.Genislik, KutuBoyutu.Yukseklik);
result.SetResolution(100, 100);
Graphics g = Graphics.FromImage(result);
g.SmoothingMode = SmoothingMode.HighQuality;
Brush drawBrush = new SolidBrush(renk);
StringFormat stringFormat = new StringFormat();
stringFormat.Alignment = StringAlignment.Center;
stringFormat.LineAlignment = StringAlignment.Center;
Rectangle rect1 = new Rectangle(0, 0, result.Width, result.Height);
Font font = new Font("Arial", 15f, FontStyle.Bold, GraphicsUnit.Pixel);
g.DrawString(Yazi, font, drawBrush, rect1, stringFormat);
drawBrush.Dispose();
return result;
}
Drawing text requires a well-defined background so that the anti-aliasing effect can work properly. You don't have any, you forgot to initialize the bitmap. Which left its pixels at the default, black with an alpha of 0.
So the text renderer will try to alias the letter to blend into a black background. You see that, those almost-black pixels now become very visible against a white background. It will only look good if you draw the bitmap on top of a black background. Fix:
using (Graphics g = Graphics.FromImage(result)) {
g.Clear(Color.White);
// etc...
}
If you cannot fix the background color then you need to give up on anti-aliasing. Set the TextRenderingHint to SingleBitPerPixelGridFit. You won't like it much :)
Add
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
to your code.
TextRenderingHint.AntiAliasGridFit works as well.

Draw Gradient Label

Is it possible to apply a gradient to label text?
Right now I am taking over a controls OnPaint and drawing the string of text that I want; however, this is to specific. I really want to make it so that the label itself gets applied the gradient colors I want. So in turn each character would have the gradient specified as the text has changed.
So instead of using the ForeColor I would apply a LinearGradientBrush. I am using WinForms at the moment.
EDIT 1
Here is the code that I am currently using. However, this only applies the gradient to all of the characters. I would like to change it so that each character in the string is applied.
// Draw the formatted text string to the DrawingContext of the control.
Font font = new Font("BankGothic Md BT", 48f, FontStyle.Bold);
LinearGradientBrush brush = new LinearGradientBrush(label1.Location, new Point(label1.Width, label1.Height), Color.Goldenrod, Color.Black);
e.Graphics.DrawString(label1.Text, font, brush, 0,0);
Edit 2
Here is what I did. I just extended the Label class and inherited OnPaint.
public partial class LabelEx : Label {
public LabelEx() {
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs e) {
// Draw the formatted text string to the DrawingContext of the control.
//base.OnPaint(e);
Font font = new Font("Tahoma", 48f, FontStyle.Bold);
LinearGradientBrush brush = new LinearGradientBrush(new Rectangle(0, 0, Width, Height + 5), Color.Gold, Color.Black, LinearGradientMode.Vertical);
e.Graphics.DrawString(Text, font, brush, 0, 0);
}
}
Which gives me a nice gradient text label.
Thanks!
Here is what I did. I just extended the Label class and inherited OnPaint.
public partial class LabelEx : Label {
public LabelEx() {
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs e) {
// Draw the formatted text string to the DrawingContext of the control.
//base.OnPaint(e);
Font font = new Font("Tahoma", 48f, FontStyle.Bold);
LinearGradientBrush brush = new LinearGradientBrush(new Rectangle(0, 0, Width, Height + 5), Color.Gold, Color.Black, LinearGradientMode.Vertical);
e.Graphics.DrawString(Text, font, brush, 0, 0);
}
}

How to determine width of a string when printed?

I'm creating a custom control, part of which is using the Graphics class to draw text to the form. Currently I'm using the following code to display it:
private float _lineHeight { get { return this.Font.Size + 5; } }
private void Control_Paint(object sender, PaintEventArgs e)
{
Graphics g = this.CreateGraphics();
Brush b = new SolidBrush(Colors[7]);
g.DrawString("Hello World!", this.Font, b, 0, 2);
g.DrawString("This has been a test of the emergency drawing system!",
this.Font, b, 0, 2 + _lineHeight);
}
I'm currently using fixedwidth fonts, and I'd like to know how wide the font will display, but there doesn't appear to be any properties for this sort of information. Is there some way of obtaining it? I want it so I can wrap lines properly when displayed.
Yes, you can use MeasureString from the Graphics class
This method returns a SizeF structure that represents
the size, in the units specified by
the PageUnit property, of the string
specified by the text parameter as
drawn with the font parameter.
private void MeasureStringMin(PaintEventArgs e)
{
// Set up string.
string measureString = "Measure String";
Font stringFont = new Font("Arial", 16);
// Measure string.
SizeF stringSize = new SizeF();
stringSize = e.Graphics.MeasureString(measureString, stringFont);
// Draw rectangle representing size of string.
e.Graphics.DrawRectangle(new Pen(Color.Red, 1), 0.0F, 0.0F, stringSize.Width, stringSize.Height);
// Draw string to screen.
e.Graphics.DrawString(measureString, stringFont, Brushes.Black, new PointF(0, 0));
}

Center text output from Graphics.DrawString()

I'm using the .NETCF (Windows Mobile) Graphics class and the DrawString() method to render a single character to the screen.
The problem is that I can't seem to get it centred properly. No matter what I set for the Y coordinate of the location of the string render, it always comes out lower than that and the larger the text size the greater the Y offset.
For example, at text size 12, the offset is about 4, but at 32 the offset is about 10.
I want the character to vertically take up most of the rectangle it's being drawn in and be centred horizontally. Here's my basic code. this is referencing the user control it's being drawn in.
Graphics g = this.CreateGraphics();
float padx = ((float)this.Size.Width) * (0.05F);
float pady = ((float)this.Size.Height) * (0.05F);
float width = ((float)this.Size.Width) - 2 * padx;
float height = ((float)this.Size.Height) - 2 * pady;
float emSize = height;
g.DrawString(letter, new Font(FontFamily.GenericSansSerif, emSize, FontStyle.Regular),
new SolidBrush(Color.Black), padx, pady);
Yes, I know there is the label control that I could use instead and set the centring with that, but I actually do need to do this manually with the Graphics class.
I'd like to add another vote for the StringFormat object.
You can use this simply to specify "center, center" and the text will be drawn centrally in the rectangle or points provided:
StringFormat format = new StringFormat();
format.LineAlignment = StringAlignment.Center;
format.Alignment = StringAlignment.Center;
However there is one issue with this in CF. If you use Center for both values then it turns TextWrapping off. No idea why this happens, it appears to be a bug with the CF.
To align a text use the following:
StringFormat sf = new StringFormat();
sf.LineAlignment = StringAlignment.Center;
sf.Alignment = StringAlignment.Center;
e.Graphics.DrawString("My String", this.Font, Brushes.Black, ClientRectangle, sf);
Please note that the text here is aligned in the given bounds. In this sample this is the ClientRectangle.
Through a combination of the suggestions I got, I came up with this:
private void DrawLetter()
{
Graphics g = this.CreateGraphics();
float width = ((float)this.ClientRectangle.Width);
float height = ((float)this.ClientRectangle.Width);
float emSize = height;
Font font = new Font(FontFamily.GenericSansSerif, emSize, FontStyle.Regular);
font = FindBestFitFont(g, letter.ToString(), font, this.ClientRectangle.Size);
SizeF size = g.MeasureString(letter.ToString(), font);
g.DrawString(letter, font, new SolidBrush(Color.Black), (width-size.Width)/2, 0);
}
private Font FindBestFitFont(Graphics g, String text, Font font, Size proposedSize)
{
// Compute actual size, shrink if needed
while (true)
{
SizeF size = g.MeasureString(text, font);
// It fits, back out
if (size.Height <= proposedSize.Height &&
size.Width <= proposedSize.Width) { return font; }
// Try a smaller font (90% of old size)
Font oldFont = font;
font = new Font(font.Name, (float)(font.Size * .9), font.Style);
oldFont.Dispose();
}
}
So far, this works flawlessly.
The only thing I would change is to move the FindBestFitFont() call to the OnResize() event so that I'm not calling it every time I draw a letter. It only needs to be called when the control size changes. I just included it in the function for completeness.
To draw a centered text:
TextRenderer.DrawText(g, "my text", Font, Bounds, ForeColor, BackColor,
TextFormatFlags.HorizontalCenter |
TextFormatFlags.VerticalCenter |
TextFormatFlags.GlyphOverhangPadding);
Determining optimal font size to fill an area is a bit more difficult. One working soultion I found is trial-and-error: start with a big font, then repeatedly measure the string and shrink the font until it fits.
Font FindBestFitFont(Graphics g, String text, Font font,
Size proposedSize, TextFormatFlags flags)
{
// Compute actual size, shrink if needed
while (true)
{
Size size = TextRenderer.MeasureText(g, text, font, proposedSize, flags);
// It fits, back out
if ( size.Height <= proposedSize.Height &&
size.Width <= proposedSize.Width) { return font; }
// Try a smaller font (90% of old size)
Font oldFont = font;
font = new Font(font.FontFamily, (float)(font.Size * .9));
oldFont.Dispose();
}
}
You'd use this as:
Font bestFitFont = FindBestFitFont(g, text, someBigFont, sizeToFitIn, flags);
// Then do your drawing using the bestFitFont
// Don't forget to dispose the font (if/when needed)
Here's some code. This assumes you are doing this on a form, or a UserControl.
Graphics g = this.CreateGraphics();
SizeF size = g.MeasureString("string to measure");
int nLeft = Convert.ToInt32((this.ClientRectangle.Width / 2) - (size.Width / 2));
int nTop = Convert.ToInt32((this.ClientRectangle.Height / 2) - (size.Height / 2));
From your post, it sounds like the ClientRectangle part (as in, you're not using it) is what's giving you difficulty.
You can use an instance of the StringFormat object passed into the DrawString method to center the text.
See Graphics.DrawString Method and StringFormat Class.

Categories