C# 如何在 .NET 中一步裁剪和调整图像大小
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8992619/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to crop and resize image in one step in .NET
提问by stephen776
I have an Image file that I would like to crop and resize at the same time using the System.Drawing class
我有一个图像文件,我想使用 System.Drawing 类同时裁剪和调整大小
I am trying to build upon the ideas found in this article :http://www.schnieds.com/2011/07/image-upload-crop-and-resize-with.html
我正在尝试以本文中的想法为基础:http: //www.schnieds.com/2011/07/image-upload-crop-and-resize-with.html
I am able to Crop and Resize seperately but when I try to combine the process, I am getting some strange output.
我能够分别裁剪和调整大小,但是当我尝试组合该过程时,我得到了一些奇怪的输出。
Here is what I have been trying
这是我一直在尝试的
using (System.Drawing.Bitmap _bitmap = new System.Drawing.Bitmap(w, h))
{
_bitmap.SetResolution(img.HorizontalResolution, img.VerticalResolution);
using (Graphics _graphic = Graphics.FromImage(_bitmap))
{
_graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
_graphic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
_graphic.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
_graphic.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
//Code used to crop
_graphic.DrawImage(img, 0, 0, w, h);
_graphic.DrawImage(img, new Rectangle(0, 0, w, h), x, y, w, h, GraphicsUnit.Pixel);
//Code I used to resize
_graphic.DrawImage(img, 0, 0, img.Width, img.Height);
_graphic.DrawImage(img, new Rectangle(0, 0, W_FixedSize, H_FixedSize), 0, 0, img.Width, img.Height, GraphicsUnit.Pixel);
//continued...
}
}
In the above code...there are two sections commented...one to crop and one one to resize.
在上面的代码中......有两部分注释......一个用于裁剪,一个用于调整大小。
For cropping, I pass in the proper coords and width/height part of the image to crop(x, y, w, h).
对于裁剪,我将图像的正确坐标和宽度/高度部分传递给裁剪(x,y,w,h)。
I would like to crop based on my parameters and draw the image based on the W_FixedSize and H_Fixed size params.
我想根据我的参数进行裁剪并根据 W_FixedSize 和 H_Fixed 大小参数绘制图像。
采纳答案by Lilith River
One thing all of the answers missed is that the resulting image will have a 50% transparent 1 pixel border around the image, due to a bug in GDI.
所有答案都遗漏的一件事是,由于 GDI 中的错误,生成的图像将在图像周围具有 50% 透明的 1 像素边框。
To properly crop and resize, you need to apply the following settings to the graphics object:
要正确裁剪和调整大小,您需要对图形对象应用以下设置:
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
Then you need to make an ImageAttributes instance to fix the border bug:
然后你需要制作一个 ImageAttributes 实例来修复边框错误:
ImageAttributes ia = new ImageAttributes();
ia.SetWrapMode(WrapMode.TileFlipXY);
Then, when calling DrawImage, pass iaas the last parameter.
然后,在调用 DrawImage 时,ia作为最后一个参数传递。
If you're dealing with any PNG, TIFF, or ICO images and converting them to a format that doesn't support transparency, you also need to call g.Clear(bgcolor) prior to calling DrawImage.
如果您正在处理任何 PNG、TIFF 或 ICO 图像并将它们转换为不支持透明度的格式,则还需要在调用 DrawImage 之前调用 g.Clear(bgcolor)。
If you're encoding to jpeg format, make sure to set the Quality parameter and dispose of the EncoderParameters object afterwards.
如果您要编码为 jpeg 格式,请确保设置 Quality 参数并随后处理 EncoderParameters 对象。
The Bitmap instance that you are reading from will lock the underlying file until after it is disposed. If you use the FromStream method, you must keep the stream open until after the Bitmap instance is disposed. A good way to do this is clone the stream into a MemoryStream instance and assign it to the Bitmap.Tag property.
您正在读取的 Bitmap 实例将锁定底层文件,直到它被释放。如果使用 FromStream 方法,则必须保持流打开,直到 Bitmap 实例被释放。执行此操作的一个好方法是将流克隆到 MemoryStream 实例并将其分配给 Bitmap.Tag 属性。
I have a more complete list of GDI+ cropping & resizing bugs to avoidon my blog.
我在我的博客上有一个更完整的 GDI+ 裁剪和调整大小错误列表。
I usually try to push people to use my imageresizing.net library, as it's designed to operate safely on a website with optimum performance. 1 line of code, and very little room for user error.
我通常会尝试推动人们使用我的 imageresizing.net 库,因为它旨在以最佳性能在网站上安全运行。1 行代码,用户错误的空间很小。
I downloaded Schnieds' example project, and I have to say it's an (unnecessarily) complicated way of doing things. Non-destructive editing is actually much easier, as shown on this article. It's easy to combine with Uploadify, although I don't cover that on the blog.
我下载了 Schnieds 的示例项目,不得不说这是一种(不必要的)复杂的做事方式。非破坏性编辑实际上要容易得多,如本文所示。它很容易与 Uploadify 结合使用,尽管我没有在博客中介绍它。
Also, re-encoding the image during upload is very destructive, both for jpeg and png files. Validation is good, but just dispose the instance after validation, don't re-encode it. Schnieds' example also leaks memory through the undisposed Bitmap instance - running it on a high-volume server would crash it quickly.
此外,在上传过程中重新编码图像非常具有破坏性,对于 jpeg 和 png 文件都是如此。验证是好的,但只需在验证后处理实例,不要重新编码。Schnieds 的示例还通过未处理的 Bitmap 实例泄漏内存 - 在高容量服务器上运行它会迅速崩溃。
回答by gordy
seems like you should be able to crop and resize with one call to DrawImage
似乎您应该能够通过一次调用 DrawImage 来裁剪和调整大小
_graphic.DrawImage(img,
new Rectangle(/*..cropped rect..*/),
new Rectangle(/*..new size..*/),
GraphicsUnit.Pixel);
回答by kleinohad
I am using this class I wrote:
我正在使用我写的这个类:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
namespace Studio.Utilities
{
public class ImageResizer
{
public void ResizeImage(string origFileLocation, string newFileLocation, string origFileName, string newFileName, int newWidth, int maxHeight, bool resizeIfWider)
{
System.Drawing.Image FullSizeImage = System.Drawing.Image.FromFile(origFileLocation + origFileName);
// Ensure the generated thumbnail is not being used by rotating it 360 degrees
FullSizeImage.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
FullSizeImage.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
if (resizeIfWider)
{
if (FullSizeImage.Width <= newWidth)
{
//newWidth = FullSizeImage.Width;
}
}
int newHeight = FullSizeImage.Height * newWidth / FullSizeImage.Width;
if (newHeight > maxHeight) // Height resize if necessary
{
//newWidth = FullSizeImage.Width * maxHeight / FullSizeImage.Height;
newHeight = maxHeight;
}
newHeight = maxHeight;
// Create the new image with the sizes we've calculated
System.Drawing.Image NewImage = FullSizeImage.GetThumbnailImage(newWidth, newHeight, null, IntPtr.Zero);
FullSizeImage.Dispose();
NewImage.Save(newFileLocation + newFileName);
}
public void ResizeImageAndRatio(string origFileLocation, string newFileLocation, string origFileName, string newFileName, int newWidth, int newHeight, bool resizeIfWider)
{
System.Drawing.Image initImage = System.Drawing.Image.FromFile(origFileLocation + origFileName);
int templateWidth = newWidth;
int templateHeight = newHeight;
double templateRate = double.Parse(templateWidth.ToString()) / templateHeight;
double initRate = double.Parse(initImage.Width.ToString()) / initImage.Height;
if (templateRate == initRate)
{
System.Drawing.Image templateImage = new System.Drawing.Bitmap(templateWidth, templateHeight);
System.Drawing.Graphics templateG = System.Drawing.Graphics.FromImage(templateImage);
templateG.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
templateG.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
templateG.Clear(Color.White);
templateG.DrawImage(initImage, new System.Drawing.Rectangle(0, 0, templateWidth, templateHeight), new System.Drawing.Rectangle(0, 0, initImage.Width, initImage.Height), System.Drawing.GraphicsUnit.Pixel);
templateImage.Save(newFileLocation + newFileName, System.Drawing.Imaging.ImageFormat.Jpeg);
}
else
{
System.Drawing.Image pickedImage = null;
System.Drawing.Graphics pickedG = null;
Rectangle fromR = new Rectangle(0, 0, 0, 0);
Rectangle toR = new Rectangle(0, 0, 0, 0);
if (templateRate > initRate)
{
pickedImage = new System.Drawing.Bitmap(initImage.Width, int.Parse(Math.Floor(initImage.Width / templateRate).ToString()));
pickedG = System.Drawing.Graphics.FromImage(pickedImage);
fromR.X = 0;
fromR.Y = int.Parse(Math.Floor((initImage.Height - initImage.Width / templateRate) / 2).ToString());
fromR.Width = initImage.Width;
fromR.Height = int.Parse(Math.Floor(initImage.Width / templateRate).ToString());
toR.X = 0;
toR.Y = 0;
toR.Width = initImage.Width;
toR.Height = int.Parse(Math.Floor(initImage.Width / templateRate).ToString());
}
else
{
pickedImage = new System.Drawing.Bitmap(int.Parse(Math.Floor(initImage.Height * templateRate).ToString()), initImage.Height);
pickedG = System.Drawing.Graphics.FromImage(pickedImage);
fromR.X = int.Parse(Math.Floor((initImage.Width - initImage.Height * templateRate) / 2).ToString());
fromR.Y = 0;
fromR.Width = int.Parse(Math.Floor(initImage.Height * templateRate).ToString());
fromR.Height = initImage.Height;
toR.X = 0;
toR.Y = 0;
toR.Width = int.Parse(Math.Floor(initImage.Height * templateRate).ToString());
toR.Height = initImage.Height;
}
pickedG.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
pickedG.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
pickedG.DrawImage(initImage, toR, fromR, System.Drawing.GraphicsUnit.Pixel);
System.Drawing.Image templateImage = new System.Drawing.Bitmap(templateWidth, templateHeight);
System.Drawing.Graphics templateG = System.Drawing.Graphics.FromImage(templateImage);
templateG.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
templateG.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
templateG.Clear(Color.White);
templateG.DrawImage(pickedImage, new System.Drawing.Rectangle(0, 0, templateWidth, templateHeight), new System.Drawing.Rectangle(0, 0, pickedImage.Width, pickedImage.Height), System.Drawing.GraphicsUnit.Pixel);
templateImage.Save(newFileLocation + newFileName, System.Drawing.Imaging.ImageFormat.Jpeg);
templateG.Dispose();
templateImage.Dispose();
pickedG.Dispose();
pickedImage.Dispose();
}
initImage.Dispose();
}
}
}
回答by stephen776
Fixed the problem...
修复了问题...
I was passing the width and height of the cropped area into the statement that instatiates a new bitmap instance.
我将裁剪区域的宽度和高度传递到创建新位图实例的语句中。
I have corrected it by creating the bitmap object in the desired fixed size of the resized image...
我通过在调整大小的图像的所需固定大小中创建位图对象来纠正它...
using (System.Drawing.Bitmap _bitmap = new System.Drawing.Bitmap(W_FixedSize, H_FixedSize))
{
_bitmap.SetResolution(img.HorizontalResolution, img.VerticalResolution);
using (Graphics _graphic = Graphics.FromImage(_bitmap))
{
_graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
_graphic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
_graphic.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
_graphic.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
//Code used to crop
_graphic.DrawImage(img, 0, 0, w, h);
_graphic.DrawImage(img, new Rectangle(0, 0, w, h), x, y, w, h, GraphicsUnit.Pixel);
//Code I used to resize
_graphic.DrawImage(img, 0, 0, img.Width, img.Height);
_graphic.DrawImage(img, new Rectangle(0, 0, W_FixedSize, H_FixedSize), 0, 0, img.Width, img.Height, GraphicsUnit.Pixel);
//continued...
}
}
回答by Karan Singh
for client-side used http://jcrop.org/
对于客户端使用http://jcrop.org/
public static class ImageHelper
{
public static byte[] CropImage(byte[] content, int x, int y, int width, int height)
{
using (MemoryStream stream = new MemoryStream(content))
{
return CropImage(stream, x, y, width, height);
}
}
public static byte[] CropImage(Stream content, int x, int y, int width, int height)
{
//Parsing stream to bitmap
using (Bitmap sourceBitmap = new Bitmap(content))
{
//Get new dimensions
double sourceWidth = Convert.ToDouble(sourceBitmap.Size.Width);
double sourceHeight = Convert.ToDouble(sourceBitmap.Size.Height);
Rectangle cropRect = new Rectangle(x, y, width, height);
//Creating new bitmap with valid dimensions
using (Bitmap newBitMap = new Bitmap(cropRect.Width, cropRect.Height))
{
using (Graphics g = Graphics.FromImage(newBitMap))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.SmoothingMode = SmoothingMode.HighQuality;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.CompositingQuality = CompositingQuality.HighQuality;
g.DrawImage(sourceBitmap, new Rectangle(0, 0, newBitMap.Width, newBitMap.Height), cropRect, GraphicsUnit.Pixel);
return GetBitmapBytes(newBitMap);
}
}
}
}
public static byte[] GetBitmapBytes(Bitmap source)
{
//Settings to increase quality of the image
ImageCodecInfo codec = ImageCodecInfo.GetImageEncoders()[4];
EncoderParameters parameters = new EncoderParameters(1);
parameters.Param[0] = new EncoderParameter(Encoder.Quality, 100L);
//Temporary stream to save the bitmap
using (MemoryStream tmpStream = new MemoryStream())
{
source.Save(tmpStream, codec, parameters);
//Get image bytes from temporary stream
byte[] result = new byte[tmpStream.Length];
tmpStream.Seek(0, SeekOrigin.Begin);
tmpStream.Read(result, 0, (int)tmpStream.Length);
return result;
}
}
public static Image Resize(Image current, int maxWidth, int maxHeight)
{
int width, height;
#region reckon size
if (current.Width > current.Height)
{
width = maxWidth;
height = Convert.ToInt32(current.Height * maxHeight / (double)current.Width);
}
else
{
width = Convert.ToInt32(current.Width * maxWidth / (double)current.Height);
height = maxHeight;
}
#endregion
#region get resized bitmap
var canvas = new Bitmap(width, height);
using (var graphics = Graphics.FromImage(canvas))
{
graphics.CompositingQuality = CompositingQuality.HighSpeed;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.DrawImage(current, 0, 0, width, height);
}
return canvas;
#endregion
}
public static Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
public static byte[] imageToByteArray(Image image)
{
using (var ms = new MemoryStream())
{
image.Save(ms, image.RawFormat);
return ms.ToArray();
}
}
}
and Used like this in controller
并在控制器中像这样使用
int cropPointX = Convert.ToInt32(model.imgX1);
int cropPointY = Convert.ToInt32(model.imgY1);
int imageCropWidth = Convert.ToInt32(model.imgWidth);
int imageCropHeight = Convert.ToInt32(model.imgHeight);
byte[] imageBytes = ConvertToBytes(model.ProductImage);
byte[] croppedImage;
if (cropPointX > 0 || cropPointY > 0 || imageCropWidth > 0 || imageCropHeight > 0)
{
croppedImage = CropImage(imageBytes, cropPointX, cropPointY, imageCropWidth, imageCropHeight);
}
else
{
croppedImage = imageBytes;
}
Stream stream = new MemoryStream(croppedImage);
Image img = Image.FromStream(stream, true, true);
if (img.Height > 522 || img.Width > 522)
{
img = Resize(img, 522, 522);
}
byte[] imageBytes = (byte[])(new ImageConverter()).ConvertTo(img, typeof(byte[]));
In imageBytes you will get cropped and resized the image. you can store image wherever you want in db or folder.
在 imageBytes 中,您将被裁剪并调整图像大小。您可以将图像存储在数据库或文件夹中的任何位置。

