views:

79

answers:

3

I am loading a 50x50 Bitmap file and then filling it a single random color at program startup. Then save the result onto the same file and assign it to a PictureBox, but running into file write problems and "A generic error occurred in GDI+", etc.

How to do this properly so that I can continually repeat this, (open bitmap, paint it random color, save and assign to picturebox.Image)?

EDIT:

  public Form1 ( )
  {
   InitializeComponent ( );

   //Bitmap bmp = new Bitmap ( 50, 50 );
   Bitmap bmp = new Bitmap ( @"C:\temp\pretty.bmp" );

   Graphics g = Graphics.FromImage ( bmp );
   Brush b = new SolidBrush ( Color.Red );
   g.FillRectangle ( b, 0, 0, 49, 49 );
   bmp.Save ( @"C:\temp\pretty.bmp" );

   this.pictureBox1.Image = ( Image ) bmp.Clone ( );
   //bmp.Dispose ( );
  }
+1  A: 

Oh. You need a different file for each of your images, otherwise you overwrite the first by the second. The things is that the image may be read only later, when it's actually needed.

Another option would be to store images in memory streams, not in files.

Vlad
+2  A: 

When you use the Bitmap constructor that takes a path parameter, it keeps the file open until you dispose the Bitmap. You need to load the bitmap from a Stream, and close the Stream so that the file is closed. This should work fine :

public Form1 ( )
{
    InitializeComponent ( );

     Bitmap bmp = null;
     using (Stream stream = File.OpenRead(@"C:\temp\pretty.bmp"))
     {
         bmp = new Bitmap(stream);
     }

     using (Graphics g = Graphics.FromImage ( bmp ))
     using (Brush b = new SolidBrush ( Color.Red ))
     {
         g.FillRectangle ( b, 0, 0, 49, 49 );
     }
     bmp.Save ( @"C:\temp\pretty.bmp" );
     this.pictureBox1.Image = bmp;
}
Thomas Levesque
You also need to dispose the `Bitmap`, the `Graphics`, and the `Brush`. (Unless you use `SolidBrushes.Black`)
SLaks
indeed... just fixed it ;)
Thomas Levesque
+3  A: 

A simple adaptation, with the proper usings, would look like:

private void Form1_Load(object sender, EventArgs e)
{
    Bitmap bmp2;

    using (Bitmap bmp1 = new Bitmap(@"C:\temp\pretty.bmp"))
    {
//Edit: Clone was keeping a link between bmp1 and bmp2 somehow
       // bmp2 = (Bitmap)bmp1.Clone();
       IntPtr hbmp = bmp1.GetHbitmap();
       bmp2 = Bitmap.FromHbitmap(hbmp);     
    }

    using (Graphics g = Graphics.FromImage(bmp2))
    using (Brush b = new SolidBrush(Color.Red))
    {
        g.FillRectangle(b, 0, 0, 49, 49);

        bmp2.Save(@"C:\temp\pretty.bmp");
    }

    this.pictureBox1.Image = bmp2;   
}
Henk Holterman
Thanks Henk. Would "using" keywords stack like that? How's their effect in that case? They all belong to the same scope?
Joan Venge
Btw this gives the generic GDI error.
Joan Venge
@Joan, `using` operates just like `if()`: 1 statement or multiple statements in braces. The indenting here is a-typical but it is an accepted practice.
Henk Holterman
@Joan: No errors here.
Henk Holterman
Thanks Henk. Are you sure? I tried several times but it throws that generic GDI error in bmp2.Save(@"C:\temp\pretty.bmp");.
Joan Venge
@Joan: Sorry, you're right. I was using 2 different filenames. Clone() isn't deep enough apparently.
Henk Holterman
Thanks Henk. ...
Joan Venge