1
votes

I'm trying to re-size an image of the Button control while preserving the aspect ratio from the original image so the new image doesn't look squashed/stretched.

And when i again get it back to the original position (Normal Window Maximized state) it should retain its original resolution.

Basically i want the images in all of monitor resolutions to look the same.

For ex: In my application, An image of a Globe looks fine with the monitor resolution 1280 * 1024 (5:4) but looks stretched like an ellipse with the monitor resolution 1920×1080 (16:9)

I know i have to do some form of transformation programatically, but am not getting how to do it. I tried calling the below method on OnResize event, though it works for the first iteration, the images gets smaller on subsequent resizing and finally i lose my image finally.

public Rectangle MaintainAspectRatio(Image imgPhoto, Rectangle thumbRect) { int sourceWidth = imgPhoto.Width; int sourceHeight = imgPhoto.Height; int sourceX = 0; int sourceY = 0; int destX = 0; int destY = 0;

    float nPercent = 0;
    float nPercentW = 0;
    float nPercentH = 0;

    nPercentW = ((float)thumbRect.Width / (float)sourceWidth);
    nPercentH = ((float)thumbRect.Height / (float)sourceHeight);

    //if we have to pad the height pad both the top and the bottom
    //with the difference between the scaled height and the desired height
    if (nPercentH < nPercentW)
    {
        nPercent = nPercentH;
        destX = (int)((thumbRect.Width - (sourceWidth * nPercent)) / 2);
    }
    else
    {
        nPercent = nPercentW;
        destY = (int)((thumbRect.Height - (sourceHeight * nPercent)) / 2);
    }

    int destWidth = (int)(sourceWidth * nPercent);
    int destHeight = (int)(sourceHeight * nPercent);

    Rectangle retRect = new Rectangle(thumbRect.X, thumbRect.Y, destWidth, destHeight);
    return retRect;
}

I use this code in my overriden OnPaint eventhandler method as :

protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Graphics g = e.Graphics;

     int iHeight;
     int iWidth;

     if (Image != null)
     {
         Rectangle ResizedRectangle = MaintainAspectRatio(Image,ClientRectangle);
         iHeight = ResizedRectangle.Height;
         iWidth = ResizedRectangle.Width;

     }
     else
     {
         iWidth = ClientRectangle.Width;
         iHeight = ClientRectangle.Height;
     }


     // Draw border
     Color oLeftTopColor = SystemColors.ControlLightLight;
     Color oRightBottomColor = SystemColors.ActiveCaption;
     Pen oLeftTopPen = new Pen(oLeftTopColor);
     Pen oRightBottomPen = new Pen(oRightBottomColor);
     // top line
     g.DrawLine(oLeftTopPen, 0, 0, iWidth - 1, 0);
     //g.DrawLine(new Pen(SystemColors.ControlLight), 1, 1, iWidth-2, 1);
     // bottom line
     g.DrawLine(oRightBottomPen, 0, iHeight, iWidth - 1, iHeight);
     //g.DrawLine(new Pen(SystemColors.ControlDark), 1, iHeight-2, iWidth-2, iHeight-2);
     // right line
     g.DrawLine(oRightBottomPen, iWidth, 0, iWidth, iHeight - 1);
     //g.DrawLine(new Pen(SystemColors.ControlDark), iWidth-2, 1, iWidth-2, iHeight-2);
     // left line
     g.DrawLine(oLeftTopPen, 0, 0, 0, iHeight - 1);
     //g.DrawLine(new Pen(SystemColors.ControlLightLight), 1, 1, 1, iHeight-2);

     // Draw image
     if (Image != null)
     {

         Rectangle oDrawRectagle = new Rectangle(
            0, 0, iWidth, iHeight);
         if (Enabled == false)
         {
             e.Graphics.DrawImage(Image, oDrawRectagle,
                0, 0, Image.Width, Image.Height,
                GraphicsUnit.Pixel);
         }
         else
         {
             e.Graphics.DrawImage(Image, oDrawRectagle);

         }
     }

     // Draw text
     if (Text != null)
     {
         int iTextTop = 5;
         int iTextLeft = 5;
         int iMaxTextWidth = iWidth - 10;
         int iMaxTextHeight = iHeight - 10;
     }
}

Can anyone guide me how should i proceed with this ?

2
To keep it simple... i just want a round shape to appear round in all monitor resolutions.this-Me
This is basically an impossible problem. The resolution of a monitor does not define an aspect ratio. That is, a 16x9 monitor could have a resolution 1920x1080. So could a 4x3 monitor. You don't actually know the aspect ratio of a display from the resolution. I can't say I'm an expert, but I think you just need to assume that an image of x by x pixels will be appear symmetric, and if it doesn't, everything else on their display will be distorted too and that's how they want it.Jamie Treworgy

2 Answers

1
votes

I tried calling the below method on OnResize event, though it works for the first iteration, the images gets smaller on subsequent resizing and finally i lose my image finally.

I think you should use the DisplaySettingsChanged instead of OnResize event, it will trigger only when resolution is changed.

1
votes

It's not very clear how you are using the image - maybe you should post the code where you actually display the image.

An image might appear deformed on different resolutions if the pixel aspect ratio (PAR) differs in the two resolutions - is this your case? Do you want to display an image independent of the PAR?

In this case you need to keep the image internally at a known DPI value (96, usually) and then stretch it with your method by the values of the current resolution's DPI, which can be obtain with something like this:

Single xDpi, yDpi;

IntPtr dc = GetDC(IntPtr.Zero);

using(Graphics g = Graphics.FromHdc(dc))
{
    xDpi = g.DpiX;
    yDpi = g.DpiY;
}

if (ReleaseDC(IntPtr.Zero) != 0)
{
    // GetLastError and handle...
}


[DllImport("user32.dll")]
private static extern IntPtr GetDC(IntPtr hwnd);    
[DllImport("user32.dll")]
private static extern Int32 ReleaseDC(IntPtr hwnd);

Then you need to scale your image so that final width = original width * 96 / xDpi, and similar for height.