Brian Tacker
Brian Tacker

Reputation: 1122

Creating, Drawing Lines and saving bitmap gives Generic GDI+ error

I have a very simple method that takes a signature as a list of points and draws them as lines on a bitmap. And I want to take that bitmap and save it to a file, but when I call the Save method Im getting "A generic error occured in GDI+" and no Inner Exception.

This seems like pretty straight forward code so Im not sure what the problem is.

using (var b = new Bitmap(width, height))
{
    var g = Graphics.FromImage(b);
    var lastPoint = points[0];
    for (int i = 1; i < points.Length; i++)
    {
        var p = points[i];
        // When the user takes the pen off the device, X/Y is set to -1
        if ((lastPoint.X >= 0 || lastPoint.Y >= 0) && (p.X >= 0 || p.Y >= 0))
            g.DrawLine(Pens.Black, lastPoint.X, lastPoint.Y, p.X, p.Y);
        lastPoint = p;
    }
    g.Flush();
    pictureBox.Image = b;
    b.Save("C:\\test.bmp");
}

I've tried saving with all the possible ImageFormats, put the graphics object in a using statement, and as a long shot I even tried:

using (var ms = new MemoryStream())
{
    b.Save(ms, ImageFormats.Bmp); // And b.Save(ms, ImageFormats.MemoryBmp);
    Image.FromStream(ms).Save("C:\\test.bmp");
}

The strange thing is, if I remove the b.Save (or ignore the exception), the pictureBox displays the image perfectly.

Any help would be appreciated.

Upvotes: 0

Views: 1592

Answers (2)

TaW
TaW

Reputation: 54433

Your code has two issues, one hiding the other:

  • Your application probably doesn't have writing rights on the root of C:, so the Save fails.
  • You also can't have a PictureBox display a Bitmap which you then destroy in the using block.

So you should change the code to something like this:

var b = new Bitmap(width, height);

using (Graphics g = Graphics.FromImage(b))
{
    var lastPoint = points[0];
    for (int i = 1; i < points.Length; i++)
    {
        var p = points[i];
        // When the user takes the pen off the device, X/Y is set to -1
        if ((lastPoint.X >= 0 || lastPoint.Y >= 0) && (p.X >= 0 || p.Y >= 0))
            g.DrawLine(Pens.Black, lastPoint.X, lastPoint.Y, p.X, p.Y);
        lastPoint = p;
    }
    // g.Flush(); not necessary
    pictureBox1.Image = b;
    b.Save("C:\\temp\\test.bmp");
}

You also should include a check on the Length of the array and consider using a List<Points> instead, also checking its Count and using DrawLines on points.ToArray() for better line joins, especially with thick, semi-transparent lines!

Upvotes: 1

jsanalytics
jsanalytics

Reputation: 13188

I would draw to the PictureBox using the corresponding Graphics from the Paint event and then save to a bitmap:

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        MyDrawing(e.Graphics);

        Bitmap b = new Bitmap(pictureBox1.Width, pictureBox1.Height);
        pictureBox1.DrawToBitmap(b, pictureBox1.ClientRectangle);
        b.Save(@"C:\test.bmp");

    }
    private void MyDrawing(Graphics g)
    {
        var lastPoint = points[0];

        for (int i = 1; i < points.Count; i++)
        {
            var p = points[i];
            // When the user takes the pen off the device, X/Y is set to -1
            if ((lastPoint.X >= 0 || lastPoint.Y >= 0) && (p.X >= 0 || p.Y >= 0))
                g.DrawLine(Pens.Black, lastPoint.X, lastPoint.Y, p.X, p.Y);
            lastPoint = p;
        }
        g.Flush();
    }

enter image description here

Saved BMP:

enter image description here

Upvotes: 2

Related Questions