2015-03-13 23 views
7

Ho ottenuto alcuni disegni di costruzione molto grandi, a volte 22466x3999 con una profondità di bit di 24 o anche maggiore. Devo essere in grado di ridimensionarle a versioni più piccole e di essere in grado di ritagliare sezioni dell'immagine in immagini più piccole.C# Ritaglia e ridimensiona le immagini di grandi dimensioni

Sono stato con il seguente codice per ridimensionare le immagini, che ho trovato 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); 
     } 

E questo codice per ritagliare le immagini:

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

Il mio problema è che ho un Sytem.OutOfMemoryException quando provo a ridimensionare l'immagine, ed è perché non riesco a caricare l'immagine completa in FullsizeImage.

Quindi, cosa mi piacerebbe sapere, come ridimensionare un'immagine senza caricare l'intera immagine in memoria?

+0

Questa non è una soluzione di programmazione, ma si potrebbe provare ad aumentare la memoria * virtual * dimensioni della vostra macchina e vedi. – Kurubaran

+0

Si dovrebbe lavorare con LockBits per tali dimensioni di immagine – Vajura

+0

@Kurubaran Ho provato ad aumentare la dimensione della memoria, che non ha funzionato, e non penso che sia la soluzione corretta per un webproject. –

risposta

5

ci sono probabilità il OutOfMemoryException non è a causa della dimensione delle immagini, ma perché non si smaltire tutte le classi monouso correttamente:

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

non sono disposti come dovrebbero. Dovresti aggiungere un'istruzione using() intorno a loro.

Se si verifica veramente questo errore con una sola immagine, è consigliabile passare al progetto x64. Un'immagine a 22466x3999 significa 225 MB in memoria, penso che non dovrebbe essere un problema per x86. (quindi cerca di smaltire prima i tuoi oggetti).

Ultimo ma non meno importante, Magick.Net è molto efficace sul ridimensionamento/ritaglio di immagini di grandi dimensioni.

+0

Grazie, aggiungerò 'using()' a Fullsizeimage e agli altri posti. Ho provato Magick.Net, ma non ho potuto farlo funzionare, ma ci proverò se questo non aiuta. –

+0

Immagine Magick.Net deve essere la strada da percorrere, perché aggiungendo usa è ancora restituito un 'OutOfMemoryException'. E se Image Magick.Net non funziona, ho intenzione di creare un servizio separato che gestisca tutte le ridimensionamento e il ritaglio delle immagini. –

+1

Anche su un grande sistema a 64 bit non è possibile creare Bitmap di dimensioni arbitrarie. Se ha bisogno di lavorare con bitmap veramente grandi, temo che usare una lib di terze parti sia l'opzione migliore .. – TaW

1

È anche possibile forzare .Net per leggere l'immagine direttamente dal disco e arrestare la memorizzazione nella cache.

Usa

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

Invece di

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

vedere https://stackoverflow.com/a/47424918/887092

Problemi correlati