c#在保留宽高比的同时将图像调整为不同大小
c#
image-processing
6
0

我正在尝试调整图像的大小,同时保留原始图像的长宽比,以使新图像看起来不被挤压。

例如:

将150 * 100的图像转换为150 * 150的图像。
高度的额外50像素需要用白色背景色填充。

这是我正在使用的当前代码。

它可以很好地调整大小,但更改原始图像的纵横比会挤压新图像。

private void resizeImage(string path, string originalFilename, 
                         int width, int height)
    {
        Image image = Image.FromFile(path + originalFilename);

        System.Drawing.Image thumbnail = new Bitmap(width, height);
        System.Drawing.Graphics graphic = 
                     System.Drawing.Graphics.FromImage(thumbnail);

        graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
        graphic.SmoothingMode = SmoothingMode.HighQuality;
        graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
        graphic.CompositingQuality = CompositingQuality.HighQuality;

        graphic.DrawImage(image, 0, 0, width, height);

        System.Drawing.Imaging.ImageCodecInfo[] info =
                         ImageCodecInfo.GetImageEncoders();
        EncoderParameters encoderParameters;
        encoderParameters = new EncoderParameters(1);
        encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality,
                         100L);            
        thumbnail.Save(path + width + "." + originalFilename, info[1], 
                         encoderParameters);
    }

编辑:我想有图像填充而不是裁剪

参考资料:
Stack Overflow
收藏
评论
共 9 个回答
高赞 时间 活跃

我也将在这里添加我的代码。此代码将允许您在执行或不执行宽高比的情况下调整图像的大小,或通过填充来调整大小。这是egrunin代码的修改版本。

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

namespace ConsoleApplication1
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var path = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.FullName;
            ResizeImage(path, "large.jpg", path, "new.jpg", 100, 100, true, true);
        }

        /// <summary>Resizes an image to a new width and height.</summary>
        /// <param name="originalPath">The folder which holds the original image.</param>
        /// <param name="originalFileName">The file name of the original image.</param>
        /// <param name="newPath">The folder which will hold the resized image.</param>
        /// <param name="newFileName">The file name of the resized image.</param>
        /// <param name="maximumWidth">When resizing the image, this is the maximum width to resize the image to.</param>
        /// <param name="maximumHeight">When resizing the image, this is the maximum height to resize the image to.</param>
        /// <param name="enforceRatio">Indicates whether to keep the width/height ratio aspect or not. If set to false, images with an unequal width and height will be distorted and padding is disregarded. If set to true, the width/height ratio aspect is maintained and distortion does not occur.</param>
        /// <param name="addPadding">Indicates whether fill the smaller dimension of the image with a white background. If set to true, the white padding fills the smaller dimension until it reach the specified max width or height. This is used for maintaining a 1:1 ratio if the max width and height are the same.</param>
        private static void ResizeImage(string originalPath, string originalFileName, string newPath, string newFileName, int maximumWidth, int maximumHeight, bool enforceRatio, bool addPadding)
        {
            var image = Image.FromFile(originalPath + "\\" + originalFileName);
            var imageEncoders = ImageCodecInfo.GetImageEncoders();
            EncoderParameters encoderParameters = new EncoderParameters(1);
            encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 100L);
            var canvasWidth = maximumWidth;
            var canvasHeight = maximumHeight;
            var newImageWidth = maximumWidth;
            var newImageHeight = maximumHeight;
            var xPosition = 0;
            var yPosition = 0;


            if (enforceRatio)
            {
                var ratioX = maximumWidth / (double)image.Width;
                var ratioY = maximumHeight / (double)image.Height;
                var ratio = ratioX < ratioY ? ratioX : ratioY;
                newImageHeight = (int)(image.Height * ratio);
                newImageWidth = (int)(image.Width * ratio);

                if (addPadding)
                {
                    xPosition = (int)((maximumWidth - (image.Width * ratio)) / 2);
                    yPosition = (int)((maximumHeight - (image.Height * ratio)) / 2);
                }
                else
                {
                    canvasWidth = newImageWidth;
                    canvasHeight = newImageHeight;                  
                }
            }

            var thumbnail = new Bitmap(canvasWidth, canvasHeight);
            var graphic = Graphics.FromImage(thumbnail);

            if (enforceRatio && addPadding)
            {
                graphic.Clear(Color.White);
            }

            graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
            graphic.SmoothingMode = SmoothingMode.HighQuality;
            graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
            graphic.CompositingQuality = CompositingQuality.HighQuality;
            graphic.DrawImage(image, xPosition, yPosition, newImageWidth, newImageHeight);

            thumbnail.Save(newPath + "\\" + newFileName, imageEncoders[1], encoderParameters);
        }
    }
}
收藏
评论

