簡體   English   中英

如何在 .NET 中一步裁剪和調整圖像大小

[英]How to crop and resize image in one step in .NET

我有一個圖像文件,我想使用 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 大小參數繪制圖像。

我正在使用我寫的這個類:

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

所有答案都遺漏的一件事是,由於 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 = System.Drawing.Drawing2D.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 屬性。

我在我的博客上有一個更完整的 GDI+ 裁剪和調整大小錯誤列表

我通常會嘗試推動人們使用我的 imageresizing.net 庫,因為它旨在以最佳性能在網站上安全運行。 1 行代碼,用戶錯誤的空間很小。

我下載了 Schnieds 的示例項目,不得不說這是一種(不必要的)復雜的做事方式。 非破壞性編輯實際上要容易得多, 如本文所示 它很容易與 Uploadify 結合使用,盡管我沒有在博客中介紹它。

此外,在上傳過程中重新編碼圖像非常具有破壞性,對於 jpeg 和 png 文件都是如此。 驗證是好的,但只需在驗證后處理實例,不要重新編碼。 Schnieds 的示例還通過未處理的 Bitmap 實例泄漏內存 - 在高容量服務器上運行它會迅速崩潰。

修復了問題...

我將裁剪區域的寬度和高度傳遞到創建新位圖實例的語句中。

我通過在調整大小的圖像的所需固定大小中創建位圖對象來糾正它...

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/

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 中,您將被裁剪並調整圖像大小。 您可以將圖像存儲在數據庫或文件夾中的任何位置。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM