图像在C#中resize – 确定resize尺寸(高度和宽度)的算法

我需要缩小高度或宽度大于预定义像素值的图像。

我写了一些代码来查看原始图像,检查宽度,高度或高度和宽度是否大于最大宽度/最大高度设置。

我现在需要根据后一个值的最大值找出要resize的尺寸。

例如:如果图像为900h x 300w且MAX高度为700h我需要将高度调整为700并将宽度调整为???? < – 这是我需要计算的..

创建和保存图像文件很简单,超出了本文的范围:

 // First I get the max height and width allowed: int resizeMaxHeight = int.Parse(Utility.GetConfigValue("ResizeMaxHeight")); // in config: 700px int resizeMaxWidth = int.Parse(Utility.GetConfigValue("ResizeMaxWidth")); // in config: 500px // Save original: try { filebase.SaveAs(savedFileName); } catch (System.IO.DirectoryNotFoundException ex) { Logger.Instance.LogException(ex, 0, "FileTransfer"); } // Determin original dimensions: Image image = System.Drawing.Image.FromFile(Server.MapPath(savedFileName)); int resizeHeight, resizeWidth; bool doResize = true; // both height and width are greater than the allowed height and width: if (image.Width > resizeMaxWidth && image.Height > resizeMaxHeight) { if (image.Height > image.Width) resizeHeight = resizeMaxHeight; else resizeWidth = resizeMaxWidth; } else if (image.Width > resizeMaxWidth) { // width is too great, but height is ok resizeWidth = resizeMaxWidth; } else if (image.Height > resizeMaxHeight) { // height is too great, but width is ok resizeHeight = resizeMaxHeight; } else { // image is ok size, don't resize: doResize = false; } 

创建缩略图:这就是我现在正在工作的……不完整:

 if (doResize) { ImageUtilities.ResizeImage(image, resizeWidth, resizeHeight); } 

以下是两种进行此计算的方法。 根据您对问题的看法,可能看起来比另一个更直观。 它们在数学上等效于几个小数位。

