The issue involves a PictureBox control embedded within a custom UserControl in a Windows Forms application. The UserControl has its AutoScaleMode set to inherit, AutoScroll disabled, AutoSize disabled, and is anchored to a panel on all sides. The PictureBox within it is also anchored on all sides to the UserControl, has its Dock property set to None and uses a Zoom SizeMode.
The PictureBox displays an image (overlay image with a transparent background) alongside a background image. Although zooming functionality (triggered by the mouse wheel) appears to work correctly from a visual standpoint, the coordinates of the mouse cursor do not align with the expected values. Specifically, the coordinates are based on the PictureBox's top-left corner being (0,0), whereas the expectation is for (0,0) to correspond to the top-left corner of the image itself.
An attempt was made to correct this discrepancy by translating the coordinates based on the aspect ratio of the image relative to the PictureBox. However, this solution only corrected the x-coordinate, leaving the y-coordinate inaccurate. This issue is attributed to the presence of transparent gaps on the sides of the image upon its initial load, with no gaps at the top or bottom, and the aspect ratio used for the translation does not change with zooming.
Furthermore, creating a Rectangle on the PictureBox results in incorrect sizing and positioning.
The challenge is to accurately translate mouse coordinates to match the image's actual display area within the PictureBox, taking into account the dynamic scaling and aspect ratio adjustments caused by the Zoom SizeMode, and ensuring that shapes drawn on the PictureBox (like Rectangles) are correctly sized and positioned relative to the zoomed image.
Below is the method used to get the coordinates relative to the image:
Public Function TranslateZoomMousePosition(coordinates As Drawing.Point) As Drawing.Point
' Test to make sure our image is not null
If truPictureBox.Image Is Nothing Then Return coordinates
' Make sure our control width and height are not 0 and our image width and height are not 0
If truPictureBox.Width = 0 OrElse truPictureBox.Height = 0 OrElse truPictureBox.Image.Width = 0 OrElse truPictureBox.Image.Height = 0 Then Return coordinates
' This is the one that gets a little tricky. Essentially, need to check
' the aspect ratio of the image to the aspect ratio of the control
' to determine how it is being rendered
Dim Image = truPictureBox.Image
Dim imageAspectRatio As Single = CSng(Image.Width) / Image.Height
Dim pbAspectRatio As Single = CSng(truPictureBox.Width) / truPictureBox.Height
Dim newX As Single = coordinates.X
Dim newY As Single = coordinates.Y
If imageAspectRatio > pbAspectRatio Then
' This means that we are limited by width,
' meaning the image fills up the entire control from left to right
Dim ratioWidth As Single = CSng(Image.Width) / truPictureBox.Width
newX *= ratioWidth
Dim scale As Single = CSng(truPictureBox.Width) / Image.Width
Dim displayHeight As Single = scale * Image.Height
Dim diffHeight As Single = truPictureBox.Height - displayHeight
diffHeight /= 2
newY -= diffHeight
newY /= scale
Else
' This means that we are limited by height,
' meaning the image fills up the entire control from top to bottom
Dim ratioHeight As Single = CSng(Image.Height) / truPictureBox.Height
newY *= ratioHeight
Dim scale As Single = CSng(truPictureBox.Height) / Image.Height
Dim displayWidth As Single = scale * Image.Width * zoomFactor
Dim diffWidth As Single = truPictureBox.Width - displayWidth
diffWidth /= 2
newX -= diffWidth
newX /= scale
End If
Return New Drawing.Point(CInt(Math.Floor(newX)), CInt(Math.Floor(newY)))
End Function