1

I'm displaying an image in a PictureBox and allowing the user to specify an area in the image by providing the width and height of the rectangle.The location of the rectangle is determined programatically.

The image displayed in the picturebox is scaled down to save processing time.So if the user specifies 200X200 Rectangle this might look large in the preview image but it will be very small in the original image which can be quite large.

How can downscale or translate the Rectangle to show how it would look in the large image.Currently i'm using the following code to upscale a rectangle in the large image.Please advice.

Rectangle ConvertToLargeRect(Rectangle smallRect, Size largeImageSize, Size smallImageSize)
{
    double xScale = (double)largeImageSize.Width / smallImageSize.Width;
    double yScale = (double)largeImageSize.Height / smallImageSize.Height;
    int x = (int)(smallRect.X * xScale + 0.5);
    int y = (int)(smallRect.Y * yScale + 0.5);
    int right = (int)(smallRect.Right * xScale + 0.5);
    int bottom = (int)(smallRect.Bottom * yScale + 0.5);
    return new Rectangle(x, y, right - x, bottom - y);
}

UPDATE: enter image description here enter image description here

techno
  • 6,100
  • 16
  • 86
  • 192
  • Could you please add an illustration or input/expected output? For me, it's a bit unclear what you are looking for. – Reza Aghaei Dec 24 '18 at 06:07
  • The second thing, s the `PictureBox` as important part of the question? Because I don't see any usage of the picture box in the method, while it may be important. Depending the size mode of the picture box, picture box image rectangle may be located at a different location rather than (0,0) and this way it will affect the location of the scaled down/up rectangle. Should we consider the picture box size mode/image rectangle or we should ignore it and just stick to the sizes? – Reza Aghaei Dec 24 '18 at 06:11
  • 1
    @RezaAghaei I'm preparing some illustration,kindly hold on. The picturebox size mode need not be considered as it will be handled using your code here https://stackoverflow.com/a/53800590/848968 .It will be always in Zoom Mode. – techno Dec 24 '18 at 06:16
  • @RezaAghaei Please check the update. – techno Dec 24 '18 at 06:40

1 Answers1

0

I'll use the following methods:

  • TranslatePictureBoxSelectedRectangleToImage
    Translates a selected rectangle on the picture box to coordinates on the image.

  • TranslateImageSelectedRectangleToPictureBox
    Translates a selected rectangle on the image box to coordinates on the picture box.

  • ScaleRectangle
    Scales a rectangle by given scale factor.

TranslatePictureBoxSelectedRectangleToImage

