在 asp.net 中调整图像大小而不会丢失图像质量
Posted
技术标签:
【中文标题】在 asp.net 中调整图像大小而不会丢失图像质量【英文标题】:Resizing an image in asp.net without losing the image quality 【发布时间】:2011-01-20 04:05:21 【问题描述】:我正在开发一个 ASP.NET 3.5 Web 应用程序,我允许我的用户上传 jpeg、gif、bmp 或 png 图像。如果上传的图片尺寸大于 103 x 32,我想将上传的图片调整为 103 x 32。我已经阅读了一些博客文章和文章,也尝试了一些代码示例,但似乎没有任何效果。有没有人成功做到这一点?
【问题讨论】:
贴出你正在使用的不起作用的代码,并说明它不起作用的原因。 你想强制 103x32?还是最合适的?ImageBuilder.Current.Build(HttpPostedFile file, string path, new ResizeSettings("width=103&height=32"));
//使用Image Resizer library
【参考方案1】:
这是我使用的代码。它支持旋转,并将图像分辨率设置为 72dpi@24 位颜色的 JPEG 标准(默认情况下,GDI+ 以 96dpi@32 位颜色保存图像)。它还修复了某些人在调整图像大小时遇到的黑/灰边框问题。
/// <summary>
/// Resizes and rotates an image, keeping the original aspect ratio. Does not dispose the original
/// Image instance.
/// </summary>
/// <param name="image">Image instance</param>
/// <param name="width">desired width</param>
/// <param name="height">desired height</param>
/// <param name="rotateFlipType">desired RotateFlipType</param>
/// <returns>new resized/rotated Image instance</returns>
public static Image Resize(Image image, int width, int height, RotateFlipType rotateFlipType)
// clone the Image instance, since we don't want to resize the original Image instance
var rotatedImage = image.Clone() as Image;
rotatedImage.RotateFlip(rotateFlipType);
var newSize = CalculateResizedDimensions(rotatedImage, width, height);
var resizedImage = new Bitmap(newSize.Width, newSize.Height, PixelFormat.Format32bppArgb);
resizedImage.SetResolution(72, 72);
using (var graphics = Graphics.FromImage(resizedImage))
// set parameters to create a high-quality thumbnail
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
// use an image attribute in order to remove the black/gray border around image after resize
// (most obvious on white images), see this post for more information:
// http://www.codeproject.com/KB/GDI-plus/imgresizoutperfgdiplus.aspx
using (var attribute = new ImageAttributes())
attribute.SetWrapMode(WrapMode.TileFlipXY);
// draws the resized image to the bitmap
graphics.DrawImage(rotatedImage, new Rectangle(new Point(0, 0), newSize), 0, 0, rotatedImage.Width, rotatedImage.Height, GraphicsUnit.Pixel, attribute);
return resizedImage;
/// <summary>
/// Calculates resized dimensions for an image, preserving the aspect ratio.
/// </summary>
/// <param name="image">Image instance</param>
/// <param name="desiredWidth">desired width</param>
/// <param name="desiredHeight">desired height</param>
/// <returns>Size instance with the resized dimensions</returns>
private static Size CalculateResizedDimensions(Image image, int desiredWidth, int desiredHeight)
var widthScale = (double)desiredWidth / image.Width;
var heightScale = (double)desiredHeight / image.Height;
// scale to whichever ratio is smaller, this works for both scaling up and scaling down
var scale = widthScale < heightScale ? widthScale : heightScale;
return new Size
Width = (int) (scale * image.Width),
Height = (int) (scale * image.Height)
;
【讨论】:
感谢指点灰边问题的解决方法。 此解决方案在不改变原始图像颜色的情况下调整大小!干得好! 谢谢你,这个解决方案真的对 med 有帮助。我结合了其他在调整大小的图像上打印文本的方法,效果很好。 此代码运行良好,但为了不丢失图像的透明度,您必须将PixelFormat.Format24bppRgb
更改为 PixelFormat.Format32bppArgb
【参考方案2】:
前段时间我也遇到了同样的问题,我是这样处理的:
private Image RezizeImage(Image img, int maxWidth, int maxHeight)
if(img.Height < maxHeight && img.Width < maxWidth) return img;
using (img)
Double xRatio = (double)img.Width / maxWidth;
Double yRatio = (double)img.Height / maxHeight;
Double ratio = Math.Max(xRatio, yRatio);
int nnx = (int)Math.Floor(img.Width / ratio);
int nny = (int)Math.Floor(img.Height / ratio);
Bitmap cpy = new Bitmap(nnx, nny, PixelFormat.Format32bppArgb);
using (Graphics gr = Graphics.FromImage(cpy))
gr.Clear(Color.Transparent);
// This is said to give best quality when resizing images
gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
gr.DrawImage(img,
new Rectangle(0, 0, nnx, nny),
new Rectangle(0, 0, img.Width, img.Height),
GraphicsUnit.Pixel);
return cpy;
private MemoryStream BytearrayToStream(byte[] arr)
return new MemoryStream(arr, 0, arr.Length);
private void HandleImageUpload(byte[] binaryImage)
Image img = RezizeImage(Image.FromStream(BytearrayToStream(binaryImage)), 103, 32);
img.Save("IMAGELOCATION.png", System.Drawing.Imaging.ImageFormat.Gif);
我刚刚读到这是获得最高质量的方法。
【讨论】:
在新版本中,我还考虑到我不会拉伸图像,但这应该很容易解决:-P(提示:ration = Math.Min(ration, 1.0);
)
嗯,还有一个few more settings that will help,比如像素偏移。
谢谢。不幸的是,当我将大 (3264 x 2448) 图像缩小到 60 x 45 时,我看到的结果顶部和左侧边缘模糊。
这是一个很好的解决方案。请注意,运行后 PropertyInfo 为空。因此,如果您打算将图像旋转为直立,请先执行此操作。【参考方案3】:
与实际调整位图大小相关的代码如下。
public static Bitmap ResizeBitmap( Bitmap originalBitmap, int requiredHeight, int requiredWidth )
int[] heightWidthRequiredDimensions;
// Pass dimensions to worker method depending on image type required
heightWidthRequiredDimensions = WorkDimensions(originalBitmap.Height, originalBitmap.Width, requiredHeight, requiredWidth);
Bitmap resizedBitmap = new Bitmap( heightWidthRequiredDimensions[1],
heightWidthRequiredDimensions[0] );
const float resolution = 72;
resizedBitmap.SetResolution( resolution, resolution );
Graphics graphic = Graphics.FromImage( (Image) resizedBitmap );
graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
graphic.DrawImage( originalBitmap, 0, 0, resizedBitmap.Width, resizedBitmap.Height );
graphic.Dispose();
originalBitmap.Dispose();
//resizedBitmap.Dispose(); // Still in use
return resizedBitmap;
private static int[] WorkDimensions(int originalHeight, int originalWidth, int requiredHeight, int requiredWidth )
int imgHeight = 0;
int imgWidth = 0;
imgWidth = requiredHeight;
imgHeight = requiredWidth;
int requiredHeightLocal = originalHeight;
int requiredWidthLocal = originalWidth;
double ratio = 0;
// Check height first
// If original height exceeds maximum, get new height and work ratio.
if ( originalHeight > imgHeight )
ratio = double.Parse( ( (double) imgHeight / (double) originalHeight ).ToString() );
requiredHeightLocal = imgHeight;
requiredWidthLocal = (int) ( (decimal) originalWidth * (decimal) ratio );
// Check width second. It will most likely have been sized down enough
// in the previous if statement. If not, change both dimensions here by width.
// If new width exceeds maximum, get new width and height ratio.
if ( requiredWidthLocal >= imgWidth )
ratio = double.Parse( ( (double) imgWidth / (double) originalWidth ).ToString() );
requiredWidthLocal = imgWidth;
requiredHeightLocal = (int) ( (double) originalHeight * (double) ratio );
int[] heightWidthDimensionArr = requiredHeightLocal, requiredWidthLocal ;
return heightWidthDimensionArr;
这篇博文包含图像大小调整和压缩(如果需要)的完整源代码
http://blog.bombdefused.com/2010/08/bulk-image-optimizer-in-c-full-source.html
【讨论】:
【参考方案4】:我通过创建图像的位图然后调整位图大小成功地做到了这一点...我不确定这是否是最好或最有效的方法,但它对我有用。
就我而言,我需要将图像的高度和宽度减半。
这就是我所做的。
private Image getImageFromBytes(byte[] myByteArray)
System.IO.MemoryStream newImageStream = new System.IO.MemoryStream(myByteArray, 0, myByteArray.Length);
Image image = Image.FromStream(newImageStream, true);
Bitmap resized = new Bitmap(image, image.Width / 2, image.Height / 2);
image.Dispose();
newImageStream.Dispose();
return resized;
【讨论】:
【参考方案5】:public static System.Drawing.Image ScaleImage(System.Drawing.Image image, int maxImageHeight)
/* we will resize image based on the height/width ratio by passing expected height as parameter. Based on Expected height and current image height, new ratio will be arrived and using the same we will do the resizing of image width. */
var ratio = (double)maxImageHeight / image.Height;
var newWidth = (int)(image.Width * ratio);
var newHeight = (int)(image.Height * ratio);
var newImage = new Bitmap(newWidth, newHeight);
using (var g = Graphics.FromImage(newImage))
g.DrawImage(image, 0, 0, newWidth, newHeight);
return newImage;
【讨论】:
【参考方案6】: decimal size = Math.Round(((decimal)fUpload.PostedFile.ContentLength / (decimal)1024), 2);
DirectoryInfo dir = new DirectoryInfo(MapPath("Images"));
FileInfo[] files = dir.GetFiles();
foreach (FileInfo info in files)
decimal size2 = Math.Round(((decimal)info.Length / (decimal)1024), 2);
string Image_name = info.Name.ToString();
string targetPath = Server.MapPath("Images/" + Image_name);
string strm = Server.MapPath("Images/" + Image_name);
var targetFile = targetPath;
ReduceImageSize(0.5, strm, targetFile, Image_name);
【讨论】:
如何实施 103x32 的限制?【参考方案7】: // Fixed Size Image Generate Code
protected void btnUpload_Click(object sender, EventArgs e)
decimal size = Math.Round(((decimal)fUpload.PostedFile.ContentLength / (decimal)1024), 2);
DirectoryInfo dir = new DirectoryInfo(MapPath("Images"));
FileInfo[] files = dir.GetFiles();
foreach (FileInfo info in files)
decimal size2 = Math.Round(((decimal)info.Length / (decimal)1024), 2);
string Image_name = info.Name.ToString();
string targetPath = Server.MapPath("Images/" + Image_name);
string strm = Server.MapPath("Images/" + Image_name);
var targetFile = targetPath;
ReduceImageSize(0.5, strm, targetFile, Image_name);
public void ReduceImageSize(double scaleFactor, String sourcePath, string targetPath, string Image_name)
// Fixed Size Image Generate Code
public void ReduceImageSize(double scaleFactor, String sourcePath, string targetPath, string Image_name)
using (var image = System.Drawing.Image.FromFile(sourcePath))
//var newWidth = (int)(image.Width * scaleFactor);
//var newHeight = (int)(image.Height * scaleFactor);
var newWidth = (int)(500 * scaleFactor);
var newHeight = (int)(500 * scaleFactor);
var thumbnailImg = new Bitmap(newWidth, newHeight);
var thumbGraph = Graphics.FromImage(thumbnailImg);
thumbGraph.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
thumbGraph.SmoothingMode = SmoothingMode.HighQuality;
thumbGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;
var imageRectangle = new System.Drawing.RectangleF (0, 0, newWidth, newHeight);
thumbGraph.DrawImage(image, imageRectangle);
MemoryStream s = new MemoryStream();
thumbnailImg.Save(s, System.Drawing.Imaging.ImageFormat.Png);
s.Position = 0;
byte[] image2 = new byte[525000];// 512kb =525000
s.Read(image2, 0, image2.Length);
Guid guid = Guid.NewGuid();
string Server_MapPath = Server.MapPath("~/Image Compress/" + Image_name + guid.ToString() + ".PNG");//Your Compressor Image Save Path
System.IO.FileStream fs = new System.IO.FileStream(Server_MapPath, System.IO.FileMode.Create, System.IO.FileAccess.ReadWrite);
fs.Write(image2, 0, image2.Length);
【讨论】:
以上是关于在 asp.net 中调整图像大小而不会丢失图像质量的主要内容,如果未能解决你的问题,请参考以下文章
在 Mono 上运行 ASP.NET 5 的 Ubuntu 上使用 MVC 6 调整图像大小