Click here to Skip to main content
15,886,689 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
Hi,
I have a WPF application where I need to convert an array of "Windows.System.Media.Imageing.BitmapImage" objects to an array of "System.Drawing.Image" objects. The following methods work well most of the time but an "OutOfMemoryException" is sometimes raised, possibly with larger image arrays.

These methods are part of a static class.

The exception is raised on the third to last line of "ConvertImage" when it reads from the stream.
C#
private static System.Drawing.Image[] ConvertImageArray(BitmapImage[] bmpThePages)
        {
            System.Drawing.Image[] sdiThePages = new System.Drawing.Image[bmpThePages.Length];

            for (int x = 0; x < bmpThePages.Length; x++)
            {
                ConvertImage(ref bmpThePages[x], ref sdiThePages[x]);
            }

            return sdiThePages;
        }

        private static void ConvertImage(ref BitmapImage bmpThePage,ref System.Drawing.Image sdiThePage)
        {
            MemoryStream ms = new MemoryStream();
            TiffBitmapEncoder encoder = new TiffBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(bmpThePage));
            encoder.Save(ms);

            sdiThePage = System.Drawing.Image.FromStream(ms);

            ms.Close();//redundant
            ms.Dispose();
}
Posted
Updated 13-Feb-11 20:13pm
v5

1 solution

Small correction:

C#
private static System.Drawing.Image ConvertImage(BitmapImage bmpThePage)
{
   using (MemoryStream ms = new MemoryStream()) {
        TiffBitmapEncoder encoder = new TiffBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(bmpThePage));
        encoder.Save(ms);
        return System.Drawing.Image.FromStream(ms);
   } //ms is disposed here 
}


You don't need parameters by ref. Input parameter is of reference type, and another one should be a return value. Also, I used using construct to dispose memory stream automatically. In this case Dispose will be called even on exception (you should always use this technique to initialize an instance of any class implementing IDisposable).

—SA
 
Share this answer
 
Comments
tedsmith256 14-Feb-11 8:48am    
Thanks for the quick reply.

Actually, with the exception of the "using" construct your suggestion is the way I had things set up in the first version of my app. The "dispose" and "ref" ideas were one of the many things I tried just for the heck of it. It still bombs with the memory exception on the last line of the ConvertImage function.

The bmpThePages[] being passed to ConvertImageArray is a disassembled multipage tiff whereby each element is a page.

My code works most of the time. There is one image that is a 39 page tiff that causes the failure. The encoding and image size is nothing that the app hasn't been able to handle in the past. However this image had the most pages of any image that I have tried. The odd thing is that it bombs on the 9th or 10th page (iteration of x) even though I have had no problem with 15 page tiffs before.
Sergey Alexandrovich Kryukov 14-Feb-11 11:08am    
It still looks as a memory leak. Could you simply track memory usage and detect some leak on a massive operation which gets a lot of memory, but not quite as much as needed to cause exception, and do it repeatedly on the _same_ data: the cycle would be convert data, than clean it. You will the leak.

You know, I never had a leak problem which I did not resolve manually, so I'm not familiar with leak-fixing tools, but you can find some. My method is manual (for .NET, with native I uses some special leak-detecting code).

Try to identify all types you used which also implement IDispose: maybe something is missing (Dispose not called). Are you sure you're not using some intermediate container which you forget to clean? Is there some other code you did not post? I mean, what's the minimal code to see the problem?

--SA
Sergey Alexandrovich Kryukov 14-Feb-11 11:10am    
Maybe, there is no bug; you just take up a lot of memory, but correctly?
What makes you thinking there is a problem? Not repeatable? But how do you know you repeat in identical conditions? If it was not repeated from cold boot, that would be convincing...
--SA
Espen Harlinn 14-Feb-11 10:29am    
Good advice, 5
tedsmith256 14-Feb-11 17:41pm    
Thank you so much for your help. I found the problem.

It was not in my posted functions. Your "second pair of eyes" helped confirm my code and look elsewhere for the leak. I opened up perfmon and saw that it was happening in a function prior to the ones posted where I call "Render" from RenderTargetBitmap. This is a documented bug in .NET 3.5.

Apparently, there was just enough memory left to iterate 9 or 10 pages into my function.

Thanks again,
Ted

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900