Question Problem with saving my picturebox in my paint program

Superfluper

New member
Joined
Aug 2, 2014
Messages
1
Programming Experience
1-3
Hello people,

I need some help with my paint program, I want to save my edited picturebox into a jpeg file but when I try to do it I get an error.
I have read on another forum that i can't save my picturebox edited with brushes and that I need to make graphics instead but I don't know how to do it :s
Please help me out here ;)

Knipsel.PNG


This is my code:
Public Class frmPaint
    Dim down = False
    Dim mybrush = Brushes.Black
    Dim BrushSize As Decimal

    Private Sub picDrawing_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles picDrawing.MouseDown
        down = True
    End Sub

    Private Sub picDrawing_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles picDrawing.MouseMove
        If txtBrushSize.Text = "" Then
            txtBrushSize.Text = 0
        Else
            txtBrushSize.Text = txtBrushSize.Text
        End If

        If down = True Then
            picDrawing.CreateGraphics.FillEllipse(mybrush, e.X, e.Y, BrushSize, BrushSize)
        End If
    End Sub

    Private Sub picDrawing_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles picDrawing.MouseUp
        down = False
    End Sub

    Private Sub btnBlack_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnBlack.Click
        mybrush = Brushes.Black
    End Sub

    Private Sub btnGreen_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGreen.Click
        mybrush = Brushes.Green
    End Sub

    Private Sub btnBlue_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnBlue.Click
        mybrush = Brushes.Blue
    End Sub

    Private Sub btnRed_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRed.Click
        mybrush = Brushes.Red
    End Sub

    Private Sub btnYellow_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnYellow.Click
        mybrush = Brushes.Yellow
    End Sub

    Private Sub btnErase_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnErase.Click
        mybrush = Brushes.White
    End Sub

    Private Sub btnClose_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnClose.Click
        Me.Close()
    End Sub

    Private Sub txtBrushSize_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtBrushSize.TextChanged
        BrushSize = txtBrushSize.Text
    End Sub

    Private Sub btnSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSave.Click
        SaveFileDialog1.ShowDialog()
    End Sub

    Private Sub btnOpen_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOpen.Click
        OpenFileDialog1.ShowDialog()
    End Sub

    Private Sub OpenFileDialog1_FileOk(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles OpenFileDialog1.FileOk
        picDrawing.ImageLocation = OpenFileDialog1.FileName
    End Sub

    Private Sub SaveFileDialog1_FileOk(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles SaveFileDialog1.FileOk
        picDrawing.Image.Save(SaveFileDialog1.FileName + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg)
    End Sub

    Private Sub frmPaint_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        txtBrushSize.Text = 30
    End Sub
End Class
 
Last edited by a moderator:
Firstly, I have fixed the code formatting in your post. Please always use code formatting tags when posting code snippets. As you can see, it makes the the code far more readable, most notably by retaining indenting. I have also removed some irrelevant stuff, like loads of blank lines and an empty method. If you're going to include irrelevant code then you just make it harder for us to read and therefore less likely that you'll get the help you want. Only post code that is relevant to your issue.

There are a number of issues with your code. Firstly, the way you're drawing. Never, NEVER call CreateGraphics. Some examples on the web do so for simplicity but you should never do so in production code. Shame on the those who write those examples and don't mention that fact, but there you go. If you're going to draw on a control then ALWAYS do so on that control's Paint event, either in the OnPaint method of a custom control or in the Paint event handler of a control on your form. In your case, you have a PictureBox on your form so you would handle its Paint event and then use the provided Graphics object to do your drawing. The reason you do that is that a control gets repainted at various times so any drawing done previously will simply disappear unless you do it again. You need to draw every time the Paint event is raised or your drawing will disappear.

The second issue is that you are drawing on the PictureBox itself and then trying to save the Image the PictureBox contains. Nowhere do you actually draw on that Image so it will not have changed at all. If you want to save a changed Image then you actually have to draw on that Image, not on the PictureBox containing that Image. Think of it like a photo in a photo frame covered in glass. If you draw on the glass and then take out the photo, would you expect to see your drawing on that photo?

Finally, the way you're loading the Image means that you won't be able to save it. There are two main ways to load an image file into a PictureBox:

1. Call Image.FromFile and assign the result to the Image property of the PictureBox.
2. Assign the file path to the ImageLocation property or call the Load method of the PictureBox and pass the file path as an argument. There's a subtle difference between those two but they are basically the same.

Originally, the first way was the only way. The problem there was that Image.FromFile locks the file until the Image object is disposed. That means that the file cannot be moved or deleted while you're using the Image. For that reason, the Imagelocation property and Load method were added. They create an Image internally but don't lock the file.

The thing is, Image.FromFile locks the file for a reason. The file is locked because the Image object maintains an open Stream on the file so that it can continue to read data from it as needed. It's that open Stream that allows you to save the Image back to the file.

If you want to be able to save the Image again afterwards then you can set the ImageLocation or call Load. You have to set the Image property. If you don't want to lock the original file then you will have to create your own Image object. You can do that by using the Bitmap constructor that takes dimensions as arguments. You can use it blank or you can use GDI+ to draw an existing Image onto it, e.g. create a Bitmap, call Image.FromFile, draw the original Image onto the Bitmap and then Dispose the Image. You can then assign the Bitmap to the image property of the PictureBox and call its Save method later.

Check out this thread of mine, which demonstrates most of the principles mentioned above:

Very Simple Drawing Program
 
Back
Top