这应该做。

private void resizeImage(string path, string originalFilename, 
                     /* note changed names */
                     int canvasWidth, int canvasHeight, 
                     /* new */
                     int originalWidth, int originalHeight)
{
    Image image = Image.FromFile(path + originalFilename);

    System.Drawing.Image thumbnail = 
        new Bitmap(canvasWidth, canvasHeight); // changed parm names
    System.Drawing.Graphics graphic = 
                 System.Drawing.Graphics.FromImage(thumbnail);

    graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
    graphic.SmoothingMode = SmoothingMode.HighQuality;
    graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
    graphic.CompositingQuality = CompositingQuality.HighQuality;

    /* ------------------ new code --------------- */

    // Figure out the ratio
    double ratioX = (double) canvasWidth / (double) originalWidth;
    double ratioY = (double) canvasHeight / (double) originalHeight;
    // use whichever multiplier is smaller
    double ratio = ratioX < ratioY ? ratioX : ratioY;

    // now we can get the new height and width
    int newHeight = Convert.ToInt32(originalHeight * ratio);
    int newWidth = Convert.ToInt32(originalWidth * ratio);

    // Now calculate the X,Y position of the upper-left corner 
    // (one of these will always be zero)
    int posX = Convert.ToInt32((canvasWidth - (originalWidth * ratio)) / 2);
    int posY = Convert.ToInt32((canvasHeight - (originalHeight * ratio)) / 2);

    graphic.Clear(Color.White); // white padding
    graphic.DrawImage(image, posX, posY, newWidth, newHeight);

    /* ------------- end new code ---------------- */

    System.Drawing.Imaging.ImageCodecInfo[] info =
                     ImageCodecInfo.GetImageEncoders();
    EncoderParameters encoderParameters;
    encoderParameters = new EncoderParameters(1);
    encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality,
                     100L);            
    thumbnail.Save(path + newWidth + "." + originalFilename, info[1], 
                     encoderParameters);
}

编辑添加:

那些想要改进此代码的人应该将其放入注释或新答案中。不要直接编辑此代码。

收藏
评论

我从此CodeProject文章中学到了如何调整图像大小和填充图像。

static Image FixedSize(Image imgPhoto, int Width, int Height)
    {
        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)Width / (float)sourceWidth);
        nPercentH = ((float)Height / (float)sourceHeight);
        if (nPercentH < nPercentW)
        {
            nPercent = nPercentH;
            destX = System.Convert.ToInt16((Width -
                          (sourceWidth * nPercent)) / 2);
        }
        else
        {
            nPercent = nPercentW;
            destY = System.Convert.ToInt16((Height -
                          (sourceHeight * nPercent)) / 2);
        }

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

        Bitmap bmPhoto = new Bitmap(Width, Height,
                          PixelFormat.Format24bppRgb);
        bmPhoto.SetResolution(imgPhoto.HorizontalResolution,
                         imgPhoto.VerticalResolution);

        Graphics grPhoto = Graphics.FromImage(bmPhoto);
        grPhoto.Clear(Color.Red);
        grPhoto.InterpolationMode =
                InterpolationMode.HighQualityBicubic;

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

        grPhoto.Dispose();
        return bmPhoto;
    }
收藏
评论

为了获得更快的结果,可以在resultSize找到获得大小的函数:

Size original = new Size(640, 480);

int maxSize = 100;

float percent = (new List<float> { (float)maxSize / (float)original.Width , (float)maxSize  / (float)original.Height }).Min();

Size resultSize = new Size((int)Math.Floor(original.Width * percent), (int)Math.Floor(original.Height * percent));

使用Linq最小化变量和重新计算,以及不必要的if/else语句

收藏
评论

// This allows us to resize the image. It prevents skewed images and 
// also vertically long images caused by trying to maintain the aspect 
// ratio on images who's height is larger than their width

public void ResizeImage(string OriginalFile, string NewFile, int NewWidth, int MaxHeight, bool OnlyResizeIfWider)

