2

Attempting to load a huge image (e.g. a 9000x9000 pixel image) into a Bitmap object can create out-of-memory errors, a "Parameter is not valid" error, and no doubt other related problems.

How can I load a 9000x9000pixel image from disk, ultimately resizing it before saving back to disk, without causing a fatal error (such as out-of-memory)?

Let's assume a 32-bit environment with 2gb of ram, C# 4.0, and will be working with image formats of jpg, gif, bmp, tif, png.

I have tried the following 3 snippets, and each fail with a memory error.

Attempt 1:

using (Bitmap srcImg = new Bitmap(@"C:\9000x9000.jpg"))
{
    // boom
}

Attempt 2:

using (Image srcImg = Image.FromFile(@"C:\9000x9000.jpg"))
{
    // kapow
}

Attempt 3:

using (FileStream fs = new FileStream(@"C:\9000x9000.jpg", FileMode.Open, FileAccess.Read))
{
    using (Image srcImg = Image.FromStream(fs))
    {
        // kelly clarkson
    }
}

My thought for a possible solution is to load the image file directly into an array (so you don't have the huge overhead of a Bitmap object), somehow resize it smaller using that array (probably need to code for different image format headers?), before finally converting to a Bitmap object of manageable size.

Thoughts or possible solutions?

Community
  • 1
  • 1
Doug S
  • 10,146
  • 3
  • 40
  • 45
  • What is the error message? First try it in a simple console application, then apply the solution in your application. – Tomas Jansson Nov 18 '12 at 21:04
  • What is the bit depth of the image? I'm curious as to how much RAM that image is trying to consume. My guess is a LOT as a 32 bit image means at least 310MB. Considering your other question I would highly recommend you upgrade to a 64 bit system with at least 8GB of ram.. possibly much more. AND I would recommend you get tools that are built for processing such large images – NotMe Nov 18 '12 at 21:09
  • Are you actually getting errors, or are you simply speculating over possible problems? I see no *a priori* reason to think that an 18 Mpx image will cause any grief, unless you actually want to make it bigger. It'll take up a few hundred MB. – Marcelo Cantos Nov 18 '12 at 21:10
  • 1
    @MarceloCantos he says he actually tried in the question and mentions out-of-memory and 'parameter is not valid' (= ArgumentException) – jeroenh Nov 18 '12 at 21:15
  • To answer: Exact error is, depending on environment: "Parameter is not valid. at System.Drawing.Bitmap..ctor" (link in question provides info about error) and "OutOfMemoryException: Out of memory. at System.Drawing.Bitmap..ctor". Bitmap object is "32-bit" (PixelFormat.Format32bppArgb) to allow for alpha transparencies, such as with png. Upgrading to a 64-bit system/8gb ram is a possible future option, but keep in mind the question specifies 32-bit/2gb; plus, optimizing the code to work on a 32-bit/2gb environment will no doubt also make it more efficient on a 64-bit/8gb environment. – Doug S Nov 18 '12 at 21:25

2 Answers2

1

Have a look at the AForge.Net library, which is supposedly good at processing large files.

Community
  • 1
  • 1
jeroenh
  • 26,362
  • 10
  • 73
  • 104
  • I get the feeling that his system is constrained pretty badly and using a library such as this one might be a great way of going. – NotMe Nov 18 '12 at 21:24
  • In regards to being "constrained", the biggest constraint is being a 32-bit system. On a 32-bit system, individual objects are quite limited as to how big they can be, and Bitmap objects have a LOT of overhead, so it doesn't take much to get an out-of-memory error on a 32-bit system, even though the system may actually have memory to spare. In any case, it'll still be great to optimize the code to take up as little memory as possible, even in a 64-bit environment. – Doug S Nov 18 '12 at 21:42
  • Initial thoughts on AForge: It appears to initially load images directly into a Bitmap object, so it would have the exact same memory issues (link at end of comment showing AForge FromFile method). I'll run some tests to verify. http://www.aforgenet.com/framework/docs/html/4b467feb-9cf0-c2b5-4a16-a1862d6e2531.htm – Doug S Nov 19 '12 at 19:52
1

Here are the steps that i followed to get it working:

1.Go to http://www.opennetcf.org/PermaLink.aspx?guid=d57ace50-2762-4b19-b07d-39421829d410 and download the Download the SDF 2.0 Beta1 Redistributables. Install.

2.Create a Smart Device Project in VS.NET 2005 targeting PPC 2003 SE device. I had to right-click my project and choose "Upgrade" to ensure it was targetting the .NET CF v2.0 rather than .NET CF 1.1 SP3.

3.I added the OpenNETCF.dll and OpenNETCF.Drawing.dll files as references from the default installation directory (C:\Program Files\OpenNETCF\Smart Device Framework 2.0)

4.I created a simple app with a picturebox on a form, that loads my image when the form is loaded. Here's the relevant code, some copied from Alex Feinman's web log:

#region Using directives
using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using OpenNETCF.Drawing.Imaging;
using System.IO;
#endregion

....

const string szFileName = @"\Storage Card\TEMP\2MBJPEG.JPG";



private void Form1_Load(object sender, EventArgs e)
{
IBitmapImage imageBitmap;
FileStream fsImage;
fsImage = new FileStream(
    szFileName,
    FileMode.Open);
imageBitmap = CreateThumbnail(
    fsImage,
    new Size(100, 100));

Bitmap bm = ImageUtils.IBitmapImageToBitmap(
    imageBitmap);
pictureBox1.Image = bm;
}


static public IBitmapImage CreateThumbnail(Stream stream, Size size)
{
IBitmapImage imageBitmap;
ImageInfo ii;
IImage image;
ImagingFactory factory = new ImagingFactoryClass();
    factory.CreateImageFromStream(
    new StreamOnFile(stream), 
    out image);
image.GetImageInfo(out ii);
factory.CreateBitmapFromImage(
    image, 
    (uint)size.Width, 
    (uint)size.Height,
    ii.PixelFormat, 
    InterpolationHint.InterpolationHintDefault, 
    out imageBitmap);
    return imageBitmap;
}
CollectMeNow
  • 73
  • 1
  • 9