Mister Crabs
Mister Crabs

Reputation: 41

There is not enough memory for the picture when using Graphics, C#

The code is very simple: I Press the button, the picture is loaded into the PictureBox.

    private void button1_Click(object sender, EventArgs e)
{
        using (FileStream stream = File.OpenRead(FullName))
        {
            pictureBox1.Image = (Bitmap)Bitmap.FromStream(stream).Clone();
            stream.Close();
            stream.Dispose();
        }
}

But when from other function\events I use Graphics on PictureBox'e, it swears that there is not enough memory on Graphics.FromImage. No matter what I do with this schedule. Example:

    using (Graphics g = Graphics.FromImage(pictureBox1.Image))
{
    g.Clear(Color.FromArgb(0, 255, 255, 255));
    pictureBox1.Invalidate();
}

The question is, why can I do anything I want with Graphics before uploading a picture to the PictureBox:cut, fill,draw; but after uploading a picture I can't? p.s. Picture tried different sizes. The same picture works before uploading(it was already in the default pictureBox) and does not work after uploading to the pictureBox. Walked quite a lot of forums on this subject, but my case(or the most similar case) is not found.

Upvotes: 0

Views: 564

Answers (2)

Jimi
Jimi

Reputation: 32248

You have 3 alternatives:

1) Assign the Image.FromStream() result without cloning it: the PictureBox Control preferes to act on its own on the underlying stream (see the .Net Source about the PictureBox.Load() method).

private void button1_Click(object sender, EventArgs e)
{
    using (FileStream stream = File.OpenRead(FullName))
    {
        pictureBox1.Image = Bitmap.FromStream(stream);
    }
    using (Graphics g = Graphics.FromImage(pictureBox1.Image))
    {
        g.Clear(Color.FromArgb(0, 255, 255, 255));
    }
}  

2) Perform all the operations inside the using block. The stream will still be valid at this point:

using (FileStream stream = File.OpenRead(FullName)
{
    pictureBox1.Image = (Image)Image.FromStream(stream).Clone();
    using (Graphics g = Graphics.FromImage(pictureBox1.Image))
    {
        g.Clear(Color.FromArgb(0, 255, 255, 255));
    }
}

3) Use the Load() method directly.

    pictureBox1.Load(FullName);

All methods will end up using the PictureBox Control internal InstallNewImage() (.Net source) method. See how the Image stream is treated.

Calling Graphics.FromImage() will not raise an exception anymore.

Upvotes: 0

Mister Crabs
Mister Crabs

Reputation: 41

So the problem is in stream,used by Graphics.FromImage. Documentation says,that stream open from Graphics.FromImage must remain open throughout the work with the image. Okay,we can use MemoryStream:

    MemoryStream ms;

private void button1_Click(object sender, EventArgs e)
{

    ms = new MemoryStream();
    using (FileStream stream = File.OpenRead(FullName))
    {
        stream.CopyTo(ms);
        pictureBox1.Image = Bitmap.FromStream(ms);
    }
}        


private void button2_Click(object sender, EventArgs e)
{
    using (Graphics g = Graphics.FromImage(pictureBox1.Image))
    {
        g.Clear(Color.FromArgb(0, 255, 255, 255));
    }     
}

And image.Clone() need to remove, because stream must have a ref to the same image, not to their copies for correct work. (To be honest, that simply programm can work without MemoryStream)

Upvotes: 1

Related Questions