OK, I found a C example and recoded it in B4A, to produce the following, which works well enough for my requirements.
My input ImageView object 'imgFill' was loaded with a bitmap produced in Photoshop, using a Black line drawing with Transparent areas
The
Fill_IMG_at procedure maintains its own 'stack' array of fill points it needs to go back to. I ran this on a variety of shapes of sizes upto
around 100x100 pixels and my stack never went over 10 items, so the arbitrary size of the array at 1000 should be plenty for similar areas.
If you try to fill an unbounded area you may well get an array overflow error though, so ensure your areas are closed.
The Test code below fills one selected area:
Sub TestFill
Dim intXfill, intYfill,intFillColour, intOldColour As Int
intFillColour = Colors.RGB(255,0,0) 'Red
intOldColour =0 '*.PNG Transparent colour
intXfill = 100 ' a seed point in my image to start the fill at
intYfill = 50
Fill_IMG_at(imgFill,intXfill,intYfill,intFillColour,intOldColour)
End Sub
'Pass in:
' - reference to an existing imageView object, ie "imgFill"
' - an x,y seed point to start filling at
' - a colour to fill with, and the oldColour to replace
Sub Fill_IMG_at(imgPassed As ImageView, floatX As Float, floatY As Float, intNewColour As Int, intOldColour As Int)
'the following code inspired by
http://lodev.org/cgtutor/floodfill.html
'using the "floodFillScanlineStack" procedure, by Lode Vandevenne
Dim canvasFill As Canvas
canvasFill.Initialize(imgPassed) 'attach Canvas to image
'Code modelled on floodFillScanlineStack
Dim x1 As Int
Dim spanAbove As Boolean
Dim spanBelow As Boolean
Dim intW As Int = imgPassed.Width
Dim intH As Int = imgPassed.Height
Dim intStackMax As Int = 1000 'arbitrary stack size = 1000 points
Dim arrStack(intStackMax,2) As Float 'subscript 0 = X, subscript 1 = Y
Dim intStackPointer As Int = -1 '-1 = empty stack
'push the first coordinate onto our stack
intStackPointer = intStackPointer + 1
arrStack(intStackPointer,0) = floatX
arrStack(intStackPointer,1) = floatY
'loop as long as stack isnt empty
Do While intStackPointer > -1
'pop a coord off our stack
floatX= arrStack(intStackPointer,0)
floatY= arrStack(intStackPointer,1)
intStackPointer=intStackPointer-1
x1 = floatX
Do While x1 >= 0 And canvasFill.Bitmap.GetPixel(x1,floatY) = intOldColour
x1=x1-1
Loop
x1=x1+1
spanAbove = False '0
spanBelow = False '0
Do While x1 < intW And canvasFill.Bitmap.GetPixel(x1,floatY) = intOldColour
canvasFill.DrawPoint(x1,floatY,intNewColour)
If spanAbove=False And floatY > 0 And canvasFill.Bitmap.GetPixel(x1,floatY-1) = intOldColour Then
'push the coordinate onto our stack
intStackPointer = intStackPointer + 1
arrStack(intStackPointer,0) = x1
arrStack(intStackPointer,1) = floatY-1
spanAbove = True '1
Else if spanAbove=True And floatY > 0 And canvasFill.Bitmap.GetPixel(x1,floatY-1) <> intOldColour Then
spanAbove = False '0
Else
End If
If spanBelow=False And floatY < intH - 1 And canvasFill.Bitmap.GetPixel(x1,floatY+1) = intOldColour Then
'push the coordinate onto our stack
intStackPointer = intStackPointer + 1
arrStack(intStackPointer,0) = x1
arrStack(intStackPointer,1) = floatY+1
spanBelow = True '1
Else If spanBelow = True And floatY < intH -1 And canvasFill.Bitmap.GetPixel(x1,floatY+1) <> intOldColour Then
spanBelow = False '0
Else
End If
x1 = x1 + 1
Loop
Loop
imgPassed.Invalidate 'force redraw of passed image from our attached canvas
End Sub