DrawingContext DrawGeometry on Canvas (wpf) - c#

I try to programmatically draw a rectangle with rounded corners in my WPF project. I'm pretty new to WPF and trying to figure out how drawing works since it's much different than WinForms. I'm using >this< link for the rounded rectangle method (my method is the same as on that website). Here is my code:
Rect rect = new Rect();
rect.Width = Width - BorderSize;
rect.Height = Height - BorderSize;
DrawingVisual drawingVisual = new DrawingVisual();
using (var draw = drawingVisual.RenderOpen())
{
DrawRoundedRectangle(draw, new SolidColorBrush(Color.FromRgb(0, 0, 0)),
new Pen(new SolidColorBrush(Color.FromRgb(0, 0, 0)), BorderSize), rect, new CornerRadius(5, 5, 5, 5));
}
ContentPresenter content = new ContentPresenter();
content.Content = drawingVisual;
previewcanvas.Children.Add(content);
This is my output on the canvas:
Not really what I'm expecting ;) there shouldn't be any text in there to begin with.
Hope someone can help me to draw the rounded rectangle!
edit
Some extra info, I need to be able to set each individual corner.

Rect rect = new Rect();
rect.Width = Width - BorderSize;
rect.Height = Height - BorderSize;
DrawingVisual drawingVisual = new DrawingVisual();
using (var draw = drawingVisual.RenderOpen())
{
DrawRoundedRectangle(draw, new SolidColorBrush(Color.FromRgb(0, 0, 0)),
new Pen(new SolidColorBrush(Color.FromRgb(0, 0, 0)), BorderSize), rect, new CornerRadius(5, 5, 5, 5));
}
RenderTargetBitmap rtb = new RenderTargetBitmap(rect.Width, rect.Height, 96, 96, PixelFormats.Default);
rtb.Render(drawingVisual);
Image image = new Image();
image.Source = rtb;
previewcanvas.Children.Add(image);

Use RadiusX and RadiusY:
rect = new Rectangle
{
Stroke = Brushes.Red,
StrokeThickness = 2,
Width = 100,
Height = 100,
RadiusX = 25,
RadiusY = 25
};
Canvas.SetLeft(rect, startPoint.X);
Canvas.SetTop(rect, startPoint.X);
canvas.Children.Add(rect);
Xaml:
<Canvas x:Name="canvas"/>

After searching I found a much easier solution:
Border border = new Border();
border.BorderThickness = new Thickness(2);
border.CornerRadius = new CornerRadius(5,15,25,35);
border.BorderBrush = (SolidColorBrush)(new BrushConverter().ConvertFrom("#000"));
border.Background = (SolidColorBrush)(new BrushConverter().ConvertFrom("#000"));
border.Width = 100;
border.Height = 100;
border.Margin = new Thickness(10);
previewcanvas.Children.Add(border);
It's kind of a cheat (since its not a Rectangle), but it works. Here's my result:

Related

Bitmap inside a bitmap

I am trying to insert an image 800x500 inside a blank bitmap of 850x610 in the center. The inner image should be in the center and It also has a title on the top. I am attaching an image to illustrate my idea:
public static Bitmap AddBorder(Bitmap srcImage)
{
Bitmap bmp = new Bitmap(srcImage.Width + 45, srcImage.Height + 100);
Graphics g = Graphics.FromImage(bmp);
g.DrawImage(srcImage, 0, 0);
g.DrawImage(srcImage, new Rectangle(bmp.Width - 1, 0, 1, bmp.Height));
g.DrawImage(srcImage, new Rectangle(0, bmp.Height - 1, bmp.Width, 1));
return bmp;
}
I have tried to draw it using drawRectangle, drawImage etc. But, I cannot pad it properly as illustrated in the above image. I also cannot add the border to inner image.
I want to get an idea about how to do that.
The below sample sets the new bitmap size, it fills it with a background (black), draws the image in the center and finally after measuring the text will align it in the center (width check only).
public static Bitmap AddBorder(Bitmap srcImage, string text)
{
Bitmap bmp = new Bitmap(850, 610);
using(Graphics g = Graphics.FromImage(bmp))
{
// Background
g.FillRectangle(Brushes.White, new Rectangle(0, 0, bmp.Width, bmp.Height));
// Source Image
Rectangle rect = new Rectangle(25, 55, 800, 500);
g.DrawImage(srcImage, rect);
// Border
int borderThickness = 2;
using(Pen pen = new System.Drawing.Pen(Brushes.Black, borderThickness))
{
pen.Alignment = System.Drawing.Drawing2D.PenAlignment.Inset;
g.DrawRectangle(pen, new Rectangle(rect.X - borderThickness, rect.Y - borderThickness, rect.Width + borderThickness, rect.Height + borderThickness));
}
// Text String
using (Font font = new Font("Arial", 16))
{
SizeF size = g.MeasureString(text, font);
g.DrawString(text, font, Brushes.Black, new PointF((bmp.Width / 2) - (size.Width / 2), rect.Top - (size.Height + borderThickness)));
}
}
return bmp;
}
Updated based on comments (Added also text above the centered image)!

