winform move an image inside a picturebox - c#

I've been trying to do this for a few hours now, but for the life of me I can't make it possible.
What I'm trying to do is simply move the image found within a picture box in a winform application. My image is roughly 1000x1000 pixels and my box is something arbitrary like 400x500, so, for example, when I click the mouse I'd want the image to move 50 to the left. But the image box should remain the same size.
For the life of me, however, I can't get this to work. What I have been able to do is the following:
if (kinectController.hands[0].fingertips.Count == 1)
{
pictureBox1.SizeMode = PictureBoxSizeMode.CenterImage;
}
This function is for my kinect finger tracking app. So when the application finds a single finder point visiable on the screen, the image is centered. However, I would eventually like the image to move along with my finger movement, which will come once I work out the basic step of moving the image a few pixels to the side.
Any help with this would be appreciated.

I did a little bit of research and apparently moving an image within a PictureBox is no easy task, at the very least I couldn't find anything that would make this possible (not saying there isn't a way to do it though).
However, I came up with a bit of a "workaround", see if this fits your needs. To accomplish this:
Create a Panel control, and size it to however much of the image you
would like to display
Inside that panel place a PictureBox control with your image in it
and set the SizeMode property to AutoSize.
Now, put this code in your form
private bool Dragging;
private int xPos;
private int yPos;
private void pictureBox1_MouseUp(object sender, MouseEventArgs e) { Dragging = false; }
private void pictureBox1_MouseDown(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
Dragging = true;
xPos = e.X;
yPos = e.Y;
}
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e) {
Control c = sender as Control;
if (Dragging && c!= null) {
c.Top = e.Y + c.Top - yPos;
c.Left = e.X + c.Left - xPos;
}
}
Now whenever you click and drag on the PictureBox, it won't actually move the image within it, but the PictureBox control within the panel. Again, not exactly what you were looking for and I'm not sure how this would convert over to Kinect, but I hope this gets you on the right track.

Not enough reputation to comment but I wanted to add on Ben Black answer if someone ever need more control over the image moving around so you can't move the image past it's borders :
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
Control c = sender as Control;
if (Dragging && c != null)
{
int maxX = pictureBox1.Size.Width * -1 + panel.Size.Width;
int maxY = pictureBox1.Size.Height * -1 + panel.Size.Height;
int newposLeft = e.X + c.Left - xPos;
int newposTop = e.Y + c.Top - yPos;
if (newposTop > 0)
{
newposTop = 0;
}
if (newposLeft > 0)
{
newposLeft = 0;
}
if (newposLeft < maxX)
{
newposLeft = maxX;
}
if (newposTop < maxY)
{
newposTop = maxY;
}
c.Top = newposTop;
c.Left = newposLeft;
}
}

Related

Panning Image in pictureBox not working

