Flood fill
Tuesday, November 18, 2025
Yesterday, Rodrigo Girão Serrão wrote an article about implementing the Floodfill algorithm in Python. He included a Javascript demonstration you can click on, as well as a step-by-step example at the end of his blog post to go over how Flood fill works.
We are going to implement this in Factor and then extend the images.viewer vocabulary:
When working with bitmap pixel data, we typically store colors using integers
in the range [0..255]. We can generate a random color simply:
:: random-color ( -- color )
255 random 255 random 255 random 255 random 4byte-array ;
This allows us to implement the flood fill four-way algorithm:
- Start from a specified pixel in an image.
- Choose a random but different color to assign.
- If the pixel is not the initial color, you’re done.
- If the pixel is, then change it’s color.
- For each surrounding pixel, continue from step 3.
CONSTANT: neighbors { { 1 0 } { 0 1 } { -1 0 } { 0 -1 } }
:: floodfill ( x y image -- ? )
image dim>> first2 :> ( w h )
{
[ x 0 >= ] [ x w < ]
[ y 0 >= ] [ y h < ]
} 0&& [
x y image pixel-at :> initial
f [ drop random-color dup initial = ] loop :> color
color x y image set-pixel-at
V{ { x y } } :> queue
[ queue empty? ] [
queue pop first2 :> ( tx ty )
neighbors [
first2 :> ( dx dy )
tx dx + :> nx
ty dy + :> ny
{
[ nx 0 >= ] [ nx w < ]
[ ny 0 >= ] [ ny h < ]
[ nx ny image pixel-at initial = ]
} 0&& [
color nx ny image set-pixel-at
{ nx ny } queue push
] when
] each
] until t
] [ f ] if ;
Note: as implemented, we change every pixel that matches the first click to a different color. It might be more aesthetic to allow for anti-aliasing to adjust colors that are fairly close to the original color.
Now, we’ll extend the image-gadget:
TUPLE: floodfill-gadget < image-gadget ;
: <floodfill-gadget> ( image -- gadget )
floodfill-gadget new-image-gadget* ;
We implement a click handler that performs a flood fill and if it changed the image, cleans up the texture object and re-renders the gadget.
:: on-click ( gadget -- )
gadget hand-rel first2 [ gl-scale >integer ] bi@ :> ( x y )
x y gadget image>> floodfill [
gadget delete-current-texture
gadget relayout-1
] when ;
That word is assigned as a gesture on button-up mouse clicks:
floodfill-gadget "gestures" f {
{ T{ button-up { # 1 } } on-click }
} define-command-map
And, for convenience, make a main window word to launch the user interface with an example image:
MAIN-WINDOW: floodfill-window { { title "Floodfill" } }
"vocab:floodfill/logo.png" <floodfill-gadget> >>gadgets ;
This is available on my GitHub.