Drawing a Rectangular Border around a Text Drawn by GraphicsPath - c#

I'm using the GraphicPath.Addstring method to add a string to the graphic path and Graphics.drawpath to draw the string. I want to calculate the width and height of the text drawn so that I can draw a rectangle around the drawn text. I have tried using Graphics.MeasureString and TextRenderer.MeasureText to calculate the width and Graphicpath.addrectangle and Graphics.Drawpath to draw the rectangle, but I'm not able to get the correct dimensions with different fonts.
Please help me solve this.

Add your string to the path then call
GraphicsPath.GetBounds();
to determine the region. This will need to be inflated depending on the pen size used to render the string.

Maybe look into Graphics.MeasureCharacterRanges

hope this example helps you
var gp = new GraphicsPath();
var g = baseControl.CreateGraphics();
var textSize = g.MeasureString(text, basefont);
gp.AddRectangle(new Rectangle(new Point(0, 0), textSize);
gp.AddString("Your String", basefont.FontFamily, basefont.Style, basefont.Size - 0.25f);

Little correction :
gp.AddRectangle(new Rectangle(new Point(0, 0), textSize.ToSize());

Related

C# Winforms. Drawing text accurately centrally within a rectangle

What I'm attempting to do is draw a number inside a circle so that it's positioned centrally both vertically and horizontally. I'm drawing both the circle and text string using the same rectangle structure and using center for both horizontal and vertical alignments. But, as you can see from the image where I drew a horizontal line across the white circle, the text is aligning its base line centrally and my eye says it's horizontally aligning slightly to the left.
I've tried fudging by adding string.height/2 to the top of the rectangle to shift it down 1/2 its height but it's still not correct. (I adjust the font size so the number will fit within the box according to the number of digits in the counter)
How can I do this properly please?
var rect = new Rectangle(bmpWidth - maxCircleDiameter, bmpHeight - maxCircleDiameter, maxCircleDiameter, maxCircleDiameter);
g.FillEllipse(Brushes.White, rect);
using (var format = NewClassFactory.GetFormat(StringAlignment.Center, StringAlignment.Center, StringTrimming.Character))
g.DrawString(toDisplay, newFont, Brushes.Black, rect, format);
You can use TextRenderer.DrawText to draw a text in a rectangle bound, using a color and font and specifying different text format flag:
var rect = new Rectangle(10, 10, 32, 32);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.FillEllipse(Brushes.White, rect);
TextRenderer.DrawText(e.Graphics, "100", this.Font, rect, Color.Black,
TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter);

Converting the path of a Rectangle into a GraphicPath/Region

I am learning about GraphicsPath and Region. And using it with Invalidate.
So, I have a Rectangle object and I want to erase this rectangle. But, I only want to erase the edge of the rectangle (that is, the lines).
At the moment I have this:
if(bErase)
{
Rectangle rcRubberBand = GetSelectionRectangle();
GraphicsPath path = new GraphicsPath();
path.AddRectangle(rcLastRubberBand);
Region reg = new Region(path);
myControl3.Invalidate(reg);
myControl3.Update();
}
It works, but it is invalidating the complete rectangle shape. I only need to invalidate the rectangle lines that I had drawn. Can I make such a path with GraphicsPath?
You can't get the system to invalidate anything but a full rectangle.
So you can't use an outline path to save time.
However it can be useful for other things. Let's look at two options :
You can create an outline path
You can exclude parts of a region
The simplest way to create an outline GraphicsPath is to widen a given path with a Pen:
GraphicsPath gp = new GraphicsPath();
gp.AddRectangle(r0);
using (Pen pen = new Pen(Color.Green, 3f)) gp.Widen(pen);
This let's you make use of all the many options of a Pen, including DashStyles, Alignment, LineJoins etc..
An alternative way is to create it with the default FillMode.Alternate and simply add a smaller figure:
Rectangle r0 = new Rectangle(11, 11, 333, 333);
Rectangle r1 = r0;
r1.Inflate(-6, -6);
GraphicsPath gp = new GraphicsPath();
gp.AddRectangle(r0);
gp.AddRectangle(r1);
Now you can fill the path
g.FillPath(Brushes.Red, gp);
or use it to clip the ClipBounds of a Graphics object g :
g.SetClip(gp);
After this anything you draw including a Clear will only affect the pixels inside the outline.
When you are done you can write:
g.ResetClip();
and continue drawing on the full size of your graphics target.
Or you can use the path as the basis for a Region:
Region r = new Region(gp);
and restrict a Control to it..:
somecontrol.Region = r;
Regions support several set operations so instead of using the above outline path you could also write this with the same result:
Region r = new Region(r0);
r.Exclude(r1);

Adding antialiasing

I am trying to using antialiasing but I don't why it isn't working:
{
Pen pen = new Pen(Color.Black, 3);
Pen r = new Pen(Color.YellowGreen, 3);
Graphics b = panel2.CreateGraphics();
b.DrawEllipse(pen, 6, 0, 90, 90);
b.SmoothingMode = SmoothingMode.AntiAlias;
b.DrawLine(r, new Point(50, 90), new Point(50, 0));
}
First it should be noted that the Graphics object does not contain any graphics; it is a tool that lets you draw onto a related bitmap, including a control's surface. Therefore changing any of its properties, like the SmoothingMode only influences graphics you draw from then on, not anything you have drawn before..
The circle certainly would have antialised pixels if you would draw it after setting the SmoothingMode from its default None to AntiAlias.
The Line is vertical, so it doesn't need antialiasing except at its ends, where there is some. But if you tilt it or move it to a non-integer position anti-aliasing will show!
Let's modify your code a little and look closely at the result:
Pen pen = new Pen(Color.Black, 3);
Pen r = new Pen(Color.YellowGreen, 3);
Graphics b = panel2.CreateGraphics();
b.DrawEllipse(pen, 6, 6, 90, 90);
b.SmoothingMode = SmoothingMode.AntiAlias;
b.DrawLine(r, new Point(50, 90), new Point(50, 0));
b.DrawLine(r, new Point(60, 90), new Point(70, 0));
b.DrawLine(r, new PointF(40.5f, 90), new PointF(40.5f, 0));
b.DrawEllipse(pen, 6, 6, 30, 30);
The smaller circle has many gray pixels and even the original green line has a lighter top end. The two new lines are fully anti-aliased now, one because it is tilted, the other because it sits 'between' pixels.
Btw: If it is turned on you will also see anti-alising when your Pen.Width is even or when it is a non-integer number. The reason for the latter should be obvious; the former comes from the PenAlignment property. Its default Center tries to center the pen, but not at the pixel boundary but at the center of the coordinate pixels. Therefore only an uneven width will completely fill the pixels and not cause anti-aliasing. For closed shapes you can change this behaviour by changing the Pen.Alignment to Inset:
This property determines how the Pen draws closed curves and
polygons. The PenAlignment enumeration specifies five values;
however, only two values—Center and Inset—will change the appearance
of a drawn line. Center is the default value for this property and
specifies that the width of the pen is centered on the outline of the
curve or polygon. A value of Inset for this property specifies that the
width of the pen is inside the outline of the curve or polygon. The
other three values, Right, Left, and Outset, will result in a pen that
is centered.
A Pen that has its alignment set to Inset will yield unreliable
results, sometimes drawing in the inset position and sometimes in the
centered position.Also, an inset pen cannot be used to draw compound
lines and cannot draw dashed lines with Triangle dash caps.
PS: The question was not about how to draw properly, so let me just note that you never ought to do it using control.CreateGraphics as this will always only result in non-persistent graphics. Instead you need to use the Paint event and its e.Graphics object..

How to make a circle shape label in Window Form?

As you all know, a label is usually in a square or rectangle shape. I really need to make circle shaped label. Can anyone please tell me is this possible or at least point me in a right direction?
Sorry, just to make things clear. I want a circle shaped label. Not just drawing a circle on the screen.
You can set the Region property of your Label :
var path = new System.Drawing.Drawing2D.GraphicsPath();
path.AddEllipse(0, 0, label1.Width, label1.Height);
this.label1.Region = new Region(path);
System.Drawing.Graphics graphics = this.CreateGraphics();
System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle(100, 100, 200, 200);
graphics.DrawEllipse(System.Drawing.Pens.Black, rectangle);

Bitmap Text Background and HorizontalAlignment

I am overlaying text to a bitmap as shown below, I need to be able to set a background colour behind the text and also set the HorizontalAlignment (i.e left/right/centre), can anyone advise me how this can be done. Also note the text size can vary.
Thanks.
Bitmap frameBitmap = new Bitmap(streamFrameWidth, streamFrameHeight,
streamFrameWidth * 3,
System.Drawing.Imaging.PixelFormat.Format24bppRgb, pFrame);
using (Graphics g = Graphics.FromImage(frameBitmap))
{
// Create font and brush.
Font drawFont = new Font("Arial", 12, FontStyle.Bold);
SolidBrush drawBrush = new SolidBrush(Color.Black);
// Create point for upper-left corner of drawing.
PointF drawPoint = new PointF(10.0F, 40.0F);
//HorizontalAlignment.
// draw the text
g.DrawString(overlayText, drawFont, drawBrush, drawPoint);
}
You can control the alignment of the drawn text by using the StringFormat parameter of the DrawString method.
Example
MSDN
You probably need TextRenderer.MeasureText.
It returns the size of the text to be displayed. Combining the size of the text with the size of the Bitmap, you can work out the appropriate location of the text based upon the required HorizontalAlignment.
Once you know the bounds (size and location) of the text, you can simply paint a color to those bounds to implement a background colour before drawing the text on top.

Categories

Resources