public RectangleF TranslatePictureBoxSelectedRectangleToImage(PictureBox p, 
    RectangleF pictureBoxSelectedRectangle)
{
    var method = typeof(PictureBox).GetMethod("ImageRectangleFromSizeMode",
        System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
    var imageRect = (Rectangle)method.Invoke(p, new object[] { p.SizeMode });
    if (p.Image == null)
        return pictureBoxSelectedRectangle;
    var cx = (float)p.Image.Width / (float)imageRect.Width;
    var cy = (float)p.Image.Height / (float)imageRect.Height;
    var r2 = pictureBoxSelectedRectangle;
    r2.Offset(-imageRect.X, -imageRect.Y);
    return new RectangleF(r2.X * cx, r2.Y * cy, r2.Width * cx, r2.Height * cy);
}

TranslateImageSelectedRectangleToPictureBox

public RectangleF TranslateImageSelectedRectangleToPictureBox(PictureBox p, 
    RectangleF imageSelectedRectangle)
{
    var method = typeof(PictureBox).GetMethod("ImageRectangleFromSizeMode",
        System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
    var imageRect = (Rectangle)method.Invoke(p, new object[] { p.SizeMode });
    if (p.Image == null)
        return imageSelectedRectangle;
    var cx = (float)p.Image.Width / (float)imageRect.Width;
    var cy = (float)p.Image.Height / (float)imageRect.Height;
    var r2 = new RectangleF(imageSelectedRectangle.X / cx, imageSelectedRectangle.Y / cy,
        imageSelectedRectangle.Width / cx, imageSelectedRectangle.Height / cy);
    r2.Offset(imageRect.X, imageRect.Y);
    return r2;
}

ScaleRectangle

public RectangleF ScaleRectangle(RectangleF r, float c)
{
    return new RectangleF(r.X * c, r.Y * c, r.Width * c, r.Height * c);
}

Example

Using above methods with following assumptions:

  • You have image1 in original size and image2 which is a programmatically resized version of image1 with zoom factor c. (It means c = (float)image2.Width/(float)image1.Width.)
  • You are showing image2 in picture box in zoom mode.

Question 1 - Having r1 as selected rectangle on picureBox1, what is the rectangle size and location on image1?

The first method shows how you can convert r1 on picture box, to a rectangle on image2. To convert it to the rectangle on image1, since you know the zoom factor which you used to create image2 from image1, it's enough to apply the same zoom factor on result of first method:

//First convert rectangle of pictureBox1 to rectangle of image2
var r2 = TranslatePictureBoxSelectedRectangleToImage(pictureBox1, r1);

//Then convert rectangle of image2 to rectangle of image1
var result = ScaleRectangle(r2, 1f/c);

Question 2 - Having r1 as selected rectangle on image1, what is the rectangle size and location on pictureBox1?

The second method shows how you can convert r1 on image2, to a rectangle on pictureBox1. To convert from a rectangle on image1, since you know the zoom factor which you used to create image2 from image1, it's enough to apply the same zoom factor on r1 to get the rectangle on image2, then use the second method:

//First convert rectangle of the image1 to rectangle of image2
var r2 = ScaleRectangle(r1, c);

//Then convert rectangle of image2 to rectangle of pictureBox1
var result = TranslateImageSelectedRectangleToPictureBox(pictureBox1, r2);
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • But the image in the picturebox is not the original image.Its just showing a preview to the user.When the main processing is done,the original full resolution image will be used.So,when i show the preview to the user the selection window(defined in pixels) should look as it should in the full resolution image.It should not appear larger as we use a small image for preview purpose.Hope you got what i meant. – techno Dec 24 '18 at 07:52
  • Not really, I guess I couldn't get it. Is the `PictureBox` using zoom mode? Is the `PictureBox` showing the original image? – Reza Aghaei Dec 24 '18 at 07:59
  • Yeah;the picturebox is using the `ZoomMode`.Its not showing the original image the image is resized programatically before setting it to the picturebox. – techno Dec 24 '18 at 08:01
  • I've added an example. I will add another one as well to do the reverse. – Reza Aghaei Dec 24 '18 at 08:18
  • Added the second example to solve the reverse problem. – Reza Aghaei Dec 24 '18 at 08:27
  • I make use of `Rectangle` object everywhere in my code.`RectangleF` need me to replace entire blocks of code and is not supported by a third part library i use.When i cast the float to int,i get division by zero expection near the zoom factor. – techno Dec 25 '18 at 07:17
  • When you work with scaling and custom paint, usually using `float` and `RectanleF` is a better idea. [`Rectangle.Round`](https://learn.microsoft.com/en-us/dotnet/api/system.drawing.rectangle.round?view=netframework-4.7.2) converts a `RectangleF` to `Rectangle`. You can easily return `Rectangle`. – Reza Aghaei Dec 25 '18 at 07:21
  • Anyway, you have all piece of code which you may find useful. Make sure you have copied them before I delete the answer :) (I'm not going to keep this answer as it seems it's not much useful while event the OP cannot use it, probably no one else will use it.) – Reza Aghaei Dec 25 '18 at 07:22
  • huh? why should you delete the answer? There is a downvote( dont know who downvoted and why).I have upvoted it now. – techno Dec 25 '18 at 07:25
  • Thanks, it's not just about downvote. It's about writing useful answers. – Reza Aghaei Dec 25 '18 at 08:14
  • Downvotes are result of some people playing behind the scenes, one downvoted the other answer, and *one* thought I am the downvoter and downvoted me. Then next downvote came in for the other answer. I couldn't get downvoted again by the same downvoter, so you get the downvote. – Reza Aghaei Dec 25 '18 at 08:19
  • I managed to solve the issue by taking the `xfactor` and `yfactor` ie : scaling of width and height (multiplication in case of size increase,division in case of size reduction) along with other pieces of code linked in your old answer. – techno Dec 25 '18 at 10:54