How to Preserve aspect ratio of a button image .net
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, 开发者_如何学PythoniWidth-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 ?
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.
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.
精彩评论