如何调整图像C#的大小


288

SizeWidthHeightGet()的性质System.Drawing.Image;
如何在运行时使用C#调整Image对象的大小?

现在,我正在Image使用以下方法创建一个新的:

// objImage is the original Image
Bitmap objBitmap = new Bitmap(objImage, new Size(227, 171));

2
不正确的做法......使用低质量的插值,并可能导致原有的流保持锁定为新的位图图像的时间... 阅读影像缩放缺陷列表做你自己的图片大小的解决方案之前。
莉莉丝·

2
处理!using(){}有效!
Scott Coates

8
如果这些答案有帮助,请考虑标记接受的答案。
2014年

3
无需使用任何其他库。马克在下面发布的代码效果很好。
Elmue 2014年

9
马克是谁?我找不到他的答案,但是有3条评论指的是它。
Sinatr

Answers:


490

这将执行高质量的调整大小:

/// <summary>
/// Resize the image to the specified width and height.
/// </summary>
/// <param name="image">The image to resize.</param>
/// <param name="width">The width to resize to.</param>
/// <param name="height">The height to resize to.</param>
/// <returns>The resized image.</returns>
public static Bitmap ResizeImage(Image image, int width, int height)
{
    var destRect = new Rectangle(0, 0, width, height);
    var destImage = new Bitmap(width, height);

    destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);

    using (var graphics = Graphics.FromImage(destImage))
    {
        graphics.CompositingMode = CompositingMode.SourceCopy;
        graphics.CompositingQuality = CompositingQuality.HighQuality;
        graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
        graphics.SmoothingMode = SmoothingMode.HighQuality;
        graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;

        using (var wrapMode = new ImageAttributes())
        {
            wrapMode.SetWrapMode(WrapMode.TileFlipXY);
            graphics.DrawImage(image, destRect, 0, 0, image.Width,image.Height, GraphicsUnit.Pixel, wrapMode);
        }
    }

    return destImage;
}

保持宽高比是读者的一项练习(实际上,我只是认为为您做到这一点不是此功能的工作)。

另外,这是一篇很好的文章,描述了图像大小调整的一些陷阱。上面的功能将覆盖其中的大多数功能,但是您仍然需要担心保存


4
调整图像大小时,代码可以完美工作,但是大小从66KB增加到132KB。头可以减少

3
@chamara这可能是由于您选择的保存质量。请参阅msdn.microsoft.com/en-us/library/bb882583(v=vs.110).aspx尝试quality = 90
mpen

3
@kstubs您确定是。Bitmap本质上只是类的名称,您可以将其保存为所需的任何文件类型。
mpen

5
@dotNetBlackBelt您可能需要添加引用System.Drawing并添加using System.Drawing.Imaging;
mpen

2
这样会不会保持原来的长宽比吧?
卡斯珀·斯科夫

148

不确定这样做有什么困难,请执行您的工作,使用重载的Bitmap构造函数创建一个重新调整大小的图像,您唯一缺少的就是将其强制转换为Image数据类型:

    public static Image resizeImage(Image imgToResize, Size size)
    {
       return (Image)(new Bitmap(imgToResize, size));
    }

    yourImage = resizeImage(yourImage, new Size(50,50));

2
您不应该yourImage在将其分配给新图像之前进行处理?
萧伯纳

3
您可以手动处理它,也可以让垃圾收集器完成它的工作。不管。
Elmue 2014年

23
此代码无法控制大小调整的质量,这非常重要。看一下马克的答案。
Elmue 2014年

42

这个问题中,您将得到一些答案,包括我的:

public Image resizeImage(int newWidth, int newHeight, string stPhotoPath)
 {
     Image imgPhoto = Image.FromFile(stPhotoPath); 

     int sourceWidth = imgPhoto.Width;
     int sourceHeight = imgPhoto.Height;

     //Consider vertical pics
    if (sourceWidth < sourceHeight)
    {
        int buff = newWidth;

        newWidth = newHeight;
        newHeight = buff;
    }

    int sourceX = 0, sourceY = 0, destX = 0, destY = 0;
    float nPercent = 0, nPercentW = 0, nPercentH = 0;

    nPercentW = ((float)newWidth / (float)sourceWidth);
    nPercentH = ((float)newHeight / (float)sourceHeight);
    if (nPercentH < nPercentW)
    {
        nPercent = nPercentH;
        destX = System.Convert.ToInt16((newWidth -
                  (sourceWidth * nPercent)) / 2);
    }
    else
    {
        nPercent = nPercentW;
        destY = System.Convert.ToInt16((newHeight -
                  (sourceHeight * nPercent)) / 2);
    }

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


    Bitmap bmPhoto = new Bitmap(newWidth, newHeight,
                  PixelFormat.Format24bppRgb);

    bmPhoto.SetResolution(imgPhoto.HorizontalResolution,
                 imgPhoto.VerticalResolution);

    Graphics grPhoto = Graphics.FromImage(bmPhoto);
    grPhoto.Clear(Color.Black);
    grPhoto.InterpolationMode =
        System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

    grPhoto.DrawImage(imgPhoto,
        new Rectangle(destX, destY, destWidth, destHeight),
        new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
        GraphicsUnit.Pixel);

    grPhoto.Dispose();
    imgPhoto.Dispose();
    return bmPhoto;
}

