How to move an image in picturebox using mouse events - c#

i am trying to move a image in picture box. i added panel to my application and also added picture box in panel. i opened an image.if the image size is big.i want to see the particular portion of image. so how can i move the image up and down (without using scroll bars) to see the particular portion of image?

You can add controls like move left, move right, move up, move down with associated actions to move the image within your picturebox. An example of how to do this for moving the image to the right is shown below. You can implement these action with mouse down and mouse up events so that the user just presses the appropriate buttons to move the picture as he wants. Also note that once you reach the maximum dimensions of the image, you can change the rectangular region to that within image bounds.
int ff = 0; //number of positions to move
Bitmap b2;
private void button1_Click(object sender, EventArgs e)
{
if (ff == 0) { b2 = new Bitmap(pictureBox1.Image);} //original image as bitmap b2
Bitmap b1 = new Bitmap(pictureBox1 .Width ,pictureBox1.Height ); //new bitmap with rectangular region of original image
Rectangle r1 = new Rectangle(ff++, 0, pictureBox1.Width, pictureBox1.Height );
Graphics g = Graphics.FromImage(b1);
g.DrawImage(b2, 0, 0, r1, GraphicsUnit.Pixel);
g.Dispose();
pictureBox1.Image = null;
pictureBox1.Image = (Image)b1;
pictureBox1.Refresh();
}

Not sure if it really answers your question, but this seems like a fun reason to play with Reactive Extensions (Rx). This video demonstrates nicely how well this stuff works with asynchronous events like mouse-input.

Related

Convert Graphics object to Bitmap

