B4J Question FloodFill for Canvas Drawing...

Magma

Expert
Licensed User
Longtime User
Well i decided to create a small drawing app...

I ve not decided if will be vector drawing (like corel)
or like Paint (windows paint) - more simple..

But i am in good way - when i will be ready - i ll posted here...

I want to create a FloodFill Tool (heh...) and i was wondering if there is any code ready or someone help...

Found a b4a (from delphi) code...
Found getpixels (erel's post)...

but can't understand the code... at all :-(

FloodFill b4a...
B4X:
Sub FloodFill (x As Int, y As Int)

    Dim BorderColor As Int
    Dim PBB (Canvas1.Width,Canvas1.Height) As Byte
    Dim dir,b As Byte
    Dim x1,y1 As Int
    Dim xRange, yRange As Int
    Dim ExitNow, NextPixel, PreviousPixel As Boolean
 
    xRange = Canvas1.Width-1
    yRange = Canvas1.Height-1

    ' Set the border colour to black - as used in the sample rectangle bitmap.
    BorderColor = fx.Colors.Black

    ' Load the bitmap info into the array.
 
    For y1 = 0 To yRange
        For x1 = 0 To xRange
            If Canvas1.Bitmap.GetPixel(x1,y1) = BorderColor Then
                PBB(x1,y1) = 64
            Else
                PBB(x1,y1) = 0
            End If
        Next
    Next
 
    ' Fill the edges with the defined border value.
    y1 = 0
    For x1 = 0 To xRange
        PBB(x1,y1) = 64
    Next
    y1 = yRange
    For x1 = 0 To xRange
        PBB(x1,y1) = 64
    Next
    x1 = 0
    For y1 = 0 To yRange
        PBB(x1,y1) = 64
    Next
    x1 = xRange
    For y1 = 0 To yRange
        PBB(x1,y1) = 64
    Next

    ' Set initial states, staring point, and direction.
    ExitNow = False
    NextPixel = True
    PreviousPixel = False
    PBB(x,y) = 136
    dir = 0
 
    ' Do the calcs. Use a loop as the algorith was written using Goto statements which B4A doesn't support.
 
    Do Until ExitNow
 
        ' Next Pixel
        If NextPixel Then
            Select dir
                Case 0 : x=x+1
                Case 1 : x=x-1
                Case 2 : y=y-1
                Case 3 : y=y+1
            End Select
         
            If Bit.And (PBB(x,y), 192) <> 0 Then
                PreviousPixel = True
                NextPixel = False
            Else
                PBB(x,y) = Bit.Or (128, dir)  ' record fill + entry-direction
                If dir <> 1 Then dir = 0      ' compute Exit direction
                NextPixel = True
                PreviousPixel = False
            End If
        End If
     
        ' Previous Pixel
        If PreviousPixel Then
            Select dir
                Case 0 : x=x-1
                Case 1 : x=x+1
                Case 2 : y=y+1
                Case 3 : y=y-1
            End Select
         
            b = PBB(x,y)
            dir=dir+1
         
            If Bit.And (b,15) = Bit.Xor (dir,1) Then dir=dir+1 ' skip entry directory.
         
            If dir > 3 Then
                dir = Bit.And (b, 15)
                If dir >= 8 Then
                    ExitNow = True
                    Exit
                Else
                    PreviousPixel = True
                    NextPixel= False
                End If
            Else
                PreviousPixel = False
                NextPixel= True
            End If
         
        End If ' PreviousPixel
     
    Loop
 
    ' Update the mutable bitmap with the result from the array.
    For y1 = 0 To yRange
        For x1 = 0 To xRange
            If Bit.And (PBB(x1,y1), 128) <> 0 Then
                Canvas1.DrawPoint(x1, y1, ccolor) 'drawpoint there is no at b4j can be drawline(x1,y1,x1,y1...)
            End If
        Next
    Next

End Sub

getpixels of erel's
B4X:
Sub GetPixels (img As Image) As Byte()
    Dim jo As JavaObject = img
    Dim reader As JavaObject = jo.RunMethod("getPixelReader", Null)
    Dim buffer(img.Width * img.Height * 4) As Byte
    Dim PixelFormat As JavaObject
    PixelFormat.InitializeStatic("javafx.scene.image.PixelFormat")
    Dim width = img.Width, height = img.Height As Int
    reader.RunMethod("getPixels", Array(0, 0, width, height, PixelFormat.RunMethod("getByteBgraInstance", Null), _
       buffer, 0, width * 4))
    Return buffer
End Sub

All good - but i can't find a way - or can't think how will be the routine i need :-(

By the way... QuickBasic and GWBASIC had a Paint !!! (was FloodFill) great times !!!

For VB6 had this API...
B4X:
The API call used to perform the fill operation is ExtFloodFill, with a VB6 declaration and parameters like so:


Private Declare Function ExtFloodFill Lib "GDI32" (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long, ByVal crColor As Long, ByVal wFillType As Long) As Long
 
Last edited:

Magma

Expert
Licensed User
Longtime User
Did you have a look at this 'how to fill area in image' thread using BitmapCreator?

Okay ... well i didn;t search that way but now i know :)

so your answer give me more questions... :)

