[RESOLVED] VS2010 - Out of memory exception while drawing
I have a form created to act as a signature form. It will be used on an iPad via Citrix and that's not negotiable per my job so please don't make suggestions about developing it with Apple software. Anyway, on to the issue:
Since this will be on an iPad I cannot use an OnMouseDown event to handle the drawing with the form. It consists of a PictureBox where the signature will occur. It works fine unless the user gets "draw happy" and starts drawing for a while. After a little time an Out of Memory Exception occurs and the program crashes. I'm trying to figure out a way for this to not occur but have not had any luck. Does anyone have any suggestions on a better way than the code below?
vb.net Code:
Public Class TestSig
Dim Alpha As Integer = 255
Dim penColor As New Color()
Dim penWidth As Single = 5
Dim bmp As New Bitmap(1024, 352)
Dim g As Graphics = Graphics.FromImage(bmp)
Dim mousePath As New System.Drawing.Drawing2D.GraphicsPath()
Dim mousePoint1, mousePoint2 As New Point
Dim xStart, yStart As Integer
Dim CurrentPen As New Pen(Color.FromArgb(Alpha, penColor), penWidth)
Private Sub TestSig_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
bmp = New Bitmap(PictureBox1.Width, PictureBox1.Height)
AddPath()
End Sub
Private Sub AddPath()
Dim gr As Graphics = Graphics.FromImage(bmp)
gr.DrawPath(CurrentPen, mousePath) 'ERROR OCCURS HERE
End Sub
Private Sub PictureBox1_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
'The below IfThen statement allows for the signee to start a new line
If (Abs(xStart - e.X) < 30) And (Abs(yStart - e.Y) < 30) Then
mousePath.AddLine(xStart, yStart, e.X, e.Y)
End If
Dim area As New Rectangle(xStart, yStart, e.X, e.Y)
area.Inflate(1, 1)
Me.PictureBox1.Invalidate(area)
Me.PictureBox1.Update()
mousePath.StartFigure()
xStart = e.X
yStart = e.Y
PictureBox1.Image = bmp
End Sub
Private Sub PictureBox1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
Me.PictureBox1.Image = bmp
AddPath()
End Sub
Re: VS2010 - Out of memory exception while drawing
I see two weird things here.
First off you are creating a new instance of Bitmap on the declaration of 'bmp'. This is instantly discarded in the forms Load eventhandler and recreated.
This itself should not be the cause for an OutOfMemoryException, but it is unnecessary.
The other thing though, is that you are re-creating the Graphics object over and over again on the line that you have marked. Create it once after creating the bitmap, then never again.
Re: VS2010 - Out of memory exception while drawing
First of all, you're starting a figure every time, which is a big no-no. Also, you're creating two bitmaps for no particular reason. You don't need to keep penColor and penWidth because you already have the Pen object containing both of those.
If you don't need a history, you can cache the image instead and only draw the last line. Alternatively, you can use a list (or linked list, might be better) of Points, which should take up less memory than a GraphicsPath but might still result in an error much later. I would recommend caching the image.
Anyway, let's ignore that for a second and optimize. How does this work?
Code:
Public Class TestSig
Dim MousePath As New Drawing2D.GraphicsPath()
Dim xStart, yStart As Integer
Dim CurrentPen As New Pen(Color.Black, 5.0!)
Private Sub PictureBox1_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
'The below IfThen statement allows for the signee to start a new line
If Math.Abs(xStart - e.X) < 30 AndAlso Math.Abs(yStart - e.Y) < 30 Then _
MousePath.AddLine(xStart, yStart, e.X, e.Y)
Dim area As New Rectangle(xStart, yStart, e.X, e.Y)
area.Inflate(1, 1)
Me.PictureBox1.Invalidate(area)
MousePath.StartFigure()
xStart = e.X
yStart = e.Y
End Sub
Private Sub PictureBox1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
e.Graphics.DrawPath(Me.CurrentPen, Me.mousePath)
End Sub
End Class
Re: VS2010 - Out of memory exception while drawing
@minitech: I think you meant to declare MousePath as a Drawing2D.GraphicsPath. Otherwise the AddLine and DrawPath statements will need some rethinking. I wonder whether the StartFigure is really necessary, but I agree with your optimization in other respects. BB
Re: VS2010 - Out of memory exception while drawing
Oops, thanks for pointing that out. I was halfway through another optimization :)
Re: VS2010 - Out of memory exception while drawing
@Atheist - I started with your suggestion first about only creating the graphics object once. I also noticed I had another graphics object being created which I wasn't even using (probably from trying different things and forgot to take it out). So I fixed those two issues and also changed the new bitmap declaration to only occur on the Load Form event. I still ended up with the same OOM exception.
@minitech - I commented out my code and used your's. When declaring MousePath at the beginning of the code 'Of Point' threw an error saying 'GraphicsPath has no type parameters'. I'm guessing this was still a leftover from the other optimization you were working on? :D
Anyway, I removed that and your code ran just like my original was but still ended up with the OOM exception. Could it be my development computer? Specs: Pentium D w/ 2.8GHz, 1GB of RAM, WinXP Prof SP3
I'll keep trying for other solutions but I'm running out of ideas :(
Re: VS2010 - Out of memory exception while drawing
It's not your computer, don't worry. And yes, it was a leftover (I really should check that more carefully).
Could you upload a sample project for testing?
Re: VS2010 - Out of memory exception while drawing
Hi llDayo, I doubt if your hardware is to blame. It's worth bearing in mind anyway that the graphics subsystem tends to throw OOM exceptions even when there is plenty of system memory to spare. It can happen when you try to load an image of unrecognized format into a picture box, although that doesn't apply to the present case. Don't give up, but you should post your new code.
By the way, I don't recall helping you before. Were you posting under another name or is that my personal OOM condition:)? On the whole I agree with minitech's approach. I prefer to use only the graphics object provided by the Paint event (e.Graphics), and I avoid passing it to another sub except for something trivial like repeatedly drawing a filled circle.
edit: aargh! only just saw minitech's last post.
BB
1 Attachment(s)
Re: VS2010 - Out of memory exception while drawing
Quick sample has been uploaded as InspInterVS10.zip
I had to add back in the creation of a bmp since a Clear button is needed for the form in case the signature needs to be restarted. Also, the form will look a little weird as it is built to mimic being run using an iPad (now outlines, title bar, min button...).
@boops boops - sorry, I had targeted the wrong responder earlier. I've edited that post to now be correct but any help is very appreciated on this issue! This thing is ready for production but this little issue will bug me even though it may never even be found.
Re: VS2010 - Out of memory exception while drawing
I can't reproduce the exception after scribbling all around for 5 minutes :)
Re: VS2010 - Out of memory exception while drawing
Here's what I've boiled it down to:
Code:
Public Class TestSig
Dim MousePath As New Drawing2D.GraphicsPath()
Dim xStart, yStart As Integer
Dim CurrentPen As New Pen(Color.Black, 5.0!)
Private Sub PictureBox1_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
'The below IfThen statement allows for the signee to start a new line
If Math.Abs(xStart - e.X) < 30 AndAlso Math.Abs(yStart - e.Y) < 30 Then
Me.MousePath.AddLine(xStart, yStart, e.X, e.Y)
Else
Me.MousePath.StartFigure()
End If
Me.PictureBox1.Invalidate()
xStart = e.X
yStart = e.Y
End Sub
Private Sub PictureBox1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
e.Graphics.DrawPath(Me.CurrentPen, Me.MousePath)
End Sub
Private Sub btnClear_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnClear.Click
'Clears the signature box
Me.MousePath.Reset()
Me.PictureBox1.Invalidate()
End Sub
Private Sub btnClose_Click(sender As System.Object, e As System.EventArgs) Handles btnClose.Click
Me.Close()
End Sub
End Class
Re: VS2010 - Out of memory exception while drawing
How long do I have to go at it ?...im not getting any exceptions
Re: VS2010 - Out of memory exception while drawing
@llDayo
I tried your code. As it stands, it throws an OOM when I click Clear. The first thing I tried was to comment out your StartFigure statement, because it seems crazy to start a new figure every time you add a new pixel or two to the path. That cured the OOM, at least for now.
If you want to have separate figures, it would make sense to have one for each stroke. For example, if you enable drawing with the left mousebutton pressed, you could start a new figure in MouseDown and close it in MouseUp. If you are not using the mouse button for drawing, do it wherever you start and stop drawing a stroke, not in MouseMove.
I also tried commenting out PictureBox1.Image = bmp in the Paint event. The only effect was to stop clearing. So I moved that statement to the end of the ClearButton click sub, which looks to me to be a more logical place for it. That worked fine.
Finally, I commented out the Update statement. It won't make a big difference with a small picture box, but I find that drawing with the mouse is smoother when you use Invalidate alone. It did seem to me to make a slight improvement even here.
BB
Re: VS2010 - Out of memory exception while drawing
boops, I think minitech beat you to it again, lol!
I used minitech's code and it is running fine as well as MUCH more smoothly (I'm beginning to suspect, based on other posts, that my computer may have a small part in throwing the error). I'm going to begin adding this code to the rest of the form in my actual project and hopefully everything will be fine and dandy. I just need to save the image as a jpeg using the new code since this signature gets placed onto a Crystal Report. Thank you all for your help and have a great weekend!