5
您忘记了imgPhoto.Dispose(); 该文件一直在使用
shrutyzet 2013年

1
这非常有帮助,我正在我的应用程序中使用它。但是,需要注意的重要一点是,该算法不适用于透明图像。它将所有透明像素变为黑色。它可能很容易修复,但只是给用户的提示。:)
meme

1
您不是要保存图像吗?imgPhoto.Save()吗?
Whiplash

@meme您能否提供有关如何修复透明文档的黑色背景的链接。
Syed Mohamed

25

为什么不使用该System.Drawing.Image.GetThumbnailImage方法?

public Image GetThumbnailImage(
    int thumbWidth, 
    int thumbHeight, 
    Image.GetThumbnailImageAbort callback, 
    IntPtr callbackData)

例:

Image originalImage = System.Drawing.Image.FromStream(inputStream, true, true);
Image resizedImage = originalImage.GetThumbnailImage(newWidth, (newWidth * originalImage.Height) / originalWidth, null, IntPtr.Zero);
resizedImage.Save(imagePath, ImageFormat.Png);

来源:http//msdn.microsoft.com/en-us/library/system.drawing.image.getthumbnailimage.aspx


6
这不是调整图像大小的正确方法。如果存在,则会从jpg中提取缩略图。如果不存在,则无法控制质量或新图像。另外,此代码本身也会发生内存泄漏。
罗伯·史密斯

1
@Bobrot为什么这会导致内存泄漏?
用户

2
GDI库中的所有内容仍在不受管理的状态下运行。如果不使用using语句或事后不处理这些对象,则系统可能需要很长时间才能对这些对象进行垃圾回收,并使内存再次可用。
罗伯·史密斯

9
就像您说的那样:可能需要很长时间。但这不是内存泄漏。如果永远不会释放内存,那将是内存泄漏。但这是垃圾收集器的正常行为,即当CPU空闲时它释放内存。using()语句不能防止内存泄漏。它只是立即释放内存,而垃圾收集器在有时间这样做时释放内存。这是此特定情况下的唯一区别。
Elmue 2014年

请参阅调整图像大小的陷阱:nathanaeljones.com/blog/2009/20-image-resizing-pitfalls “使用GetThumbnailImage()。GetThumbnailImage()似乎是显而易见的选择,许多文章建议使用它。不幸的是,它总是抓住嵌入式jpeg如果有缩略图,则有些照片具有这些缩略图,有些则没有-这通常取决于您的相机。您会奇怪为什么GetThumbnailImage在某些照片上效果很好,而在另一些照片上却模糊不清。因此,比10px x 10px”。
Nick Painter

12

你可以试试净贵宾,在C#绑定libvips。它是一个惰性的,流式,按需驱动的图像处理库,因此它可以执行此类操作,而无需加载整个图像。

例如,它带有一个方便的图像缩略图:

Image image = Image.Thumbnail("image.jpg", 300, 300);
image.WriteToFile("my-thumbnail.jpg");

它还支持智能裁切,这是一种智能地确定图像最重要部分并在裁切图像时使其聚焦的方法。例如:

Image image = Image.Thumbnail("owl.jpg", 128, crop: "attention");
image.WriteToFile("tn_owl.jpg");

owl.jpg偏心成分在哪里:

猫头鹰

给出以下结果:

猫头鹰聪明的庄稼

首先,它会缩小图像以使垂直轴达到128像素,然后使用该attention策略将其裁剪为128像素。该图片会在图像中搜索可能引起人眼注意的功能,请参阅Smartcrop()有关详细信息。


您对libvips的绑定似乎很棒。我一定会看看你的lib。感谢您将其提供给C#Developer!
FrenchTastic

太好了!我不知道图像处理库看起来会这么好。
dalvir '19

真好!比ImageMagick的沉重
摩西大号

10

这将 -

  • 无需循环即可调整宽度和高度的大小
  • 不超过图片的原始尺寸