1) why can't use snapshot of canvas like bc.CopyPixelsFromBitmap(Canvas1.Snapshot) 'bc is bitmapcreator...
2) which is best, bitmapcreator or canvas ?
3) and what is for using xui.scale here... something with pane_touch (because is float or what i am missing?)
FloodFill(x / xui.Scale, y / xui.Scale, Rnd(0xff000000, 0xffffffff))

Thanks you for fast answer !
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
1) why can't use snapshot of canvas like bc.CopyPixelsFromBitmap(Canvas1.Snapshot) 'bc is bitmapcreator...
You need to give more information. What doesn't work? I have never tried to use it.
2) which is best, bitmapcreator or canvas ?
A combination of B4XCanvas and BitmapCreator.
3) and what is for using xui.scale here..
Cross platform! In B4J only you can forget it. xui.Scale is the scale in B4A.

Currently, I am also working on a simple Paint program. Simple like the good old Windows Paint, but with transparent color.
Just a screenshot, it is still in progress.
 

Attachments

  • KCPaint.jpg
    KCPaint.jpg
    267.6 KB · Views: 217
Upvote 0

Magma

Expert
Licensed User
Longtime User
Well ... i was using the simple canvas... i am attaching my simple thoughts (my project)...

For the situatution of "not working with canvas snapshot" - if you run project - already fill is selected - try to fill the circle just nothing... but as i already said you making it different way... so may be must try bitmapcreator....

What exactly the difference of b4xcanvas with canvas (b4x means cross platform) what else?.... i am suspecting that this will work with bitmapcreator...
more speed ? - ???


Why not use only bitmapcreator and not b4xcanvas... bitmapcreator seems more powerful... what exactly is the advantage using b4xcanvas... ?
 

Attachments

  • MagmaDraw.zip
    3.1 KB · Views: 202
Upvote 0

Magma

Expert
Licensed User
Longtime User
In this point of project - you can select stroke, tool (nowdrawing), color, and fill if will be filled..

B4X:
    stroke=1 ' the stroke of object
    nowdrawing=5 ' here selecting the tool - no.5 is FloodFill/paint
    ccolor=fx.Colors.Black 'selecting color - simple color...
    filled=True 'will be filled ? or not...
 
Upvote 0

Magma

Expert
Licensed User
Longtime User
@Sam Joseph - Well it is simple to do that... but for now i am as you can see at start... of project... actually understand that b4xcanvas and bitmapcreator is better ! so i ve changed the way i working...

+working as vector... not difficult but need more time...

As i understand you want to cycle colors (ex. from red to yellow) - rotate shapes - small to big the shape - and stamp shape as dragging (diff color, maybe rotate, small to big) - correct ?
 
Last edited:
Upvote 0

klaus

Expert
Licensed User
Longtime User
I had a look at your project.
It took me a while to find the problem.

You call FloodFill(EventData.x,EventData.y, 0)
You set a transparent color therefore nothing will be drawn.
Replacing it with a color like FloodFill(EventData.x,EventData.y, xui.Color_Red) works.
Then you never copy the BitmapCreator bitmap onto Canvas1.
I added Canvas1.DrawImage(bc.Bitmap, 0, 0, canvas2.Width, canvas2.height).

With the new routine it works:
B4X:
Sub Canvas1_MouseReleased (EventData As MouseEvent)
    If willdraw=1 Then
      
        If nowdrawing=5 Then
            'Dim bmp As B4XBitmap = xui.LoadBitmapResize(File.DirAssets, "2.png", ImageView1.Width / xui.Scale, ImageView1.Height / xui.Scale, False)
            bc.Initialize(Canvas1.Width, Canvas1.Height)
            bc.CopyPixelsFromBitmap(Canvas1.Snapshot)
            FloodFill(EventData.x,EventData.y, xui.Color_Red)
            Canvas1.DrawImage(bc.Bitmap, 0, 0, canvas2.Width, canvas2.height)
            Sleep(0)
        End If
      
        canvas2.DrawImage(Canvas1.Snapshot, 0, 0, canvas2.Width, canvas2.height)
    End If
    willdraw=0
End Sub

BitmapCreator is a library to work on bitmaps.
To display it, you need a node (or view in B4i or B4A).
For the display, you can use an ImageView. And use BitmapCreator.SetBitmapToImageView(ImageView) to transfer the Bitmap, this works only with ImageViews.
In this case you don't need a Canvas. But you may need one, or another BitmapCreator, for the intermediate drawing.
If you use a Canvas you need to draw the BitmapCreator.Bitmap onto the Canvas, in you case with Canvas1.DrawImage(bc.Bitmap, 0, 0, canvas2.Width, canvas2.height).

Attached my current version, it is still in progress!
It is mainly intended for small bitmaps like icons etc.
Not everything is working yet and there are for sure some bugs.
I use three CustomViews which are also still in progress.

Did you have a look at the B4X Graphics Booklet ?
 

Attachments

  • KCPaintV1_1.zip
    33.9 KB · Views: 191
Upvote 0
Top