How to save Graphics to file?
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 6 of 6

Thread: How to save Graphics to file?

  1. #1
    Join Date
    Apr 2012
    Posts
    6

    How to save Graphics to file?

    Hi and thanks for reading this.
    I try to create a painting program that draws on a form or more particulary on a Graphics object on the form.
    do you know how can I save the drawing to a file?

    also, when something hide the form the drawings are deleted, what is the solution to this problem?

    thanks
    Dror

  2. #2
    Join Date
    Jun 2008
    Posts
    2,477

    Re: How to save Graphics to file?

    You're going about this backward. Create a Bitmap (or any other image type) object and use this code to get a Graphics object:

    Code:
    var img = new Bitmap(width, height);
    var g = Graphics.FromImage(img);
    Now, draw to the Graphics object when needed. To save the image, use:

    Code:
    img.Save(path, ImageFormat.Whatever);
    When you are done with the Graphics object be sure to call Dispose() on it.

    The reason your drawing disappears when the form is repainted is because you are doing it wrong. You should be doing all of your drawing inside an OnPaint handler, not by calling CreateGraphics from random pieces of code. Read up on the Windows Message Loop
    If you liked my post go ahead and give me an upvote so that my epee.... ahem, reputation will grow.

    Yes; I have a blog too - http://the-angry-gorilla.com/

  3. #3
    Join Date
    Apr 2012
    Posts
    6

    Re: How to save Graphics to file?

    thanks for your reply.
    I tried your first suggestion but now it doesnt draw anything!
    so I guess it doesnt work or Im doing something the wrong way.

    as for your second suggestion, the drawing done in the mouse event so I guess I need to call to paint event from it but its a little complicated, but I might try it letter.

  4. #4
    Join Date
    Jan 2010
    Posts
    1,099

    Re: How to save Graphics to file?

    Windowed applications basically run as a one big while loop. The Windows OS posts messages which represent various notifications (like, mouse moved there-and-there, a button was pressed, a paint is due, etc.), and the application windows respond to these. So basically, all application UI logic happens in small chunks, each time the loop body is run. You don't see this directly, but this is what's happening under the hood. Mostly, the closest you get exposed to it are the C# events. Under the hood, the messages queue up, until they are ready to be processed, and the cycle repeats until your app exits. That's why calling some computationally-heavy method on the UI thread can block you application - since that method takes a long time to complete, the Windows message loop gets stuck.

    Now, generally, windows are only repainted when required (as determined by the system) - for example, when some control appears/disappears, or a portion of the window previously hidden is revealed. When you do custom drawing, you need to tell your app when it should repaint itself.

    This is generally done by calling the Invalidate() method - this essentially tells the form that it needs to redraw itself the next chance it gets. It will do so by calling it's OnPaint() method, which you can override, or, alternatively, you can respond to the Paint event, which is raised by OnPaint(), that is, it's essentially called by it.

    So, what you need to do is to store your drawing data somewhere, and then use it later in the OnPaint() metod (or in the Paint event) to actually draw the image.
    There are two approaches you can take, depending on how complex is the thing you're drawing.

    For example, if you're drawing a set of strait lines, you can just store the points, and redraw on every update. This way, you can even implement things like clicking on a vertex and moving it, and it will animate.
    If the graphics are more complex, or if such functionality is not required, you can, as BigEd781 suggested, create an image to draw on, that will essentially act as an off-screen buffer, and then, when everything is done, draw the whole thing at once by drawing the image on the form. This way, you can preserve complex images between updates.
    Note that this involves using two Graphics objects: one created from the image (used to draw your shapes), and the other obtained from the paint event arguments (used to present the image on the form).

    Also, you can reduce flicker by calling the SetStyle() method in the form's constructor, with the parameters:
    SetStyle(ControlStyles.AllPaintingInWmPaint, true);

    This will prevent the form to erase the the whole thing to the BackColor before every update. If the back-buffer image is not transparent, you can just draw it on top of whatever is currently displayed on the form.
    Last edited by TheGreatCthulhu; April 19th, 2012 at 09:25 AM.

  5. #5
    Join Date
    Apr 2012
    Posts
    6

    Re: How to save Graphics to file?

    thanks for answering.
    I've tried to draw on a bitmap as suggested (without var instead i use the cariables as global) but now it doesn't paint at all.

    please help

  6. #6
    Join Date
    Jan 2010
    Posts
    1,099

    Re: How to save Graphics to file?

    I've attached a VS project that shows you how to do it. It's a VS2008 project, in case you're using an older version.

    What the app does is let's you draw a bunch of connected line segments by clicking on the form.
    All the relevant code is in Form1.cs, and it's has some comments to help you understand what's going on.
    I'll reproduce it here:
    Code:
    public partial class Form1 : Form
        {
            private Bitmap backBuffer = new Bitmap(400, 300);
            private Graphics backBuffGraphics = null;
    
            private List<Point> points = new List<Point>();
            
            public Form1()
            {
                InitializeComponent();
                
                ClientSize = new Size(400, 300);
                backBuffGraphics = Graphics.FromImage(backBuffer);
    
                // This next bit apparently doesn't work with forms, but it 
                // should work with pannels and such...
                // Anyway, the alternative is to override OnPaintBackground()
                // and make it do nothing.
                //SetStyle(ControlStyles.AllPaintingInWmPaint, true);      
            }
    
            protected override void OnMouseDown(MouseEventArgs e)
            {
                points.Add(e.Location);     // Simply records the click location.
                base.OnMouseDown(e);        // These On* methods raise the events - 
                                            // u can chose where u want to call them.
                
                // Invalidate tells the form that it needs to repaint istself
                // when the time comes.
                Invalidate();
            }
    
            protected override void OnPaint(PaintEventArgs e)
            {
                backBuffGraphics.Clear(BackColor);      // erase the back buffer
                            
                // DRAWING TO THE BACK BUFFER - nothing is shown, it all happens
                // in the bacground - avoids flicker, and other bad effects
                
                // Draw the lines...
                if (points.Count >= 2)
                    backBuffGraphics.DrawLines(Pens.Blue, points.ToArray());
    
                // Draw the points...
                foreach (Point pt in points)
                    DrawVertex(backBuffGraphics, pt);   // a helper method defined below
    
                // Now draw the back buffer to the front buffer, so that it becomes visible
                e.Graphics.DrawImage(backBuffer, ClientRectangle);
    
                base.OnPaint(e);
            }
    
            private void DrawVertex(Graphics g, Point pt)
            {
                Rectangle rect = new Rectangle(pt.X - 2, pt.Y - 2, 4, 4);
                g.DrawRectangle(Pens.Black, rect);
            }
    
            protected override void OnPaintBackground(PaintEventArgs e)
            {
                // Do nothing...
                //base.OnPaintBackground(e);            
            }
        }
    The basic drawing functionality doesn't require a lot of code. To show you what I mean, here's the same code, but without comments - this is essentially the whole program:
    Code:
    public partial class Form1 : Form
        {
            private Bitmap backBuffer = new Bitmap(400, 300);
            private Graphics backBuffGraphics = null;
    
            private List<Point> points = new List<Point>();
            
            public Form1()
            {
                InitializeComponent();
                
                ClientSize = new Size(400, 300);
                backBuffGraphics = Graphics.FromImage(backBuffer);              
            }
    
            protected override void OnMouseDown(MouseEventArgs e)
            {
                points.Add(e.Location);
                base.OnMouseDown(e);
    
                Invalidate();
            }
    
            protected override void OnPaint(PaintEventArgs e)
            {
                backBuffGraphics.Clear(BackColor);
    
                if (points.Count >= 2)
                    backBuffGraphics.DrawLines(Pens.Blue, points.ToArray());
    
                foreach (Point pt in points)
                    DrawVertex(backBuffGraphics, pt);
    
                e.Graphics.DrawImage(backBuffer, ClientRectangle);
    
                base.OnPaint(e);
            }
    
            private void DrawVertex(Graphics g, Point pt)
            {
                Rectangle rect = new Rectangle(pt.X - 2, pt.Y - 2, 4, 4);
                g.DrawRectangle(Pens.Black, rect);
            }
    
            protected override void OnPaintBackground(PaintEventArgs e)
            {}
        }
    I encourage you to experiment with that a bit. You can add the ability to save to a file, by using the capabilities of the Bitmap class.
    Attached Files Attached Files
    Last edited by TheGreatCthulhu; April 24th, 2012 at 08:15 AM. Reason: Forgot to attach the project XD

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center