How to draw on the screenshot captured

I have captured current window using C# code, the code is shown below. I want to draw a rectangle on the captured section(For highlighting things). Anyone know how can I highlight the things using C# code? I want to draw on the cursor position below mentioned.
public Bitmap CaptureScreen()
{
enmScreenCaptureMode screenCaptureMode = enmScreenCaptureMode.Window;
Rectangle bounds;
if (screenCaptureMode == enmScreenCaptureMode.Screen)
{
bounds = Screen.GetBounds(Point.Empty);
CursorPosition = Cursor.Position;
}
else
{
var foregroundWindowsHandle = GetForegroundWindow();
var rect = new Rect();
GetWindowRect(foregroundWindowsHandle, ref rect);
bounds = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
CursorPosition = new Point(Cursor.Position.X - rect.Left, Cursor.Position.Y - rect.Top);
}
var result = new Bitmap(bounds.Width, bounds.Height);
using (var g = Graphics.FromImage(result))
{
Pen pen = new Pen(Color.Red);
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
}
return result;
}
I have passed the clicked point and element clicked using the AutomationElement, and drawn an eclipse using the elements BoundingRectangle property. Code shown below.
public Bitmap CaptureScreen(System.Windows.Point point, AutomationElement element)
{
enmScreenCaptureMode screenCaptureMode = enmScreenCaptureMode.Window;
Rectangle bounds;
var foregroundWindowsHandle = GetForegroundWindow();
var rect = new Rect();
GetWindowRect(foregroundWindowsHandle, ref rect);
if (screenCaptureMode == enmScreenCaptureMode.Screen)
{
bounds = Screen.GetBounds(Point.Empty);
CursorPosition = Cursor.Position;
}
else
{
bounds = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
CursorPosition = new Point(Cursor.Position.X - rect.Left, Cursor.Position.Y - rect.Top);
}
var result = new Bitmap(bounds.Width, bounds.Height);
using (var g = Graphics.FromImage(result))
{
Pen pen = new Pen(Color.Red,2);
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
//float drawX = (float)point.X - rect.Left;
//float drawY = (float)point.Y - rect.Top;
float drawX = (float)element.Current.BoundingRectangle.X - rect.Left;
float drawY = (float)element.Current.BoundingRectangle.Y - rect.Top;
g.DrawEllipse(pen, drawX, drawY, (float) element.Current.BoundingRectangle.Width, (float)element.Current.BoundingRectangle.Height);
}
return result;
}
If you want to draw programmatically, maybe try System.Drawing.
You probably won't need the first line.
// Load the image (probably from your stream)
Image image = Image.FromFile( imagePath );
using (Graphics g = Graphics.FromImage(image))
{
// Modify the image using g here...
// Create a brush with an alpha value and use the g.FillRectangle function
SolidBrush shadowBrush = new SolidBrush(Red);
g.DrawRectangle(shadowBrush, /*RectanglePointsHere*/);
}
image.Save( imageNewPath );

RenderTargetBitmap doesn't seem to render my rectangle

I have the following code:
LinearGradientBrush linGrBrush = new LinearGradientBrush();
linGrBrush.StartPoint = new Point(0,0);
linGrBrush.EndPoint = new Point(1, 0);
linGrBrush.GradientStops.Add(new GradientStop(Colors.Red, 0.0));
linGrBrush.GradientStops.Add(new GradientStop(Colors.Yellow, 0.5));
linGrBrush.GradientStops.Add(new GradientStop(Colors.White, 1.0));
Rectangle rect = new Rectangle();
rect.Width = 1000;
rect.Height = 1;
rect.Fill = linGrBrush;
rect.Arrange(new Rect(0, 0, 1, 1000));
rect.Measure(new Size(1000, 1));
If I do
myGrid.Children.Add(rect);
Then the gradient is drawn fine on the window.
I want to use this gradient for an intensity map somewhere else, so I need to get the pixels out of it. To do this, I understand I can convert it to a bitmap, using RenderTargetBitmap. Here's the next part of the code:
RenderTargetBitmap bmp = new RenderTargetBitmap(
1000,1,72,72,
PixelFormats.Pbgra32);
bmp.Render(rect);
Image myImage = new Image();
myImage.Source = bmp;
To test this, I do:
myGrid.Children.Add(myImage);
But nothing appears on the window. What am I doing wrong?
Arrange has to be called after Measure, and the Rect values should be passed correctly.
Instead of
rect.Arrange(new Rect(0, 0, 1, 1000)); // wrong width and height
rect.Measure(new Size(1000, 1));
you should do
var rect = new Rectangle { Fill = linGrBrush };
var size = new Size(1000, 1);
rect.Measure(size);
rect.Arrange(new Rect(size));
var bmp = new RenderTargetBitmap(1000, 1, 96, 96, PixelFormats.Pbgra32);
bmp.Render(rect);

Calculating text width for DXF

