2015-04-09 1 views
19

Zeit auf einem System arbeite ich, dass ein sehr großes Bild zu laden, mit minimaler Breite x heigh> = 10.000.000 Pixel.Wie Bitmap aus dem Speicher zu vermeiden, wenn für dh auf sehr großes Bild Arbeits: 10.000.000 Pixel und über

Aber das Verhältnis der Upload-Bild des Benutzers nicht in der Regel unsere Anforderungsquote entsprechen, so muss ich es auf das richtige Verhältnis zuschneiden, aber wenn System.Drawing Bitmap zu beschneiden, ich habe immer SytemOutOfMemory Ausnahme.

Ich habe Bitmap.Clone und Graphic.DrawImage mit korrekten RectangleF versuchen, aber ohne Glück.

Gibt es sowieso, dies zu tun, ohne die OutOfMemory Ausnahme zu bekommen oder gibt es Alternativen zu System.Drawing Bibliothek diese Aufgabe leicht zu erledigen?

Mein Code, um das Bild von Benutzer-Upload-Datei zu laden:

var fileBinary = new byte[stream.Length]; 
    stream.Read(fileBinary, 0, fileBinary.Length); 
    stream.Position = 0; 
    var fileExtension = Path.GetExtension(fileName); 
    using (Image image = Image.FromStream(stream, false, false)) 
    { 
     //validation and check ratio 
     CropImage(image, PORTRAIT_RATIO, fileExtension); 
    } 

Und die CropImage Funktion:

//Crop Image from center with predefine ratio 
    private byte[] CropImage(Image sourceImg, float ratio, string fileExtension) 
     var height = sourceImg.Height; 
     var width = sourceImg.Width; 

     var isPortrait = width < height; 
     RectangleF croppingRec = new RectangleF(); 

     float positionX = 0; 
     float positionY = 0; 
     float cropHeight = (float)height; 
     float cropWidth = cropHeight * PORTRAIT_RATIO; 
     positionY = 0; 
     positionX = (width - cropWidth)/2; 

     if (cropWidth > width) 
     { 
      cropWidth = width; 
      cropHeight = cropWidth * (1/PORTRAIT_RATIO); 
      positionX = 0; 
      positionY = ((height - cropHeight)/2); 

     } 

     croppingRec.Width = cropWidth; 
     croppingRec.Height = cropHeight; 
     croppingRec.X = positionX; 
     croppingRec.Y = positionY; 

     Bitmap bmpImage = sourceImg as Bitmap; 
     Bitmap bmpCrop = bmpImage.Clone(croppingRec, bmpImage.PixelFormat); 
     bmpCrop.Save("D:/test" + fileExtension, ImageFormat.Jpeg); 

     ImageConverter converter = new ImageConverter(); 

     return (byte[])converter.ConvertTo(bmpCrop, typeof(byte[])); 
    } 

} 
+0

check out http://imageresizing.net/ – jle

+4

haben Sie versucht, als '64bit' App mit speziellen Flag kompilieren, die Speicher Einschränkungen von der CLR entfernt (abgesehen von max 2GB für einzelne Liste Sammlung)? – Tigran

+7

10 Millionen Pixel sind normalerweise kein Problem, eine halbe Milliarde ist das theoretische Maximum, aber in einem 32-Bit-Prozess neigen Sie dazu, lange vorher zu fallen. In der Regel 25 Millionen, wenn Ihr Programm eine Weile läuft. Der wahrscheinlichste Fehler in Ihrem Code ist es, vergessen zu haben, Dispose() aufzurufen, es ist eine steinharte Voraussetzung, wenn Sie die Bitmap-Klasse verwenden und viel zu viele Programmierer vergessen es. Niemand kann Ihren Fehler sehen, wenn Sie Ihren Code nicht veröffentlichen. –

Antwort

0

Versuchen graphicsmagick.net Bibliothek verwenden, dann verwenden Sie die Crop-Methode auf MagickImage. Es sollte immer noch gut unter asp.net funktionieren, und behandelt riesige Image-Dateien mit der Festplatte für Scratch.

2

Sie könnten die Bitmap in ein Byte-Array konvertieren. Versuchen Sie so etwas wie dieses (sieht hackie aber ich weiß nicht, einen anderen Weg):

int pixelSize = 3; 
int bytesCount = imgHeight * imgWidth * pixelSize; 
byte[] byteArray= new byte[bytesCount]; 

BitmapData bitmapData = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, imgWidth, imgHeight), ImageLockMode.ReadOnly, bitmap.PixelFormat); 
Marshal.Copy(bitmapData.Scan0, byteArray, 0, bytesCount); 

Jedes Pixel in diesem Array von 3 Bytes dargestellt wird (dies hängt von der Bitmap-Typ). Sie wissen also, dass die Länge einer Bitmap-Zeile 3 * imgWidth beträgt. Mit diesem können Sie einfach im Byte-Array navigieren und genau das, was Sie brauchen, in ein neues Array kopieren.

Sie würde dann eine neue Bitmap mit der gewünschten Endgröße erstellen, die Bitmap-Daten und Marshal.Copy in, dass das neue Array erhalten:

Bitmap newBitmap = new Bitmap(Width, Height); 
BitmapData newBitmapData = b.LockBits(BoundsRect, 
           ImageLockMode.WriteOnly, 
           newBitmap.PixelFormat); 
Marshal.Copy(newByteArray, 0, newBitmapData.Scan0, newBytesCount); 

am Ende die Bitmaps Unlock:

newBitmap.UnlockBits(newBitmapData); 
bitmap.UnlockBits(bitmapData); 

Hoffe, das hilft. Prost.

Verwandte Themen