I'm working on an app feature where the user selects a portion of an image I have displayed by drawing a rectangle over it,

And then the cropped part of the image pops up in another Image control in the window. I have a Mouse Down, Mouse Move, and Mouse Up event to gather the starting coordinates, width, and height of this rectangle, and have successfully gotten the cropped selection to display, but the result is slightly off on the X-axis when you select something from the top of the image, and as you get closer to the bottom, the skew becomes more and more dramatic for both X and Y.



As it stands right now, I have an Image control (ImageViewer1) and a Canvas (Canvas1) layered on top of that where the blue Rectangle is drawn. The Canvas fits the size of the document displayed in the Image control (ImageViewer1.Source), so all coordinates plotted should match exactly.
First, I gathered the mouse's first coordinates in my MouseDown event:
var mouseDownPosition = Mouse.GetPosition(Canvas1);
mouseDownPoint = new System.Windows.Point(mouseDownPosition.X, mouseDownPosition.Y);
//^^ I know this was unnecessary, but it's there now lol
Kept drawing the rectangle in my MouseMove event (no issues there), Then collected the final coordinates of the mouse in my MouseUp event:
var mouseUpPosition = Mouse.GetPosition(Canvas1);
mouseUpPoint = new System.Windows.Point(mouseUpPosition.X, mouseUpPosition.Y);
int rectX = Convert.ToInt32((Math.Min(mouseDownPoint.X, mouseUpPoint.X)));
int rectY = Convert.ToInt32((Math.Min(mouseDownPoint.Y, mouseUpPoint.Y)));
int rectWidth = Convert.ToInt32((Math.Abs(mouseUpPoint.X - mouseDownPoint.X)));
int rectHeight = Convert.ToInt32((Math.Abs(mouseUpPoint.Y - mouseDownPoint.Y)));
int sourceToActualXRatio = Convert.ToInt32(imageWidth / ImageViewer1.Source.Width);
int sourceToActualYRatio = Convert.ToInt32(imageHeight / ImageViewer1.Source.Height);
rectX *= sourceToActualXRatio;
rectY *= sourceToActualYRatio;
rectWidth *= sourceToActualXRatio;
rectHeight *= sourceToActualYRatio;
imageWidth and imageHeight contain the measurements of the actual full-size image, and I created ratios from them (sourceToActualXRatio, sourceToActualYRatio) to multiply my rectangle measurements by so that I could scale it up and get the right selection.
I think this is working because the dimensions seem correct in the CroppedBitmap, but the X and Y axis placement is just wildly unpredictable, so I think there's logic to how the rectX and rectY variables must be scaled that I'm missing.
Finally, I create the CroppedBitmap with those rectangle dimensions:
BitmapSource bms = (BitmapSource)ImageViewer1.Source;
CroppedBitmap cropped_bitmap = new CroppedBitmap(bms, new Int32Rect(rectX, rectY, rectWidth, rectHeight));
ImageViewer2.Source = cropped_bitmap;
Thanks to anyone willing to help!