How to get real image pixel point x,y from PictureBox

前端 未结 1 1640
难免孤独
难免孤独 2021-01-27 18:30

I have a pictureBox2 and it is set to zoom, I am trying to find out how to to get a real x,y pixel location on the image by Mouse.Click on

相关标签:
1条回答
  • 2021-01-27 19:00

    Note that with SizeMode set to Zoom, the PictureBox keeps aspect ratio, and centers the image, so on top of calculating the adjusted coordinates, you also have to take padding into account.

    My advice, don't use the Click event; it is meant to detect button clicks, not to actually process interaction of the mouse with an object. Use MouseDown instead.

    The first thing we need to do is get the width and height of the original image. As I noted in my comment, this is simply the object inside the Image property of the PictureBox.

    Next, we need the dimensions and location of the zoomed image. For that, we can start from the dimensions of the ClientRectangle of the PictureBox. Divide those by the image width and height and you'll get the horizontal and vertical zoom values. If the SizeMode would be set to StretchImage, that'd be all we need, but since aspect ratio is conserved, you need the smallest of the two values to have the actual zoom factor.

    Once we got that, multiply the original width and height by this zoom factor to get the zoomed width and height, then subtract that from the actual ClientRectangle dimensions and divide it by two to get the padding for both dimensions. This can of course be simplified by checking which of the two possible zoom factors is used, and only calculating the padding for the other one, since the dimension of which the zoom factor was used obviously has 0 padding.

    Now you got the padding and zoom factor, the rest is simple: subtract the padding values from the mouse coordinates, and then divide both results by the zoom factor.

    private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
    {
        // Default check: left mouse button only
        if (e.Button == MouseButtons.Left)
            ShowCoords(e.X, e.Y);
    }
    
    private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
    {
        // Allows dragging to also update the coords. Checking the button
        // on a MouseMove is an easy way to detect click dragging.
        if (e.Button == MouseButtons.Left)
            ShowCoords(e.X, e.Y);
    }
    
    private void ShowCoords(Int32 mouseX, Int32 mouseY)
    {
        Int32 realW = pictureBox1.Image.Width;
        Int32 realH = pictureBox1.Image.Height;
        Int32 currentW = pictureBox1.ClientRectangle.Width;
        Int32 currentH = pictureBox1.ClientRectangle.Height;
        Double zoomW = (currentW / (Double)realW);
        Double zoomH = (currentH / (Double)realH);
        Double zoomActual = Math.Min(zoomW, zoomH);
        Double padX = zoomActual == zoomW ? 0 : (currentW - (zoomActual * realW)) / 2;
        Double padY = zoomActual == zoomH ? 0 : (currentH - (zoomActual * realH)) / 2;
    
        Int32 realX = (Int32)((mouseX - padX) / zoomActual);
        Int32 realY = (Int32)((mouseY - padY) / zoomActual);
        lblPosXval.Text = realX < 0 || realX > realW ? "-" : realX.ToString();
        lblPosYVal.Text = realY < 0 || realY > realH ? "-" : realY.ToString();
    }
    

    Example project

    Note, I used sharp pixel zoom here to better show the effect. It's a little trick you can do by subclassing PictureBox and overriding its OnPaint method, to adjust the Graphics object from the PaintEventArgs object and set its InterpolationMode to NearestNeighbor (It's also advised to set PixelOffsetMode to Half; there's a bug where sharp zoom is shifted half a pixel unless you do that). Then you call base.OnPaint() with that adjusted event args object.

    I also added some more info on it here, but that's all just stuff you can get from the in-between values of the pixel coordinates calculation process anyway.

    0 讨论(0)
提交回复
热议问题