I have developed windows application in c# where I have a pictureBox inside a panel. I have applied zoom in and zoom out functionality in it. Now I want the image inside the pictureBox to pan. I have applied mouseDown, mouseMove and mouseUp event on pictureBox. The code for it is:
private void pictureBox2_MouseDown(object sender, MouseEventArgs e)
{
if (pflag == 1)
{
dragging = true;
start = e.Location;
}
}
private void pictureBox2_MouseMove(object sender, MouseEventArgs e)
{
// panning code
if (pflag == 1)
{
if (dragging && zoom == 1)
{
pictureBox2.Location = new Point(pictureBox2.Left + (e.Location.X - start.X), pictureBox2.Top + (e.Location.Y - start.Y));
}
}
}
private void pictureBox2_MouseUp(object sender, MouseEventArgs e)
{
if (pflag == 1)
{
dragging = false;
}
}
Here the image is panning but with no boundary control. Sometimes even the image goes below the panel area while panning. What I need here is, image should move top, left , right, bottom according to zoom factor i.e like how scroll bar works and not beyond that.
You don't need to worry about zoom as the mouse coordinates will be fine as they are. The distance of the shown pixels should be the same as those the cursor is moving..
You also do not really need the dragging variable, unless you use it for something else.
However you do need to check the mouse button during the MouseMove:
if (pflag == 1 && e.Button == System.Windows.Forms.MouseButtons.Left )
Do note few things:
The user expects that the spot he drags stays with the mouse cursor just as the pixel he touches should always move with the fingertip. Do not surprise him by scaling in the zoom-factor!
If you wanted to do that you would need to use a factor, not adding an number.
Yes, the scrollbars will factor in the zoom but also the lift will still stay with the mouse!
Here is an example of how to set limits to prevent the user from going too far. It it a little involved because it needs to work when zoomed in or out. Do not start with illegal positions, though, nor get into those while zooming!
// panning code
if ( pflag == 1 && e.Button == System.Windows.Forms.MouseButtons.Left )
{
{
Rectangle panRect = new Rectangle(panel1.Location, panel1.ClientSize);
Rectangle picRect = new Rectangle(pictureBox2.Location, pictureBox2.ClientSize);
int newLeft = pictureBox2.Left + (e.Location.X - start.X);
int newTop = pictureBox2.Top + (e.Location.Y - start.Y);
int newRight = newLeft + picRect.Width;
int newBottom = newTop + picRect.Height;
if ((newLeft < 0 && newRight < panRect.Width)
|| (newLeft > 0 /*&& newRight > panRect.Width */)) newLeft = picRect.Left;
if ((newTop < 0 && newBottom < panRect.Width)
|| (newTop > 0 /*&& newBottom > panRect.Height*/)) newTop = picRect.Top;
pictureBox2.Location = new Point(newLeft, newTop);
}
Text = "" + pictureBox2.Location;
}
Note the two parts I have commented out! As it is you can't move a picture that is smaller than the viewport; you can allow it by removing the comments but should then take care when zooming in to move it up and left to zero as it should never sit in the positve range and also overlap or else the scrollbars will behave in a weird way..!

Zoom Image in Picture Box

I am creating an application, in which user will be able to Upload an image and then Zoom in and Out the image on a particular location (current mouse pointer).
Also user should be able to drag the image to see other parts of the image when the image is zoomed.
I have implemented some functionality to achieve it but i am scaling the complete image. I want to know that how i can scale a particular portion of image, or scale the complete image and then point to that location where my current mouse pointer is placed.
Code:
private void DisplayIsdDiagram(BO.IsdDiagram IsdDiagram)
{
DoubleBuffered = true;
zoomFac = 1;
translateX = 0;
translateY = 0;
transStartX = 0f;
transStartY = 0f;
picIsdDiagram.BorderStyle = BorderStyle.Fixed3D;
bmp = new Bitmap(Image.FromStream(new MemoryStream(IsdDiagram.Image.ToArray())));
if (bmp.Width > bmp.Height)
{
ratio = (float)picIsdDiagram.Width / (float)bmp.Width;
translateRatio = (float)bmp.Width / (float)picIsdDiagram.Width;
}
else
{
ratio = (float)picIsdDiagram.Height / (float)bmp.Height;
translateRatio = (float)bmp.Height / (float)picIsdDiagram.Height;
}
//picIsdDiagram.Image = bmp;
picIsdDiagram.Refresh();
picIsdDiagram.MouseWheel += new MouseEventHandler(picIsdDiagram_MouseWheel);
}
private void picIsdDiagram_MouseWheel(object sender, MouseEventArgs e)
{
IsZooming = true;
if (e.Delta < 0)
{
if (zoomFac > 1)
zoomFac = zoomFac - (float)0.1;
}
else
{
if (zoomFac <= 5)
zoomFac = zoomFac + (float)0.1;
}
picIsdDiagram.Refresh();
IsZooming = false;
}
private void picIsdDiagram_MouseDown(object sender, MouseEventArgs e)
{
IsZooming = false;
IsMouseDown = true;
transStartX = e.X;
transStartY = e.Y;
}
private void picIsdDiagram_MouseUp(object sender, MouseEventArgs e)
{
IsZooming = false;
IsMouseDown = false;
translateX = translateX + ((e.X - transStartX) * (translateRatio / zoomFac));
translateY = translateY + ((e.Y - transStartY) * (translateRatio / zoomFac));
picIsdDiagram.Refresh();
}
private void picIsdDiagram_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.ScaleTransform(ratio * zoomFac, ratio * zoomFac);
if (IsZooming == false && IsMouseDown == true)
g.TranslateTransform(translateX, translateY);
g.DrawImage(bmp, 0, 0);
}
I tried to get the current mouse position from MouseHover event and tried to Translate the picture when only Zoom is done, but that is not working.
Also the Picture Box has some other multiple Picture boxes inside it, to show some representation on the big image. While scaling the Big Image, small images (inside images) should not be scaled. Although there position needs to be recalculated to show them at their real places even after zooming on the Big image.
So in above i am facing two problems:
1) To Zoom an Image at any particular location (current mouse pointer)
by scrolling.
2) To regenerate the coordinates of the sub images while
zooming and translating.
Any help that can guide me in correct direction.
Also if by any other means, i could be able to achieve this functionality.
Application : Windows
Control : Picture Box (Please suggest if any other control can be used, if not possible with this)
Language : C#
Waiting for response!
PictureEdit control provided by DevExpress 13.2

