C#从中心裁剪图像

我正在使用.NET(4.5)MVC(4.0)C#(5.0)开发应用程序。 我想从我已经拥有的图像生成图像缩略图。 现在的要求是它应该从图像中心生成最大方形部分的缩略图而不拉伸除了图像之外的整个图像是方形尺寸。

例如我的原始图像大小:578×700我想生成占位符大小的缩略图:200×150,185×138,140×140,89×66,80×80,45×45,28×28

我创建了我的下面的代码,但没有得到确切的结果。 这是生成缩略图的核心方法

public string GenerateThumbnailFromImage(string imageFilePath, int thumbWidth, int thumbHeight) { try { //Check if file exist if (File.Exists(imageFilePath)) { //bool preserveAspectRatio = true; string oldFilePath = imageFilePath; string folderPath = Path.GetDirectoryName(imageFilePath); string filename = Path.GetFileNameWithoutExtension(imageFilePath); //Rename file with thumbnail size filename = filename + "_" + thumbWidth.ToString() + Path.GetExtension(imageFilePath); imageFilePath = Path.Combine(folderPath, filename); using (Image image = Image.FromFile(oldFilePath)) { decimal originalWidth = image.Width; decimal originalHeight = image.Height; decimal requiredThumbWidth = thumbWidth; decimal requiredThumbHeight = thumbHeight; decimal startXPosition = 0; decimal startYPosition = 0; decimal screenWidth = originalWidth; decimal screenHeight = originalHeight; decimal ar = thumbWidth  originalHeight) startXPosition = (originalWidth - originalHeight) / 2; else if (originalHeight > originalWidth) startYPosition = (originalHeight - originalWidth) / 2; if (thumbWidth>thumbHeight) { requiredThumbWidth = thumbWidth; requiredThumbHeight = requiredThumbWidth*ar; } else if (thumbHeight>thumbWidth) { requiredThumbHeight = thumbHeight; requiredThumbWidth = requiredThumbHeight*ar; } else { requiredThumbWidth = thumbWidth; requiredThumbHeight = thumbWidth; } using (var bmp = new Bitmap((int)requiredThumbWidth, (int)requiredThumbHeight)) { Graphics gr = Graphics.FromImage(bmp); gr.SmoothingMode = SmoothingMode.HighQuality; gr.CompositingQuality = CompositingQuality.HighQuality; gr.InterpolationMode = InterpolationMode.High; var rectDestination = new Rectangle(0, 0, (int)requiredThumbWidth, (int)requiredThumbHeight); gr.DrawImage(image, rectDestination, (int)startXPosition, (int)startYPosition, (int)screenWidth, (int)screenHeight, GraphicsUnit.Pixel); bmp.Save(imageFilePath); return filename; } } } return null; } catch (Exception ex) { GlobalUtil.HandleAndLogException(ex, this); throw ex; } finally { } } 

试试这个:

 bool SaveCroppedImage(Image image, int targetWidth, int targetHeight, string filePath) { ImageCodecInfo jpgInfo = ImageCodecInfo.GetImageEncoders().Where(codecInfo => codecInfo.MimeType == "image/jpeg").First(); Image finalImage = image; System.Drawing.Bitmap bitmap = null; try { int left = 0; int top = 0; int srcWidth = targetWidth; int srcHeight = targetHeight; bitmap = new System.Drawing.Bitmap(targetWidth, targetHeight); double croppedHeightToWidth = (double)targetHeight / targetWidth; double croppedWidthToHeight = (double)targetWidth / targetHeight; if (image.Width > image.Height) { srcWidth = (int)(Math.Round(image.Height * croppedWidthToHeight)); if (srcWidth < image.Width) { srcHeight = image.Height; left = (image.Width - srcWidth) / 2; } else { srcHeight = (int)Math.Round(image.Height * ((double)image.Width / srcWidth)); srcWidth = image.Width; top = (image.Height - srcHeight) / 2; } } else { srcHeight = (int)(Math.Round(image.Width * croppedHeightToWidth)); if (srcHeight < image.Height) { srcWidth = image.Width; top = (image.Height - srcHeight) / 2; } else { srcWidth = (int)Math.Round(image.Width * ((double)image.Height / srcHeight)); srcHeight = image.Height; left = (image.Width - srcWidth) / 2; } } using (Graphics g = Graphics.FromImage(bitmap)) { g.SmoothingMode = SmoothingMode.HighQuality; g.PixelOffsetMode = PixelOffsetMode.HighQuality; g.CompositingQuality = CompositingQuality.HighQuality; g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.DrawImage(image, new Rectangle(0, 0, bitmap.Width, bitmap.Height), new Rectangle(left, top, srcWidth, srcHeight), GraphicsUnit.Pixel); } finalImage = bitmap; } catch { } try { using (EncoderParameters encParams = new EncoderParameters(1)) { encParams.Param[0] = new EncoderParameter(Encoder.Quality, (long)100); //quality should be in the range [0..100] .. 100 for max, 0 for min (0 best compression) finalImage.Save(filePath, jpgInfo, encParams); return true; } } catch { } if (bitmap != null) { bitmap.Dispose(); } return false; } 

您需要获取目标大小与实际大小的比率。 缩放较短的一面,直到它接触实际图像大小。 从中心开始裁剪并将其缩放到所需的大小。

这是代码:

public static Image ResizeImage(Image imgToResize, Size destinationSize) { var originalWidth = imgToResize.Width; var originalHeight = imgToResize.Height; //how many units are there to make the original length var hRatio = (float)originalHeight/destinationSize.Height; var wRatio = (float)originalWidth/destinationSize.Width; //get the shorter side var ratio = Math.Min(hRatio, wRatio); var hScale = Convert.ToInt32(destinationSize.Height * ratio); var wScale = Convert.ToInt32(destinationSize.Width * ratio); //start cropping from the center var startX = (originalWidth - wScale)/2; var startY = (originalHeight - hScale)/2; //crop the image from the specified location and size var sourceRectangle = new Rectangle(startX, startY, wScale, hScale); //the future size of the image var bitmap = new Bitmap(destinationSize.Width, destinationSize.Height); //fill-in the whole bitmap var destinationRectangle = new Rectangle(0, 0, bitmap.Width, bitmap.Height); //generate the new image using (var g = Graphics.FromImage(bitmap)) { g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.DrawImage(imgToResize, destinationRectangle, sourceRectangle, GraphicsUnit.Pixel); } return bitmap; }
public static Image ResizeImage(Image imgToResize, Size destinationSize) { var originalWidth = imgToResize.Width; var originalHeight = imgToResize.Height; //how many units are there to make the original length var hRatio = (float)originalHeight/destinationSize.Height; var wRatio = (float)originalWidth/destinationSize.Width; //get the shorter side var ratio = Math.Min(hRatio, wRatio); var hScale = Convert.ToInt32(destinationSize.Height * ratio); var wScale = Convert.ToInt32(destinationSize.Width * ratio); //start cropping from the center var startX = (originalWidth - wScale)/2; var startY = (originalHeight - hScale)/2; //crop the image from the specified location and size var sourceRectangle = new Rectangle(startX, startY, wScale, hScale); //the future size of the image var bitmap = new Bitmap(destinationSize.Width, destinationSize.Height); //fill-in the whole bitmap var destinationRectangle = new Rectangle(0, 0, bitmap.Width, bitmap.Height); //generate the new image using (var g = Graphics.FromImage(bitmap)) { g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.DrawImage(imgToResize, destinationRectangle, sourceRectangle, GraphicsUnit.Pixel); } return bitmap; } 

这样叫:

var thumbImage = ImageHelper.ResizeImage(image, new Size(45, 45)); thumbImage.Save(thumbFullPath);
var thumbImage = ImageHelper.ResizeImage(image, new Size(45, 45)); thumbImage.Save(thumbFullPath); 

在您的NuGet包中,添加James South的 ImageFactory解决方案。 你需要的一切都在那里。 我希望我能买到更多的啤酒。

样品用法:

 using (ImageFactory imgf = new ImageFactory(preserveExifData: true)) { imgf .Load(img) .Crop(rect) .Format(new JpegFormat { Quality = 100 }) .Save(destination) } // given that : // 'img' is your Image object, could be an Image.FromFile() object or the likes // 'rect' is the size of your crop and that you have already did the math // new JpegFormat { Quality = 70 } is part of the package // and 'destination' is the destination path of your new image in your disk 

之前做了几次,诀窍是首先调整图像的高度,将宽度重新缩放到你必须减小高度的比例,然后从宽度重复,如果它仍然不适合宽度,并减少更高比例的新比例高度。 这样你有一个总是适合的缩略图,可能是X或Y中的一些空格,但图像仍然是相同的比例,而不是拉伸。

 int originalHeight; int originalWidth; int imageHeight; int imageWidth; int requiredHeight; int requiredWidth; double scale; if(originalHeight > requiredHeight) { scale = requiredHeight / originalHeight; imageHeight = requiredHeight; imageWidth = originalHeight * scale; } if(imageWidth > requiredWidth) { scale = requiredWidth / imageWidth; imageWidth = requiredWidth; imageHeight = imageHeight * scale; } 

然后使用Graphics对象将该Image绘制到此大小的新Bitmap

 public Image ScaleImage(Image image, int maxWidth, int maxHeight) { 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(maxWidth, maxWidth); using (var graphics = Graphics.FromImage(newImage)) { // Calculate x and y which center the image int y = (maxHeight/2) - newHeight / 2; int x = (maxWidth / 2) - newWidth / 2; // Draw image on x and y with newWidth and newHeight graphics.DrawImage(image, x, y, newWidth, newHeight); } return newImage; } 

同样使用ImageFactory NuGet包,我建议使用“ resize裁剪”function。

在这里查看此示例

 using ImageProcessor; using ImageProcessor.Imaging; using System.Drawing; using System.IO; public static byte[] ResizeAndCrop(byte[] image, int width, int height) { using (var ms = new MemoryStream()) { using (var imgf = new ImageFactory(true)) imgf .Load(image) .Resize(new ResizeLayer(new Size(width, height), ResizeMode.Crop)) .Save(ms); return ms.ToArray(); } } 

这将采用其byte[]格式的任何图像并从中心裁剪。

这是由ResizeLayer中的anchorPosition参数设置的,该参数的deafult值为AnchorPosition.Center

 new ResizeLayer(new Size(width, height), ResizeMode.Crop/*, AnchorPosition.Center*/)