按最大高度和最大宽度的限制等比例调整图像大小

133

使用 System.Drawing.Image

如果图像的宽度或高度超过了最大值,需要按比例调整大小。调整大小后,需确保宽度和高度都不超过限制。

宽度和高度将自动调整大小,直到其大小不超过最大值和最小值,并且保持原始比例。


@Sarawut Positwinyu - 但是你想要什么宽高比? - Bibhu
如果一张图片无法按照高度和宽度的最大值和最小值进行调整,并且需要保持纵横比,您希望发生什么? - Conrad Frix
@Sarawut Positwinyu - 请查看此维基链接,了解有关纵横比的更多信息。http://en.wikipedia.org/wiki/Aspect_ratio_%28image%29 - Bibhu
@Conrad Frix有这样的情况吗?我真的不知道,但如果确实没有办法维持比率。将大小减小到小于最大大小更为重要,没有最小大小要求。 - Sarawut Positwinyu
1
@Sarawut Positwinyu,您没有误用“纵横比”这个术语。或者如果您确实这样做了,那么您也不是一个人(参见http://windows.microsoft.com/en-US/windows7/Resize-a-picture-using-Paint)。 - Conrad Frix
显示剩余2条评论
3个回答

326

像这样吗?

public static void Test()
{
    using (var image = Image.FromFile(@"c:\logo.png"))
    using (var newImage = ScaleImage(image, 300, 400))
    {
        newImage.Save(@"c:\test.png", ImageFormat.Png);
    }
}

public static Image ScaleImage(Image image, int maxWidth, int maxHeight)
{
    var ratioX = (double)maxWidth / image.Width;
    var ratioY = (double)maxHeight / image.Height;
    var ratio = Math.Min(ratioX, ratioY);

    var newWidth = (int)(image.Width * ratio);
    var newHeight = (int)(image.Height * ratio);

    var newImage = new Bitmap(newWidth, newHeight);

    using (var graphics = Graphics.FromImage(newImage))
        graphics.DrawImage(image, 0, 0, newWidth, newHeight);

    return newImage;
}

8
@Alex 很好地运用了 Math.Min(我总是忘记它), - Conrad Frix
5
我建议您在 Graphics 对象上使用 using 语句,以至少节省一些资源 :) - Schalk
4
请确保在使用asp.net时使用System.Drawing.Image。 - Induster
如果我错了,请纠正我。但是,如果最大宽度和最大高度的纵横比与原始图像的纵横比不同,那么这不会使图像变形吗?计算应该在边界框(maxWidth / maxHeight)内计算出适当的调整大小,这将导致图像在几乎所有情况下都小于边界框。这样无论如何都适合边界框,这在大多数情况下是错误的。 - Ryan Mann
1
@Smith - 如果你不需要保存图片,请不要运行Save方法。这正是我的ScaleImage方法所做的-返回图像而不保存它。 - Alex Aza
显示剩余6条评论

7

更长的解决方案,但涵盖了以下情况:

  1. Is the image smaller than the bounding box?
  2. Is the Image and the Bounding Box square?
  3. Is the Image square and the bounding box isn't
  4. Is the image wider and taller than the bounding box
  5. Is the image wider than the bounding box
  6. Is the image taller than the bounding box

    private Image ResizePhoto(FileInfo sourceImage, int desiredWidth, int desiredHeight)
    {
        //throw error if bouning box is to small
        if (desiredWidth < 4 || desiredHeight < 4)
            throw new InvalidOperationException("Bounding Box of Resize Photo must be larger than 4X4 pixels.");            
        var original = Bitmap.FromFile(sourceImage.FullName);
    
        //store image widths in variable for easier use
        var oW = (decimal)original.Width;
        var oH = (decimal)original.Height;
        var dW = (decimal)desiredWidth;
        var dH = (decimal)desiredHeight;
    
        //check if image already fits
        if (oW < dW && oH < dH)
            return original; //image fits in bounding box, keep size (center with css) If we made it bigger it would stretch the image resulting in loss of quality.
    
        //check for double squares
        if (oW == oH && dW == dH)
        {
            //image and bounding box are square, no need to calculate aspects, just downsize it with the bounding box
            Bitmap square = new Bitmap(original, (int)dW, (int)dH);
            original.Dispose();
            return square;
        }
    
        //check original image is square
        if (oW == oH)
        {
            //image is square, bounding box isn't.  Get smallest side of bounding box and resize to a square of that center the image vertically and horizontally with Css there will be space on one side.
            int smallSide = (int)Math.Min(dW, dH);
            Bitmap square = new Bitmap(original, smallSide, smallSide);
            original.Dispose();
            return square;
        }
    
        //not dealing with squares, figure out resizing within aspect ratios            
        if (oW > dW && oH > dH) //image is wider and taller than bounding box
        {
            var r = Math.Min(dW, dH) / Math.Min(oW, oH); //two dimensions so figure out which bounding box dimension is the smallest and which original image dimension is the smallest, already know original image is larger than bounding box
            var nH = oH * r; //will downscale the original image by an aspect ratio to fit in the bounding box at the maximum size within aspect ratio.
            var nW = oW * r;
            var resized = new Bitmap(original, (int)nW, (int)nH);
            original.Dispose();
            return resized;
        }
        else
        {
            if (oW > dW) //image is wider than bounding box
            {
                var r = dW / oW; //one dimension (width) so calculate the aspect ratio between the bounding box width and original image width
                var nW = oW * r; //downscale image by r to fit in the bounding box...
                var nH = oH * r;
                var resized = new Bitmap(original, (int)nW, (int)nH);
                original.Dispose();
                return resized;
            }
            else
            {
                //original image is taller than bounding box
                var r = dH / oH;
                var nH = oH * r;
                var nW = oW * r;
                var resized = new Bitmap(original, (int)nW, (int)nH);
                original.Dispose();
                return resized;
            }
        }
    }
    

1
我认为你在使用比率计算调整大小后的图像新高度时有几个错别字。 正确的是 var nH = oH * r; 错误的是:var nH = oW * r; - wloescher
只是固定的,从未被注释过。 - Ryan Mann

5

可行的解决方案:

对于大小小于100Kb的图像进行调整大小

WriteableBitmap bitmap = new WriteableBitmap(140,140);
bitmap.SetSource(dlg.File.OpenRead());
image1.Source = bitmap;

Image img = new Image();
img.Source = bitmap;
WriteableBitmap i;

do
{
    ScaleTransform st = new ScaleTransform();
    st.ScaleX = 0.3;
    st.ScaleY = 0.3;
    i = new WriteableBitmap(img, st);
    img.Source = i;
} while (i.Pixels.Length / 1024 > 100);

更多参考请访问http://net4attack.blogspot.com/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接