Itayel
Itayel

Reputation: 11

A generic error occurred in GDI+ while saving image to MemoryStream

Hi i'm getting to following exception 'System.Runtime.InteropServices.ExternalException at System.Drawing.Image.Save' when trying to save JPEG file to a memory stream.

images = new List<Bitmap>(seriesDataList.Count());

foreach (var seriesData in seriesDataList)
{
    using (chart = new Chart { Width = ChartWidth, Height = ChartHeight })
    {
        chart.ChartAreas.Add(new ChartArea(seriesData.Key));

        var series = new Series(seriesData.Key)
        {
            ChartType = SeriesChartType.Doughnut,
            Font = ChartTextFont,
            LegendText = "#VALX (#PERCENT)",
        };

        BindSeriesData(seriesData.ToList(), series);
        series["PieLabelStyle"] = seriesData.Count() <= MaxValuesForShowingLabels ? "Outside" : "Disabled";
        series["PieLineColor"] = "Black";
        chart.Series.Add(series);

        var legend = new Legend(seriesData.Key)
        {
            Enabled = true,
            Font = ChartTextFont,
            Docking = Docking.Right,
            Title = seriesData.Key,
            TitleFont = ChartTitleFont,
            TitleAlignment = StringAlignment.Near
        };

        chart.Legends.Add(legend);

        using (var memoryStream = new MemoryStream())
        {
            chart.SaveImage(memoryStream, ChartImageFormat.Jpeg); // Working fine
            images.Add(new Bitmap(memoryStream));
        }
    }
}

using (var fullImage = MergeImages(images))
           {
                using (var memoryStream = new MemoryStream())
                {
                    fullImage.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Jpeg); // ERROR HERE
                    return Convert.ToBase64String(memoryStream.ToArray());
                }
            }

In other cases where the full image not built from many images the flow is working. It fails in low rate for this image type only. Saw other related question suggested to wrap memoryStream with 'using' which i'm already doing.

Any suggestions?

Upvotes: 0

Views: 1726

Answers (1)

JonasH
JonasH

Reputation: 36361

As mentioned by Klaus Gütter in the comments, you are not allowed to dispose the stream before the bitmap.

One option to fix this would be to return a clone of the bitmap, that should ensure all the pixel-data is copied to a separate buffer, allowing the original stream to be freed.

using var bmp = new Bitmap(memoryStream);
images.Add(bmp.Clone(new Rectangle(0,0, bmp.Width, bmp.Height), PixelFormat.Format32bppArgb);

Another option could be to just not dispose the memory stream. Since MemoryStream just represents a chunk of managed memory it is safe to rely on the garbage collector for clean up. A good rule of thumb is to always dispose disposable objects, but this is less important when you know that the object only owns managed resources, like memory.

Upvotes: 1

Related Questions