//////////////

private void ResizeImage(Image img, double maxWidth, double maxHeight)
{
    double resizeWidth = img.Source.Width;
    double resizeHeight = img.Source.Height;

    double aspect = resizeWidth / resizeHeight;

    if (resizeWidth > maxWidth)
    {
        resizeWidth = maxWidth;
        resizeHeight = resizeWidth / aspect;
    }
    if (resizeHeight > maxHeight)
    {
        aspect = resizeWidth / resizeHeight;
        resizeHeight = maxHeight;
        resizeWidth = resizeHeight * aspect;
    }

    img.Width = resizeWidth;
    img.Height = resizeHeight;
}

11
OP询问有关System.Drawing.Image的问题,由于无法设置'Width'和'Height'属性,因此您的代码无法使用。但是,它将适用于System.Windows.Controls.Image。
mmmdreg 2013年

10
public static Image resizeImage(Image image, int new_height, int new_width)
{
    Bitmap new_image = new Bitmap(new_width, new_height);
    Graphics g = Graphics.FromImage((Image)new_image );
    g.InterpolationMode = InterpolationMode.High;
    g.DrawImage(image, 0, 0, new_width, new_height);
    return new_image;
}

您忘记了处理图形。似乎与具有更好插值模式的新Bitmap(图像,宽度,高度)相同的原理。我很好奇默认是什么?甚至比还差Low吗?
Sinatr

9

这段代码与以上答案之一发布的代码相同。但是会将透明像素转换为白色而不是黑色...谢谢:)

    public Image resizeImage(int newWidth, int newHeight, string stPhotoPath)
    {
        Image imgPhoto = Image.FromFile(stPhotoPath);

        int sourceWidth = imgPhoto.Width;
        int sourceHeight = imgPhoto.Height;

        //Consider vertical pics
        if (sourceWidth < sourceHeight)
        {
            int buff = newWidth;

            newWidth = newHeight;
            newHeight = buff;
        }

        int sourceX = 0, sourceY = 0, destX = 0, destY = 0;
        float nPercent = 0, nPercentW = 0, nPercentH = 0;

        nPercentW = ((float)newWidth / (float)sourceWidth);
        nPercentH = ((float)newHeight / (float)sourceHeight);
        if (nPercentH < nPercentW)
        {
            nPercent = nPercentH;
            destX = System.Convert.ToInt16((newWidth -
                      (sourceWidth * nPercent)) / 2);
        }
        else
        {
            nPercent = nPercentW;
            destY = System.Convert.ToInt16((newHeight -
                      (sourceHeight * nPercent)) / 2);
        }

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


        Bitmap bmPhoto = new Bitmap(newWidth, newHeight,
                      PixelFormat.Format24bppRgb);

        bmPhoto.SetResolution(imgPhoto.HorizontalResolution,
                     imgPhoto.VerticalResolution);

        Graphics grPhoto = Graphics.FromImage(bmPhoto);
        grPhoto.Clear(Color.White);
        grPhoto.InterpolationMode =
            System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

        grPhoto.DrawImage(imgPhoto,
            new Rectangle(destX, destY, destWidth, destHeight),
            new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
            GraphicsUnit.Pixel);

        grPhoto.Dispose();
        imgPhoto.Dispose();

        return bmPhoto;
    }

7

在该应用程序中,我创建了一个具有多个选项的函数。它很大,但是可以调整图像的大小,可以保持宽高比,可以切割边缘以仅返回图像的中心:

