Click here to Skip to main content
15,903,856 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
hello,

first a little background.
I digitize my old Super8 movies using a flatbed scanner
(for details see http://hosting.aktionspotenzial.de/CineToVidWiki )

I recognized, that I get better results, if I scan the movie strips
upside down (emulsion towards the scanner glass). To do this I must also scan the strips from film end towards film start (backward).
To extract the frames properly (that is: not to get mirrored images and a backwards running film) I have to renumber the files containing the strips and I also have to horizontally flip the images.

Therefore I have written a little program, that can do that for me.
The conversion and image saving method is shown below. This method is called in a loop (from a Forms class providing the GUI for the application), this loop provides the filenames of the image source and the image target.
BUT:
As the images are pretty large ( 4MB in JPEG compression, about 170 MB as a Windows Bitmap) this works only for a few images (but this exactly as intended), and then stops with an OutOfMemory Exception.

The loop code looks like this

C#
for (i = startFileIndex; i <= endFileIndex; i++)
{  /* 001 start for */
    errFileName = fileEntries[i];
    aFileURLB = stripDirectoryB + fileEntries[i];
    aFileURLF = stripDirectoryF + fileEntries[numberOfStrips - i - 1];
    aNewImage = new NewImage();
    imgIndex  = aNewImage.flipAndRenameImage(aFileURLB, aFileURLF, errFileName,i);
    ........
    ......
    aNewImage = null;
}  /* 001 end for */


As you can see in the provided code below, I have tried several things to free memory in the heap, but without any success.


Has anybody an idea, what to do, to get rid of the OutOfMemory exception. I would appreciate that very much.



---------- this is the code that is called from the loop -----------
---------- in each cycle of the calling loop a new instance of NewImage is created and discarded ( set to NULL ) at the end of the cycle -------------------------------

C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Windows.Media.Imaging;
// using System.Windows.Controls;

namespace ReformatStrips
{
    public class NewImage
    {

        public Stream imageStreamSource;
        public FileStream imageStreamTarget;
        public BitmapSource bitmapSource;
        public JpegBitmapDecoder decoder;
        public JpegBitmapEncoder encoder;

        public NewImage()
        {
            // Nothings specific to do
        }

        public int flipAndRenameImage(string aFileURLB, string aFileURLF, string errFileName, int fileIndex)
        {  /*  start of method */
            try
            {
                // Open a Stream and decode a JPEG image
                imageStreamSource = new FileStream(aFileURLB, FileMode.Open, FileAccess.Read, FileShare.Read);
                decoder = new JpegBitmapDecoder(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
                bitmapSource = decoder.Frames[0];

                imageStreamTarget = new FileStream(aFileURLF, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
                encoder = new JpegBitmapEncoder();
                encoder.FlipHorizontal = true;
                encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
                encoder.Save(imageStreamTarget);
                imageStreamTarget.Flush();

                imageStreamSource.Close();
                imageStreamTarget.Close();
                imageStreamSource.Dispose();
                imageStreamTarget.Dispose();
                bitmapSource = null;
                imageStreamSource = null;
                imageStreamTarget = null;
                decoder = null;
                encoder = null;
                fileIndex = 0;
 
                GC.WaitForFullGCComplete(1000);
                GC.Collect(0, GCCollectionMode.Forced);
            }
            catch (Exception e)
            {
                imageStreamTarget.Flush();
                imageStreamTarget.Close();
                GC.WaitForFullGCComplete(1000);
                GC.Collect(0, GCCollectionMode.Forced);

                Console.WriteLine(e.ToString());
            }
            return fileIndex;
        }  /*  end of method */
    }
}

Posted
Updated 3-Aug-10 6:48am
v3
Comments
William Winner 3-Aug-10 13:01pm    
First, a little advice about how this forum is meant to work.

1) You ask a question. (step 1 done properly)
2) People try to answer your question (step 2 done properly)
3) If you have a question about a specific answer or you want to post some kind of comment to that answer, use the "Add Comment" button at the bottom of the answer (not done properly).
4) When the answer is solved (meaning that you don't have the problem anymore) mark the answer(s) that helped you as solved (not done properly).

Don't post an "answer" if it doesn't answer the question and you're commenting on someone else's answer. And don't mark an answer as being the solution if it doesn't solve the problem.
Wolfgang Kurz 3-Aug-10 14:40pm    
Thanks William, I'll try to learn from your comments

You could first try to add this at the end of your loop:

C#
GC.Collect();
GC.WaitForPendingFinalizers();


It would be better to re-use the NewImage instance you already got. This would certainly speed up processing.

The reason you get this error is probably because the garbage collector isn't called as often as you discard memory every iteration.

Good luck!
 
Share this answer
 
v2
Asking the garbage to collect does not gaurantee it will do so with every object. There are complex rules for garbage collection that will sometimes cause problems (e.g., the large object heap). One thing you may be running into is that there may not be enough CONTIGUOUS free space to allocate some of the larger objects used by your program. You can try to get around this by making use of the using statement, which will deterministically destroy objects if they follow the IDisposable pattern. If that doesn't work, some of your images may just be too big to process without using some specialized library. You may also want to try using a memory profiler to see exactly what is taking up all the memory.
 
Share this answer
 
Comments
Wolfgang Kurz 3-Aug-10 13:27pm    
Reason for my vote of 5
The using did the trick
One little tip...read up on static classes (Static Classes and Static Class Members[^])

You really want to NewImage to be a static class here.

Also, I would do all of your memory cleanup at the end of the flipAndRenameImage method (right before you return fileIndex). Do all of your disposing and setting variables to null at the end outside of the Try/Catch block.
 
Share this answer
 
You can try not to call GC voluntarily, as more memory demands the GC call by itself.

Add a finally block and make all objects null in there.

public Stream imageStreamSource;
public FileStream imageStreamTarget;
public BitmapSource bitmapSource;
public JpegBitmapDecoder decoder;
public JpegBitmapEncoder encoder;

Declare all these objects within the method.
 
Share this answer
 
Hello,

Many thanks for the hint, but
I still get the same message at the same place in the code after 7 frames processed.

System.OutOfMemoryException: Insufficient memory to continue the execution of the program.
   at System.Windows.Media.Imaging.BitmapEncoder.SaveFrame(SafeMILHandle frameEncodeHandle, SafeMILHandle encoderOptions, BitmapFrame frame)
   at System.Windows.Media.Imaging.BitmapEncoder.Save(Stream stream)
   at ReformatStrips.NewImage.flipAndRenameImage(String aFileURLB, String aFileURLF, String errFileName, Int32 fileIndex) in D:\C#Prog\Visual Studio 2010\Projects\ReformatStrips\ReformatStrips\NewImage.cs:line 43


Hello again
and many thanks for the hints.
Finally the "using" statement did the trick.
The exception occured but as I have incorporated some code that allows
correct continuation after the exception the program ends successfully.



Disposing limited resource.
Disposing limited resource.
System.OutOfMemoryException: Insufficient memory to continue the execution of the program.
   at System.Windows.Media.Imaging.BitmapEncoder.SaveFrame(SafeMILHandle frameEncodeHandle, SafeMILHandle encoderOptions, BitmapFrame frame)
   at System.Windows.Media.Imaging.BitmapEncoder.Save(Stream stream)
   at ReformatStrips.NewImage.flipAndRenameImage(String aFileURLB, String aFileURLF, String errFileName, Int32 fileIndex) in D:\C#Prog\Visual Studio 2010\Projects\ReformatStrips\ReformatStrips\NewImage.cs:line 50
Disposing limited resource.     Processing continued after the
Disposing limited resource.     the exception and ended successfully
 
Share this answer
 
v4
Comments
William Winner 3-Aug-10 13:02pm    
Reason for my vote of 1
not an actual answer but a comment to another answer.

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