我有一个Image文件,我想使用System.Drawing类同时裁剪和调整大小
我试图建立在本文中发现的想法:http://www.schnieds.com/2011/07/image-upload-crop-and-resize-with.html
我能够单独裁剪和调整大小,但是当我尝试组合这个过程时,我得到了一些奇怪的输出。
这是我一直在尝试的
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...
}
}
在上面的代码中...有两个部分评论...一个裁剪,一个调整大小。
对于裁剪,我将图像的适当坐标和宽度/高度部分传递到裁剪(x,y,w,h)。
我想基于我的参数进行裁剪,并根据W_FixedSize和H_Fixed大小参数绘制图像。
错过的所有答案之一是由于GDI中的错误,所得到的图像将在图像周围具有50%透明的1像素边界。
要正确裁剪和调整大小,您需要将以下设置应用于图形对象:
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 = CompositingMode.SourceOver;
然后,您需要创建一个ImageAttributes实例来修复边框错误:
ImageAttributes ia = new ImageAttributes();
ia.SetWrapMode(WrapMode.TileFlipXY);
然后,在调用DrawImage时,将ia
作为最后一个参数传递。
如果您正在处理任何PNG,TIFF或ICO图像并将其转换为不支持透明度的格式,则还需要在调用DrawImage之前调用g.Clear(bgcolor)。
如果您要编码为jpeg格式,请确保设置Quality参数并在之后处理EncoderParameters对象。
您正在读取的Bitmap实例将锁定基础文件,直到它被丢弃。如果使用FromStream方法,则必须保持流打开,直到处理Bitmap实例。执行此操作的一种好方法是将流克隆到MemoryStream实例中,并将其分配给Bitmap.Tag属性。
我的博客上有more complete list of GDI+ cropping & resizing bugs to avoid。
我经常试图将人们推向use my imageresizing.net library,因为它旨在安全地在具有最佳性能的网站上运行。 1行代码,用户错误的空间很小。
我下载了Schnieds的示例项目,我不得不说这是一种(不必要的)复杂的做事方式。非破坏性编辑实际上更容易,as shown on this article。虽然我没有在博客上介绍它,但很容易与Uploadify结合使用。
此外,在上传期间重新编码图像对于jpeg和png文件都是非常具有破坏性的。验证很好,但只需在验证后处理实例,不要重新编码。 Schnieds的例子还通过未使用的Bitmap实例泄漏内存 - 在高容量服务器上运行它会使其快速崩溃。
我正在使用我写的这堂课:
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();
}
}
}
看起来你应该能够通过一次调用DrawImage来裁剪和调整大小
_graphic.DrawImage(img,
new Rectangle(/*..cropped rect..*/),
new Rectangle(/*..new size..*/),
GraphicsUnit.Pixel);
修正了问题......
我将裁剪区域的宽度和高度传递给实例化新位图实例的语句。
我通过在调整大小的图像的所需固定大小创建位图对象来纠正它...
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...
}
}
对于客户端使用的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();
}
}
}
并在控制器中使用这样的
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[]));
在imageBytes中,您将被裁剪并调整图像大小。您可以在db或文件夹中的任何位置存储图像。