How to draw on the screenshot captured - c#

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 );

Related

How to save the image from picturebox including the drawn graphics on it?

i want to save the image in the pictureBox1 including the Graphics.
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.DrawRectangle(Pens.Green, 0, 0, pictureBox1.Width - 1, pictureBox1.Height - 1);
Pen p = new Pen(Color.Red);
e.Graphics.DrawLine(p, 256, 0, 256, 512);
e.Graphics.DrawLine(p, 0, 256, 512, 256);
DrawPieOnPicturebox(e.Graphics);
}
public void DrawPieOnPicturebox(Graphics myPieGraphic)
{
Color myPieColors = Color.FromArgb(150, Color.LightGreen);
Size myPieSize = new Size((int)distanceFromCenterPixels, (int)distanceFromCenterPixels);
Point myPieLocation = new Point((pictureBox1.Width - myPieSize.Width) / 2, (pictureBox1.Height - myPieSize.Height) / 2);
DrawMyPie(myPiePercent, myPieColors, myPieGraphic, myPieLocation, myPieSize);
}
int counter = 0;
public void DrawMyPie(int myPiePerecent, Color myPieColor, Graphics myPieGraphic, Point
myPieLocation, Size myPieSize)
{
using (SolidBrush brush = new SolidBrush(myPieColor))
{
myPieGraphic.FillPie(brush, new Rectangle(myPieLocation, myPieSize), Convert.ToSingle(myPiePerecent * 360 / 100), Convert.ToSingle(15 * 360 / 100));
}
myBitmap = new Bitmap(pictureBox1.Image);
myBitmap.Save(#"d:\" + counter + "mybitmap1.bmp");
myBitmap.Dispose();
counter++;
}
it's saving the image in the pictureBox1 but without the drawn FillPie. i want to add to the saved bitmap also the drawn FillPie.
I think your best bet would be to use myPieGraphic.DrawImage followed by your myPieGraphic.FillPie, the use the myPieGraphic.Save method.
It's unclear how this is layered in your app but I'm assuming you have an Image in a Picturebox and then you draw on top of it using a Graphics?
Doing that will render to separate "Layers" so to speak they are not the same Image/Graphics. If you instead draw both the Image and your Pie using the same Graphics you can then save directly from it.
I think that will produce the result you want.
See link for all Graphics methods:
https://learn.microsoft.com/en-us/dotnet/api/system.drawing.graphics.addmetafilecomment?view=dotnet-plat-ext-7.0
Edit: Answering comment.
using(MemoryStream ms = new MemoryStream()) {
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
using (var fs = new FileStream(#"c:\temp\test.png", FileMode.Create))
{
var bytes = ms.ToArray();
await fs.WriteAsync(bytes , 0, bytes.Length);
}
}

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 add shape to an existent Picturebox image C#

I have created an Image and I want to add a rectangle around the image and recreate it as Image again to be drawn in a PictureBox
but I'm getting out of memory exception
How can I modify the image.
public void Draw(SizeF size)
{
int scale = 100;
Graphics refGraph = this.CreateGraphics();
IntPtr hdc = refGraph.GetHdc();
SolidBrush brush = new SolidBrush(Color.Black);
Pen pen = new Pen(Color.Black, 4);
try
{
Metafile image = new Metafile(hdc, EmfType.EmfOnly, "Shapes");
using (Graphics g = Graphics.FromImage(image))
{
PointF center = new PointF((float)base.Width / 2, base.Height / 2);
//Draw a rect
RectangleF Block = new RectangleF(new PointF(center.X - size.Width * scale / 2, center.Y - size.Height * scale / 2), new SizeF(size.Width * scale, size.Height * scale));
g.FillRectangle(brush, Block);
}
//Image = image;
ModifyImage(image);
}
finally
{
refGraph.ReleaseHdc(hdc);
refGraph.Dispose();
pen.Dispose();
brush.Dispose();
}
Invalidate();
}
public void ModifyImage(Metafile image)
{
Graphics g = Graphics.FromImage(image);
PointF center = new PointF((float)Image.Width / 2, Image.Height / 2);
int bufferAmount = 5;
g.DrawRectangle(Pens.White, center.X - (Image.Width + bufferAmount) / 2, center.Y - (Image.Height + bufferAmount) / 2, Image.Width + bufferAmount, Image.Height + bufferAmount);
pictureBox.Image = image;
}
Thanks
You can create a Graphics from the image using the FromImage method, then use Graphics drawing methods to draw whatever you like. Here is a code sample:
System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(yourImage);
//you may use any pen
graphics.DrawRectangle(System.Drawing.Pens.Blue,0,0,yourImageWidth,yourImageHeight)
yourPictureBox.Image = yourImage;
Create a Graphics object from your image and draw onto it by using a Pen defining the border strength and its color:
using (var gfx = Graphics.FromImage(img))
{
using (var pen = new Pen(MYCOLOR, 3)
gfx.DrawRectangle(pen, MYRECT)
}
Note, this will manipulate your source image directly. If you want to have two images, one with and another without a border, you should clone your image before you draw over it:
var imgWithBorder = img.Clone();
// work with imgWithBorder ...

Drawline with same pen width, but the line widths are different in result

I draw lines with the same pen, but the line widths are different in result. Why?
Bitmap b = new Bitmap(400, 400);
Graphics g = Graphics.FromImage(b);
g.PageUnit = GraphicsUnit.Point;
g.Clear(Color.White);
Pen pen = new Pen(Color.Red, 1.2f);
for (int i = 20; i < 200; i = i + 20)
{
g.DrawLine(pen, 10, i, 190, i);
}
g.Dispose();
b.Save("d:/temp/test.png", ImageFormat.Png);
b.Dispose()
Here is the result:
MSDN for GraphicsUnit
It's because you're working with Points and not Pixels and the variation in the width of the lines is the result of a rounding errors in the placement of the line and the width of the line in relation to how it gets rendered in pixels in the final product.
If you don't care about printing the image, it might be best to stick with Pixels.
Edit: If you want to continue using points, space things relative to your pen width:
Bitmap b = new Bitmap(400, 400);
Graphics g = Graphics.FromImage(b);
g.PageUnit = GraphicsUnit.Point;
g.Clear(Color.White);
Pen pen = new Pen(Color.Red, 1.2f);
for (float i = 20f * pen.Width; i < 200f * pen.Width; i = i + 20f * pen.Width)
{
g.DrawLine(pen, 10f, i, 190f, i);
}
g.Dispose();
b.Save("c:/temp/test.png", ImageFormat.Png);
b.Dispose();

GraphicsPath eliminate text border

I'm using the GraphicsPath object to draw text in a rectangle. The rectangle is larger than the text, and I want to draw the text in any of the rectangle's corners, and also at the center of its edges.
The problem I have is that when I draw the path, a border is being left around the source rectangle. I want to be able to eliminate that border and make the text touch its bounding rectangle.
Here is the code I have:
private void Form1_Paint(object sender, PaintEventArgs e)
{
var g = e.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality;
Rectangle textRect = new Rectangle(100, 100, 150, 150);
Font f = new Font("Arial", 16);
float emSize = f.Height * f.FontFamily.GetCellAscent(f.Style) /
f.FontFamily.GetEmHeight(f.Style);
foreach (StringAlignment lineAlignment in Enum.GetValues(typeof(StringAlignment)))
{
foreach (StringAlignment alignment in Enum.GetValues(typeof(StringAlignment)))
{
StringFormat sf = new StringFormat() { LineAlignment = lineAlignment, Alignment = alignment };
using (GraphicsPath gp = new GraphicsPath())
{
gp.AddString("txt", f.FontFamily, (int)f.Style, emSize, textRect, sf);
RectangleF bounds = gp.GetBounds();
g.FillPath(Brushes.Black, gp);
g.DrawRectangle(Pens.Red, Rectangle.Round(bounds));
}
}
}
g.DrawRectangle(Pens.Blue, textRect);
}
And here is the result:
Basically, I want the red rectangles (and the text they contain) to touch the blue rectangle, and to eliminate the border between them. Also, I need to use the GraphicsPath and not DrawString.
I ended up writing a helper method to calculate the offset of the rectangles and translate the text before drawing it. Here is the method I wrote:
private PointF FixAlignment(RectangleF parentRect, RectangleF childRect,
StringAlignment lineAlignment, StringAlignment alignment)
{
float xOffset = 0;
float yOffset = 0;
switch (lineAlignment)
{
case StringAlignment.Near:
yOffset = parentRect.Top - childRect.Top;
break;
case StringAlignment.Far:
yOffset = parentRect.Bottom - childRect.Bottom;
break;
}
switch (alignment)
{
case StringAlignment.Near:
xOffset = parentRect.Left - childRect.Left;
break;
case StringAlignment.Far:
xOffset = parentRect.Right - childRect.Right;
break;
}
return new PointF(xOffset, yOffset);
}
I used it in the Form1_Paint method like this:
private void Form1_Paint(object sender, PaintEventArgs e)
{
var g = e.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality;
Rectangle textRect = new Rectangle(100, 100, 150, 150);
Font f = new Font("Arial", 16);
float emSize = f.Height * f.FontFamily.GetCellAscent(f.Style) /
f.FontFamily.GetEmHeight(f.Style);
foreach (StringAlignment lineAlignment in Enum.GetValues(typeof(StringAlignment)))
{
foreach (StringAlignment alignment in Enum.GetValues(typeof(StringAlignment)))
{
StringFormat sf = new StringFormat() { LineAlignment = lineAlignment, Alignment = alignment };
using (GraphicsPath gp = new GraphicsPath())
{
gp.AddString("txt", f.FontFamily, (int)f.Style, emSize, textRect, sf);
RectangleF bounds = gp.GetBounds();
// Calculate the rectangle offset
PointF offset = FixAlignment(textRect, bounds, lineAlignment, alignment);
// Translate using the offset
g.TranslateTransform(offset.X, offset.Y);
g.FillPath(Brushes.Black, gp);
g.DrawRectangle(Pens.Red, Rectangle.Round(bounds));
// Translate back to the original location
g.TranslateTransform(-offset.X, -offset.Y);
}
}
}
g.DrawRectangle(Pens.Blue, textRect);
}
Here is the result:

Categories

Resources