System Drawing Invert Region build out of Path - c#

Ive got a panel and im drawing a heart on that panel..
But i dont want to draw the heart i want to draw everything except the heart so the heart is transparent.
Can i invert the Region selected out of the Path?
System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath();
path.AddArc(0, 0, (this.Width / 2), (this.Height / 2), 135, 195);
path.AddArc((this.Width / 2), 0, (this.Width / 2), (this.Height / 2), 210, 195);
path.AddLine((this.Width / 2), this.Height, (this.Width / 2), this.Height);
this.Region = new Region(path);
this.BackColor = Color.Black;
What it looks like(white = transparent):
What i want it to look like(white = transparent):

I think you can just add 2 graphics paths together.
You could try this code out:
private void panel1_Paint(object sender, PaintEventArgs e)
{
GraphicsPath path = new GraphicsPath();
path.AddArc(0, 0, (this.Width / 2), (this.Height / 2), 135, 195);
path.AddArc((this.Width / 2), 0, (this.Width / 2), (this.Height / 2), 210, 195);
path.AddLine((this.Width / 2), this.Height, (this.Width / 2), this.Height);
GraphicsPath path2 = new GraphicsPath();
path2.AddRectangle(new Rectangle(new Point(0, 0), panel1.Size));
path2.AddPath(path, false);
e.Graphics.FillPath(Brushes.Black, path2);
}
Result is:

You can try excluding a region from from the Graphic object of your panel's Paint event:
GraphicsPath path = new GraphicsPath();
path.AddArc(0, 0, (this.Width / 2), (this.Height / 2), 135, 195);
path.AddArc((this.Width / 2), 0, (this.Width / 2), (this.Height / 2), 210, 195);
path.AddLine((this.Width / 2), this.Height, (this.Width / 2), this.Height);
using (Region r = new Region(path)) {
e.Graphics.ExcludeClip(r);
}
// continue drawing...
e.Graphics.Clear(Color.Yellow);
or if trying to modify the control's region, then just use the Region's Exclude property:
GraphicsPath path = new GraphicsPath();
path.AddArc(0, 0, (this.Width / 2), (this.Height / 2), 135, 195);
path.AddArc((this.Width / 2), 0, (this.Width / 2), (this.Height / 2), 210, 195);
path.AddLine((this.Width / 2), this.Height, (this.Width / 2), this.Height);
Region r = new Region(new Rectangle(Point.Empty, this.ClientSize));
r.Exclude(path);
this.Region = r;

I don't know of a way to invert the selection, but you can always draw a heart in the background color, then change the background color to black.
this.BackColor = Form.BackColor;
Form.BackColor = Color.Black;

Original solution here. I've modified that for your needs
this.Region = InvertRegion(new Region(path), this.Width, this.Height);
and
private Region InvertRegion(Region region, int width, int height)
{
Bitmap mask = new Bitmap(width, height);
Graphics.FromImage(mask).FillRegion(Brushes.Black, region);
int matchColor = Color.Black.ToArgb();
Region inverted = new System.Drawing.Region();
inverted.MakeEmpty();
Rectangle rc = new Rectangle(0, 0, 0, 0);
bool inimage = false;
for (int y = 0; y < mask.Height; y++)
{
for (int x = 0; x < mask.Width; x++)
{
if (!inimage)
{
if (mask.GetPixel(x, y).ToArgb() != matchColor)
{
inimage = true;
rc.X = x;
rc.Y = y;
rc.Height = 1;
}
}
else
{
if (mask.GetPixel(x, y).ToArgb() == matchColor)
{
inimage = false;
rc.Width = x - rc.X;
inverted.Union(rc);
}
}
}
if (inimage)
{
inimage = false;
rc.Width = mask.Width - rc.X;
inverted.Union(rc);
}
}
return inverted;
}

Related

How to use AddArc() method in C#

