开发者

.Net Bitmap class constructor (int, int) and (int, int, PixelFormat) throws ArgumentException on perfectly good arguments

开发者 https://www.devze.com 2022-12-14 12:46 出处:网络
I have some code that does something like this (Irrelevant bits snipped): void foo(Bitmap bmp1, Bitmap bmp2)

I have some code that does something like this (Irrelevant bits snipped):

void foo(Bitmap bmp1, Bitmap bmp2)
{
    Bitmap bmp3;
    if(something)
        bmp3 = new Bitmap(bmp1.Width, bmp1.Height + bmp2.Height);
    else
        bmp3 = new Bitmap(bmp1.Width, 18000);
    (more stuff here that runs fine)
}

Anywho most of the time this ran fine. At first. As the project continued it started to fail on the new Bitmap line. The error it gives is: "Arg开发者_如何学编程umentException was unhandled. Parameter is not valid." There's no mention of which parameter it has a problem with or anything. I'm stumped. Here's what I know for sure:

  1. bmp1 and bmp2 have never been null when this error is thrown.
  2. The if statement's presence has never made a difference; it dies just as frequently without.
  3. Both examples of the constructor use have thrown this error.

I'm tempted to say this is a memory error, except it doesn't mention anything of the sort. The first dozen times or so this happened the heights totalled over 18000 (hence the magic number above). Figuring it was some kind of soft barrier to our system, we just limited the images at that height which made the exceptions go away after a while.

For some sample data, the exception I'm looking at right now has bmp1.Width at 2550, bmp1.Height at 6135 and bmp2.Height at 6285.

Anyone have any ideas?


GDI+ does not generate very good exception messages. The exception you got is flaky, this one will generate it reliably on my machine:

    private void button1_Click(object sender, EventArgs e) {
        var bmp = new Bitmap(20000, 20000);
    }

What's really going on is that this bitmap requires too much contiguous unmanaged memory to store the bitmap bits, more than is available in your process. On a 32-bit operating system, you can only ever hope to allocate a chunk of memory around 550 megabytes. That goes quickly down-hill from there.

The issue is address space fragmentation, the virtual memory of your program stores a mix of code and data at various addresses. Total memory space is around 2 gigabytes but the biggest hole is much smaller than that. You can only consume all memory with lots of small allocations, big ones fail much quicker.

Long story short: it is trying to tell you that the size you requested cannot be supported.

A 64-bit operating system doesn't have this problem. Be sure to take advantage of it with Project > Properties > Build tab, Platform target = AnyCPU and Prefer 32-bit = unticked. Also, WPF relies on WIC, an imaging library that's a lot smarter about allocating buffers for bitmaps.


Check whether bmp1 or bmp2 has been Disposed (even if not null). See here:

The Mysterious Parameter Is Not Valid Exception


Anyone have any ideas?

Wrap the call that is throwing ArgumentException with a try-catch(Exception ex) and step into the exception block to see the raw exception. It should give you more detail, like which argument is supposedly invalid.

try
{
    bmp3 = new Bitmap(bmp1.Width, bmp1.Height + bmp2.Height);
}
catch (Exception ex)
{   
    throw;  // breakpoint here, examine "ex"
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号