{
    System.Drawing.Image FullsizeImage = System.Drawing.Image.FromFile(OriginalFile);

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

    if (OnlyResizeIfWider)
    {
        if (FullsizeImage.Width <= NewWidth)
        {
            NewWidth = FullsizeImage.Width;
        }
    }

    int NewHeight = FullsizeImage.Height * NewWidth / FullsizeImage.Width;
    if (NewHeight > MaxHeight)
    {
        // Resize with height instead
        NewWidth = FullsizeImage.Width * MaxHeight / FullsizeImage.Height;
        NewHeight = MaxHeight;
    }

    System.Drawing.Image NewImage = FullsizeImage.GetThumbnailImage(NewWidth, NewHeight, null, IntPtr.Zero);

    // Clear handle to original file so that we can overwrite it if necessary
    FullsizeImage.Dispose();

    // Save resized picture
    NewImage.Save(NewFile);
}

收藏
评论

我使用以下方法来计算所需的图像尺寸:

using System.Drawing;
public static Size ResizeKeepAspect(this Size src, int maxWidth, int maxHeight, bool enlarge = false)
{
    maxWidth = enlarge ? maxWidth : Math.Min(maxWidth, src.Width);
    maxHeight = enlarge ? maxHeight : Math.Min(maxHeight, src.Height);

    decimal rnd = Math.Min(maxWidth / (decimal)src.Width, maxHeight / (decimal)src.Height);
    return new Size((int)Math.Round(src.Width * rnd), (int)Math.Round(src.Height * rnd));
}

这将纵横比和尺寸的问题放在单独的方法中。

收藏
评论

注意:此代码将调整大小并删除长宽比之外的所有内容,而不是填充它。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

namespace MyPhotos.Common
{
    public class ThumbCreator
    {

        public enum VerticalAlign
        {
            Top,
            Middle,
            Bottom
        }

        public enum HorizontalAlign
        {
            Left,
            Middle,
            Right
        }

        public void Convert(string sourceFile, string targetFile, ImageFormat targetFormat, int height, int width, VerticalAlign valign, HorizontalAlign halign)
        {
            using (Image img = Image.FromFile(sourceFile))
            {
                using (Image targetImg = Convert(img, height, width, valign, halign))
                {
                    string directory = Path.GetDirectoryName(targetFile);
                    if (!Directory.Exists(directory))
                    {
                        Directory.CreateDirectory(directory);
                    }
                    if (targetFormat == ImageFormat.Jpeg)
                    {
                        SaveJpeg(targetFile, targetImg, 100);
                    }
                    else
                    {
                        targetImg.Save(targetFile, targetFormat);
                    }
                }
            }
        }

        /// <summary> 
        /// Saves an image as a jpeg image, with the given quality 
        /// </summary> 
        /// <param name="path">Path to which the image would be saved.</param> 
        // <param name="quality">An integer from 0 to 100, with 100 being the 
        /// highest quality</param> 
        public static void SaveJpeg(string path, Image img, int quality)
        {
            if (quality < 0 || quality > 100)
                throw new ArgumentOutOfRangeException("quality must be between 0 and 100.");


            // Encoder parameter for image quality 
            EncoderParameter qualityParam =
                new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
            // Jpeg image codec 
            ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");

            EncoderParameters encoderParams = new EncoderParameters(1);
            encoderParams.Param[0] = qualityParam;

            img.Save(path, jpegCodec, encoderParams);
        }

        /// <summary> 
        /// Returns the image codec with the given mime type 
        /// </summary> 
        private static ImageCodecInfo GetEncoderInfo(string mimeType)
        {
            // Get image codecs for all image formats 
            ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();

            // Find the correct image codec 
            for (int i = 0; i < codecs.Length; i++)
                if (codecs[i].MimeType == mimeType)
                    return codecs[i];
            return null;
        }

