# Drawing on an Image with transparency? (to erase a section)

#### mickle026

##### Member
First of all I am just an amateur with no formal training, so please don't flame me for my errors - I am really trying to get this right.

I have 2 questions

1. How can I erase a circle in an image to make a transparent section
2. How can I reload the edited image to the picture box (so that it can be saved later)

I have a form where a user loads an image to create a connect 4 game board. I draw on it the circles to cut the holes in it, and want to then be able to save it as a game board. Saving it is not the problem. Drawing the image is not a problem. The part I need help with is reloading the drawing with the graphic edits and transparency.
I know I must be missing something really simple but its frustrating the heck out of me!

I am aware that some dim statements are not in the proper places ;-/

The form contains 3 controls - 2 buttons (Load and create) and a picture box. Here is my NOT working properly code.

VB.NET:
Imports System.Drawing.Drawing2D
Imports System.IO
Imports System.Drawing.Imaging

Public Class FrmCreateBoard

Private Sub FrmCreateBoard_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
PictureBox1.BackColor = Color.Transparent
PictureBox1.Size = New Size(794, 680)
End Sub

Private Sub butLoadImage_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles butLoadImage.Click
Me.OpenFileDialog1.Filter = "JPEG files (*.jpg)|*.jpg|GIF files (*.gif)|*.gif|All files (*.*)|*.*"
If OpenFileDialog1.ShowDialog() = DialogResult.OK Then
PictureBox1.Image = Image.FromFile(OpenFileDialog1.FileName)

Dim original As Image = PictureBox1.Image
Dim resized As Image = ResizeImage(original, New Size(1024, 768))
Dim memStream As MemoryStream = New MemoryStream()
'resized.Save(memStream, ImageFormat.Jpeg)
PictureBox1.Image = resized
End If
End Sub

Public Shared Function ResizeImage(ByVal image As Image, ByVal size As Size, Optional ByVal preserveAspectRatio As Boolean = True) As Image
Dim newWidth As Integer
Dim newHeight As Integer
If preserveAspectRatio Then
Dim originalWidth As Integer = image.Width
Dim originalHeight As Integer = image.Height
Dim percentWidth As Single = CSng(size.Width) / CSng(originalWidth)
Dim percentHeight As Single = CSng(size.Height) / CSng(originalHeight)
Dim percent As Single = If(percentHeight < percentWidth,
percentHeight, percentWidth)
newWidth = CInt(originalWidth * percent)
newHeight = CInt(originalHeight * percent)
Else
newWidth = size.Width
newHeight = size.Height
End If
Dim newImage As Image = New Bitmap(newWidth, newHeight)
Using graphicsHandle As Graphics = Graphics.FromImage(newImage)
graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic
graphicsHandle.DrawImage(image, 0, 0, newWidth, newHeight)
End Using
Return newImage
End Function

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

' draw circle with mock bevel by drawing transparent circle on a larger solid circle
Dim xpos As Integer = 60
Dim ypos As Integer = 60
For ydirection = 1 To 6
For xdirection = 1 To 7
DrawCircle(New Point(xpos, ypos), 44, Pens.RosyBrown, Brushes.RosyBrown)   '(X,Y,radius)
DrawCircle(New Point(xpos, ypos), 40, Pens.Transparent, Brushes.Transparent)   '(X,Y,radius)
xpos = xpos + 110
Next
xpos = 60 ' start again at start of line (picturebox)
ypos = ypos + 110
Next
End Sub

Private Sub DrawCircle(ByVal cp As Point, ByVal radius As Integer, ByVal p As Pen, ByVal b As Brush)
Dim Board As Image = PictureBox1.Image
'create bitmap
Dim NewImage As Bitmap
NewImage = New Bitmap(PictureBox1.Width, PictureBox1.Height)
'create graphics object from picture
Dim gr As Graphics = Graphics.FromImage(NewImage)
' draw the board backround (to draw on top of)
gr.DrawImage(Board, New Rectangle(0, 0, PictureBox1.Width, PictureBox1.Height))
' now draw the circles on the board
gr = PictureBox1.CreateGraphics
gr.DrawEllipse(p, rect) ' p = pen colour, rect = object to draw on
gr.FillEllipse(b, rect) ' b = brush colour, rect = object to draw on
' Now need to recreate the picture in the picturebox from the graphics component and reload it
PictureBox1.Image = NewImage
' cleanup
gr.Dispose()
End Sub

