如何在C#中调整图像大小以保持纵横比

本文关键字:图像 调整 | 更新日期: 2023-09-27 18:27:15

我需要知道一种方法,可以调整图像的大小,使其适合盒子,而不会使图像拉伸过大。盒子已经设置了宽度和高度,我希望图像尽可能多地填充盒子,但保持原来的纵横比。

如何在C#中调整图像大小以保持纵横比

//calculate the ratio
double dbl = (double)image.Width / (double)image.Height;
//set height of image to boxHeight and check if resulting width is less than boxWidth, 
//else set width of image to boxWidth and calculate new height
if( (int)((double)boxHeight * dbl) <= boxWidth )
{
    resizedImage = new Bitmap(original, (int)((double)boxHeight * dbl), boxHeight);
}
else
{
    resizedImage = new Bitmap(original, boxWidth, (int)((double)boxWidth / dbl) );
}

相同比例缩放的公式为:

newWidth =  (int)((double)boxHeight * dbl)
or
newHeight =  (int)((double)boxWidth / dbl)

Math.Max可以简化问题:

double ratio = Math.Max((double)image.width / (double)box.width , (double)image.height / (double)box.height);
image.width = (int)(image.width / ratio);
image.height = (int)(image.height / ratio);
 Bitmap original,resizedImage;
try
                {
                    using (FileStream fs = new System.IO.FileStream(imageLabel.Text, System.IO.FileMode.Open))
                    {
                        original = new Bitmap(fs);
                    }
                    int rectHeight = BOXWIDTH;
                    int rectWidth = BOXWIDTH;
                    //if the image is squared set it's height and width to the smallest of the desired dimensions (our box). In the current example rectHeight<rectWidth
                    if (original.Height == original.Width)
                    {
                        resizedImage = new Bitmap(original, rectHeight, rectHeight);
                    }
                    else
                    {
                        //calculate aspect ratio
                        float aspect = original.Width / (float)original.Height;
                        int newWidth, newHeight;
                        //calculate new dimensions based on aspect ratio
                        newWidth = (int)(rectWidth * aspect);
                        newHeight = (int)(newWidth / aspect);
                        //if one of the two dimensions exceed the box dimensions
                        if (newWidth > rectWidth || newHeight > rectHeight)
                        {
                           //depending on which of the two exceeds the box dimensions set it as the box dimension and calculate the other one based on the aspect ratio
                            if (newWidth > newHeight)
                            {
                                newWidth = rectWidth;
                                newHeight = (int)(newWidth / aspect);
                            }
                            else
                            {
                                newHeight = rectHeight;
                                newWidth = (int)(newHeight * aspect);
                            }
                        }
                        resizedImage = new Bitmap(original, newWidth, newHeight);

                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show( ex.Message);
                }
            }

接受的答案可能有效,但我盯着它看了很长时间,不明白具体是怎么做的,所以我想分享我的想法:首先缩小高度,然后检查宽度,如果需要,再缩小一次,始终保持长宽比。

我使用SixLabors.ImageSharp是因为它与Linux兼容,但一旦有了newHeightnewWidth,就可以很容易地交换大小调整功能。

using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
public class ImageSharpService : IImageService
{
    public async Task ShrinkAndSaveAsync(Stream stream, string savePath, int maxHeight, int maxWidth)
    {
        using Image image = Image.Load(stream);
        // check if resize is needed
        if (ResizeNeeded(image.Height, image.Width, maxHeight, maxWidth, out int newHeight, out int newWidth))
            // swap this part out if not using ImageSharp
            image.Mutate(x => x.Resize(new ResizeOptions
            {
                Size = new Size(newWidth, newHeight)
            }));
        await image.SaveAsync(savePath);
    }
    private bool ResizeNeeded(int height, int width, int maxHeight, int maxWidth, out int newHeight, out int newWidth)
    {
        // first use existing dimensions
        newHeight = height;
        newWidth = width;
        // if below max on both then do nothing
        if (height <= maxHeight && width <= maxWidth) return false;
        // naively check height first
        if (height > maxHeight)
        {
            // set down to max height
            newHeight = maxHeight;
            // calculate what new width would be
            var heightReductionRatio = maxHeight / height; // ratio of maxHeight:image.Height
            newWidth = width * heightReductionRatio; // apply ratio to image.Width
        }
        // does width need to be reduced? 
        // (this will also re-check width after shrinking by height dimension)
        if (newWidth > maxWidth)
        {
            // if so, re-calculate height to fit for maxWidth
            var widthReductionRatio = maxWidth / newWidth; // ratio of maxWidth:newWidth (height reduction ratio may have been applied)
            newHeight = maxHeight * widthReductionRatio; // apply new ratio to maxHeight to get final height
            newWidth = maxWidth;
        }
        // if we got here, resize needed and out vars have been set
        return true;
    }
}

我相信,如果你只改变高度或宽度,它将保持更好的比例,宽度/高度也会随之改变。所以你可以尝试