Search code examples
c#winformszoomingmouseoverpicturebox

How to retrieve zoom factor of a WinForms PictureBox?


I need the precise position of my mouse pointer over a PictureBox.

I use the MouseMove event of the PictureBox.

On this PictureBox, I use the "zoom" property to show an image.

What is the correct way for getting the position of the mouse on the original (unzoomed) image?

Is there a way to find the scale factor and use it?

I think need to use imageOriginalSize/imageShowedSize to retrieve this scale factor.

I use this function:

float scaleFactorX = mypic.ClientSize.Width / mypic.Image.Size.Width;
float scaleFactorY = mypic.ClientSize.Height / mypic.Image.Size.Height;

Is possible to use this value to get the correct position of the cursor over the image?


Solution

  • I had to solve this same problem today. I wanted it to work for images of any width:height ratio.

    Here's my method to find the point 'unscaled_p' on the original full-sized image.

                Point p = pictureBox1.PointToClient(Cursor.Position);
                Point unscaled_p = new Point();
    
                // image and container dimensions
                int w_i = pictureBox1.Image.Width; 
                int h_i = pictureBox1.Image.Height;
                int w_c = pictureBox1.Width;
                int h_c = pictureBox1.Height;
    

    The first trick is to determine if the image is a horizontally or vertically larger relative to the container, so you'll know which image dimension fills the container completely.

                float imageRatio = w_i / (float)h_i; // image W:H ratio
                float containerRatio = w_c / (float)h_c; // container W:H ratio
    
                if (imageRatio >= containerRatio)
                {
                    // horizontal image
                    float scaleFactor = w_c / (float)w_i;
                    float scaledHeight = h_i * scaleFactor;
                    // calculate gap between top of container and top of image
                    float filler = Math.Abs(h_c - scaledHeight) / 2;  
                    unscaled_p.X = (int)(p.X / scaleFactor);
                    unscaled_p.Y = (int)((p.Y - filler) / scaleFactor);
                }
                else
                {
                    // vertical image
                    float scaleFactor = h_c / (float)h_i;
                    float scaledWidth = w_i * scaleFactor;
                    float filler = Math.Abs(w_c - scaledWidth) / 2;
                    unscaled_p.X = (int)((p.X - filler) / scaleFactor);
                    unscaled_p.Y = (int)(p.Y / scaleFactor);
                }
    
                return unscaled_p;
    

    Note that because Zoom centers the image, the 'filler' length has to be factored in to determine the dimension that is not filled by the image. The result, 'unscaled_p', is the point on the unscaled image that 'p' correlates to.

    Hope that helps!