Moving Picturebox on a Grid is inaccurate because Mouse Positions are inaccurate

I have an Application where I put Pictureboxes on a Panel. After I successfully implemented Drag&Drop for the Pictureboxes, I wanted to add a Grid option to conviniently move the Pictureboxes on the Panel. The code I used is
private void PB14_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (grid)
{
if (MousePosition.X % 10 == 0)
{
PBList[14].Location = new Point(PList[parent].PointToClient(new Point(MousePosition.X, MousePosition.Y)).X, PBList[14].Location.Y);
}
if (MousePosition.Y % 10 == 0)
{
PBList[14].Location = new Point(PBList[14].Location.X, PList[parent].PointToClient(new Point(MousePosition.X, MousePosition.Y)).Y);
}
}
else
{
...
}
}
}
PList is a List of Panels, PList[parent] is the parent in which the picturebox (out of a Pictureboxlist) PBList[14] is.
The Problem is that the Picturebox is not smoothely moving, sometimes it doesnt move at all. I found out that some values for the % operation are better some are worse, for example if I put
if (MousePosition.X % 30 == 0)
in the if statement, it is worse than 10.
I put the values of the if() in labels and i saw that it would sometimes skip the calculation, means the value jumped from 9 to 1, skipping the pixel where it should be 0 and the Picturebox didnt move.
Do you know any better ways of calculating the mouse coordinates for this purpose?
You'll want to determine the closest pixel of the grid pixels to your mouse position.
PBList[14].Location = new Point(PList[parent].PointToClient(new Point(MousePosition.X - (MousePosition.X % 10) + 5, MousePosition.Y - (MousePosition.Y % 10) + 5)).X);
Although my confusion is setting in here about the required parameters for PointToClient.
The jist of it is, recalculate the position for each mouse move regardless of whether it is directly on your 'grid by 10s', assign the location if it is different from the last (to save resources on re-painting) and find the closest 'grid by 10s' position by subracting the co-ords remainder of 10 from the co-ord
The problem is you only move anything when the mouse is exactly over one of the grid points.
One way to do this is allowing an extra pixel on each side:
if ((MousePosition.X+1) % 30 < 3)
{
int newX = MousePosition.X + 1 - ((MousePosition.X+1) % 30);
PBList[14].Location = new Point(PList[parent].PointToClient(new Point(newX, MousePosition.Y)).X, PBList[14].Location.Y);
}
//Same for Y
I was able to add snap-to-grid behaviour to my typical drag-and-drop implementation. The grid is based on the Control's Height and Width. You can change this by replacing control.Height and control.Width with constants, if you prefer. You may also want to prevent the Control from being dragged off screen.
private void OnMouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
control.Left = ((e.X + control.Left) / control.Width) * control.Width;
control.Top = ((e.Y + control.Top) / control.Height) * control.Height;
}
}
If you want the Control to drag smoothly and only snap-to-grid when you release the mouse button instead:
private void OnMouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
control.Left += e.X - offset.X;
control.Top += e.Y - offset.Y;
}
}
private void OnMouseUp(object sender, MouseEventArgs e)
{
control.Left = ((control.Left + control.Width / 2) / control.Width) * control.Width;
control.Top = ((control.Top + control.Height / 2) / control.Height) * control.Height;
}
private void OnMouseDown(object sender, MouseEventArgs e)
{
offset = e.Location;
}

