Reputation: 465
I got some very large building drawings, sometimes 22466x3999 with a bit depth of 24, or even larger. I need to be able to resize these to smaller versions, and to be able to cut out sections of the image to smaller images.
I have been using the following code to resize the images, which I found 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);
}
And this code to crop the images:
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;
}
}
My problem is that i get a Sytem.OutOfMemoryException when I try to resize the image, and that's because I can't load the full image in to FullsizeImage.
So what I would like to know, how do I resize an image without loading the entire image into memory?
Upvotes: 7
Views: 4362
Reputation: 18543
You can also force .Net to read the image directly from disk and stop memory caching.
Use
sourceBitmap = (Bitmap)Image.FromStream(sourceFileStream, false, false);
Instead of
...System.Drawing.Image.FromFile(OriginalFile);
see https://stackoverflow.com/a/47424918/887092
Upvotes: 1
Reputation: 7320
There are chances the OutOfMemoryException
is not because of the size of the images, but because you don't dispose all the disposables classes correctly :
Bitmap target
MemoryStream stream
System.Drawing.Image NewImage
are not disposed as they should. You should add a using()
statement around them.
If you really encounter this error with just one image, then you should consider switch your project to x64. A 22466x3999 picture means 225Mb in memory, I think it shouldn't be an issue for x86. (so try to dispose your objects first).
Last but not least, Magick.Net is very efficient about resizing / cropping large pictures.
Upvotes: 5