[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

microsoft.public.dotnet.framework.drawing

FloodFll FillPixel - Bob Powell

JZ

10/18/2004 2:19:00 PM

Hi,

I was recently given some code on this newsgroup by Bob Powell to enable me
to floofill, which I converted into VB.Net.

http://groups.google.com/groups?hl=en&lr=&c2coff=1&safe=off&threadm=416fecd4%240%2422880%24cc9e4d1f%40news-text.dial.pipex.com&rnum=1&prev=/groups%3Fq%3Dscribble%2Bdotnet%26hl%3Den%26lr%3D%26c2coff%3D1%26safe%3Doff%26scoring%3Dd%26selm%3D416fecd4%25240%252422880%2524cc9e4d1f%2540news-text.dial.pipex.com%...

I think the FillPixel function is recursive.

Most of the time the code works fine.

Except sometimes the code never ends...
I'm not quite sure why this happens..

Heres the function.

'/ <summary>
'/ Fills a pixel and its un-filled neigbors with a specified color
'/ </summary>
'/ <param name="pos">The position at which to begin</param>
'/ <param name="bmd">The locked bitmap data</param>
'/ <param name="c">The color with which to fill the area</param>
'/ <param name="org">The original colour of the point. Filling stops when
all connected pixels of this color are exhausted</param>
Private Shared Sub FillPixel(ByVal pos As Point, ByVal bmd As BitmapData,
ByVal c As Color, ByVal org As Color)
Dim currpos As New Point(0, 0)
stack.Push(pos)

Do
currpos = CType(stack.Pop(), Point)
SetPixel(currpos, bmd, c)

If Color.op_Equality(GetPixel(New Point(currpos.X + 1, currpos.Y), bmd),
org) = True Then
stack.Push(New Point(currpos.X + 1, currpos.Y))
End If

If Color.op_Equality(GetPixel(New Point(currpos.X, currpos.Y - 1), bmd),
org) = True Then
stack.Push(New Point(currpos.X, currpos.Y - 1))
End If

If Color.op_Equality(GetPixel(New Point(currpos.X - 1, currpos.Y), bmd),
org) = True Then
stack.Push(New Point(currpos.X - 1, currpos.Y))
End If

If Color.op_Equality(GetPixel(New Point(currpos.X, currpos.Y + 1), bmd),
org) = True Then
stack.Push(New Point(currpos.X, currpos.Y + 1))
End If

Loop While stack.Count > 0

End Sub 'FillPixel

Any help would be greatly appreciated!

--
JZ


4 Answers

Bob Powell

10/18/2004 2:58:00 PM

0

The fill pixel routine isn't recursive but it's possible that the VB version
may have a bugette in it.

Let me look at it for a while.

--
Bob Powell [MVP]
Visual C#, System.Drawing

Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/gdipl...

The GDI+ FAQ RSS feed: http://www.bobpowell.net/f...
Windows Forms Tips and Tricks RSS: http://www.bobpowell.net/tips...
Bob's Blog: http://bobpowelldotnet.blogspot.co...






"JZ" <jj@anon.anon.com> wrote in message
news:4173d0df$0$20212$cc9e4d1f@news-text.dial.pipex.com...
> Hi,
>
> I was recently given some code on this newsgroup by Bob Powell to enable
me
> to floofill, which I converted into VB.Net.
>
>
http://groups.google.com/groups?hl=en&lr=&c2coff=1&safe=off&threadm=416fecd4%240%2422880%24cc9e4d1f%40news-text.dial.pipex.com&rnum=1&prev=/groups%3Fq%3Dscribble%2Bdotnet%26hl%3Den%26lr%3D%26c2coff%3D1%26safe%3Doff%26scoring%3Dd%26selm%3D416fecd4%25240%252422880%2524cc9e4d1f%2540news-text.dial.pipex.com%...
>
> I think the FillPixel function is recursive.
>
> Most of the time the code works fine.
>
> Except sometimes the code never ends...
> I'm not quite sure why this happens..
>
> Heres the function.
>
> '/ <summary>
> '/ Fills a pixel and its un-filled neigbors with a specified color
> '/ </summary>
> '/ <param name="pos">The position at which to begin</param>
> '/ <param name="bmd">The locked bitmap data</param>
> '/ <param name="c">The color with which to fill the area</param>
> '/ <param name="org">The original colour of the point. Filling stops when
> all connected pixels of this color are exhausted</param>
> Private Shared Sub FillPixel(ByVal pos As Point, ByVal bmd As BitmapData,
> ByVal c As Color, ByVal org As Color)
> Dim currpos As New Point(0, 0)
> stack.Push(pos)
>
> Do
> currpos = CType(stack.Pop(), Point)
> SetPixel(currpos, bmd, c)
>
> If Color.op_Equality(GetPixel(New Point(currpos.X + 1, currpos.Y),
bmd),
> org) = True Then
> stack.Push(New Point(currpos.X + 1, currpos.Y))
> End If
>
> If Color.op_Equality(GetPixel(New Point(currpos.X, currpos.Y - 1),
bmd),
> org) = True Then
> stack.Push(New Point(currpos.X, currpos.Y - 1))
> End If
>
> If Color.op_Equality(GetPixel(New Point(currpos.X - 1, currpos.Y),
bmd),
> org) = True Then
> stack.Push(New Point(currpos.X - 1, currpos.Y))
> End If
>
> If Color.op_Equality(GetPixel(New Point(currpos.X, currpos.Y + 1),
bmd),
> org) = True Then
> stack.Push(New Point(currpos.X, currpos.Y + 1))
> End If
>
> Loop While stack.Count > 0
>
> End Sub 'FillPixel
>
> Any help would be greatly appreciated!
>
> --
> JZ
>
>


Bob Powell

10/18/2004 2:59:00 PM

0

Can you tell me in what circumstances the loop never finishes?

--
Bob Powell [MVP]
Visual C#, System.Drawing

Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/gdipl...

The GDI+ FAQ RSS feed: http://www.bobpowell.net/f...
Windows Forms Tips and Tricks RSS: http://www.bobpowell.net/tips...
Bob's Blog: http://bobpowelldotnet.blogspot.co...






"JZ" <jj@anon.anon.com> wrote in message
news:4173d0df$0$20212$cc9e4d1f@news-text.dial.pipex.com...
> Hi,
>
> I was recently given some code on this newsgroup by Bob Powell to enable
me
> to floofill, which I converted into VB.Net.
>
>
http://groups.google.com/groups?hl=en&lr=&c2coff=1&safe=off&threadm=416fecd4%240%2422880%24cc9e4d1f%40news-text.dial.pipex.com&rnum=1&prev=/groups%3Fq%3Dscribble%2Bdotnet%26hl%3Den%26lr%3D%26c2coff%3D1%26safe%3Doff%26scoring%3Dd%26selm%3D416fecd4%25240%252422880%2524cc9e4d1f%2540news-text.dial.pipex.com%...
>
> I think the FillPixel function is recursive.
>
> Most of the time the code works fine.
>
> Except sometimes the code never ends...
> I'm not quite sure why this happens..
>
> Heres the function.
>
> '/ <summary>
> '/ Fills a pixel and its un-filled neigbors with a specified color
> '/ </summary>
> '/ <param name="pos">The position at which to begin</param>
> '/ <param name="bmd">The locked bitmap data</param>
> '/ <param name="c">The color with which to fill the area</param>
> '/ <param name="org">The original colour of the point. Filling stops when
> all connected pixels of this color are exhausted</param>
> Private Shared Sub FillPixel(ByVal pos As Point, ByVal bmd As BitmapData,
> ByVal c As Color, ByVal org As Color)
> Dim currpos As New Point(0, 0)
> stack.Push(pos)
>
> Do
> currpos = CType(stack.Pop(), Point)
> SetPixel(currpos, bmd, c)
>
> If Color.op_Equality(GetPixel(New Point(currpos.X + 1, currpos.Y),
bmd),
> org) = True Then
> stack.Push(New Point(currpos.X + 1, currpos.Y))
> End If
>
> If Color.op_Equality(GetPixel(New Point(currpos.X, currpos.Y - 1),
bmd),
> org) = True Then
> stack.Push(New Point(currpos.X, currpos.Y - 1))
> End If
>
> If Color.op_Equality(GetPixel(New Point(currpos.X - 1, currpos.Y),
bmd),
> org) = True Then
> stack.Push(New Point(currpos.X - 1, currpos.Y))
> End If
>
> If Color.op_Equality(GetPixel(New Point(currpos.X, currpos.Y + 1),
bmd),
> org) = True Then
> stack.Push(New Point(currpos.X, currpos.Y + 1))
> End If
>
> Loop While stack.Count > 0
>
> End Sub 'FillPixel
>
> Any help would be greatly appreciated!
>
> --
> JZ
>
>


Bob Powell

10/18/2004 3:07:00 PM

0

I just noticed in the original post that I gave you the C# version twice and
not my VB version.
Sorry about that. Brainfade on my part.

NOTE that this code only copes with 32 bit-per-pixel images. All others WILL
FAIL!

Try this.... (after my sig)

--
Bob Powell [MVP]
Visual C#, System.Drawing

Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/gdipl...

The GDI+ FAQ RSS feed: http://www.bobpowell.net/f...
Windows Forms Tips and Tricks RSS: http://www.bobpowell.net/tips...
Bob's Blog: http://bobpowelldotnet.blogspot.co...

-------------------------------------------------------------------

Public Class MapFill


Public Sub New()

End Sub 'New


Private Shared stack As New Stack()



'/ <summary>

'/ Checks to make sure a pixel is in an image.

'/ </summary>

'/ <param name="pos">The position to check</param>

'/ <param name="bmd">The BitmapData from which the bounds are
determined</param>

'/ <returns>True if the point is in the image</returns>

Private Shared Function CheckPixel(pos As Point, bmd As BitmapData) As
Boolean

Return pos.X > - 1 AndAlso pos.Y > - 1 AndAlso pos.X < bmd.Width AndAlso
pos.Y < bmd.Height

End Function 'CheckPixel



'/ <summary>

'/ Returns the color at a specific pixel

'/ </summary>

'/ <param name="pos">The position of the pixel</param>

'/ <param name="bmd">The locked bitmap data</param>

'/ <returns>The color of the pixel under the nominated point</returns>

Private Shared Function GetPixel(pos As Point, bmd As BitmapData) As Color

If CheckPixel(pos, bmd) Then

'always assumes 32 bit per pixels

Dim offset As Integer = pos.Y * bmd.Stride + 4 * pos.X

Return Color.FromArgb(Marshal.ReadByte(bmd.Scan0, offset + 2),
Marshal.ReadByte(bmd.Scan0, offset + 1), Marshal.ReadByte(bmd.Scan0,
offset))

Else

Return Color.FromArgb(0, 0, 0, 0)

End If

End Function 'GetPixel


'/ <summary>

'/ Sets a pixel at a nominated point to a specified color

'/ </summary>

'/ <param name="pos">The coordinate of the pixel to set</param>

'/ <param name="bmd">The locked bitmap data</param>

'/ <param name="c">The color to set</param>

Private Shared Sub SetPixel(pos As Point, bmd As BitmapData, c As Color)

If CheckPixel(pos, bmd) Then

'always assumes 32 bit per pixels

Dim offset As Integer = pos.Y * bmd.Stride + 4 * pos.X

Marshal.WriteByte(bmd.Scan0, offset + 2, c.R)

Marshal.WriteByte(bmd.Scan0, offset + 1, c.G)

Marshal.WriteByte(bmd.Scan0, offset, c.B)

Marshal.WriteByte(bmd.Scan0, offset + 3, CByte(255))

End If

End Sub 'SetPixel



'/ <summary>

'/ Fills a pixel and its un-filled neigbors with a specified color

'/ </summary>

'/ <param name="pos">The position at which to begin</param>

'/ <param name="bmd">The locked bitmap data</param>

'/ <param name="c">The color with which to fill the area</param>

'/ <param name="org">The original colour of the point. Filling stops when
all connected pixels of this color are exhausted</param>

Private Shared Sub FillPixel(pos As Point, bmd As BitmapData, c As Color,
org As Color)

Dim currpos As New Point(0, 0)

stack.Push(pos)

Do

currpos = CType(stack.Pop(), Point)

SetPixel(currpos, bmd, c)

If GetPixel(New Point(currpos.X + 1, currpos.Y), bmd).Equals(org) Then

stack.Push(New Point(currpos.X + 1, currpos.Y))

End If

If GetPixel(New Point(currpos.X, currpos.Y - 1), bmd).Equals(org) Then

stack.Push(New Point(currpos.X, currpos.Y - 1))

End If

If GetPixel(New Point(currpos.X - 1, currpos.Y), bmd).Equals(org) Then

stack.Push(New Point(currpos.X - 1, currpos.Y))

End If

If GetPixel(New Point(currpos.X, currpos.Y + 1), bmd).Equals(org) Then

stack.Push(New Point(currpos.X, currpos.Y + 1))

End If

Loop While stack.Count > 0

End Sub 'FillPixel


'/ <summary>

'/ Fills a bitmap with color.

'/ </summary>

'/ <remarks>If a non 32-bit image is passed to this routine and only 32 bit
image will be created, the original image will be copied to the new image
and filling will take place on the new image which will be handed back when
complete. </remarks>

'/ <param name="img">The image to fill</param>

'/ <param name="pos">The position to begin filling at</param>

'/ <param name="color">The color to fill</param>

'/ <returns>A Bitmap object with the filled area.</returns>

Public Shared Function Fill(img As Image, pos As Point, color As Color) As
Bitmap

'Ensure the bitmap is in the right format

Dim bm As Bitmap = CType(img, Bitmap)

If img.PixelFormat <> PixelFormat.Format32bppArgb Then

'if it isn't, convert it.

bm = New Bitmap(img.Width, img.Height, PixelFormat.Format32bppArgb)

Dim g As Graphics = Graphics.FromImage(bm)

g.InterpolationMode = InterpolationMode.NearestNeighbor

g.DrawImage(img, New Rectangle(0, 0, bm.Width, bm.Height), 0, 0, img.Width,
img.Height, GraphicsUnit.Pixel)

g.Dispose()

End If


'Lock the bitmap data

Dim bmd As BitmapData = bm.LockBits(New Rectangle(0, 0, bm.Width,
bm.Height), ImageLockMode.ReadWrite, bm.PixelFormat)


'get the color under the point. This is the original.

Dim org As Color = GetPixel(pos, bmd)


'Fill the first pixel and recursively fill all it's neighbors

FillPixel(pos, bmd, color, org)


'unlock the bitmap

bm.UnlockBits(bmd)


Return bm

End Function 'Fill

End Class 'MapFill


-------------------------------------------------------------------




"JZ" <jj@anon.anon.com> wrote in message
news:4173d0df$0$20212$cc9e4d1f@news-text.dial.pipex.com...
> Hi,
>
> I was recently given some code on this newsgroup by Bob Powell to enable
me
> to floofill, which I converted into VB.Net.
>
>
http://groups.google.com/groups?hl=en&lr=&c2coff=1&safe=off&threadm=416fecd4%240%2422880%24cc9e4d1f%40news-text.dial.pipex.com&rnum=1&prev=/groups%3Fq%3Dscribble%2Bdotnet%26hl%3Den%26lr%3D%26c2coff%3D1%26safe%3Doff%26scoring%3Dd%26selm%3D416fecd4%25240%252422880%2524cc9e4d1f%2540news-text.dial.pipex.com%...
>
> I think the FillPixel function is recursive.
>
> Most of the time the code works fine.
>
> Except sometimes the code never ends...
> I'm not quite sure why this happens..
>
> Heres the function.
>
> '/ <summary>
> '/ Fills a pixel and its un-filled neigbors with a specified color
> '/ </summary>
> '/ <param name="pos">The position at which to begin</param>
> '/ <param name="bmd">The locked bitmap data</param>
> '/ <param name="c">The color with which to fill the area</param>
> '/ <param name="org">The original colour of the point. Filling stops when
> all connected pixels of this color are exhausted</param>
> Private Shared Sub FillPixel(ByVal pos As Point, ByVal bmd As BitmapData,
> ByVal c As Color, ByVal org As Color)
> Dim currpos As New Point(0, 0)
> stack.Push(pos)
>
> Do
> currpos = CType(stack.Pop(), Point)
> SetPixel(currpos, bmd, c)
>
> If Color.op_Equality(GetPixel(New Point(currpos.X + 1, currpos.Y),
bmd),
> org) = True Then
> stack.Push(New Point(currpos.X + 1, currpos.Y))
> End If
>
> If Color.op_Equality(GetPixel(New Point(currpos.X, currpos.Y - 1),
bmd),
> org) = True Then
> stack.Push(New Point(currpos.X, currpos.Y - 1))
> End If
>
> If Color.op_Equality(GetPixel(New Point(currpos.X - 1, currpos.Y),
bmd),
> org) = True Then
> stack.Push(New Point(currpos.X - 1, currpos.Y))
> End If
>
> If Color.op_Equality(GetPixel(New Point(currpos.X, currpos.Y + 1),
bmd),
> org) = True Then
> stack.Push(New Point(currpos.X, currpos.Y + 1))
> End If
>
> Loop While stack.Count > 0
>
> End Sub 'FillPixel
>
> Any help would be greatly appreciated!
>
> --
> JZ
>
>


JZ

10/18/2004 5:15:00 PM

0

Hi,

Thanks for your reply.
I thought I'd made a mistake in my vb translation, looking at your code, in
the FillPixel function.
But the problem still occurs.

I've absolutely no idea why the problem occurs.
Very odd.

But it seems to happen if the same area is filled twice.

This code works around the problem. I THINK, SO FAR.

Dim test As New Bitmap(FullImage)
Dim TempPixelColour As Color = test.GetPixel(CurXPos, CurYPos)

If TempPixelColour.R = m_CurrentColour.R And TempPixelColour.G =
m_CurrentColour.G And TempPixelColour.B = m_CurrentColour.B Then
Exit Sub
End If

--
JZ