2012-01-24 1 views
9

У меня есть файл образа, который я хотел бы, чтобы обрезать и изменять размер в то же время, используя класс System.DrawingКак обрезать и изменять размер изображения в одном шаге в .NET

Я пытаюсь построить на идеях в этой статье: 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.

+0

вы можете посмотреть исходный код http://imager.codeplex.com (около 100 строк) или использовать его как dll – Omu

ответ

5

Одно все ответы пропущенных в том, что полученное изображение будет иметь 50% прозрачный 1 пиксельная граница вокруг изображения из-за ошибки в GDI.

Чтобы правильно обрезать и изменить размер, необходимо применить следующие параметры для графического объекта:

 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, в качестве последнего параметра передайте .

Если вы имеете дело с изображениями PNG, TIFF или ICO и преобразуете их в формат, который не поддерживает прозрачность, вам также необходимо вызвать g.Clear (bgcolor) до вызова DrawImage.

Если вы кодируете формат jpeg, обязательно установите параметр качества и затем удалите объект 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 - запуск его на сервере большой громкости приведет к его быстрому сбою.

+0

Спасибо за подробный ответ. Я посмотрю на все упомянутое и надеюсь, что вы придумаете более чистое решение. – stephen776

+0

Не могли бы вы указать мне пример внедрения решения из сообщения в блоге, о котором упоминалось в программе Uploadify? – stephen776

+0

Как эта утечка памяти через экземпляр растрового изображения, если он завернут в оператор using? – stephen776

5

кажется, что вы должны быть в состоянии обрезать и изменять размер с одним вызовом DrawImage

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

Я думаю, что у вас есть прямоугольники назад, [страница MSDN] (http: //msdn.microsoft.com/en-us/library/ms142040(v=vs.100).aspx) говорит, что порядок: изображение, dest rect, source rect, графический блок. –

+0

Это, по сути, нарисует изображение нужной области обрезки, в правильном пространстве с измененным размером ... бит, кроме того, я получаю большой черный квадрат по высоте и ширине обрезанной области, нарисованной вместе с обрезанной областью. – stephen776

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

    } 
} 
+0

Очень ценим, человек! Я преобразовал его как метод расширения изображения и использовал с помощью операторов, поэтому я мог бы сделать конечную точку просто вернуть поток изображения для предварительного просмотра. Если кто-то захочет это увидеть, дайте мне знать. – JohnnyFun

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

Большое спасибо. Этот код работает для обрезки изображения без сохранения пропорций и обрезает изображение точно в соответствии с заданной высотой и шириной. –

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 или папке.

Смежные вопросы