I have this little code to use AddArc() method in a label, but when I execute the code the label disappears. I believe it is the numbers I have used, I followed instructions from the Windows documentation and it had these parameters there too.
GraphicsPath gp = new GraphicsPath();
Rectangle rec = new Rectangle(20, 20, 50, 100);
gp.AddArc(rec, 0 , 180);
label2.Region = new Region(gp);
label2.Invalidate();
I used another code to make the correct way or curve in a text
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
var center = new Point(Width / 2, Height / 2);
var radius = Math.Min(Width, Height) / 3;
var text = "Hello";//txtUp.Text;
var font = new Font(FontFamily.GenericSansSerif, 24, FontStyle.Bold);
for (var i = 0; i < text.Length; ++i)
{
var c = new String(text[i], 1);
var size = e.Graphics.MeasureString(c, font);
var charRadius = radius + size.Height;
var angle = (((float)i / text.Length) - 2);
var x = (int)(center.X + Math.Cos(angle) * charRadius);
var y = (int)(center.Y + Math.Sin(angle) * charRadius);
e.Graphics.TranslateTransform(x, y);
e.Graphics.RotateTransform((float)(90 + 360 * angle / (2 * Math.PI)));
e.Graphics.DrawString(c, font, Brushes.Red, 0, 0);
e.Graphics.ResetTransform();
e.Graphics.DrawArc(new Pen(Brushes.Transparent, 2.0f), center.X - radius, center.Y - radius, radius * 2, radius * 2, 0, 360);
}
}
but it wont show in front of a panel is it possible.
This is what it looks like:
Is it possible to move that text in front of the green circle?

Scaling Picturebox does not change image at all

I'm using a picturebox to create a visual of an instance of my truss class. I'm creating the visual by drawing directly onto the picture box in the paint event. The method looks like this
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (isDraw)
{
//Preparing to draw
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.Bicubic;
RunEntry entry = this.passedHistory.SelectedItem as RunEntry;
AnsFile objToDraw = entry.FileRead;
Pen pen = new Pen(Color.Black);
//Getting size of bitmap
int maxWidth = 0, maxHeight = 0;
foreach (AnsJoint joint in objToDraw.AnsJoints)
{
if (joint.Location.X.Length > maxWidth)
{
maxWidth = (int)joint.Location.X.Length;
}
if (joint.Location.Y.Length > maxHeight)
{
maxHeight = (int)joint.Location.Y.Length;
}
}
//Drawing joints
foreach (AnsJoint joint in objToDraw.AnsJoints)
{
PointF jointPoint = this.ToCartesian(new PointF((float)joint.Location.X.Length - 4f, (float)joint.Location.Y.Length + 10f), maxHeight);
e.Graphics.DrawString(joint.JointID.ToString(), new Font(FontFamily.GenericMonospace, 6f, FontStyle.Regular, GraphicsUnit.Point, 1, false), Brushes.Black, jointPoint);
}
//Draw the panels and links
foreach (AnsMember member in objToDraw.AnsMembers)
{
List<AnsPanel> panels = member.Panels; //Drawing the panels
foreach (AnsPanel pan in panels)
{
pen.Color = Color.Red;
PointF p1 = this.ToCartesian(new PointF((float)pan.I.Location.X.Length, (float)pan.I.Location.Y.Length), maxHeight);
PointF p2 = this.ToCartesian(new PointF((float)pan.J.Location.X.Length, (float)pan.J.Location.Y.Length), maxHeight);
g.DrawEllipse(pen, p1.X - 2.5f, p1.Y - 2.5f, 5, 5);
g.DrawEllipse(pen, p2.X - 2.5f, p2.Y - 2.5f, 5, 5);
g.DrawEllipse(pen, p1.X - 3, p1.Y - 3.3f, 5, 5);
g.DrawEllipse(pen, p2.X - 3, p2.Y - 3.3f, 5, 5);
pen.Color = Color.Black;
g.DrawLine(pen, p1, p2);
}
List<AnsLink> links = member.Links; //Drawing the links
foreach (AnsLink link in links)
{
PointF p1 = this.ToCartesian(new PointF((float)link.I.Location.X.Length, (float)link.I.Location.Y.Length), maxHeight);
PointF p2 = this.ToCartesian(new PointF((float)link.J.Location.X.Length, (float)link.J.Location.Y.Length), maxHeight);
g.FillEllipse(Brushes.Green, p1.X - 1.5f, p1.Y - 1.5f, 3, 3);
g.FillEllipse(Brushes.Green, p2.X - 1.5f, p2.Y - 1.5f, 3, 3);
g.DrawLine(pen, p1, p2);
}
}
g.ScaleTransform(.5f, .5f);
pictureBox1.Tag = entry.FileName;
}
}
Which yields the result I'm expecting
except that I want the truss image to scale to fill the picturebox more. I added the ScaleTransform call to the end of the paint event method but that doesn't seem to have any impact as the picture is the same size with or without the call. How can I scale what I draw on the picturebox to the size of the picturebox?
Call ScaleTransform before you do your drawing. You can calculate the desired scale factor like this:
// place this code after the calculation of maxWidth and maxHeight
// but before the drawing code
PictureBox p = (PictureBox)sender;
float scaleFactor = Math.Min(
((float)p.Width) / maxWidth,
((float)p.Height) / maxHeight
);
g.ScaleTransform(scaleFactor, scaleFactor);

need to draw an Google marker image via C# Graphics

I need to draw an Google marker image via C# Graphics
for that i;ll need the exact coordinates of Google marker
how can i do that Please help .
My Current Code is .
private void Shape8(PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
int startMarker = 0;
int MarkerDiameter = 30;
int EllipseDiameter = 15;
const int StartX = 150;
const int StartY = 350;
int X = StartX;
int Y = StartY;
GraphicsPath path = new GraphicsPath();
Rectangle ellipse = new Rectangle(X, Y, EllipseDiameter, EllipseDiameter);
path.AddEllipse(ellipse);
path.CloseFigure();
X = X + (EllipseDiameter / 2) - (MarkerDiameter / 2);
Y = Y - (EllipseDiameter * 2) - (MarkerDiameter / 2);
startMarker = StartY - 10 - (Convert.ToInt32(MarkerDiameter * 1.5));//Space Between marker and circle.
AddMarker8(ref path, X, startMarker, StartX, StartY, EllipseDiameter, MarkerDiameter, "Concept1");
e.Graphics.FillPath(Brushes.Pink, path);
e.Graphics.DrawPath(Pens.Black, path);
e.Graphics.FillEllipse(Brushes.White, ellipse);
path.CloseAllFigures();
}
private void AddMarker8(ref GraphicsPath path, int X, int Y, int StartX, int StartY, int EllipseDiameter, int MarkerDiameter, string conceptName)
{
float startAngle = 180.0F;
float sweepAngle = 180.0F;
int fontStyle = (int)FontStyle.Regular;
path.AddString(conceptName, new FontFamily("Arial"), fontStyle, 15, new Point(X + (MarkerDiameter / 2), Y - 15), lblFormat);
Rectangle rect = new Rectangle(X, Y, MarkerDiameter, MarkerDiameter);
path.AddArc(rect, startAngle, sweepAngle);
Point lastpoint = new Point(X + (MarkerDiameter / 2), (Y + (MarkerDiameter * 2)) - (MarkerDiameter / 2));
path.AddCurve(new Point[] {
new Point(X+(MarkerDiameter), Y + (MarkerDiameter / 2)), //a
new Point((X +MarkerDiameter)-(MarkerDiameter/4) ,(Y +(MarkerDiameter ))) ,//A.5
lastpoint ,//c
new Point(X +(MarkerDiameter / 4) ,(Y +(MarkerDiameter ))) ,//B.5
new Point(X, Y + (MarkerDiameter / 2))//b
}, 0.5f);
path.CloseFigure();
}
Try the following code
private void DrawMarker(int X, int Y, double Scale, Color BorderColor, Color FillColor, PaintEventArgs e, char Letter = '\0')
{
Graphics G1 = e.Graphics;
Pen Pen1 = new Pen(BorderColor, 8);
SolidBrush Brush1 = new SolidBrush(BorderColor);
SolidBrush Brush2 = new SolidBrush(FillColor);
G1.SmoothingMode = SmoothingMode.AntiAlias;
G1.ResetTransform();
G1.ScaleTransform(Convert.ToSingle(0.4 * Scale), Convert.ToSingle(0.4 * Scale));
GraphicsPath GraphicsPath1 = new GraphicsPath();
GraphicsPath1.AddBeziers(new Point(X + 51, Y + 169), new Point(X + 47, Y + 137), new Point(X + 42, Y + 107), new Point(X + 14, Y + 77));
GraphicsPath1.AddBeziers(new Point(X + 87, Y + 77), new Point(X + 62, Y + 107), new Point(X + 55, Y + 137), new Point(X + 51, Y + 169));
GraphicsPath GraphicsPath2 = new GraphicsPath();
GraphicsPath2.AddEllipse(X + 5, Y + 5, 92, 92);
G1.FillPath(Brush2, GraphicsPath2);
G1.DrawPath(Pen1, GraphicsPath2);
G1.SetClip(new Rectangle(X, Y + 85, 103, 84));
G1.FillPath(Brush2, GraphicsPath1);
G1.DrawPath(Pen1, GraphicsPath1);
G1.ResetClip();
if (Letter != '\0')
{
Font Font1 = new Font("Arial", 52, FontStyle.Bold);
StringFormat StringFormat1 = new StringFormat
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center
};
G1.DrawString(Convert.ToString(Letter), Font1, Brush1, new Rectangle(X, Y, 103, 103), StringFormat1);
Font1.Dispose();
StringFormat1.Dispose();
}
else
{
G1.FillEllipse(Brush1, new Rectangle(X + 32, Y + 32, 37, 37));
}
Pen1.Dispose();
Brush1.Dispose();
Brush2.Dispose();
GraphicsPath1.Dispose();
GraphicsPath2.Dispose();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
DrawMarker(0, 0, 0.5, Color.Black, Color.Tomato, e, Convert.ToChar("A"));
DrawMarker(80, 0, 0.8, Color.Black, Color.Red, e, Convert.ToChar("B"));
DrawMarker(160, 0, 1, Color.Black, Color.Linen, e, Convert.ToChar("C"));
DrawMarker(210, 0, 1.3, Color.Black, Color.Orange, e, Convert.ToChar("D"));
DrawMarker(260, 0, 1.6, Color.Black, Color.Green, e);
}
after running it, the result should be like this

