I have a little console application in C# that takes a pair of pictures from a folder (containing a few hundred images) in .jpg-format, merges them to one picture and stores the result as .tif in another folder. This process is repeated for all pictures in the source folder.
It works fine for a few loop iterations, but then I get an unhandled external exception with an GDI+ generic error (the inner exception is null) when trying to save the result. As I create new files for storing and as it works for a few pictures before crashing, I dont think this is caused by some permission problem or a lock on a file. I suspect it might be some memory issue, because when I use 24bit (Format24bppRgb) for the .tif, it crashes after approx 13 iterations, when I use 48bit (Format48bppRgb) it crashes after approx 8 iterations.
The current image to be saved when it crashes is already present on the disk as an empty .tif of less than 1KB. The application is not run from Visual Studio but directly from the .exe (as I have read of memory problems when creating large images in an application running from within Visual Studio)
The sizes of the source images range from 800x600 to 24 megapixels. Result sizes can be larger, as when a landscape oriented image is combined with a portrait oriented picture it results in a square image with the greater width and height of the source images. The machine where I run the application has 8GB of RAM, of which at max approx. 50% is used.
The loop looks like this:
foreach (var f in files)
{
if ((count % 2) == 0)
{
bmp1 = new Bitmap(f);
int index2 = Array.IndexOf(files, f) + 1;
if (index2 >= files.Length) { break; }
bmp2 = new Bitmap(files.ElementAt(index2));
Merge2Rand(bmp1, bmp2,rand).Save(outputDir + "\\0\\out" + count + ".tif", myImageCodecInfo, myEncoderParameters);
Console.WriteLine(count + " - " + watch.ElapsedMilliseconds / 60000 + "min");
}
count++;
}
This is the merging function:
public static Bitmap Merge2Rand(Bitmap bmp1, Bitmap bmp2, Random rand)
{
int newH = Math.Max(bmp2.Height, bmp1.Height);
int newW = Math.Max(bmp2.Width, bmp1.Width);
int offsetH1 = 0;
if (bmp1.Height < newH) offsetH1 = rand.Next(0, (newH - bmp1.Height) + 1);
int offsetW1 = 0;
if (bmp1.Width < newW) offsetW1 = rand.Next(0, (newW - bmp1.Width) + 1);
int offsetH2 = 0;
if (bmp2.Height < newH) offsetH2 = rand.Next(0, (newH - bmp2.Height) + 1);
int offsetW2 = 0;
if (bmp2.Width < newW) offsetW2 = rand.Next(0, (newW - bmp2.Width) + 1);
Bitmap newBMP = new Bitmap(newW, newH, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
for (int i = 0; i < newW; i++)
{
for (int j = 0; j < newH; j++)
{
Color p1;
Color p2;
if ((i>=offsetW1 && bmp1.Width+offsetW1 > i+offsetW1 ) && (j>=offsetH1 && bmp1.Height+offsetH1 > j+offsetH1))
{
p1 = bmp1.GetPixel(i, j);
}
else
{
p1 = Color.FromArgb(0, 0, 0, 0);
}
if ((i>=offsetW2 && bmp2.Width + offsetW2 > i +offsetW2) && (j>=offsetH2 && bmp2.Height + offsetH2 > j +offsetH2))
{
p2 = bmp2.GetPixel(i, j);
}
else
{
/
p2 = Color.FromArgb(0, 0, 0, 0);
}
int rVal = (p1.R + p2.R) / 2;
int gVal = (p1.G + p2.G) / 2;
int bVal = (p1.B + p2.B) / 2;
newBMP.SetPixel(i, j, Color.FromArgb(0, rVal, gVal, bVal));
}
}
return newBMP;
I use the following encoding for the .tif files:
ImageCodecInfo myImageCodecInfo;
myImageCodecInfo = GetEncoderInfo("image/tiff");
System.Drawing.Imaging.Encoder myEncoder;
myEncoder = System.Drawing.Imaging.Encoder.Compression;
EncoderParameters myEncoderParameters;
myEncoderParameters = new EncoderParameters(1);
EncoderParameter myEncoderParameter;
myEncoderParameter = new EncoderParameter(myEncoder, (long)EncoderValue.CompressionLZW);
myEncoderParameters.Param[0] = myEncoderParameter;
private static ImageCodecInfo GetEncoderInfo(String mimeType)
{
int j;
ImageCodecInfo[] encoders;
encoders = ImageCodecInfo.GetImageEncoders();
for (j = 0; j < encoders.Length; ++j)
{
if (encoders[j].MimeType == mimeType)
return encoders[j];
}
return null;
}