如何在.NET中一步裁剪和调整图像大小

问题描述 投票:9回答:5

我有一个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大小参数绘制图像。

c# asp.net .net asp.net-mvc asp.net-mvc-3
5个回答
5
投票

错过的所有答案之一是由于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实例泄漏内存 - 在高容量服务器上运行它会使其快速崩溃。


7
投票

我正在使用我写的这堂课:

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();
            }

    }
}

6
投票

看起来你应该能够通过一次调用DrawImage来裁剪和调整大小

_graphic.DrawImage(img,
   new Rectangle(/*..cropped rect..*/),
   new Rectangle(/*..new size..*/),
   GraphicsUnit.Pixel);

4
投票

修正了问题......

我将裁剪区域的宽度和高度传递给实例化新位图实例的语句。

我通过在调整大小的图像的所需固定大小创建位图对象来纠正它...

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...
    }
}

0
投票

对于客户端使用的http://jcrop.org/

http://jcrop.org/demos/basic

   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或文件夹中的任何位置存储图像。

© www.soinside.com 2019 - 2024. All rights reserved.