How to retrieve zoom factor of a WinForms PictureBox?

13,506

Solution 1

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!

Solution 2

If I have understood you correctly I believe you would want to do something of this nature:

Assumption: the PictureBox fits to the image width/height, there is no space between the border of the PictureBox and the actual image.

ratioX = e.X / pictureBox.ClientSize.Width;
ratioY = e.Y / pictureBox.ClientSize.Height;

imageX = image.Width * ratioX;
imageY = image.Height * ratioY;

this should give you the points ot the pixel in the original image.

Share:
13,506
devilkkw
Author by

devilkkw

devilkkw

Updated on July 19, 2022

Comments

  • devilkkw
    devilkkw almost 2 years

    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?

  • Dene B
    Dene B almost 12 years
    I missed out the (float) for the ratio, do that, at the moment if you say had var ratioX, then it will likely be an int, meaning ratioX/Y will always be zero.
  • Harald Coppoolse
    Harald Coppoolse over 9 years
    Perfect upon one small error: for the ratio you should not use width and height of the complete control, but the width and height of the Control.ClientSize, so without borders. Quite often the difference is not noticeable, until you show a border and do some calculations. You'll see that some pixels are missing