End Class

My first question

When I reload the image in the picture box with:

PictureBox1.Image = NewImage

I expected to see my new image with the drawing on it, but I get the original image with no drawing on it? This is where I have done something wrong. How do I fix this?

My second question.

My second circle doesn't erase anything, its just transparent. The intention is to cut a hole in the image so when its saved as a "*.png" it will be full of transparent areas.
Any ideas why its not doing what it wanted?

Help very much appreciated.

Last edited:

#### mickle026

##### Member
This always happens!

I eventually post after days of scratching my head then I figure some of it out. I have figured out the redrawing of the image, I was already doing this when I resized the image! - LOL. Now i need to know how to convert a circle in the image to make a hole - ie transparent section.

Here is the fixed code for redrawing the image. What i was not doing was using a "Using" section

VB.NET:
    Private Sub DrawCircle(ByVal cp As Point, ByVal radius As Integer, ByVal p As Pen, ByVal b As Brush)
Dim Board As Image = PictureBox1.Image
'create bitmap
'Dim NewImage As Bitmap
Dim NewImage As Image = New Bitmap(PictureBox1.Width, PictureBox1.Height)
'create graphics object from picture
Using gr As Graphics = Graphics.FromImage(NewImage)
gr.InterpolationMode = InterpolationMode.HighQualityBicubic
' draw the board backround (to draw on top of)
gr.DrawImage(Board, New Rectangle(0, 0, PictureBox1.Width, PictureBox1.Height))
' now draw the circles on the board
gr.DrawEllipse(p, rect) ' p = pen colour, rect = object to draw on
gr.FillEllipse(b, rect) ' b = brush colour, rect = object to draw on
' Now need to recreate the picture in the picturebox from the graphics component and reload it
End Using
PictureBox1.Image = NewImage

End Sub

Any help with making a circle transparent would be fantastic. (holes in image to save it as png)

Many thanks

Last edited:

#### mickle026

##### Member
Figured out a solution to the transparency, although I had to use a solid colour and convert it to transparent. Im not sure if this is ideal but it works for some images. What I don't want is for it to make any areas transparent that I have not drawn. IE if the user loads an image with the colour pen in it that I am making transparent, so there must be a better solution ????

First I set my inner circle to white as the color transparent didn't work as a color ???

VB.NET:
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

' draw circle with mock bevel by drawing transparent circle on a larger solid circle
Dim xpos As Integer = 60
Dim ypos As Integer = 60
For ydirection = 1 To 6
For xdirection = 1 To 7
DrawCircle(New Point(xpos, ypos), 44, Pens.RosyBrown, Brushes.RosyBrown)   '(X,Y,radius)
DrawCircle(New Point(xpos, ypos), 40, Pens.White, Brushes.White)   '(X,Y,radius)                    <------------------- set the brush to white
xpos = xpos + 110
Next
xpos = 60 ' start again at start of line (picturebox)
ypos = ypos + 110
Next
End Sub

Then in the drawing routine I converted all the white to transparent

VB.NET:
    Private Sub DrawCircle(ByVal cp As Point, ByVal radius As Integer, ByVal p As Pen, ByVal b As Brush)
Dim Board As Image = PictureBox1.Image
'create bitmap
'Dim NewImage As Bitmap
'NewImage = New Bitmap(PictureBox1.Width, PictureBox1.Height)
Dim NewImage As Image = New Bitmap(PictureBox1.Width, PictureBox1.Height)
'create graphics object from picture
'Dim gr As Graphics = Graphics.FromImage(NewImage)
Using gr As Graphics = Graphics.FromImage(NewImage)
gr.InterpolationMode = InterpolationMode.HighQualityBicubic
' draw the board backround (to draw on top of)
gr.DrawImage(Board, New Rectangle(0, 0, PictureBox1.Width, PictureBox1.Height))
' now draw the circles on the board
'gr = PictureBox1.CreateGraphics
gr.DrawEllipse(p, rect) ' p = pen colour, rect = object to draw on
gr.FillEllipse(b, rect) ' b = brush colour, rect = object to draw on
' Now need to recreate the picture in the picturebox from the graphics component and reload it
End Using
PictureBox1.Image = NewImage
' cleanup
Dim g As New System.Drawing.Bitmap(PictureBox1.Image)
g.MakeTransparent(System.Drawing.Color.White)
PictureBox1.Image = g
End Sub

