2015-03-13 3 views
7

У меня есть очень большие рисунки здания, иногда 22466x3999 с бит глубиной 24 или даже больше. Мне нужно иметь возможность изменять их размер до меньших версий и иметь возможность вырезать части изображения на более мелкие изображения.C# Обрезка и изменение размера больших изображений

Я использую следующий код, чтобы изменить размер изображения, которые я нашел here:

 public static void ResizeImage(string OriginalFile, string NewFile, int NewWidth, int MaxHeight, bool OnlyResizeIfWider) 
     { 
      System.Drawing.Image FullsizeImage = System.Drawing.Image.FromFile(OriginalFile); 
      if (OnlyResizeIfWider) 
      { 
       if (FullsizeImage.Width <= NewWidth) 
       { 
        NewWidth = FullsizeImage.Width; 
       } 
      } 
      int NewHeight = FullsizeImage.Height * NewWidth/FullsizeImage.Width; 
      if (NewHeight > MaxHeight) 
      { 
       NewWidth = FullsizeImage.Width * MaxHeight/FullsizeImage.Height; 
       NewHeight = MaxHeight; 
      } 
      System.Drawing.Image NewImage = FullsizeImage.GetThumbnailImage(NewWidth, NewHeight, null, IntPtr.Zero); 
      FullsizeImage.Dispose(); 
      NewImage.Save(NewFile); 
     } 

И этот код, чтобы обрезать изображения:

public static MemoryStream CropToStream(string path, int x, int y, int width, int height) 
     { 
      if (string.IsNullOrWhiteSpace(path)) return null; 
      Rectangle fromRectangle = new Rectangle(x, y, width, height); 
      using (Image image = Image.FromFile(path, true)) 
      { 
       Bitmap target = new Bitmap(fromRectangle.Width, fromRectangle.Height); 
       using (Graphics g = Graphics.FromImage(target)) 
       { 
        Rectangle croppedImageDimentions = new Rectangle(0, 0, target.Width, target.Height); 
        g.DrawImage(image, croppedImageDimentions, fromRectangle, GraphicsUnit.Pixel); 
       } 
       MemoryStream stream = new MemoryStream(); 
       target.Save(stream, image.RawFormat); 
       stream.Position = 0; 
       return stream; 
      } 
     } 

Моя проблема заключается в том, что я получаю Sytem.OutOfMemoryException, когда я пытаюсь изменить размер изображения, и это потому, что я не могу загрузить полное изображение в FullsizeImage.

Итак, что бы я хотел знать, как изменить размер изображения без загрузки всего изображения в память?

+0

Это не решение программирования, но вы могли бы попробовать увеличить * виртуальной памяти * размер вашей машины и посмотреть. – Kurubaran

+0

Вы должны работать с LockBits для таких размеров изображений – Vajura

+0

@Kurubaran Я пытался увеличить объем памяти, который не работал, и я не думаю, что это правильное решение для веб-проекта. –

ответ

5

Есть шансы OutOfMemoryException не из-за размера изображений, а потому, что вы не выбрасывайте все классы Disposables правильно:

  • Bitmap target
  • MemoryStream stream
  • System.Drawing.Image NewImage

не располагаются так, как должны. Вы должны добавить заявление using().

Если вы действительно столкнулись с этой ошибкой только с одним изображением, вам следует рассмотреть возможность переключения вашего проекта на x64. Изображение 22466x3999 означает 225 Мб в памяти, я думаю, что это не должно быть проблемой для x86. (поэтому сначала попытайтесь уничтожить свои объекты).

И последнее, но не менее важное: Magick.Net очень эффективен при изменении размера/обрезке больших изображений.

+0

Спасибо, я добавлю 'using()' в Fullsizeimage и другие места. Я попробовал Magick.Net, но я не мог заставить его работать, но я попробую, если это не поможет. –

+0

Image Magick.Net - это путь, потому что добавление использования по-прежнему возвращает «OutOfMemoryException». И если Image Magick.Net не будет работать, я собираюсь сделать отдельный сервис, который обрабатывает все изменения размера и обрезки изображения. –

+1

Даже на большой 64-битной системе вы не можете создавать растровые изображения произвольных размеров. Если ему нужно работать с действительно большими растровыми изображениями, я боюсь, что использование сторонней библиотеки - лучший вариант. – TaW

1

Вы также можете заставить .Net читать изображение непосредственно с диска и останавливать кеширование памяти.

Использование

sourceBitmap = (Bitmap)Image.FromStream(sourceFileStream, false, false);

Вместо

...System.Drawing.Image.FromFile(OriginalFile);

см https://stackoverflow.com/a/47424918/887092

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