Drawing line at different position of cursor - c#

[![enter image description here][10]][10]
I am drawing a line on picture in picture Box and saving this picture in a folder(my computer). When i am trying to draw line, it draws line on different position rather than cursor position.
code---
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (paint)
{
Pen ppen = new Pen(Color.Black,1);
Bitmap bmp = new Bitmap(pictureBox1.Image);
try
{
Gr =Graphics.FromImage(bmp);
Gr.DrawLine(ppen,e.X,e.Y,Xold, Yold);
pictureBox1.Image = bmp;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString(), "Error",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
Xold = e.X;
Yold = e.Y;
}

For this to work you need to make sure that the PB doesn't zoom or stretch (or even center) the image.
Set SizeMode = Normal !
If you need a different SizeMode you will have to do a little math to calculate the image coodinates form the image.Size and the PB.ClientSize..
The calculation is simple but will be different for each SizeMode:
For Center all you need is to add an offset to one of the coordinates.
For Zoom You need to calculate the zoom factor and multiply it into both coordinates.
And for Stretch you need to calculate the zoom factors of both dimensions independently and multiply it into each respective coordinate.
Btw: The way you draw lines by ading single lines will work only for simple Pens. Once you use semitransparent pens or fancy linecaps you will see artifacts at the junctions. If you need to avoid these, collect the points and use DrawLines (pl!) in the Paint event; then, upon MouseUp draw them into the Bitmap and then clear the list of points..

Related

Saving off picturebox composed of image and drawings

Here is what I am trying to do. I have an Image that is 1920X1080. I am showing that image in a PictureBox and allowing a user to draw an ellipse on the screen. Once they finish that I will need to save that image off with the image and ellipse in 1 photo.
So I have tried several ways:
1. Just trying to save the image and ellipse from the PictureBox. No success doing that.
2. To store the location of the ellipse on the picture box and then redraw that ellipse on a new copy of the image using a graphics object. The problem with this one is that when it saves off the ellipse is not in the right place due to the size of the PictureBox and the original image difference.
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
pictureBox1.Cursor = Cursors.Default;
if (isMoving)
{
Circles.Add(mouseDownPosition, mouseMovePosition);
}
isMoving = false;
}
Bitmap newImage = new Bitmap(new Bitmap(#"C:\Personal\test\Sample.jpg"));
Graphics g = Graphics.FromImage(newImage);
foreach (var circle in Circles)
{
g.DrawEllipse(new Pen(Color.Red, 3), new Rectangle(circle.Key, new Size(circle.Value.X - circle.Key.X, circle.Value.Y - circle.Key.Y)));
}
newImage.Save(#"C:\Projects\Projects\SampleCombine.jpg");
I am really just looking for a way to take exactly what I see on the PictureBox and save it as its own jpg.
My take is that I need to figure out how to reposition the "Circle" based on where it was drawn and where it should be drawn on a larger file.
Any ideas?

How zoom into a drawn rectangle of picturebox which is inside a panel?

I have a PictureBox inside a Panel in order to zoom and pan. I created the possibility to select 4 points with the mouse click and draw a rectangle on the PictureBox. Once the rectangle is over my picture I pass the coordinates of the rectangle to the method "cropRectangle". This method crops the rectangle and replace the old image with the cropped one. This works very well:
(OriginalImage is the bitmap of the actual image in the pictureBox)
private void cropRectangle(Rectangle rect){
double left = (rect.X) * originalImage.Width / pictureBox.Width,
top = (rect.Y) * originalImage.Width / pictureBox.Height,
right = (rect.Width) * originalImage.Width / pictureBox.Width,
bottom = (rect.Height) * originalImage.Height / pictureBox.Height;
rect = new Rectangle (Convert.ToInt32(left), Convert.ToInt32(top), Convert.ToInt32(right), Convert.ToInt32(bottom));
Bitmap bitmap = orignalImage.Clone(rect, originalImage.PixelFormat);
pictureBox.Image = (Image)bitmap;
centerPictureBox();
// fit image into pictureBox with respect to the ratio
float ratio = orignalImage.Width / orignalImage.Height;
pictureBox.Width = panel.Width;
pictureBox.Height = Convert.ToInt32(pictureBox.Width * ratio);
centerPictureBox();
}
What I am trying to do now is to zoom the selected area instead to crop it. The rectangle of the picturebox has to match with the panel.
How can I show only the selected area (rectangle) of the picturebox through the panel without cropping the image?
You should stick with modifying the existing Bitmap using the Graphics object instead of changing the size of the PictureBox. You don't want to be tied to a UI control when the desired functionality is already available elsewhere.
Here are rough steps to achieve that:
Create a temporary Bitmap object that will store the zoomed image. Bitmap tBitmap = new Bitmap(zoomX, zoomY, PixelFormat.Format24bppRgb);
Calculate the zoom factors and stuff like you already do (I didn't check if the code is correct but I assume that it is) when you want to zoom.
Create a new Graphics object from the temporary bitmap. Graphics graphics = Graphics.FromImage(tBitmap);
Set the InterpolationMode so that the image is scaled with a good quality. graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
Draw the zoomed image using the DrawImage method (using the original image from the PictureBox). graphics.DrawImage(pictureBox.Image, new Rectangle(0, 0, pictureBox.Width, pictureBox.Height), new Rectangle(/*The crop rectangle you draw already*/), GraphicsUnit.Pixel);
Set the newly drawn bitmap as the Image in your PictureBox. pictureBox.Image = tBitmap;
Remember to dispose of the graphics object we used for drawing. graphics.Dispose();
You might need to refresh the PictureBox to force it to redraw itself. pictureBox.Refresh();
Those are the basic steps to follow. I didn't have time to go through your existing code that deeply so you might need to change some additional things to make it work.
Here's also an MSDN article that covers the same stuff: Cropping and Scaling Images in GDI+
You might be interested in this control (ZoomPicBox) which allows for zooming and panning a picture box.
All credit for this code is Bob Powell and it was taken from his site (which seems to be down now and has been for a long time now.).
I copied the code from archive.org at this link:
https://web.archive.org/web/20080313161349/http://www.bobpowell.net/zoompicbox.htm
That link has additional information and is worth a read. The code is available in VB.Net as well.
I don't know why Bob Powell's site is down, but it was a great site for Windows Graphics information.
I felt this code was worth repeating. This control can be dragged onto the form.
namespace bobpowell.net
{
/// <summary>
/// ZoomPicBox does what it says on the wrapper.
/// </summary>
/// <remarks>
/// PictureBox doesn't lend itself well to overriding. Why not start with something basic and do the job properly?
/// </remarks>
public class ZoomPicBox : ScrollableControl
{
Image _image;
[
Category("Appearance"),
Description("The image to be displayed")
]
public Image Image
{
get{return _image;}
set
{
_image=value;
UpdateScaleFactor();
Invalidate();
}
}
float _zoom=1.0f;
[
Category("Appearance"),
Description("The zoom factor. Less than 1 to reduce. More than 1 to magnify.")
]
public float Zoom
{
get{return _zoom;}
set
{
if(value<0 || value<0.00001)
value=0.00001f;
_zoom=value;
UpdateScaleFactor();
Invalidate();
}
}
/// <summary>
/// Calculates the effective size of the image
///after zooming and updates the AutoScrollSize accordingly
/// </summary>
private void UpdateScaleFactor()
{
if(_image==null)
this.AutoScrollMinSize=this.Size;
else
{
this.AutoScrollMinSize=new Size(
(int)(this._image.Width*_zoom+0.5f),
(int)(this._image.Height*_zoom+0.5f)
);
}
}
InterpolationMode _interpolationMode=InterpolationMode.High;
[
Category("Appearance"),
Description("The interpolation mode used to smooth the drawing")
]
public InterpolationMode InterpolationMode
{
get{return _interpolationMode;}
set{_interpolationMode=value;}
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
// do nothing.
}
protected override void OnPaint(PaintEventArgs e)
{
//if no image, don't bother
if(_image==null)
{
base.OnPaintBackground(e);
return;
}
//Set up a zoom matrix
Matrix mx=new Matrix(_zoom,0,0,_zoom,0,0);
//now translate the matrix into position for the scrollbars
mx.Translate(this.AutoScrollPosition.X / _zoom, this.AutoScrollPosition.Y / _zoom);
//use the transform
e.Graphics.Transform=mx;
//and the desired interpolation mode
e.Graphics.InterpolationMode=_interpolationMode;
//Draw the image ignoring the images resolution settings.
e.Graphics.DrawImage(_image,new Rectangle(0,0,this._image.Width,this._image.Height),0,0,_image.Width, _image.Height,GraphicsUnit.Pixel);
base.OnPaint (e);
}
public ZoomPicBox()
{
//Double buffer the control
this.SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.ResizeRedraw |
ControlStyles.UserPaint |
ControlStyles.DoubleBuffer, true);
this.AutoScroll=true;
}
}
}
I have found a elegant solution to my problem:
private void zoomInsideRectangle(Rectangle rect){
float zoomFactor = ((float)panel.Width / rect.Width) - 1;
pictureBox.Width = pictureBox.Width + convertToIntPerfect(pictureBox.Width * zoomFactor);
pictureBox.Height = pictureBox.Height + convertToIntPerfect(pictureBox.Height * zoomFactor);
rect.X = rect.X + convertToIntPerfect(rect.X * zoomFactor);
rect.Y = rect.Y + convertToIntPerfect(rect.Y * zoomFactor);
pictureBox.Left = convertToIntPerfect(-rect.X);
pictureBox.Top = convertToIntPerfect(-rect.Y);
}
Since I know the length of the panel where I can see the picturebox. I take the ratio of the panel and the width of my rectangle that I want to zoom in. This ratio is my zoomratio.
I multiply the size of the picturebox with the ratio that I calculated.
I anchor the picturebox by the left and top with the coordinates of my rectangle. But right before doing that I have to multiply my coordinates of my rectangle with the zoomratio since I changed the size of the picturebox.
I didn't implemented the Y transformation since the original ratio of the image will be damaged.

Draw rectangle in picture box C#

I have an application that shows different images in a pictureBox. There are a few other picture boxes that do other things and I want to keep the default paint method.
When the image is correct I have to draw a green rectangle and when the image is incorrect I don't have to do anything.
I have seen that it is needed to override the paint method to draw rectangles but if I override the method it will always draw the green rectangle.
EDIT:
I have written this method:
private void pictureBox_Paint(object sender, PaintEventArgs e)
{
Rectangle rect = new Rectangle(e.ClipRectangle.X, e.ClipRectangle.Y, e.ClipRectangle.Width, e.ClipRectangle.Height);
e.Graphics.DrawRectangle(new Pen(Color.Green, 20), rect);
}
And I call add the event to it like this:
pbFrontView.Paint += pictureBox_Paint;
pbLeftView.Paint += pictureBox_Paint;
So, I have many picture boxes and different images (this is in my main function)
if(drawRectanglePbFront)
//Draw rectangle in pbFrontView
if(drawRectanglePbLeft)
//Draw rectangle in pbLeft
...
Is there any way to know which pinture box has invoked "pictureBox_Paint" ? If, yes I could move "if(drawRectanglePbFront) ..." inside of "pictureBox_Paint" and manage everything there

I need to render an image on top of a drawn Object

I need to make a program that'll enable the user to customize his own car.
My problem is I have to draw the customizables by code and I have to add a PNG image of details on top of the drawn car.
The user has to select the colors, rim designs, and decals from the right
The car will be drawn when the PIMP button is pressed.
I have to add the PNG image, the second image, on top of the drawn image(first image), to make it look like the third image.
My current code looks like:
private void button1_Click(object sender, EventArgs e)
{
Graphics g;
g = this.CreateGraphics();
if (color == 1)
{
g.FillPolygon(blue, body);
}
else if (color ==2)
{
g.FIllPolygon(red, body);
}
g.FillPolygon(blackBrush, window);
pCard.Visible = True;
//pCard is an existing PictureBox where the Image is the cardetails.PNG
backcolor = transparent
}
When I press the PIMP button it draws the first image, but when it draws the PictureBox of cardetails.png, the transparent color displays the color gray and covers the first image.
I am very new to C# and Visual Basic. The only thing i know how to do here is to draw that blue car.
Load the image that contains the details you want to add:
Image decalImage = Image.FromFile("cardetails.png");
It would probably be best if you do not load it in your button1_Click method.
Then draw the image upon your graphics object using
g.DrawImage(decalImage, x, y);
Where x and y would be the position to draw it to.

PictureBox performing unwanted scaling C#

I currently have a windows form app with a pictureBox in the middle of it which i am drawing various images too. The images are drawing fine except for the fact that they are all being scaled up by exactly 25%. I should also add that i am drawing everything inside a Paint method, using the PaintEventArgs to get the graphics device.
Ive made sure the SizeMode is set to Normal, ive checked over and over that the scale factor of the graphics object is 1 and all the image objects that i pass to the paint method are of the size they should be, but when they get drawn they are a different size.
I have until now just been calling g.drawImage(image, Rectangle) and passing the width and height of the image as the width and height of the Rectangle so that they are forced to be drawn at the correct size but i feel that this should be a short term fix and i am overlooking something simple.
Any help would be great, thanks in advance.
Code is as follows (only the important bits):
public class Level : PictureBox
{
...
private Image image;
...
public Level(TabPage parent, Panel propertiesPanel, ItemManager items, string levelName)
{
...
image = Image.FromFile(#"Levels/" + levelName);
Size = image.Size;
SizeMode = PictureBoxSizeMode.Normal;
MouseClick += new MouseEventHandler(level_MouseClick);
MouseMove += new MouseEventHandler(level_MouseMove);
Paint += new PaintEventHandler(level_Paint);
Invalidate();
}
private void level_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
//With the rectangle fix (drawing to correct size)
g.DrawImage(image, new Rectangle(0, 0, image.Size.Width, image.Size.Height));
////Without the fix (as i thought it should be be this is where it scales it)
//g.DrawImage(image, new Point(0, 0));
drawPlacedItems(g);
drawItemPreview(g);
}
This sounds like the HorizontalResolution and VerticalResolution properties of your image are being applied when you don't want them to, modify your code as per Jeremy's link to Image sizing issue in bitmap that ensures that HorizontalResolution and VerticalResolution are reset or ignored before calling DrawImage.

Categories

Resources