c#图像resize,同时保留宽高比
我正在尝试调整图像的大小,同时保留原始图像的宽高比,以免新图像变形。
例如:
将150 * 100图像转换为150 * 150图像。
高度的额外50个像素需要填充白色背景颜色。
这是我正在使用的当前代码。
对于resize非常有效,但是改变原始图像的纵横比可以压缩新图像。
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); }
编辑:我想有图像填充而不是裁剪
这应该做到这一点。
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; }
我使用下面的方法来计算所需的图像大小:
using System.Drawing; public static Size ResizeKeepAspect(Size CurrentDimensions, int maxWidth, int maxHeight) { int newHeight = CurrentDimensions.Height; int newWidth = CurrentDimensions.Width; if (maxWidth > 0 && newWidth > maxWidth) //WidthResize { Decimal divider = Math.Abs((Decimal)newWidth / (Decimal)maxWidth); newWidth = maxWidth; newHeight = (int)Math.Round((Decimal)(newHeight / divider)); } if (maxHeight > 0 && newHeight > maxHeight) //HeightResize { Decimal divider = Math.Abs((Decimal)newHeight / (Decimal)maxHeight); newHeight = maxHeight; newWidth = (int)Math.Round((Decimal)(newWidth / divider)); } return new Size(newWidth, newHeight); }
这就把宽高比的问题放在一个单独的方法中,只返回新的图像尺寸。
更新:
这是一个较短的版本:
public static Size ResizeKeepAspect(Size src, int maxWidth, int maxHeight) { 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)); }
只是将其概括为高宽比和大小,图像的东西可以在这个function之外完成
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; }
为了得到更快的结果,可以在resultSize
find获得大小的函数:
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
来最小化variables和重新计算,以及不必要的if/else
语句
我也要在这里添加我的代码。 此代码将允许您调整带宽或不带宽高比的图像大小,或使用填充resize。 这是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); } } }
// 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); }
注:此代码resize,并删除宽高比,而不是填充它的一切。
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; } } }
这是一个不太具体的扩展方法,与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; } } }
保持方面定量,并消除信箱和Pillarbox。
static Image FixedSize(Image imgPhoto, int Width, int Height) { int sourceWidth = imgPhoto.Width; int sourceHeight = imgPhoto.Height; int X = 0; int Y = 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; } else { nPercent = nPercentW; } int destWidth = (int)(sourceWidth * nPercent); int destHeight = (int)(sourceHeight * nPercent); Bitmap bmPhoto = new Bitmap(destWidth, destHeight, PixelFormat.Format24bppRgb); bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution); Graphics grPhoto = Graphics.FromImage(bmPhoto); grPhoto.DrawImage(imgPhoto, new Rectangle(X, Y, destWidth, destHeight), new Rectangle(X, Y, sourceWidth, sourceHeight), GraphicsUnit.Pixel); grPhoto.Dispose(); return bmPhoto; }
即插即用! 我写了一个很容易做到这一点的图书馆! 请参阅链接… 文档和下载
private static Size CalculateDimensions(Size originalSize, Size targetSize) { Size newSize = new Size(); int cooficientA = targetSize.Height * originalSize.Width; int cooficientB = targetSize.Width * originalSize.Height; if (cooficientA < cooficientB) { newSize.Width = (int)Math.Round((double)cooficientA / originalSize.Height); newSize.Height = targetSize.Height; } else { newSize.Width = targetSize.Width; newSize.Height = (int)Math.Round((double)cooficientB / originalSize.Width); } return newSize; } Size newSize = CalculateDimensions(originalSize, targetSize); x = (targetSize.Width - newSize.Width) / 2; y = (targetSize.Height - newSize.Height) / 2;
我只是写了这个因为这里没有任何答案很简单。 您可以replace硬编码的128,无论您想要什么或基于原始图像的大小。 我想要的只是将图像重新缩放为128×128图像,保持纵横比并将结果集中在新图像中。
private Bitmap CreateLargeIconForImage(Bitmap src) { Bitmap bmp = new Bitmap(128, 128); Graphics g = Graphics.FromImage(bmp); float scale = Math.Max((float)src.Width / 128.0f, (float)src.Height / 128.0f); PointF p = new PointF(128.0f - ((float)src.Width / scale), 128.0f - ((float)src.Height / scale)); SizeF size = new SizeF((float)src.Width / scale, (float)src.Height / scale); g.DrawImage(src, new RectangleF(p, size)); return bmp; }