/// <summary>
    /// Resize image with a directory as source
    /// </summary>
    /// <param name="OriginalFileLocation">Image location</param>
    /// <param name="heigth">new height</param>
    /// <param name="width">new width</param>
    /// <param name="keepAspectRatio">keep the aspect ratio</param>
    /// <param name="getCenter">return the center bit of the image</param>
    /// <returns>image with new dimentions</returns>
    public Image resizeImageFromFile(String OriginalFileLocation, int heigth, int width, Boolean keepAspectRatio, Boolean getCenter)
    {
        int newheigth = heigth;
        System.Drawing.Image FullsizeImage = System.Drawing.Image.FromFile(OriginalFileLocation);

        // Prevent using images internal thumbnail
        FullsizeImage.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
        FullsizeImage.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);

        if (keepAspectRatio || getCenter)
        {
            int bmpY = 0;
            double resize = (double)FullsizeImage.Width / (double)width;//get the resize vector
            if (getCenter)
            {
                bmpY = (int)((FullsizeImage.Height - (heigth * resize)) / 2);// gives the Y value of the part that will be cut off, to show only the part in the center
                Rectangle section = new Rectangle(new Point(0, bmpY), new Size(FullsizeImage.Width, (int)(heigth * resize)));// create the section to cut of the original image
                //System.Console.WriteLine("the section that will be cut off: " + section.Size.ToString() + " the Y value is minimized by: " + bmpY);
                Bitmap orImg = new Bitmap((Bitmap)FullsizeImage);//for the correct effect convert image to bitmap.
                FullsizeImage.Dispose();//clear the original image
                using (Bitmap tempImg = new Bitmap(section.Width, section.Height))
                {
                    Graphics cutImg = Graphics.FromImage(tempImg);//              set the file to save the new image to.
                    cutImg.DrawImage(orImg, 0, 0, section, GraphicsUnit.Pixel);// cut the image and save it to tempImg
                    FullsizeImage = tempImg;//save the tempImg as FullsizeImage for resizing later
                    orImg.Dispose();
                    cutImg.Dispose();
                    return FullsizeImage.GetThumbnailImage(width, heigth, null, IntPtr.Zero);
                }
            }
            else newheigth = (int)(FullsizeImage.Height / resize);//  set the new heigth of the current image
        }//return the image resized to the given heigth and width
        return FullsizeImage.GetThumbnailImage(width, newheigth, null, IntPtr.Zero);
    }

为了使访问该函数更容易,可以添加一些重载的函数:

/// <summary>
    /// Resize image with a directory as source
    /// </summary>
    /// <param name="OriginalFileLocation">Image location</param>
    /// <param name="heigth">new height</param>
    /// <param name="width">new width</param>
    /// <returns>image with new dimentions</returns>
    public Image resizeImageFromFile(String OriginalFileLocation, int heigth, int width)
    {
        return resizeImageFromFile(OriginalFileLocation, heigth, width, false, false);
    }

    /// <summary>
    /// Resize image with a directory as source
    /// </summary>
    /// <param name="OriginalFileLocation">Image location</param>
    /// <param name="heigth">new height</param>
    /// <param name="width">new width</param>
    /// <param name="keepAspectRatio">keep the aspect ratio</param>
    /// <returns>image with new dimentions</returns>
    public Image resizeImageFromFile(String OriginalFileLocation, int heigth, int width, Boolean keepAspectRatio)
    {
        return resizeImageFromFile(OriginalFileLocation, heigth, width, keepAspectRatio, false);
    }

现在是最后两个可选的布尔值。像这样调用函数:

System.Drawing.Image ResizedImage = resizeImageFromFile(imageLocation, 800, 400, true, true);

6
public string CreateThumbnail(int maxWidth, int maxHeight, string path)
{

    var image = System.Drawing.Image.FromFile(path);
    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);
    Graphics thumbGraph = Graphics.FromImage(newImage);

    thumbGraph.CompositingQuality = CompositingQuality.HighQuality;
    thumbGraph.SmoothingMode = SmoothingMode.HighQuality;
    //thumbGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;

    thumbGraph.DrawImage(image, 0, 0, newWidth, newHeight);
    image.Dispose();

    string fileRelativePath = "newsizeimages/" + maxWidth + Path.GetFileName(path);
    newImage.Save(Server.MapPath(fileRelativePath), newImage.RawFormat);
    return fileRelativePath;
}

单击此处http://bhupendrasinghsaini.blogspot.in/2014/07/resize-image-in-c.html


6

这是我为特定要求制定的代码,即:目的地始终为横向比例。它应该给您一个好的开始。

public Image ResizeImage(Image source, RectangleF destinationBounds)
{
    RectangleF sourceBounds = new RectangleF(0.0f,0.0f,(float)source.Width, (float)source.Height);
    RectangleF scaleBounds = new RectangleF();

    Image destinationImage = new Bitmap((int)destinationBounds.Width, (int)destinationBounds.Height);
    Graphics graph = Graphics.FromImage(destinationImage);
    graph.InterpolationMode =
        System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

    // Fill with background color
    graph.FillRectangle(new SolidBrush(System.Drawing.Color.White), destinationBounds);

    float resizeRatio, sourceRatio;
    float scaleWidth, scaleHeight;

    sourceRatio = (float)source.Width / (float)source.Height;

    if (sourceRatio >= 1.0f)
    {
        //landscape
        resizeRatio = destinationBounds.Width / sourceBounds.Width;
        scaleWidth = destinationBounds.Width;
        scaleHeight = sourceBounds.Height * resizeRatio;
        float trimValue = destinationBounds.Height - scaleHeight;
        graph.DrawImage(source, 0, (trimValue / 2), destinationBounds.Width, scaleHeight);
    }
    else
    {
        //portrait
        resizeRatio = destinationBounds.Height/sourceBounds.Height;
        scaleWidth = sourceBounds.Width * resizeRatio;
        scaleHeight = destinationBounds.Height;
        float trimValue = destinationBounds.Width - scaleWidth;
        graph.DrawImage(source, (trimValue / 2), 0, scaleWidth, destinationBounds.Height);
    }

    return destinationImage;

}