Set autoscroll position on mouse move

I need to update scroll bar position when I click on image and move picturebox. It is always at the beggining, it only moving on the right side (horizontall) and down (vertical).
private void pictureBox1_MouseMove_1(object sender, MouseEventArgs e)
{
....
Point currentMousePos = e.Location;
int distanceX = currentMousePos.X - mouseX;
int distanceY = currentMousePos.Y - mouseY;
int newX = pictureBox1.Location.X + distanceX;
int newY = pictureBox1.Location.Y + distanceY;
if (newX + pictureBox1.Image.Width + 10 < pictureBox1.Image.Width && pictureBox1.Image.Width + newX + 10 > panel1.Width)
{
pictureBox1.Location = new Point(newX, pictureBox1.Location.Y);
}
if (newY + pictureBox1.Image.Height + 10 < pictureBox1.Image.Height && pictureBox1.Image.Height + newY + 10 > panel1.Height)
{
pictureBox1.Location = new Point(pictureBox1.Location.X, newY);
}
}
I think you need to change the AutoScrollPosition of the parent panel and not play around with the Location points of the PictureBox. After all, the scroll bars of the parent panel are already taking care of the position of the PictureBox.
Try something like this (by the way, my code only does this when a button is pressed, otherwise, I think it would be a weird user interface design):
private Point _StartPoint;
void pictureBox1_MouseDown(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left)
_StartPoint = e.Location;
}
void pictureBox1_MouseMove(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
Point changePoint = new Point(e.Location.X - _StartPoint.X,
e.Location.Y - _StartPoint.Y);
panel1.AutoScrollPosition = new Point(-panel1.AutoScrollPosition.X - changePoint.X,
-panel1.AutoScrollPosition.Y - changePoint.Y);
}
}
LarsTech's code isn't 100% correct. 2 notes:
Note that if slider is moved, then the same point on screen changes it's coordinates relative to pictureBox1 (as pictureBox moved with moved slider). Therefore we want to use the screen coordinates (Control.MousePosition instead of e.Location).
Changing panel1.AutoScrollPosition causes the move of pictureBox relative to mouseCursor, so the pictureBox1.MouseMove event is fired again, even if cursor didn't move on the screen. Adding _StartPoint = Control.MousePosition prevents unwanted scrolling.

Track cusor location and add image from cusor location into PDF with iTextSharp

