Search code examples
c#wpfmathcoordinatescrop

Calculate coordinates rectangle for picture cropping, when picture bigger than rectangle


I'm developing my own picture viewer and in the process of creating an image cropping method. It does work with my current code. However, the application is dynamically resizing the image to fit the user's screen. So when it is resized, the calculated X.Y coordinates of the image are incorrect. I'm not very good at math, so I don't know how to calculate that.

This is the code that I am using

    internal static Int32Rect GetCrop()
    {
        var cropArea = cropppingTool.CropTool.CropService.GetCroppedArea();
        var x = Convert.ToInt32(cropArea.CroppedRectAbsolute.X);
        var y = Convert.ToInt32(cropArea.CroppedRectAbsolute.Y);
        var width = Convert.ToInt32(cropArea.CroppedRectAbsolute.Width);
        var height = Convert.ToInt32(cropArea.CroppedRectAbsolute.Height);

        return new Int32Rect(x, y, width, height);
    }

The cropArea variable is from my own modified version of https://github.com/dmitryshelamov/UI-Cropping-Image. It is a Rect that returns X and Y coordinates and width and height from the user drawn square, used to select cropping area of image.

I have the variables for resized image width and height, and the original pixel width and pixel height of the images. The cropping UI uses the resized variables, to fit on the user's screen.

For clarity, the image size is calculated as so, with image control set to Stretch.Fill

    double width = sourceBitmap.PixelWidth;
    double height = sourceBitmap.PixelHeight;
    double maxWidth = Math.Min(SystemParameters.PrimaryScreenWidth - 300, width);
    double maxHeight = Math.Min(SystemParameters.PrimaryScreenHeight - 300, height);

    var aspectRatio = Math.Min(maxWidth / width, maxHeight / height);
    width *= aspectRatio;
    height *= aspectRatio;

    image.Width = width;
    image.Height = height;

So the question is, how do I calculate the offset between rendered size and actual pixel size?


Solution

  • If I understand this: you've calculated a ratio named aspectRatio to scale the image from it's actual size to the size of the screen. You have a cropping tool that gives you coordinates based on the scaled size image, and you want to convert those coordinates so they can be applied to the image's original size.

    Assuming the above is right, this should be simple.

    If the scaled height and width are calculated by:

    scaledWidth = originalWidth * ratio
    scaledHeigth = originalHeigth * ratio
    

    Then you can reverse the multiplication by dividing instead:

    originalWidth = scaledWidth / ratio
    originalHeight = scaledHeight / ratio
    

    This also applies to any coordinates within the image. You can take coordinates from the scaled image, and convert them into coordinates for the original image like so:

    originalX = scaledRect.X / ratio
    originalY = scaledRect.Y / ratio
    originalWidth = scaledRect.Width / ratio
    originalHeight = scaledRect.Height / ratio
    

    You'll have to be careful to make sure that none of the values of scaledRect are 0, since division and 0 don't mix. A value of 0 in the scaled coordinate will also translate to 0 in the original coordinate space, so 0 should just stay 0. You can do this with if statements.