views:

82

answers:

3

Hello everybody,

I'm working with big size images (for ex. 16000x9440 px) and cut some regions for other things. I'm getting an exception "Out of memory" when create a new Bitmap instance:

using (FileStream fileStream = new FileStream(mapFileResized, FileMode.Open))
{
    byte[] data = new byte[fileStream.Length];
    fileStream.Read(data, 0, data.Length);
    using (MemoryStream memoryStream = new MemoryStream(data))
    {
        using (Bitmap src = new Bitmap(memoryStream)) // <-- exception
        {
            tile = new Bitmap(tileWidth, tileHeight, PixelFormat.Format24bppRgb);
            tile.SetResolution(src.HorizontalResolution, src.VerticalResolution);
            tile.MakeTransparent();
            using (Graphics grRect = Graphics.FromImage(tile))
            {
                grRect.CompositingQuality = CompositingQuality.HighQuality;
                grRect.SmoothingMode = SmoothingMode.HighQuality;
                grRect.DrawImage(
                        src,
                        new RectangleF(0, 0, tileWidth, tileHeight),
                        rTile,
                        GraphicsUnit.Pixel
                );
            }
        }
    }
}

When I use small image sizes (for ex. 8000x4720 px) then all work fine.

How can I work with big size images?

PS tile Bitmap is disposed in finally block.

Best regards, Alex.

+2  A: 

Not a complete answer to your question, but you are probably better of using a library like ImageMagick.NET

Maurits Rijk
It has the same problem.
Hans Passant
According to the architecture page (http://www.imagemagick.org/script/architecture.php#tera-pixel) ImageMagick can "read, process, or write mega-, giga-, or tera-pixel image sizes." Haven't tried this though.
Maurits Rijk
+1  A: 

MemoryStream is implemented using an array of bytes that stores the data. If you read more data than the array can hold, a new array of double size is allocated and the bytes copied from one array to the other.

Since you apparently know how much data you're going to need, you can allocated the correct size up front and thus avoid the resizing.

However, once you reach a certain size you will run out of memory. .NET imposes a 2 GB limit on a single object (even on 64 bit), so the internal array in MemoryStream will never be able to grow beyond that. If your image is larger than that you'll get an out of memory exception.

Brian Rasmussen
+6  A: 

You are using about a gigabyte of ram, not very suprising that you run out of memory.

Assuming you use a 32bpp Fileformat with 16000x9440 pixel you get a filesize of about:

16000 * 9440 * (32/8) = ~576MB

byte[] data = new byte[fileStream.Length];
fileStream.Read(data, 0, data.Length);
using (MemoryStream memoryStream = new MemoryStream(data))
{
  [... snip ...]
}

You load the whole File into a memory stream, this requires 576MB.

[... snip ...]
    using (Bitmap src = new Bitmap(memoryStream)) // <-- exception
    {
        [... snip ...]
    }
[... snip ...]

You load the whole stream contents into a bitmap, this requires at least another 576MB (depending on how much memory the bitmap requires per pixel, should be at least 4, propably more). At that point you have the image twice in memory which seriously hurts for such big images.

You can reduce the memory footprint by getting rid of the memory stream and loading the bitmap directly from the file stream.

Another solution would be to load only a part of the bitmap and load the other parts on-demand (much like google maps), but i can't help you with that solution, might require reading the bitmap manually.

dbemerlin
+1 for, beside explaining what the problem is, offering alternatives.
Aistina
Thx for advice, I removed memoryStream declaration and load Bitmap directly from fileStream:using (Bitmap src = new Bitmap(fileStream)).But it didn't help =( I have a Windows 7 x64 and above 5GB of VRAM as free.Solution with partly loading procedure sounds good, maybe it can be helpfull.
Jo Asakura
This doesn't explain it, a .NET program can easily allocate well over 1 gigabyte of memory.
Hans Passant
Some troubles were resolved by using next construction: using (Image src = Image.FromStream(fileStream, false, false)); But next step is using 32000x18880 px image and it doesn't work =)
Jo Asakura