Adding lineargradientbrush inside graphicspath in c#

hello how to fill lineargradientbrush on the graphicspath..
i have this code and solidbrush can only fill it.. i dont know how to fill it with lineargradientbrush.. any help please..
i have this code..
class KamoteButton : Button
{
protected override void OnPaint(PaintEventArgs pevent)
{
int width = this.Width-1;
int height = this.Height-1;
Color gradColor_a = Color.FromArgb(162, 177, 183);
Color gradColor_b = Color.FromArgb(104, 111, 114);
int radius = this.Width / 8;
Graphics gFx = pevent.Graphics;
gFx.SmoothingMode = SmoothingMode.AntiAlias;
GraphicsPath gp = new GraphicsPath();
gp.AddArc(0, 0, radius, radius, 180, 90);
gp.AddLine(width / 8, 0, width - width / 8, 0);
gp.AddArc(width - radius, 0, radius, radius, 270, 90);
gp.AddLine(width, width / 8, width, height - width / 8);
gp.AddArc(width - radius, height - radius, radius, radius, 0, 90);
gp.AddLine(width - width / 8, height, width / 8, height);
gp.AddArc(0, height - radius, radius, radius, 90, 90);
gp.AddLine(0, height - width / 8, 0, width / 8);
Rectangle r = new Rectangle(0, 0, 100, 100);
LinearGradientBrush lbg = new LinearGradientBrush(gp, gradColor_a, gradColor_b, LinearGradientMode.Vertical);
SolidBrush sb = new SolidBrush(Color.Red);
gFx.FillPath(lbg, gp);
this.Region = new Region(gp);
}
}
Your code to create the GradientBrushh won't compile:
LinearGradientBrush lbg = new LinearGradientBrush(gp,
gradColor_a, gradColor_b, LinearGradientMode.Vertical);
There is no constructor with a Path as parameter. Replace it with 2 points or 1 Rect

How to make a Non Rectangular Winform?

I am using the code below to change to shape of the winform.
It's changing the shape, but not like how I wanted.
I need the form to have curved corners.
What points should I use to get it?
public void MakeNonRectangularForm()
{
var p = new GraphicsPath();
int width = ClientSize.Width;
int height = ClientSize.Height;
p.AddClosedCurve(new Point[] { new Point(width / 2, height / 2),
new Point(width, 0), new Point(width, height / 3),
new Point(width - width / 3, height),
new Point(width / 7, height - height / 8)});
Region = new Region(p);
}
The following is some code I have used to create rounded edges before, using AddArc and lines to piece together the border:
(You can play with xRadius and yRadius to achieve your desired amount of "rounded-ness")
int xRadius = {insert value here};
int yRadius = {insert value here};
GraphicsPath edge = new GraphicsPath();
int rightHandLeft = this.Width - xRadius - 1;
int bottomSideTop = this.Height - yRadius - 1;
edge.AddArc(0, 0, xRadius, yRadius, 180, 90);
edge.AddLine(xRadius, 0, rightHandLeft, 0);
edge.AddArc(rightHandLeft, 0, xRadius, yRadius, 270, 90);
edge.AddLine(this.Width, yRadius, this.Width, bottomSideTop);
edge.AddArc(rightHandLeft, bottomSideTop, xRadius, yRadius, 0, 90);
edge.AddLine(rightHandLeft, this.Height, xRadius, this.Height);
edge.AddArc(0, bottomSideTop, xRadius, yRadius, 90, 90);
edge.AddLine(0, bottomSideTop, 0, yRadius);
this.Region = new Region(edge);

Categories

Resources