太棒了!!! 我在人像图片方面遇到了麻烦,在尝试了许多在网络上寻求的解决方案后,这才是完美的!非常感谢!
法比奥

3

如果您正在使用BitmapSource

var resizedBitmap = new TransformedBitmap(
    bitmapSource,
    new ScaleTransform(scaleX, scaleY));

如果要更好地控制质量,请首先运行以下命令:

RenderOptions.SetBitmapScalingMode(
    bitmapSource,
    BitmapScalingMode.HighQuality);

(默认BitmapScalingMode.Linear等于BitmapScalingMode.LowQuality。)



1

调整大小并保存图像以适合宽度和高度,例如画布,使图像保持比例

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;

namespace Infra.Files
{
    public static class GenerateThumb
    {
        /// <summary>
        /// Resize and save an image to fit under width and height like a canvas keeping things proportional
        /// </summary>
        /// <param name="originalImagePath"></param>
        /// <param name="thumbImagePath"></param>
        /// <param name="newWidth"></param>
        /// <param name="newHeight"></param>
        public static void GenerateThumbImage(string originalImagePath, string thumbImagePath, int newWidth, int newHeight)
        {
            Bitmap srcBmp = new Bitmap(originalImagePath);
            float ratio = 1;
            float minSize = Math.Min(newHeight, newHeight);

            if (srcBmp.Width > srcBmp.Height)
            {
                ratio = minSize / (float)srcBmp.Width;
            }
            else
            {
                ratio = minSize / (float)srcBmp.Height;
            }

            SizeF newSize = new SizeF(srcBmp.Width * ratio, srcBmp.Height * ratio);
            Bitmap target = new Bitmap((int)newSize.Width, (int)newSize.Height);

            using (Graphics graphics = Graphics.FromImage(target))
            {
                graphics.CompositingQuality = CompositingQuality.HighSpeed;
                graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                graphics.CompositingMode = CompositingMode.SourceCopy;
                graphics.DrawImage(srcBmp, 0, 0, newSize.Width, newSize.Height);

                using (MemoryStream memoryStream = new MemoryStream())
                {
                    target.Save(thumbImagePath);
                }
            }
        }
    }
}

1

将以下功能与以下示例结合使用以更改图像尺寸:

//Example : 
System.Net.Mime.MediaTypeNames.Image newImage = System.Net.Mime.MediaTypeNames.Image.FromFile("SampImag.jpg");
System.Net.Mime.MediaTypeNames.Image temImag = FormatImage(newImage, 100, 100);

//image size modification unction   
public static System.Net.Mime.MediaTypeNames.Image FormatImage(System.Net.Mime.MediaTypeNames.Image img, int outputWidth, int outputHeight)
{

    Bitmap outputImage = null;
    Graphics graphics = null;
    try
    {
         outputImage = new Bitmap(outputWidth, outputHeight, System.Drawing.Imaging.PixelFormat.Format16bppRgb555);
         graphics = Graphics.FromImage(outputImage);
         graphics.DrawImage(img, new Rectangle(0, 0, outputWidth, outputHeight),
         new Rectangle(0, 0, img.Width, img.Height), GraphicsUnit.Pixel);

         return outputImage;
     }
     catch (Exception ex)
     {
           return img;
     }
}

2
请考虑在上面的答案中解释如何使用此代码,该代码的功能以及如何解决原始问题中的问题。
蒂姆·维西

我还添加了用例。结合以下示例使用上述功能。图片newImage = Image.FromFile(“ SampImag.jpg”); 图像temImag = FormatImage(newImage,100,100);
Prasad KM


0

注意:这不适用于ASP.Net Core,因为WebImage依赖于System.Web,但是在ASP.Net的早期版本中,我多次使用了此代码段,这很有用。

String ThumbfullPath = Path.GetFileNameWithoutExtension(file.FileName) + "80x80.jpg";
var ThumbfullPath2 = Path.Combine(ThumbfullPath, fileThumb);
using (MemoryStream stream = new MemoryStream(System.IO.File.ReadAllBytes(fullPath)))
{
      var thumbnail = new WebImage(stream).Resize(80, 80);
      thumbnail.Save(ThumbfullPath2, "jpg");
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.