This was the code I added:

VB.NET:
  Dim g As New System.Drawing.Bitmap(PictureBox1.Image)
g.MakeTransparent(System.Drawing.Color.White)
PictureBox1.Image = g

I could not use gr.MakeTransparent because transparency is not in the graphics object but is in the bitmap object.

#### JohnH

##### VB.NET Forum Moderator
Staff member
You can do this by using methods Graphics.SetClip with a GraphicsPath (.AddEllipse), then Graphics.Clear(Color.Transparent). Graphics.ResetClip afterwards.

It is not necessary to create a new image each time, you can use the PictureBox.Image directly, as long as the first loaded image supports transparency. You just need to call PictureBox.Refresh after modifying the image for the control to repaint it.

Also take care to dispose any graphics related object once you're done using it.

#### mickle026

##### Member

This is exactly what i am looking for. Maybe you can help a little further :shame: I have looked up a done as you suggested but it clips a rectangle, not an ellipse ??
I know I must be miss-understanding the Graphics path method.

Called by DrawCircle(New Point(xpos, ypos), 40, Pens.Transparent, Brushes.Transparent)
There are two methods in my code, one for solid circle and one for transparent.

VB.NET:
            Dim rect As Rectangle = New Rectangle(cp.X - radius, cp.Y - radius, 2 * radius, 2 * radius)
Dim myPath As New GraphicsPath
If p.Color = Color.Transparent Then
gr.SetClip(rect)
gr.DrawPath(Pens.Transparent, myPath)
gr.Clear(Color.Transparent)
gr.ResetClip()
Else
gr.DrawEllipse(p, rect) ' p = pen colour, rect = object to draw on
gr.FillEllipse(b, rect) ' b = brush colour, rect = object to draw on
End If
gr.Dispose()

or this - incorporating the combine mode gr.SetClip(rect, combineMode.Replace) MSDN says this works (http://msdn.microsoft.com/en-us/library/ms142117.aspx), but its not doing it on my machine :frustrated:
VB.NET:
 Dim rect As Rectangle = New Rectangle(cp.X - radius, cp.Y - radius, 2 * radius, 2 * radius)
Dim myPath As New GraphicsPath ' create a graphics path
If p.Color = Color.Transparent Then
gr.DrawPath(Pens.Transparent, myPath) ' draw the path to the image
gr.SetClip(rect, combineMode.Replace) ' set a clip region
gr.Clear(Color.Transparent) ' clear the clip region
gr.ResetClip() ' reset the clip so it can be re-used
Else
gr.DrawEllipse(p, rect) ' p = pen colour, rect = object to draw on
gr.FillEllipse(b, rect) ' b = brush colour, rect = object to draw on
End If

Here I set my rect (area) as a circle, but it clips a square (rectangle)

I have figured out by painting the clip region that the clip region is NOT an ellipse, it IS a rectangle

Last edited:

#### mickle026

##### Member
Figured the solution.

It was indeed the clip region, the FIX is to clip the region myPath

gr.SetClip(myPath, CombineMode.Replace) ' set a clip region to the ellipse

VB.NET:
Dim rect As Rectangle = New Rectangle(cp.X - radius, cp.Y - radius, 2 * radius, 2 * radius)
Dim myPath As New GraphicsPath ' create a graphics path
If p.Color = Color.Transparent Then
gr.DrawPath(Pens.Transparent, myPath) ' draw the path to the image
gr.SetClip(myPath, combineMode.Replace) ' set a clip region   <------------------------ Clip the path region (Not the rect) !!
gr.Clear(Color.Transparent) ' clear the clip region
gr.ResetClip() ' reset the clip so it can be re-used
Else
gr.DrawEllipse(p, rect) ' p = pen colour, rect = object to draw on
gr.FillEllipse(b, rect) ' b = brush colour, rect = object to draw on
End If

Thanks JohnH, you put me on the correct path. I have posted my solution for others to see because examples of this have been so hard to find.

Many thanks - I really do appreciate your help and i am going to enjoy the new toy you have shown me was there (GraphicsPath) ;-)

#### mickle026

##### Member
Here is the full code to the createboard form. Below if a view of the part made game.

Form consists of a picturebox and 3 buttons

VB.NET:
Imports System.Drawing.Drawing2D
Imports System.IO
Imports System.Drawing.Imaging

Public Class FrmCreateBoard

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