I'm looking for the most appropriate way to allow the user to import an image to a PDF and allow them to drag the picture around the PDF/winform and specify where the image is placed.
I'm thinking the best way to go about doing this is pulling the location from the cusor.
Something like:
Rectangle rect = new Rectangle(400, 772, 545, 792);
Instead of pre-defined coordinates, have the output be the selected cursor location of the user.
Any help would be very much appreciated.
Thank you in advance!
Users might have a hard time picking an image location just by pressing the mouse cursor on a form. Instead I recommend allowing them to drag a relatively sized rectangle around a grid. You'll have to translate coordinates appropriately, including fixing the Y value since iTextSharp starts at the bottom left instead of the top left, but that shouldn't be too hard.
Below is a full working C# 2010 WinForms app that allows you to drag a red rectangle around a black square. The comments in the code should pretty much explain everything. It has one big problem that need to be addressed, it stores the X/Y coordinates are screen-based and not form based, so if you drag once, move the entire form and drag again it will get "funky". This can be solved by calculating the x/y relative to the form instead which I'll leave up to you.
Hopefully this gets you down a path that works for you!
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
//Basic dimensions of our "border" and our "image". Assumes 72 dots per inch which isn't technically correct but gives us something to work with
private int BORDER_WIDTH = (int)11 * 72;
private int BORDER_HEIGHT = (int)8.5 * 72;
private int IMAGE_WIDTH = (int)2 * 72;
private int IMAGE_HEIGHT = (int)3 * 72;
private int IMAGE_OFFSET = 5;
//These will store the x/y when we press our mouse down so that we can calculate the drag later
private int offsetX;
private int offsetY;
//Our main "image" that we'll move around
PictureBox pb;
//The "border" to move the image around in
PictureBox border;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//Resize the form and make it not user-resizable
this.Size = new Size(BORDER_WIDTH + 30, BORDER_HEIGHT + 50);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
//Create our "image"
pb = new PictureBox();
pb.Size = new Size(IMAGE_WIDTH, IMAGE_HEIGHT);
pb.Location = new Point(IMAGE_OFFSET, IMAGE_OFFSET);
pb.BackColor = Color.Red;
//Bind a handler to the mouse down event
pb.MouseDown += new MouseEventHandler(this.pbMouseDown);
this.Controls.Add(pb);
//Create our "border"
border = new PictureBox();
border.Size = new Size(BORDER_WIDTH, BORDER_HEIGHT);
border.Location = new Point(IMAGE_OFFSET, IMAGE_OFFSET);
border.BackColor = Color.Black;
this.Controls.Add(border);
}
private void pbMouseDown(object sender, MouseEventArgs e)
{
//Store the current x/y so that we can use them in calculations later
offsetX = e.X;
offsetY = e.Y;
//When the mouse is down we want to remove the original mouse down handler
pb.MouseDown -= new MouseEventHandler(this.pbMouseDown);
//Add to more handler looking for mouse up and mouse movement
pb.MouseUp += new MouseEventHandler(this.pbMouseUp);
pb.MouseMove += new MouseEventHandler(this.pbMouseMove);
}
private void pbMouseUp(object sender, MouseEventArgs e)
{
//When the mouse button is released, remove old handlers and add back the down event
pb.MouseMove -= new MouseEventHandler(this.pbMouseMove);
pb.MouseUp -= new MouseEventHandler(this.pbMouseUp);
pb.MouseDown += new MouseEventHandler(this.pbMouseDown);
//Pop up a message, this is where something with iTextSharp would be done
MessageBox.Show(String.Format("The top left of the image is at {0}x{1}", pb.Top - IMAGE_OFFSET, pb.Left - IMAGE_OFFSET));
}
private void pbMouseMove(object sender, MouseEventArgs e)
{
//Calculate where to draw the "image" at next
//First, calculate based on the current image's location, the offset that we stored ealier and the current mouse position
int newLeft = e.X + pb.Left - offsetX;
int newTop = e.Y + pb.Top - offsetY;
//Next, make sure that we haven't gone over one of the boundaries of the "border"
if (newLeft < border.Left) newLeft = border.Left;
if (newTop < border.Top) newTop = border.Top;
if (newLeft + pb.Width > border.Right) newLeft = border.Right - pb.Width;
if (newTop + pb.Height > border.Bottom) newTop = border.Bottom - pb.Height;
//Finally, assign the new value
pb.Left = newLeft;
pb.Top = newTop;
}
}
}

Categories