I am using netDXF (https://netdxf.codeplex.com/) to generate a DXF file for use with AutoCAD. However, I have an issue with getting the width of MText correct. I want to be able to define a width that the text should fit into, and change the width factor of the text (squash it horizontally) so that it fits in the defined area. So if I have a 40mm width to fit the text into and the text is 80mm long, it needs to have a width factor of 0.5. The only problem is that I don't know how to accurately determine the width of the text. I have tried the following methods and was unsuccessful in getting the correct result:
Why is Graphics.MeasureString() returning a higher than expected number?
Measure a String without using a Graphics object?
http://www.codeproject.com/Articles/2118/Bypass-Graphics-MeasureString-limitations
I have attached my code. I am basically printing a horizontal line using each of the 3 methods to calculate text width and comparing it to the actual text width. If I change the font, I get varying results. I have attached two images. One using the code with Calibri and one with Arial. I need the line to be on the edges of the text no matter what font I use.
Here is my code:
public void TestMethod1()
{
Application.SetCompatibleTextRenderingDefault(false);
//text width in mm
float textWidth = 40;
float textHeight = 200;
string labelText = "HELLO WORLD!";
TextStyle textStyle = new TextStyle("Calibri");
DxfDocument dxf = new DxfDocument();
Layer layer1 = new Layer("layer1");
layer1.Color = new AciColor(0, 0, 255);
layer1.Name = "Text";
MText text1 = new MText(new Vector2(0, 0), textHeight, 0, textStyle);
text1.Layer = layer1;
text1.AttachmentPoint = MTextAttachmentPoint.MiddleCenter;
//Will the text fit in the bounds of the rectangle? If not change width factor so it does.
Font f = new Font(textStyle.FontName, textHeight);
Size size = TextRenderer.MeasureText(labelText, f);
SizeF sizeF = graphicsMeasureString(labelText, f);
int width = MeasureDisplayStringWidth(labelText, f);
float widthFactor = Math.Min(1, textWidth / sizeF.Width);
MTextFormattingOptions mtextOptions = new MTextFormattingOptions(text1.Style);
//mtextOptions.WidthFactor = widthFactor;
text1.Write(labelText, mtextOptions);
//Red, g.MeasureString
Line line1 = new Line(new Vector2(0 - sizeF.Width / 2, 0), new Vector2(0 + sizeF.Width / 2, 0));
line1.Color = new AciColor(255, 0, 0);
//Green, TextRenderer
Line line2 = new Line(new Vector2(0 - size.Width / 2, 5), new Vector2(0 + size.Width / 2, 5));
line2.Color = new AciColor(0, 255, 0);
//Yellow, MeasureDisplayStringWidth
Line line3 = new Line(new Vector2(0 - width / 2, -5), new Vector2(0 + width / 2, -5));
line3.Color = new AciColor(255, 255, 0);
dxf.AddEntity(text1);
dxf.AddEntity(line1);
dxf.AddEntity(line2);
dxf.AddEntity(line3);
dxf.Save("Text Width Test.dxf");
}
public SizeF graphicsMeasureString(string text, Font f)
{
Bitmap fakeImage = new Bitmap(1, 1);
Graphics g = Graphics.FromImage(fakeImage);
SizeF sizeF = g.MeasureString(text, f, new PointF(100, 0), StringFormat.GenericTypographic);
return sizeF;
}
public int MeasureDisplayStringWidth(string text, Font f)
{
Size size = TextRenderer.MeasureText(text, f);
Bitmap fakeImage = new Bitmap(1, 1);
Graphics g = Graphics.FromImage(fakeImage);
System.Drawing.StringFormat format = new System.Drawing.StringFormat();
System.Drawing.RectangleF rect = new System.Drawing.RectangleF(0, 0, 1000, 1000);
System.Drawing.CharacterRange[] ranges = { new System.Drawing.CharacterRange(0, text.Length) };
System.Drawing.Region[] regions = new System.Drawing.Region[1];
format.SetMeasurableCharacterRanges(ranges);
regions = g.MeasureCharacterRanges(text, f, rect, format);
rect = regions[0].GetBounds(g);
return (int)(rect.Right + 1.0f);
}

how to fill C# Fill rectangle From bottom to top?

I have drawn vertical Rectangle but i want to fill it from bottom to top.
here is the code i used
System.Drawing.Drawing2D.LinearGradientBrush linGrBrush =
new System.Drawing.Drawing2D.LinearGradientBrush(
new Point(0, 12),
new Point(0,2),
Color.FromArgb(0, 0, 0, 0),
Color.FromArgb(255, 190, 0, 0));
Pen pen = new Pen(linGrBrush);
e.Graphics.FillRectangle(linGrBrush,groupBox2.Width -50,10, 25, x);
using (Pen Pen1 = new Pen(Color.BurlyWood, 4))
{
e.Graphics.DrawRectangle(Pen1, groupBox2.Width -50,10, 25, 200);
}
x is color fill offset which fill is used to fill rectangle after every 2 seconds.
I think that you should adjust the starting and the ending points of the gradient:
System.Drawing.Drawing2D.LinearGradientBrush linGrBrush =
new System.Drawing.Drawing2D.LinearGradientBrush(
new Point(0, 1),
new Point(0,0),
Color.FromArgb(0, 0, 0, 0),
Color.FromArgb(255, 190, 0, 0));

Categories

Resources