' draw circle with mock bevel by drawing transparent circle on a larger solid circle
Dim xpos As Integer = 60
Dim ypos As Integer = 60
For ydirection = 1 To 6
For xdirection = 1 To 7
DrawCircle(New Point(xpos, ypos), 44, Pens.RosyBrown, Brushes.RosyBrown)   '(X,Y,radius)
DrawCircle(New Point(xpos, ypos), 40, Pens.Transparent, Brushes.Transparent)   '(X,Y,radius)
xpos = xpos + 110
Next
xpos = 60 ' start again at start of line (picturebox)
ypos = ypos + 110
Next
End Sub

Private Sub DrawCircle(ByVal cp As Point, ByVal radius As Integer, ByVal p As Pen, ByVal b As Brush)
Dim Board As Image = PictureBox1.Image
'create bitmap
Dim NewImage As Image = New Bitmap(PictureBox1.Width, PictureBox1.Height)
'create graphics object from picture
Using gr As Graphics = Graphics.FromImage(NewImage)
gr.InterpolationMode = InterpolationMode.HighQualityBicubic
' draw the board backround (to draw on top of)
gr.DrawImage(Board, New Rectangle(0, 0, PictureBox1.Width, PictureBox1.Height))
' now draw the circles on the board
Dim myPath As New GraphicsPath ' create a graphics path
If p.Color = Color.Transparent Then
gr.DrawPath(Pens.Transparent, myPath) ' draw the path to the image
gr.SetClip(myPath, CombineMode.Replace) ' set a clip region to the ellipse
gr.Clear(Color.Transparent) ' clear the clip region
gr.ResetClip() ' reset the clip so it can be re-used
Else
gr.DrawEllipse(p, rect) ' p = pen colour, rect = object to draw on
gr.FillEllipse(b, rect) ' b = brush colour, rect = object to draw on
End If
' Now need to recreate the picture in the picturebox from the graphics component and reload it
gr.Dispose()
End Using
PictureBox1.Image = NewImage

End Sub

Public Shared Function ResizeImage(ByVal image As Image, ByVal size As Size, Optional ByVal preserveAspectRatio As Boolean = True) As Image
Dim newWidth As Integer
Dim newHeight As Integer
If preserveAspectRatio Then
Dim originalWidth As Integer = image.Width
Dim originalHeight As Integer = image.Height
Dim percentWidth As Single = CSng(size.Width) / CSng(originalWidth)
Dim percentHeight As Single = CSng(size.Height) / CSng(originalHeight)
Dim percent As Single = If(percentHeight < percentWidth,
percentHeight, percentWidth)
newWidth = CInt(originalWidth * percent)
newHeight = CInt(originalHeight * percent)
Else
newWidth = size.Width
newHeight = size.Height
End If
Dim newImage As Image = New Bitmap(newWidth, newHeight)
Using graphicsHandle As Graphics = Graphics.FromImage(newImage)
graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic
graphicsHandle.DrawImage(image, 0, 0, newWidth, newHeight)
End Using
Return newImage
End Function

Private Sub butLoadImage_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles butLoadImage.Click
Me.OpenFileDialog1.Filter = "JPEG files (*.jpg)|*.jpg|GIF files (*.gif)|*.gif|All files (*.*)|*.*"
If OpenFileDialog1.ShowDialog() = DialogResult.OK Then
PictureBox1.Image = Image.FromFile(OpenFileDialog1.FileName)

'Dim original As Image = Image.FromFile("C:\path\to\some.jpg")
Dim original As Image = PictureBox1.Image
Dim resized As Image = ResizeImage(original, New Size(1024, 768))
Dim memStream As MemoryStream = New MemoryStream()
'resized.Save(memStream, ImageFormat.Jpeg)
PictureBox1.Image = resized
End If
End Sub

Private Sub FrmCreateBoard_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
PictureBox1.BackColor = Color.Transparent
PictureBox1.Size = New Size(794, 680)
End Sub

Private Sub SaveBoard_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SaveBoard.Click
PictureBox1.Image.Save(Application.StartupPath + "\images\test.png", System.Drawing.Imaging.ImageFormat.Png)  <---- replace with your image path to save or a save dialog
End Sub
End Class

Last edited:

Replies
1
Views
2K
Replies
0
Views
2K
Replies
0
Views
1K
Replies
6
Views
4K
Replies
0
Views
1K