        public Image Convert(Image img, int height, int width, VerticalAlign valign, HorizontalAlign halign)
        {
            Bitmap result = new Bitmap(width, height);
            using (Graphics g = Graphics.FromImage(result))
            {
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                float ratio = (float)height / (float)img.Height;
                int temp = (int)((float)img.Width * ratio);
                if (temp == width)
                {
                    //no corrections are needed!
                    g.DrawImage(img, 0, 0, width, height);
                    return result;
                }
                else if (temp > width)
                {
                    //den e för bred!
                    int overFlow = (temp - width);
                    if (halign == HorizontalAlign.Middle)
                    {
                        g.DrawImage(img, 0 - overFlow / 2, 0, temp, height);
                    }
                    else if (halign == HorizontalAlign.Left)
                    {
                        g.DrawImage(img, 0, 0, temp, height);
                    }
                    else if (halign == HorizontalAlign.Right)
                    {
                        g.DrawImage(img, -overFlow, 0, temp, height);
                    }
                }
                else
                {
                    //den e för hög!
                    ratio = (float)width / (float)img.Width;
                    temp = (int)((float)img.Height * ratio);
                    int overFlow = (temp - height);
                    if (valign == VerticalAlign.Top)
                    {
                        g.DrawImage(img, 0, 0, width, temp);
                    }
                    else if (valign == VerticalAlign.Middle)
                    {
                        g.DrawImage(img, 0, -overFlow / 2, width, temp);
                    }
                    else if (valign == VerticalAlign.Bottom)
                    {
                        g.DrawImage(img, 0, -overFlow, width, temp);
                    }
                }
            }
            return result;
        }
    }
}
收藏
评论

只需将其归纳为宽高比和尺寸,即可在此功能之外完成图像处理

public static d.RectangleF ScaleRect(d.RectangleF dest, d.RectangleF src, 
  bool keepWidth, bool keepHeight)  
{
    d.RectangleF destRect = new d.RectangleF();

    float sourceAspect = src.Width / src.Height;
    float destAspect = dest.Width / dest.Height;

    if (sourceAspect > destAspect)
    {
        // wider than high keep the width and scale the height
        destRect.Width = dest.Width;
        destRect.Height = dest.Width / sourceAspect;

        if (keepHeight)
        {
            float resizePerc = dest.Height / destRect.Height;
            destRect.Width = dest.Width * resizePerc;
            destRect.Height = dest.Height;
        }
    }
    else
    {
        // higher than wide – keep the height and scale the width
        destRect.Height = dest.Height;
        destRect.Width = dest.Height * sourceAspect;

        if (keepWidth)
        {
            float resizePerc = dest.Width / destRect.Width;
            destRect.Width = dest.Width;
            destRect.Height = dest.Height * resizePerc;
        }

    }

    return destRect;
}
收藏
评论

这是与Image配合使用的一种不太具体的扩展方法,而不是为您进行加载和保存。它还允许您指定插值方法,并在使用NearestNeighbour插值时正确渲染边缘。

该图像将在您指定区域的边界内渲染,因此您始终知道输出的宽度和高度。例如:

在范围内缩放

namespace YourApp
{
    #region Namespaces
    using System;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.Drawing.Drawing2D;
    #endregion

    /// <summary>Generic helper functions related to graphics.</summary>
    public static class ImageExtensions
    {
        /// <summary>Resizes an image to a new width and height value.</summary>
        /// <param name="image">The image to resize.</param>
        /// <param name="newWidth">The width of the new image.</param>
        /// <param name="newHeight">The height of the new image.</param>
        /// <param name="mode">Interpolation mode.</param>
        /// <param name="maintainAspectRatio">If true, the image is centered in the middle of the returned image, maintaining the aspect ratio of the original image.</param>
        /// <returns>The new image. The old image is unaffected.</returns>
        public static Image ResizeImage(this Image image, int newWidth, int newHeight, InterpolationMode mode = InterpolationMode.Default, bool maintainAspectRatio = false)
        {
            Bitmap output = new Bitmap(newWidth, newHeight, image.PixelFormat);

            using (Graphics gfx = Graphics.FromImage(output))
            {
                gfx.Clear(Color.FromArgb(0, 0, 0, 0));
                gfx.InterpolationMode = mode;
                if (mode == InterpolationMode.NearestNeighbor)
                {
                    gfx.PixelOffsetMode = PixelOffsetMode.HighQuality;
                    gfx.SmoothingMode = SmoothingMode.HighQuality;
                }

                double ratioW = (double)newWidth / (double)image.Width;
                double ratioH = (double)newHeight / (double)image.Height;
                double ratio = ratioW < ratioH ? ratioW : ratioH;
                int insideWidth = (int)(image.Width * ratio);
                int insideHeight = (int)(image.Height * ratio);

                gfx.DrawImage(image, new Rectangle((newWidth / 2) - (insideWidth / 2), (newHeight / 2) - (insideHeight / 2), insideWidth, insideHeight));
            }

            return output;
        }
    }
}
收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号