I do have following issue with my graphics object.
EDIT:
I do have a picturebox_image (imageRxTx) which is a live stream from a camera. What I do in the paint event is to draw some lines on top of the image imageRxTx (not shown in the code below). This works so far without problem.
Now I need to check for circles in imageRxTx and therefore I have to use the method ProcessImage() which needs a Bitmap as parameter. Unfortunately I do not have the Bitmap image but rather the handle (hDC) to my imageRxTx.
Question: How can I get the imageRxTx from my graphics-object and "convert" it to a bitmap-image which I need to use in the method ProcessImage(Bitmap bitmap)? This method needs to be called continously in the paint-event in order to check the live-stream of my camera (imageRxTx).
Here my code:
private void imageRxTx_paint(object sender, PaintEventArgs e)
{
var settings = new Settings();
// Create a local version of the graphics object for the PictureBox.
Graphics Draw = e.Graphics;
IntPtr hDC = Draw.GetHdc(); // Get a handle to image_RxTx.
Draw.ReleaseHdc(hDC); // Release image_RxTx handle.
//Here I need to send the picturebox_image 'image_RxTx' to ProcessImage as Bitmap
AForge.Point center = ProcessImage( ?....? );
}
// Check for circles in the bitmap-image
private AForge.Point ProcessImage(Bitmap bitmap)
{
//at this point I should read the picturebox_image 'image_RxTx'
...
The video image is updated here:
private void timer1_Elapsed(object sender, EventArgs e)
{
// If Live and captured image has changed then update the window
if (PIXCI_LIVE && LastCapturedField != pxd_capturedFieldCount(1))
{
LastCapturedField = pxd_capturedFieldCount(1);
image_RxTx.Invalidate();
}
}
As the title suggests, your main problem is a (common) misconception about what a Graphics object is.
So far I can draw to my graphics object without problem
No! A 'Graphics' object does not contain any graphics. It is only the tool used to draw graphics onto a related Bitmap. So you don't draw onto the Graphics object at all; you use it to draw onto imageRxTx, whatever that is, probably the surface of some Control or Form..
This line is using an often confusing rather useless format of the Bitmap constructor:
Bitmap bmp = new Bitmap(image_RxTx.Width, image_RxTx.Height, Draw);
The last parameter is doing next to nothing; its only function is to copy the Dpi setting. In particular it does not clone or copy any content from 'Draw', which, as you know now, a Graphics object doesn't have anyway, nor any of its other settings. So yes, the bmp Bitmap is still empty after that.
If you want to draw into bmp you need to use a Graphics object that is actually bound to it:
using (Graphics G = Graphics.FromImage(bmp)
{
// draw now..
// to draw an Image img onto the Bitmap use
G.DrawImage(img, ...);
// with the right params for source and destination!
}
None of this should probably happen in the Paint event! But all the preparation code is unclear as to what you really want to do. You should explain just what is the source of the drawing and what is the target!
If instead you want to get the stuff you draw onto image_RxTx into a Bitmap you can use this method somwhere outside (!) the Paint event:
Bitmap bmp = new Bitmap(image_RxTx.Width, image_RxTx.Height);
image_RxTx.DrawToBitmap(bmp, image_RxTx.ClientRectangle);
This will use the Paint event to draw the control into a Bitmap. Not that the result includes the whole PictureBox: The BackgroundImage, the Image and the surface drawing!
Update: To get the combined content of the PictureBox, that is both its Image and what you have drawn onto the surface, you should use the code above (the last 2 lines) in the Tick event of a Timer or right after the line that triggers the Paint event. (You didn't show us how that happens.) You can't acutally put it in the Paint event itself, as it will use the Paint event and therefore would cause an infinite loop!
The method Graphics.CopyFromScreen is probably what you're looking for.
var rect = myControl.DisplayRectangle;
var destBitmap = new Bitmap(rect.Width, rect.Height, PixelFormat.Format24bppRgb);
using (var gr = Graphics.FromImage(destBitmap))
{
gr.CopyFromScreen(myControl.PointToScreen(new Point(0, 0)), new Point(0, 0), rect.Size);
}

Best way to make images scrollable that where painted on the control

I draw images (lets say 200x200) on control in C# depending on how many there are (could be over 100) they get drawn offscreen since they are stacked one above the other. What is the best way to make a dynamic scroll so that i can scroll to the ones that are offscreen.
I was thinking of using a Panel and painting them on there and then just place the Panel on the control. But with the panel being transparent and the control on which the panel is sitting is changing its image (its a map that you can move with draging) the panel lags behind when drawing and creates a ugly jitter effect.
So are there any good solutions where i wont need to implement the whole logic of a scroller myself for such a solution?
PictureBox is doublebuffered and will take care of the flicker.
For your case don't draw onto a control, no matter which, but instead draw into a PictureBox's Image.
Put the PictureBox inside an autoscroll panel and make it a large as the Size you need. No jitter, smooth scrolling..
Here is an example. It randomly draws around 200 small images into the Image of a PictureBox. I create the Image with a large size and I put the PB into a Panel:
Random R = new Random();
private void button1_Click(object sender, EventArgs e)
{
panel1.AutoScroll = true;
pictureBox1.Parent = panel1;
pictureBox1.Location = Point.Empty;
pictureBox1.Image = new Bitmap(3000, 500);
pictureBox1.ClientSize = pictureBox1.Image.Size;
var imgFiles = Directory.GetFiles(#"D:\scrape\", "*.png");
foreach(string file in imgFiles)
{
using (Graphics G = Graphics.FromImage(pictureBox1.Image))
using (Bitmap bmp = new Bitmap(file))
{
if (bmp.Size.Width < 300)
{
for (int i = 0; i < 10; i++ )
G.DrawImage(bmp, R.Next(2500), R.Next(400));
}
}
}
}
You can easily adapt it to your own project, I'm sure..

How can I correctly align an image to the right edge of a "Label"?

Using a standard Label I aligned my image to the right side.
However there is a small indent (marked in red) that I cannot remove.
So my question: Is there an easy way to correctly align/snap an image to the right edge of a label? Or do I need to edit the label paint method so I can manually draw the image?
The label in question sits inside a "Panel", the following is my code:
label1.BackColor = System.Drawing.Color.Red;
label1.Image = global::TestProject.Properties.Resources.Header;
label1.ImageAlign = System.Drawing.ContentAlignment.MiddleRight;
label1.Size = new System.Drawing.Size(200, 40);
The simple answer appears to be: No there is no easy way to correctly align the image.
The "PictureBox" seems like the preferred component for working with images, however the image can be correctly aligned by editing the paint method of the label:
label1.Paint += new System.Windows.Forms.PaintEventHandler(this.label1_Paint);
And the paint method:
private void label1_Paint(object sender, PaintEventArgs e)
{
Image image = global::TestProject.Properties.Resources.Header;
Graphics g = e.Graphics;
//Align to far right: label width - image width
g.DrawImage(image, this.label1.Width - image.Width, 0);
}

C# drawing on picturebox, not persistent

I have a List<> object, "imagelist", that contains the paths of many images such as .png's. Now, with the following code:
private void paint_picture(PictureBox picture, string pathofpic)
{
Graphics g = picture.CreateGraphics();
Bitmap drawnpic = null;
if (imagelist.ContainsKey(picture.Name))
{
drawnpic = new Bitmap(pathofpic);
g.DrawImage(drawnpic, 0, 0, picture.Size.Width, picture.Size.Height);
imagelist[picture.Name] = pathofpic;
}
drawnpic.Dispose();
g.Dispose();
}
I call this every time the card's image is changed, but I can't seem to make the image persist on the picturebox, when I drag the picturebox across the form (for example, over other pictureboxes). The click and drag code is just moving the picturebox with the mouse, not really relevant.
I've tried invalidating the form when I de-select the image, but it doesn't do anything.
Is there something I'm missing? Screenshot below, I dragged one image around the form and it overwrote the other images it moved across:
That’s how painting works – you have to handle its Paint event and keep painting the same thing each time it needs repainting.
What you can do is draw on top of your original image:
Bitmap b = new Bitmap(picture.Image);
using (Graphics g = Graphics.FromImage(b)) {
using (Bitmap drawnpic = new Bitmap(pathofpic)) {
g.DrawImage(drawnpic, 0, 0, b.Width, b.Height);
}
}
picture.Image = b;
Then you’d save the original image somewhere and probably use it instead of picture.Image in the new Bitmap line.
And PascalCase for method names, please. ;)

Drawing in Winforms

I have written this code, however, it doesn't work. Not only will this not work, but none of the methods I have tried for drawing have worked. I've spent more than an hour or two trying to solve this, but to no success. Ive tried simple programs where all it does is display a small line, but it wont work no matter what i do :c
What am I doing wrong, or what could cause this?
private void pictureBox1_MouseDown(object sender,
MouseEventArgs m,
EventArgs e,
PaintEventArgs q)
{
if (m.Button == System.Windows.Forms.MouseButtons.Left)
{
Point currpoint = System.Windows.Forms.Cursor.Position;
Point origin = new Point(0, 0);
decimal sizee = nud.Value;
int size = Convert.ToInt32(sizee);
Random randonGen = new Random();
Color randomColor = Color.FromArgb(randonGen.Next(255),
randonGen.Next(255),
randonGen.Next(255));
Pen selPen = new Pen(randomColor, size);
Graphics g = Graphics.FromImage(pictureBox1.Image);
g.DrawLine(selPen, 3, 3, 133, 133);
}
}
Try adding a
pictureBox1.Invalidate();
call.
This is not the right way to draw to a picture box:
private void pictureBox1_MouseDown(object sender,
MouseEventArgs m,
EventArgs e,
PaintEventArgs q)
{
if (m.Button == System.Windows.Forms.MouseButtons.Left)
{
Point currpoint = System.Windows.Forms.Cursor.Position;
Point origin = new Point(0, 0);
decimal sizee = nud.Value;
int size = Convert.ToInt32(sizee);
Random randonGen = new Random();
Color randomColor = Color.FromArgb(randonGen.Next(255),
randonGen.Next(255),
randonGen.Next(255));
Pen selPen = new Pen(randomColor, size);
using(Graphics g = pictureBox1.CreateGraphics()) // Use the CreateGraphics method to create a graphic and draw on the picture box. Use using in order to free the graphics resources.
{
g.DrawLine(selPen, 3, 3, 133, 133);
}
}
}
Btw, this method will create a temporary image which is reseted when the control is invalidated. For a more persistent drawing, you need to listen to the Paint event of the picture box and draw your graphics there.
You must draw it from image first. then attach it to pictureBox1
Bitmap canvas = new Bitmap(pictureBox1.Width, pictureBox1.Height);
Graphics g = Graphics.FromImage(canvas);
Point currpoint = System.Windows.Forms.Cursor.Position;
Point origin = new Point(0, 0);
decimal sizee = nud.Value;
int size = Convert.ToInt32(sizee);
Random randonGen = new Random();
Color randomColor = Color.FromArgb(randonGen.Next(255),
randonGen.Next(255),
randonGen.Next(255));
Pen selPen = new Pen(randomColor, size);
g.DrawLine(selPen, 3, 3, 133, 133);
pictureBox1.image = canvas;
This is an old question and if anyone else has a similar problem. See below. First let's examine the Ops code.
(1) See code: The first recommended change is to keep the Pen's format simple until we have a better understanding about how the Pen actually works when drawing to graphics. Look at the Op's line where we create graphics from image which is a perfectly good example of how to directly draw ("which means to write") to the supplied bitmap by use of the bitmap's graphics context. Next, the Op provides an excellent example of the Graphics DrawLine method which can draw the defined line to the supplied bitmap.
(2) Due to missing details we have to make the following assumptions about the Op's supplied bitmap and about their method for drawing a line to the bitmap. Assuming there already exists an image inside this pictureBox1; if an image is not set the graphics we get from image will be from a null image or that each pixel will be black just as a footnote:
(a) Is the Pen's color unique to the existing bitmap and is the alpha component of the color high enough to actually see the resultant color when it's drawn (when in doubt use a unique solid color or at least set the alpha channel to 255)?
(b) This line the Op wants to draw is starting Left 3, Top 3 to Left 133 and that is 3-pixels to the right of bitmap's left side where this line has a height of 133 and as such the Pen's line size was changed to a width = 3 for demonstration purposes.
(c) The final consideration, is the pictureBox1.Size sufficient for us to see this drawn line? The line's geometry forms a rectangle similar to this RectangleF(3, 3, 3, 133) structure, so if the pictureBox1 Bounds rectangle intersects with the derived line's rectangle then the area of that intersection is where the line could be drawn and considered visible.
Before we can draw to the pictureBox1 image from graphics we must first convert the pictureBox1 image data back to a usable image type like a bitmap for example. The reason is the picture box stores only pixel data in array format and is not directly usable by GDI/GDI+ without conversion to an image type ie. bitamp, jpeg, png etc..
One can avoid this messy conversion if you handle you own painting by the way of a custom user control and by properly handling the PaintEventArgs OnPaint implementation and/or by using related graphics screen buffer context scenarios.
For those who just want the answer about what's missing:
private void button1_Click(Object sender, EventArgs e)
{
Pen selPen = new Pen(Color.Red, 2); // The Op uses random color which is not good idea for testing so we'll choose a solid color not on the existing bitmap and we'll confine our Pen's line size to 2 until we know what we're doing.
// Unfortionately the picture box "image" once loaded is not directly usable afterwords.
// We need tp recreate the pictureBox1 image to a usable form, being the "newBmp", and for efficiency the bitmap type is chosen
Bitmap newBmp = new Bitmap(pictureBox1.Width, pictureBox1.Height, PixelFormat.Format32bppArgb); // Tip: Using System.Drawing.Imaging for pixel format which uses same pixel format as screen for speed
// We create the graphics from our new and empty bitmap container
Graphics g = Graphics.FromImage(newBmp);
// Next we draw the pictureBox1 data array to our equivelent sized bitmap container
g.DrawImage(pictureBox1.Image, 0, 0);
g.DrawLine(selPen, 3, 3, 3, 133); // Format: (pen, x1, y1, x2, y2)
pictureBox1.Image = newBmp;
// Don't forget to dispose of no longer needed resources
g.Dispose();
selPen.Dispose();
newBmp.Dispose(); // or save newBmp to file before dispose ie. newBmp.Save("yourfilepath", ImageFormat.Jpeg) or in whatever image type you disire;
}
The Op's code so far only draws a line to the bitmap's surface next if we are to "see" this change we must either save bitmap to file to be viewed later in an image viewer or we must draw the updated bitmap to our display monitor, the screen.
There are several methods with which to draw to your monitor's screen. The most common graphics contexts one could use are Control.CreateGraghics, graphics to screen method from (PaintEventArgs) and/or by using a graphics screen buffer sometimes called and used as a manual double buffered graphics context in which all is implemented by the way of DrawImage method from graphics.
The simplest solution, in this case based upon the Op's own code, is to display this newly updated bitmap using the pictureBox1 control. We'll simply update the control's image with the newly updated bitmap of course once first converted to a usage graphics image as seen in the above code descriptions.
Happy coding!

Categories