14

Theoretically, it should be 65,535 x 65,535 given you have enough memory, about 17GB.

However, creating a .NET 4.5 Console Application to test it out, it throws System.ArgumentException: Parameter is not valid.

The application is built for 64bit platform. Running on 64bit platform with 32GB of memory. Maximum resolution I've been able to get is 22,000 x 22,000 pixels.

I could not find any documentation on this.

And odd behavior is that even at 22,000 x 22,000 pixels, it doesn't always work. It sometimes works, and it sometimes throws the exception. This make me think it's related to contiguous memory allocation, but there is about 30GB of free memory.

Does anybody have any experience with this? And if I wanted to work with say, 100,000 x 100,000 pixel image and larger, what would be the best way besides implementing my own bitmap?

EDIT: The problem isn't .NET Maximum Object Size. This can be overcome by targeting for 64bit platforms, and setting the gcAllowVeryLargeObjects flag in the application config. In this way, I can get the application to consume over 15GB of memory with a single array of integers. So far, the answer seems to lie in the underlying implementation of the GDI+, but how do I get around it?

Seong Yup Yoo
  • 335
  • 1
  • 3
  • 11
  • 1
    .NET Bitmap uses GDI+, see this question for discussion on limitations http://stackoverflow.com/questions/2932436/net-gdi-image-size-file-codec-limitations – Steve Mitcham Mar 20 '15 at 21:01
  • I disassembled the constructor for Bitmap(int,int) and it calls GdipCreateBitmapFromScan0, which must be returning an error code. The Bitmap constructor maps the error codes to various .NET exceptions. – Moby Disk Mar 20 '15 at 21:37
  • 1
    Out of interest, why are you saying 65,535 x 65,535? For [`Image`](http://msdn.microsoft.com/en-us/library/system.drawing.image) (which [`BitMap`](https://msdn.microsoft.com/en-us/library/system.drawing.bitmap) is a subclass of), the [`Width`](http://msdn.microsoft.com/en-us/library/system.drawing.image.width) and [`Height`](http://msdn.microsoft.com/en-us/library/system.drawing.image.height) properties are `int` types, whereas your question implies they are `ushort`. – Wai Ha Lee Mar 20 '15 at 22:16
  • There does not seem to be a real limitation. `new Bitmap(33.488.914, 1)` is the maximum which works for me in a single dimension. – Thomas Weller Mar 20 '15 at 22:28
  • 65535 x 65535 is the maximum jpeg format limitation 256*256 – Seong Yup Yoo Mar 21 '15 at 02:06

3 Answers3

27

This is a GDI+ limitation imposed by Windows. GDI+ creates a memory-mapped file view for the pixel data of the bitmap. That makes it very efficient, bitmaps tend to be large and the MMF helps to keep the pixel data out of the paging file. RAM pages can simply be discarded and re-read from the file. Also rather notorious, lots of programmers have seen their Save() call fail with a wonky exception when they forgot to dispose the old bitmap.

Windows restricts how large the view on an MMF can be, in other words the amount of data in the file that can be directly addressed, as documented in this MSDN article:

The size of a file mapping object that is backed by a named file is limited by disk space. The size of a file view is limited to the largest available contiguous block of unreserved virtual memory. This is at most 2 GB minus the virtual memory already reserved by the process.

"Largest available continuous block" is the restriction in a 32-bit process, tends to hover around ~600 MB, give or take. The 2 GB limit kicks in on a 64-bit process. Technically GDI+ could bypass this limit by remapping the view. But it doesn't, the LockBits() method (also heavily used internally) would be inefficient and very awkward to use.

To use larger bitmaps you need to move to the successor of GDI+, WIC (Windows Imaging Component). Exposed in .NET through the System.Windows.Media.Imaging namespace.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
8

You are running into the maximum allowed object size within .net. That is covered here: Very large collection in .Net causes out-of-memory exception

Edit: You appear to be running into a limitation of GDI Plus. Hans' answer can provides you with an alternative. If you can live within the limitations, then my answer can provide some guidance.

Knowing that you can calcuate the largest bitmap you can create.

  • The max is object size is 2GB:2,147,483,648
  • Default bitmap is 32bpp (4 bytes), the largest area we can have is 2GB / 4 = 536,870,912
  • If we want a square, the largest we can get is sqrt(2GB/4) = 23,170

So the following code works fine:

Bitmap b = new Bitmap(23170,23170);

But the following fails:

Bitmap b = new Bitmap(23171,23170);

If you want to store an image with larger dimensions, you would have to change the pixel format to a lower number of bpp:

Bitmap b = new Bitmap(65535,65535, PixelFormat.Format4bppIndexed);
Community
  • 1
  • 1
John Koerner
  • 37,428
  • 8
  • 84
  • 134
  • Doesn't bpp usually mean *bits* per pixel, not bytes? – harold Mar 20 '15 at 21:16
  • @harold Yep, that was a typo. – John Koerner Mar 20 '15 at 21:19
  • Your theory is unsound, the Image and Bitmap classes only store a *handle*, not the pixel data. – Hans Passant Mar 20 '15 at 21:21
  • @HansPassant Interesting. I am seeing the memory allocated in my process and hitting the exact limits I would expect based on the pixel format. See my update for a changed pixel format allowing a larger bitmap to be allocated. – John Koerner Mar 20 '15 at 21:28
  • @JohnKoerner it is very possible that GDI+ has the same size limitation but it is GDI+'s size limitation, not .NET's that is limiting you. The limit is `Int32.MaxValue` and it makes since that the object limit in .NET and the object limit in GDI+ would be that value. – Scott Chamberlain Mar 20 '15 at 21:40
  • @JohnKoerner Your numbers look right, and it seems the cap is at 2GB, and it seems the limit might be the 2GB .net object limit, but you can get around the .net maximum allowed object size by making you application 64bit, and setting the gcAllowVeryLargeObjects flag in the app config, which I did. In this way, I am able to create an array of integers that take up over 15GB of memory. I think this limit is more likely to be coming from the underlying GDI+ library. I don't know how to get around it, and I would rather not implement my own bitmap :/ – Seong Yup Yoo Mar 20 '15 at 21:54
1

The size limit in bytes for the Bitmap file format spec is 2^32 bytes.
You reach this limit faster depending on how many bytes per pixel you use.

Mauro Sampietro
  • 2,739
  • 1
  • 24
  • 50