Android Question how to fill area in image

sz4t4n

Member
Licensed User
Longtime User
Hello,

i want to create simple "game" for my doughter becouse most of them in play store are full of ads (even if i pay). I just want to know if there is a simple way (maybe bitmapcreator) to fill area on image with one color (like "fill with color" in old windows paint).

upload_2019-11-18_16-22-7.png

to have this result:

upload_2019-11-18_16-21-34.png


My idea is to load simple image (black and white) and fill white area with selected color. Any advise?
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
LZOyID3fib.gif


B4J code:

B4X:
Sub Process_Globals
   Private MainForm As Form
   Private ImageView1 As B4XView
   Private bc As BitmapCreator
   Private xui As XUI
   Private Pane1 As B4XView
End Sub

Sub AppStart (Form1 As Form, Args() As String)
   MainForm = Form1
   MainForm.RootPane.LoadLayout("1") 'Load the layout file.
   MainForm.Show
   Dim bmp As B4XBitmap = xui.LoadBitmapResize(File.DirAssets, "1.png", ImageView1.Width / xui.Scale, ImageView1.Height / xui.Scale, False)
   bc.Initialize(bmp.Width, bmp.Height)
   bc.CopyPixelsFromBitmap(bmp)
   bc.SetBitmapToImageView(bc.Bitmap, ImageView1)
End Sub


Sub Pane1_Touch (Action As Int, X As Float, Y As Float)
   If Action = Pane1.TOUCH_ACTION_UP Then
       FloodFill(x / xui.Scale, y / xui.Scale, Rnd(0xff000000, 0xffffffff))
       bc.SetBitmapToImageView(bc.Bitmap, ImageView1)
   End If
End Sub

Private Sub FloodFill (X As Int, Y As Int, ReplacementColor As Int)
   Dim xx As List
   xx.Initialize
   Dim yy As List
   yy.Initialize
   Dim tpm, rpm As PremultipliedColor
   Dim argb As ARGBColor
   bc.GetPremultipliedColor(X, Y, tpm)
   bc.ARGBToPremultipliedColor(bc.ColorToARGB(ReplacementColor, argb), rpm)
   If ColorsEqual(rpm, tpm) Then Return
   SetAndAddToQueue(X, Y, xx, yy, tpm, rpm)
   Do While xx.Size > 0
       Dim nx As Int = xx.Get(0)
       Dim ny As Int = yy.Get(0)
       xx.RemoveAt(0)
       yy.RemoveAt(0)
       SetAndAddToQueue(nx, ny + 1, xx, yy, tpm, rpm)
       SetAndAddToQueue(nx, ny - 1, xx, yy, tpm, rpm)
       SetAndAddToQueue(nx + 1, ny, xx, yy, tpm, rpm)
       SetAndAddToQueue(nx - 1, ny, xx, yy, tpm, rpm)
   Loop
   
End Sub

Private Sub SetAndAddToQueue (x As Int, y As Int, xx As List, yy As List, tpm As PremultipliedColor, rpm As PremultipliedColor)
   If x < 0 Or x >= bc.mWidth Or y < 0 Or y >= bc.mHeight Then Return
   Dim temp As PremultipliedColor
   If ColorsEqual(bc.GetPremultipliedColor(x, y, temp), tpm) Then
       bc.SetPremultipliedColor(x, y, rpm)
       xx.Add(x)
       yy.Add(y)
   End If
End Sub

Private Sub ColorsEqual(pm1 As PremultipliedColor, pm2 As PremultipliedColor) As Boolean
   Return pm1.r = pm2.r And pm1.g = pm2.g And pm1.b = pm2.b
End Sub

Based on the "queue based implementation": https://en.wikipedia.org/wiki/Flood_fill
 
Upvote 0

AnandGupta

Expert
Licensed User
Longtime User
Upvote 0

sz4t4n

Member
Licensed User
Longtime User
Upvote 0

sz4t4n

Member
Licensed User
Longtime User
Upvote 0

klaus

Expert
Licensed User
Longtime User
Hi Erel.
Is there an advantage to use the "queue based implementation" algorithm instead of the stack-based recursive method like this:
B4X:
'fills all pixels with the OldColor with the new color
Private Sub FloodFill(x As Int, y As Int, OldColor As Int, NewColor As Int)
    If bc.GetColor(x, y) = OldColor Then
        bc.SetColor(x, y, NewColor)
        If x < bc.Bitmap.Width - 1 Then
            FloodFill(x + 1, y, OldColor, NewColor)           
        End If
        If x > 0 Then
            FloodFill(x - 1, y, OldColor, NewColor)           
        End If
        If y < bmcIcon.Bitmap.Height - 1 Then
            FloodFill(x, y + 1, OldColor, NewColor)           
        End If
        If y > 0 Then
            FloodFill(x, y - 1, OldColor, NewColor)           
        End If
    Else
        Return
    End If
End Sub
 
Upvote 0

sz4t4n

Member
Licensed User
Longtime User
hello again. I transfered code to b4a and i have some small issue (probably with scalling) with accurcy of touching. Color is changed in different location than touch is. Can someone give me some advice?
 

Attachments

  • draw-b4a.zip
    511.2 KB · Views: 307
Upvote 0

inakigarm

Well-Known Member
Licensed User
Longtime User
hello again. I transfered code to b4a and i have some small issue (probably with scalling) with accurcy of touching. Color is changed in different location than touch is. Can someone give me some advice?
[SOLVED] Offset on Imgvw/Pane I've not tested your B4a code but it happens also on B4J (attached B4J program)


floodfill test.gif
 

Attachments

  • test_floodfill.zip
    48.6 KB · Views: 284
Last edited:
Upvote 0

thetahsk

Active Member
Licensed User
Longtime User
Check your layout in the visual designer. The top/left coordinates of pane1 and imageview1 differs. So you have always a FloodFill offset in the Pane1_Touch event.
You can also remove the Pane1_Touch event and use the ImageView1_MouseClicked event.

B4X:
Sub ImageView1_MouseClicked (EventData As MouseEvent)
    'Disable the Pane1_Touch event when you are using this event
    FloodFill(EventData.X / xui.Scale, EventData.Y / xui.Scale, Rnd(0xff000000, 0xffffffff))
    bc.SetBitmapToImageView(bc.Bitmap, ImageView1)
End Sub
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Is there an advantage to use the "queue based implementation" algorithm instead of the stack-based recursive method like this:
The stack can become very deep. It can impact performance and might trigger a stack overflow. The queue based solution is safer.

hello again. I transfered code to b4a and i have some small issue (probably with scalling) with accurcy of touching. Color is changed in different location than touch is. Can someone give me some advice?
There is an assumption in the code that the bitmap size is exactly the same as the ImageView and Panel sizes.
For this to be correct you need to set KeepAspectRatio to False:
B4X:
Dim bmp As B4XBitmap = xui.LoadBitmapResize(File.DirAssets, "11.png", bigImg.Width / xui.Scale, bigImg.Height / xui.Scale, False)
 
Upvote 0
Top