I am trying to automatically generate a thumbnail from an image uploaded by a user but I keep getting the exception "Out of memory". From what I understand the out of memory exception is thrown when you specify a starting position or a width/height that's outside of the image but even if I do this
var rct = new Rectangle(5, 5, 10, 10);
var whatever = bitmap.Clone(rct, bitmap.PixelFormat);
on an image that is 800x900 pixels I still get the "Out of memory" exception, I can't figure out what's wrong with it and I can't really get any good answers from other threads since everything regarding the OOM exception is just the mistake of going outside the image boundaries. Does anyone have an explanation or solution to this?
EDIT: A bit more context
The loop for the images.
foreach (var blob in fileInfoList)
{
var blockBlobName = CheckExistence(BaseBlobUrl, blob.FileName, blob.FileNameWithoutExtension);
var image = new Image()
{
BlobUrl = Path.Combine(BaseBlobUrl, blockBlobName),
FullName = blob.FileName,
FileName = blob.FileNameWithoutExtension,
BlockBlobName = blockBlobName,
OwningOrganizationId = CurrentUser.UserOrganization.OrganizationId,
ThumbnailUrl = CreateThumbnail(blob.File, blockBlobName),
Name = "Whatever"
};
blobList.Add(image);
RepositoryFactory.AzureStorageRepository.SaveImage(blob.File, blockBlobName, blob.ContentType, CurrentUser.UserOrganization.Organization.Id);
}
The method that is being called by each image in the list to generate the thumbnail.
public string CreateThumbnail(byte[] b, string parentImageName)
{
Bitmap bmp;
using (var ms = new MemoryStream(b))
{
bmp = new Bitmap(ms);
}
Bitmap thumbnail = bmp;
Rectangle rect = new Rectangle(5, 5, 10, 10);
if (bmp.Width > bmp.Height)
thumbnail = bmp.Clone(rect, bmp.PixelFormat);
else if (bmp.Height > bmp.Width)
thumbnail = bmp.Clone(new Rectangle((bmp.Height/2) - (bmp.Width/2), 0, bmp.Width, bmp.Width), bmp.PixelFormat);
byte[] bmpArray = new byte[0];
using (var ms = new MemoryStream())
{
finalCrop.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
ms.Close();
bmpArray = ms.ToArray();
}
var name = "Thumbnail_" + parentImageName;
RepositoryFactory.AzureStorageRepository.SaveThumbnail(bmpArray, name, "jpg/image", CurrentUser.UserOrganization.Organization.Id);
return BaseBlobUrl + "thumbnails/" + name;
}
I think the problem you're getting here is that Bitmaps need to be disposed. If one gets garbage collected without releasing its underlying unmanaged content (i.e. being disposed), then that memory can not be recovered...
Also note that you will need to dispose both bitmaps. Best thing to do is wrap them in a using, something like this:
using (var ms = new MemoryStream(b))
{
using (Bitmap bmp = new Bitmap(ms))
using (Bitmap thumbnail = bmp)
{
Rectangle rect = new Rectangle(5, 5, 10, 10);
if (bmp.Width > bmp.Height)
thumbnail = bmp.Clone(rect, bmp.PixelFormat);
else if (bmp.Height > bmp.Width)
thumbnail = bmp.Clone(new Rectangle((bmp.Height / 2) - (bmp.Width / 2), 0, bmp.Width, bmp.Width), bmp.PixelFormat);
byte[] bmpArray = new byte[0];
using (var ms = new MemoryStream())
{
finalCrop.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
ms.Close();
bmpArray = ms.ToArray();
}
var name = "Thumbnail_" + parentImageName;
RepositoryFactory.AzureStorageRepository.SaveThumbnail(bmpArray, name, "jpg/image", CurrentUser.UserOrganization.Organization.Id);
return BaseBlobUrl + "thumbnails/" + name;
}
}
It is worth noting that using will call Dispose() on it's target, even if an exception is thrown (thus having the same finally type functionality as @Scott Chamberlain answer
Okay so I found an answer to my problem by disposing the Bitmaps. After this bit of code
Bitmap thumbnail = bmp;
I added
bmp.Dispose();
And during debugging I noticed that none of the properties from bmp were left in the Bitmap called thumbnail so I changed it into the following
Bitmap thumbnail = new Bitmap(bmp);
Thank you all for telling me to dispose the Bitmaps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With