Wichilie
Wichilie

Reputation: 127

ExternalException when saving .bmp to MemoryStream as .png

I'm converting a batch of .bmp's to .png. This is the relevant part of the code:

foreach (string path in files) {
    using (fs = new FileStream(path, FileMode.Open)) bmp = new Bitmap(fs);

    using (ms = new MemoryStream()) {
        bmp.Save(ms, ImageFormat.Png);
        bmp.Dispose();

        png = Image.FromStream(ms);
    }

    png.Save(path);
}

At the line bmp.Save(ms, ImageFormat.Png); the following exception is thrown:

System.Runtime.InteropServices.ExternalException: 'A generic error occurred in GDI+.'

According to MSDN this means the image was either saved with the wrong format or to the same location it was read from. The latter is not the case. However, I don't see how I gave it the wrong format: on the same MSDN page an example is given where a .bmp is converted to a .gif in the same manner.

Does it have to do with me saving to a MemoryStream? This is done so that I can overwrite the original file with the converted one. (Note that the .bmp suffix is kept intentionally. This shouldn't be the problem, since the exception appears before the final file is saved.)

Upvotes: 1

Views: 1518

Answers (1)

rene
rene

Reputation: 42453

In the MSDN documentation of that Bitmap constructor it says:

You must keep the stream open for the lifetime of the Bitmap.

and that same remark can be found on Image.FromStream.

So your code should carefully handle the scope and lifetime of the streams it uses for each of those bitmaps/images.

Combining all that the following code handles those streams correctly:

foreach (string path in files) {
   using (var ms = new MemoryStream()) //keep stream around
   {
        using (var fs = new FileStream(path, FileMode.Open)) // keep file around
        {
            // create and save bitmap to memorystream
            using(var bmp = new Bitmap(fs))
            {
                bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
            }
        }
        // write the PNG back to the same file from the memorystream
        using(var png = Image.FromStream(ms))
        {
            png.Save(path);
        }
    }
}

Upvotes: 1

Related Questions