两者对Math.Round都是安全的,但只有ConstrainVerbose产生的结果总是小于maxWidth / maxHeight。

 SizeF ConstrainConcise(int imageWidth, int imageHeight, int maxWidth, int maxHeight){ // Downscale by the smallest ratio (never upscale) var scale = Math.Min(1, Math.Min(maxWidth / (float)imageWidth, maxHeight / (float) imageHeight)); return new SizeF(scale * imageWidth, scale * imageHeight); } SizeF ConstrainVerbose(int imageWidth, int imageHeight, int maxWidth, int maxHeight){ // Coalculate the aspect ratios of the image and bounding box var maxAspect = (float) maxWidth / (float) maxHeight; var aspect = (float) imageWidth / (float) imageHeight; // Bounding box aspect is narrower if (maxAspect <= aspect && imageWidth > maxWidth) { // Use the width bound and calculate the height return new SizeF(maxWidth, Math.Min(maxHeight, maxWidth / aspect)); } else if (maxAspect > aspect && imageHeight > maxHeight) { // Use the height bound and calculate the width return new SizeF(Math.Min(maxWidth, maxHeight * aspect), maxHeight); }else{ return new SizeF(imageWidth, imageHeight); } } 

蛮力单位测试在这里

如果图像高度大于图像宽度,Nathaniel发布的解决方案实际上失败了。 以下示例生成正确的结果:

 private Size ResizeFit(Size originalSize, Size maxSize) { var widthRatio = (double)maxSize.Width / (double)originalSize.Width; var heightRatio = (double) maxSize.Height/(double) originalSize.Height; var minAspectRatio = Math.Min(widthRatio, heightRatio); if (minAspectRatio > 1) return originalSize; return new Size((int)(originalSize.Width*minAspectRatio), (int)(originalSize.Height*minAspectRatio)); } 

您可以使用一些整数技巧来避免计算纵横比(并使用双精度数)。

 // You have the new height, you need the new width int orgHeight = 1200; int orgWidth = 1920; int newHeight = 400; int newWidth = (newHeight * orgWidth) / orgHeight; // 640 

要么…

 // You have the new width, you need the new height. int orgWidth = 1920; int orgHeight = 1200; int newWidth = 800; int newHeight = (newWidth * orgHeight) / orgWidth; // 500 

以下示例将图像调整为任何所需的矩形(desWidth和desHeight),并将图像置于该矩形内。

 static Image ResizeImage(Image image, int desWidth, int desHeight) { int x, y, w, h; if (image.Height > image.Width) { w = (image.Width * desHeight) / image.Height; h = desHeight; x = (desWidth - w) / 2; y = 0; } else { w = desWidth; h = (image.Height * desWidth) / image.Width; x = 0; y = (desHeight - h) / 2; } var bmp = new Bitmap(desWidth, desHeight); using (Graphics g = Graphics.FromImage(bmp)) { g.CompositingQuality = CompositingQuality.HighQuality; g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.DrawImage(image, x, y, w, h); } return bmp; } 

我为Bitmaps做了类似的事情,但想法是一样的:

 1. get image height and width 2. get current screen resolution 3. calculate aspect ratio (ASR) from image size Handle following cases: 4. if ASR >=1 and image width > image height if image width > screen width {} if image height > screen height {} else if image width > screen width {} else {} else if image height > screen height {} else if image width > screen width {} else {} 

// SCREEN_SIZE是可配置的; Defs.SCREEN_SIZE = 100; //并且boolPixelAR为true;

请尝试以下代码:

  // PERCENTAGE OF IMAGE -> TODO: Configurable? IMAZE ZOOM / SCREEN PERCENTAGE Double HScale = __bmp.Width;// *Defs.SCREEN_SIZE / 100; Double VScale = __bmp.Height;// *Defs.SCREEN_SIZE / 100; Double __aspectRatio; Double __screenRatio = _currentScreenSize.Width / _currentScreenSize.Height; // PERCENTAGE OF SCREEN if (!_boolPixelAR) { HScale = _currentScreenSize.Width * Defs.SCREEN_SIZE / 100; VScale = _currentScreenSize.Height * Defs.SCREEN_SIZE / 100; } else { __aspectRatio = HScale / VScale; if( __aspectRatio >= 1) if (HScale >= _currentScreenSize.Width) { // Long Edge is WIDTH. For 100%, HScale = WIDTH VScale = ((VScale * _currentScreenSize.Width) / HScale) * Defs.SCREEN_SIZE / 100; HScale = _currentScreenSize.Width * Defs.SCREEN_SIZE / 100; if (VScale > _currentScreenSize.Height) { // Long Edge is HEIGHT. For 100%, VScale = HEIGHT //__aspectRatio = VScale / HScale; HScale = ((HScale * _currentScreenSize.Height) / VScale) * Defs.SCREEN_SIZE / 100; VScale = _currentScreenSize.Height * Defs.SCREEN_SIZE / 100; } } else if (VScale > _currentScreenSize.Height) { // Long Edge is HEIGHT. For 100%, VScale = HEIGHT //__aspectRatio = VScale / HScale; HScale = ((HScale * _currentScreenSize.Height) / VScale) * Defs.SCREEN_SIZE / 100; VScale = _currentScreenSize.Height * Defs.SCREEN_SIZE / 100; } else { //Do nothing... Just set Zoom. HScale = HScale * Defs.SCREEN_SIZE / 100; VScale = VScale * Defs.SCREEN_SIZE / 100; } else if (VScale > _currentScreenSize.Height) { // Long Edge is HEIGHT. For 100%, VScale = HEIGHT //__aspectRatio = VScale / HScale; HScale = ((HScale * _currentScreenSize.Height) / VScale) * Defs.SCREEN_SIZE / 100; VScale = _currentScreenSize.Height * Defs.SCREEN_SIZE / 100; } else if (HScale >= _currentScreenSize.Width) { // Long Edge is WIDTH. For 100%, HScale = WIDTH VScale = ((VScale * _currentScreenSize.Width) / HScale) * Defs.SCREEN_SIZE / 100; HScale = _currentScreenSize.Width * Defs.SCREEN_SIZE / 100; } else { //Do nothing... Just set Zoom. HScale = HScale * Defs.SCREEN_SIZE / 100; VScale = VScale * Defs.SCREEN_SIZE / 100; } ////__aspectRatio = VScale / HScale; //HScale = ((HScale * _currentScreenSize.Height) / VScale) * Defs.SCREEN_SIZE / 100; //VScale = _currentScreenSize.Height * Defs.SCREEN_SIZE / 100; } Bitmap scaledBmp = GraphicsFactory.ResizeImage( __bmp, Convert.ToInt32(HScale), Convert.ToInt32(VScale)); 

将图像拟合为新尺寸需要两个操作:

  1. resize – 调整源图像的大小以恰好适合一个维度(宽度或高度 – 比率较小的一个)

  2. 裁剪 – 将上一操作的结果裁剪为目标尺寸

这是一个小样本:

  private static Image Resize(Image img, int width, int height) { Bitmap b = new Bitmap(width, height); using (Graphics g = Graphics.FromImage((Image)b)) { g.DrawImage(img, 0, 0, width, height); } return (Image)b; } public static Image Crop(Image image, int width, int height) { int cropx = image.Width > width ? image.Width / 2 - width / 2 : 0; int cropy = image.Height > height ? image.Height / 2 - height / 2 : 0; width = image.Width > width ? width : image.Width; height = image.Height > height ? height : image.Height; Rectangle cropRect = new Rectangle(cropx, cropy, width, height); var target = new Bitmap(cropRect.Width, cropRect.Height); using (Graphics g = Graphics.FromImage(target)) { g.DrawImage(image, new Rectangle(0, 0, target.Width, target.Height), cropRect, GraphicsUnit.Pixel); } return target; } public static Image FitToSize(Image image, int width, int height) { var wratio = 1.0 * image.Width / width; var hratio = 1.0 * image.Height / height; int wresize; int hresize; if (wratio >= hratio && wratio > 1) { wresize = (int)Math.Round((double)image.Width / hratio); hresize = height; image = Resize(image, wresize, hresize); image = Crop(image, width, height); } else if (hratio >= wratio && hratio > 1) { hresize = (int)Math.Round((double)image.Height / wratio); wresize = width; image = Resize(image, wresize, hresize); image = Crop(image, width, height); } return image; }