Bitmap/Flood fill: Difference between revisions

no edit summary
imported>Chinhouse
No edit summary
 
(41 intermediate revisions by 17 users not shown)
Line 1:
{{task|Raster graphics operations}}[[Category:Graphics algorithms]]
{{task|Raster graphics operations}}Implement a [[wp:flood fill|flood fill]].
 
A flood fill is a way of filling an area using ''color banks'' to define the contained area or a ''target color'' which "determines" the area (the ''valley'' that can be flooded; Wikipedia uses the term ''target color''). It works almost like a water flooding from a point towards the banks (or: inside the valley): if there's a hole in the banks, the flood is not contained and all the image (or all the "connected valleys") get filled.
Line 8:
[[Image:Unfilledcirc.png|128px|thumb|right]]
'''Testing''': the basic algorithm is not suitable for ''truecolor'' images; a possible test image is the one shown on the right box; you can try to fill the white area, or the black inner circle.
=={{header|Action!}}==
In the following solution a simple implementation of queue has been used.
{{libheader|Action! Bitmap tools}}
<syntaxhighlight lang="action!">INCLUDE "H6:RGBCIRCL.ACT" ;from task Midpoint circle algorithm
 
RGB black,white,yellow,blue
 
DEFINE PTR="CARD"
TYPE PointB=[BYTE px,py]
TYPE Queue=[PTR qfront,qrear,qdata INT capacity]
 
PROC QueueInit(Queue POINTER q)
DEFINE MAXSIZE="500"
CARD ARRAY a(MAXSIZE)
 
q.qfront=0
q.qrear=0
q.capacity=MAXSIZE
q.qdata=a
RETURN
 
BYTE FUNC IsQueueEmpty(Queue POINTER q)
IF q.qfront=q.qrear THEN
RETURN (1)
FI
RETURN (0)
 
PROC QueuePush(Queue POINTER q PointB POINTER p)
PTR rear
PointB POINTER tmp
 
rear=q.qrear+1
IF rear=q.capacity THEN
rear=0
FI
IF rear=q.qfront THEN
Break()
FI
tmp=q.qdata+q.qrear*2
tmp.px=p.px
tmp.py=p.py
q.qrear=rear
RETURN
 
PROC QueuePop(Queue POINTER q PointB POINTER p)
PointB POINTER tmp
 
IF IsQueueEmpty(q) THEN
Break()
FI
tmp=q.qdata+q.qfront*2
p.px=tmp.px
p.py=tmp.py
q.qfront==+1
IF q.qfront=q.capacity THEN
q.qfront=0
FI
RETURN
 
PROC DrawImage(RgbImage POINTER img BYTE x,y)
RGB POINTER p
BYTE i,j
 
p=img.data
FOR j=0 TO img.h-1
DO
FOR i=0 TO img.w-1
DO
IF RgbEqual(p,yellow) THEN
Color=1
ELSEIF RgbEqual(p,white) THEN
Color=2
ELSEIF RgbEqual(p,blue) THEN
Color=3
ELSE
Color=0
FI
Plot(x+i,y+j)
p==+RGBSIZE
OD
OD
RETURN
 
PROC FloodFill(RgbImage POINTER img BYTE x0,y0 RGB POINTER col)
Queue q
RGB c,tmp
PointB p
 
GetRgbPixel(img,x0,y0,c)
IF RgbEqual(c,col) THEN
RETURN
FI
p.px=x0 p.py=y0
QueueInit(q)
QueuePush(q,p)
WHILE IsQueueEmpty(q)=0
DO
QueuePop(q,p)
x0=p.px y0=p.py
 
GetRgbPixel(img,x0,y0,tmp)
IF RgbEqual(tmp,c) THEN
SetRgbPixel(img,x0,y0,col)
 
IF x0>0 THEN
GetRgbPixel(img,x0-1,y0,tmp)
IF RgbEqual(tmp,c) THEN
p.px=x0-1 p.py=y0
QueuePush(q,p)
FI
FI
IF x0<img.w-1 THEN
GetRgbPixel(img,x0+1,y0,tmp)
IF RgbEqual(tmp,c) THEN
p.px=x0+1 p.py=y0
QueuePush(q,p)
FI
FI
IF y0>0 THEN
GetRgbPixel(img,x0,y0-1,tmp)
IF RgbEqual(tmp,c) THEN
p.px=x0 p.py=y0-1
QueuePush(q,p)
FI
FI
IF y0<img.h-1 THEN
GetRgbPixel(img,x0,y0+1,tmp)
IF RgbEqual(tmp,c) THEN
p.px=x0 p.py=y0+1
QueuePush(q,p)
FI
FI
FI
OD
RETURN
 
PROC Main()
RgbImage img
BYTE CH=$02FC,size=[40]
BYTE ARRAY p(4800)
BYTE n
INT x,y
RGB POINTER col
 
Graphics(7+16)
SetColor(0,13,12) ;yellow
SetColor(1,0,14) ;white
SetColor(2,8,6) ;blue
SetColor(4,0,0) ;black
 
RgbBlack(black)
RgbYellow(yellow)
RgbWhite(white)
RgbBlue(blue)
 
InitRgbImage(img,size,size,p)
FillRgbImage(img,black)
 
RgbCircle(img,size/2,size/2,size/2-1,white)
RgbCircle(img,2*size/5,2*size/5,size/5,white)
DrawImage(img,0,(96-size)/2)
 
FloodFill(img,3*size/5,3*size/5,white)
DrawImage(img,size,(96-size)/2)
 
FloodFill(img,2*size/5,2*size/5,blue)
DrawImage(img,2*size,(96-size)/2)
 
FloodFill(img,3*size/5,3*size/5,yellow)
DrawImage(img,3*size,(96-size)/2)
 
DO UNTIL CH#$FF OD
CH=$FF
RETURN</syntaxhighlight>
{{out}}
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Flood_fill.png Screenshot from Atari 8-bit computer]
=={{header|Ada}}==
<langsyntaxhighlight lang="ada">procedure Flood_Fill
( Picture : in out Image;
From : Point;
Line 116 ⟶ 290:
Column (From);
end if;
end Flood_Fill;</langsyntaxhighlight>
The procedure has the following parameters. ''Picture'' is the image to change. ''From'' is the point to start at. ''Fill'' is the color to fill with. ''Replace'' is the color to replace. ''Distance'' defines the range of color around ''Replace'' to replace as well. The distance is defined as a maximum of the differences of stimuli. The following code snippet reads the test file, fills the area between two circles red, and writes the result:
<langsyntaxhighlight lang="ada">declare
File : File_Type;
begin
Line 136 ⟶ 310:
Close (File);
end;
end;</langsyntaxhighlight>
=={{header|Applesoft BASIC}}==
 
<syntaxhighlight lang="gwbasic"> 100 GR:GOSUB 330"DRAW THE DEATH STAR"
110 COLOR= 12
120 X = 20:Y = 30: GOSUB 140"FLOOD FILL"
130 END
140 C = SCRN( X,Y)
150 X(S) = X:Y(S) = Y:S = S + 1
160 FOR S = 0 TO 0 STEP - 1
170 X = X(S):Y = Y(S)
180 LX = X
190 IF SCRN( LX - 1,Y) = C THEN PLOT LX - 1,Y:LX = LX - 1: GOTO 190
200 IF SCRN( X,Y) = C THEN PLOT X,Y:X = X + 1: GOTO 200
210 X1 = LX:X2 = X - 1:YP = Y + 1: GOSUB 250"SCAN"
220 X1 = LX:X2 = X - 1:YP = Y - 1: GOSUB 250"SCAN"
230 NEXT S
240 RETURN
250 TRUE = NOT FALSE
260 ADDED = FALSE
270 FOR XP = X1 TO X2:
280 INSIDE = SCRN( XP,YP) = C
290 IF NOT INSIDE THEN ADDED = FALSE
300 IF INSIDE AND NOT ADDED THEN X(S) = XP:Y(S) = YP:S = S + 1:ADDED = TRUE
310 NEXT XP
320 RETURN
330 COLOR= 15: CX = 20:CY = 20:R = 18: GOSUB 350"CIRCLE"
340 COLOR= 0: CX = 15:CY = 15:R = 6
350 F = 1 - R:X = 0:Y = R:DX = 0:DY = - 2 * R:PLOT CX,CY + R:PLOT CX,CY - R:HLIN CX - R,CX + R AT CY: IF X > = Y THEN RETURN
360 FOR I = 0 TO 1:IF F > = 0 THEN Y = Y - 1:DY = DY + 2:F = F + DY
370 X = X + 1:DX = DX + 2:F = F + DX + 1:HLIN CX - X,CX + X AT CY + Y:HLIN CX - X,CX + X AT CY - Y:HLIN CX - Y,CX + Y AT CY + X:HLIN CX - Y,CX + Y AT CY - X: I = X > = Y : NEXT I : RETURN</syntaxhighlight>
=={{header|AutoHotkey}}==
* <code>x</code>, <code>y</code> are the initial coords (relative to screen unless the <code>relative</code> parameter is true).
Line 147 ⟶ 349:
=== Recursive ===
This is limited to %StackSize% pixels.
<langsyntaxhighlight AutoHotkeylang="autohotkey">SetBatchLines, -1
CoordMode, Mouse
CoordMode, Pixel
Line 187 ⟶ 389:
FloodFill(x-1, y-1, target, replacement, key)
}
}</langsyntaxhighlight>
 
=== Iterative ===
<langsyntaxhighlight AutoHotkeylang="autohotkey">#NoEnv
#SingleInstance, Force
 
Line 244 ⟶ 446:
DllCall("ReleaseDC", UInt, 0, UInt, hDC)
DllCall("DeleteObject", UInt, hBrush)
}</langsyntaxhighlight>
 
=={{header|BBC BASIC}}==
BBC BASIC has a built-in flood fill statement, but to satisfy the terms of the task it is not used in this example.
<langsyntaxhighlight lang="bbcbasic"> MODE 8
GCOL 15
CIRCLE FILL 640, 512, 500
Line 271 ⟶ 472:
PROCflood(X%, Y%-2, C%)
NEXT
ENDPROC</langsyntaxhighlight>
 
=={{header|C}}==
===Simple and complete example in C89===
<syntaxhighlight lang="c">/*
<lang C>/*
* RosettaCode: Bitmap/Flood fill, language C, dialects C89, C99, C11.
*
Line 289 ⟶ 489:
* standard output file.
*
* Note: In order for athis program to work properly it is necessary to allocate
* enough memory for the program stack. For example, in Microsoft Visual Studio,
* the option /stack:134217728 declares a 128MB stack instead of the default
Line 305 ⟶ 505:
static BYTE oldColor;
static BYTE newColor;
 
 
void floodFill(int i, int j)
Line 320 ⟶ 519:
}
}
 
 
/* *****************************************************************************
Line 332 ⟶ 530:
}
 
static void skipCommentLines(FILE* file)
{
int c;
Line 370 ⟶ 568:
}
}
 
/* *****************************************************************************
* The main entry point.
*/
 
int main(void)
Line 379 ⟶ 581:
writePortableBitMap(stdout);
return EXIT_SUCCESS;
}</langsyntaxhighlight>
 
===FirstSecond example ===
<syntaxhighlight lang="c">
<lang c>
// http://commons.wikimedia.org/wiki/File:Julia_immediate_basin_1_3.png
 
Line 490 ⟶ 692:
}
</syntaxhighlight>
</lang>
 
===SecondThird example===
{{improve|C|Very difficult to make it work, and still doesn't work correctly after that. Needs to be replaced with something sensible.}}
 
The <code>sys/queue.h</code> is not POSIX. (See [[FIFO#C|FIFO]])
 
<langsyntaxhighlight lang="c">/* #include <sys/queue.h> */
typedef struct {
color_component red, green, blue;
Line 505 ⟶ 707:
void floodfill(image img, int px, int py,
rgb_color_p bankscolor,
rgb_color_p rcolor);</langsyntaxhighlight>
 
<langsyntaxhighlight lang="c">#include "imglib.h"
 
typedef struct _ffill_node {
Line 599 ⟶ 801:
}
return pixelcount;
}</langsyntaxhighlight>
 
The '''pixelcount''' could be used to know the area of the filled region. The ''internal'' parameter <code>tolerance</code> can be tuned to cope with antialiasing, bringing "sharper" resuts.
Line 607 ⟶ 809:
(Comments show changes to fill the white area instead of the black circle)
 
<langsyntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h>
#include "imglib.h"
Line 633 ⟶ 835:
}
return 0;
}</langsyntaxhighlight>
=={{header|C sharp|C#}}==
{{works with|C#|3.0}}
{{libheader|System.Drawing}}
 
This implementation matches exact colours only. Since the example image has grey pixels around the edges of the circles, these will remain grey after the interiors are filled.
 
<syntaxhighlight lang="csharp">
using System;
using System.Collections.Generic;
using System.Drawing;
 
namespace FloodFill
{
class Program
{
private static bool ColorMatch(Color a, Color b)
{
return (a.ToArgb() & 0xffffff) == (b.ToArgb() & 0xffffff);
}
 
static void FloodFill(Bitmap bmp, Point pt, Color targetColor, Color replacementColor)
{
Queue<Point> q = new Queue<Point>();
q.Enqueue(pt);
while (q.Count > 0)
{
Point n = q.Dequeue();
if (!ColorMatch(bmp.GetPixel(n.X, n.Y),targetColor))
continue;
Point w = n, e = new Point(n.X + 1, n.Y);
while ((w.X >= 0) && ColorMatch(bmp.GetPixel(w.X, w.Y),targetColor))
{
bmp.SetPixel(w.X, w.Y, replacementColor);
if ((w.Y > 0) && ColorMatch(bmp.GetPixel(w.X, w.Y - 1),targetColor))
q.Enqueue(new Point(w.X, w.Y - 1));
if ((w.Y < bmp.Height - 1) && ColorMatch(bmp.GetPixel(w.X, w.Y + 1),targetColor))
q.Enqueue(new Point(w.X, w.Y + 1));
w.X--;
}
while ((e.X <= bmp.Width - 1) && ColorMatch(bmp.GetPixel(e.X, e.Y),targetColor))
{
bmp.SetPixel(e.X, e.Y, replacementColor);
if ((e.Y > 0) && ColorMatch(bmp.GetPixel(e.X, e.Y - 1), targetColor))
q.Enqueue(new Point(e.X, e.Y - 1));
if ((e.Y < bmp.Height - 1) && ColorMatch(bmp.GetPixel(e.X, e.Y + 1), targetColor))
q.Enqueue(new Point(e.X, e.Y + 1));
e.X++;
}
}
}
 
static void Main(string[] args)
{
Bitmap bmp = new Bitmap("Unfilledcirc.bmp");
FloodFill(bmp, new Point(200, 200), Color.White, Color.Red);
FloodFill(bmp, new Point(100, 100), Color.Black, Color.Blue);
bmp.Save("Filledcirc.bmp");
}
}
}
</syntaxhighlight>
=={{header|C++}}==
{{libheader|OpenCV}}
Line 641 ⟶ 903:
 
'''Interface'''
<langsyntaxhighlight lang="cpp">#ifndef PROCESSING_FLOODFILLALGORITHM_H_
#define PROCESSING_FLOODFILLALGORITHM_H_
 
Line 668 ⟶ 930:
 
#endif /* PROCESSING_FLOODFILLALGORITHM_H_ */
</syntaxhighlight>
</lang>
'''Implementation'''
<langsyntaxhighlight lang="cpp">#include "FloodFillAlgorithm.h"
 
FloodFillAlgorithm::~FloodFillAlgorithm() {
Line 714 ⟶ 976:
}
 
</syntaxhighlight>
</lang>
 
=={{header|C sharp|C#}}==
{{works with|C#|3.0}}
{{libheader|System.Drawing}}
 
This implementation matches exact colours only. Since the example image has grey pixels around the edges of the circles, these will remain grey after the interiors are filled.
 
<lang csharp>
using System;
using System.Collections.Generic;
using System.Drawing;
 
namespace FloodFill
{
class Program
{
private static bool ColorMatch(Color a, Color b)
{
return (a.ToArgb() & 0xffffff) == (b.ToArgb() & 0xffffff);
}
 
static void FloodFill(Bitmap bmp, Point pt, Color targetColor, Color replacementColor)
{
Queue<Point> q = new Queue<Point>();
q.Enqueue(pt);
while (q.Count > 0)
{
Point n = q.Dequeue();
if (!ColorMatch(bmp.GetPixel(n.X, n.Y),targetColor))
continue;
Point w = n, e = new Point(n.X + 1, n.Y);
while ((w.X >= 0) && ColorMatch(bmp.GetPixel(w.X, w.Y),targetColor))
{
bmp.SetPixel(w.X, w.Y, replacementColor);
if ((w.Y > 0) && ColorMatch(bmp.GetPixel(w.X, w.Y - 1),targetColor))
q.Enqueue(new Point(w.X, w.Y - 1));
if ((w.Y < bmp.Height - 1) && ColorMatch(bmp.GetPixel(w.X, w.Y + 1),targetColor))
q.Enqueue(new Point(w.X, w.Y + 1));
w.X--;
}
while ((e.X <= bmp.Width - 1) && ColorMatch(bmp.GetPixel(e.X, e.Y),targetColor))
{
bmp.SetPixel(e.X, e.Y, replacementColor);
if ((e.Y > 0) && ColorMatch(bmp.GetPixel(e.X, e.Y - 1), targetColor))
q.Enqueue(new Point(e.X, e.Y - 1));
if ((e.Y < bmp.Height - 1) && ColorMatch(bmp.GetPixel(e.X, e.Y + 1), targetColor))
q.Enqueue(new Point(e.X, e.Y + 1));
e.X++;
}
}
}
 
static void Main(string[] args)
{
Bitmap bmp = new Bitmap("Unfilledcirc.bmp");
FloodFill(bmp, new Point(200, 200), Color.White, Color.Red);
FloodFill(bmp, new Point(100, 100), Color.Black, Color.Blue);
bmp.Save("Filledcirc.bmp");
}
}
}
</lang>
 
=={{header|D}}==
This version uses the bitmap module from the Bitmap Task, matches exact colours only, and is derived from the Go version (to avoid stack overflow because unlike Go the D stack is not segmented).
 
<langsyntaxhighlight lang="d">import std.array, bitmap;
 
void floodFill(Color)(Image!Color img, in uint x, in uint y,
Line 809 ⟶ 1,008:
img.floodFill(200, 200, RGB(127, 0, 0));
img.savePPM6("unfilled_circ_flooded.ppm");
}</langsyntaxhighlight>
=={{header|Delphi}}==
 
See [[#Pascal]].
=={{header|E}}==
 
Using the image type from [[Basic bitmap storage#E]].
 
<langsyntaxhighlight lang="e">def floodFill(image, x, y, newColor) {
def matchColor := image[x, y]
def w := image.width()
Line 883 ⟶ 1,083:
 
fillScan(x, y)
}</langsyntaxhighlight>
 
[[File:Filledcirc-E.png|128px|thumb|right|Filled sample image]]Note that this does not make any attempt to smoothly fill 'banks' or have a tolerance; it matches exact colors only. This will fill the example image with red inside green, and there will be black/white fringes:
 
<syntaxhighlight lang="e">{
<lang e>{
println("Read")
def i := readPPM(<import:java.io.makeFileInputStream>(<file:Unfilledcirc.ppm>))
Line 897 ⟶ 1,097:
i.writePPM(<import:java.io.makeFileOutputStream>(<file:Filledcirc.ppm>))
println("Done")
}</langsyntaxhighlight>
 
=={{header|ERRE}}==
In "PC.LIB" library there is a FILL procedure that do the job, but the example program implements the algorithm in ERRE language using an iterative method. This program is taken from the distribution disk and works in 320x200 graphics.
<syntaxhighlight lang="erre">
<lang ERRE>
PROGRAM MYFILL_DEMO
 
Line 989 ⟶ 1,188:
FLOOD_FILL(100,100,0,1)
END PROGRAM
</syntaxhighlight>
</lang>
Note: I haven't an "Upload files" item, so I can't show the resulting image!
 
=={{header|Euler Math Toolbox}}==
 
Using an emulated stack. EMT's recursive stack space is limited. For the notebook with images see [http://www.euler-math-toolbox.de/renegrothmann/Flood%20Fill.html this page].
 
<syntaxhighlight lang="text">
>file="test.png";
>A=loadrgb(file); ...
Line 1,033 ⟶ 1,231:
>B=floodfill(B,200,200,rgb(0,0,0.5),0.5);
>insrgb(B);
</syntaxhighlight>
</lang>
 
=={{header|FBSL}}==
'''Using pure FBSL's built-in graphics functions:'''
<langsyntaxhighlight lang="qbasic">#DEFINE WM_LBUTTONDOWN 513
#DEFINE WM_CLOSE 16
 
Line 1,073 ⟶ 1,270:
CIRCLE(FBSL.GETDC, Breadth / 2, Height / 2, 85, &HFFFFFF, 0, 360, 1, TRUE) _ ' White
(FBSL.GETDC, Breadth / 3, Height / 3, 30, 0, 0, 360, 1, TRUE) ' Black
END SUB</langsyntaxhighlight>
'''Output:''' [[File:FBSLFlood.PNG]]
 
=={{header|Forth}}==
This simple recursive algorithm uses routines from [[Basic bitmap storage]].
<langsyntaxhighlight lang="forth">: third 2 pick ;
: 3dup third third third ;
: 4dup 2over 2over ;
Line 1,105 ⟶ 1,301:
swap 1- swap
then
r> drop ;</langsyntaxhighlight>
 
=={{header|Fortran}}==
{{works with|Fortran|90 and later}}
Line 1,112 ⟶ 1,307:
Here the ''target color'' paradigm is used. Again the <code>matchdistance</code> parameter can be tuned to ignore small differences that could come because of antialiasing.
 
<langsyntaxhighlight lang="fortran">module RCImageArea
use RCImageBasic
use RCImagePrimitive
Line 1,217 ⟶ 1,412:
end subroutine floodfill
 
end module RCImageArea</langsyntaxhighlight>
 
Usage example excerpt (which on the test image will fill with green the inner black circle):
 
<langsyntaxhighlight lang="fortran"> call floodfill(animage, point(100,100), rgb(0,0,0), rgb(0,255,0))</langsyntaxhighlight>
=={{header|FreeBASIC}}==
{{trans|BBC BASIC}}
<langsyntaxhighlight lang="freebasic">' version 04-11-2016
' compile with: fbc -s console
 
Line 1,278 ⟶ 1,473:
Sleep 2000
If InKey <> "" OrElse InKey = Chr(255) + "k" Then End
Loop</langsyntaxhighlight>
 
=={{header|Go}}==
An addition to code from the bitmap task:
<langsyntaxhighlight lang="go">package raster
 
func (b *Bitmap) Flood(x, y int, repl Pixel) {
Line 1,298 ⟶ 1,492:
}
ff(x, y)
}</langsyntaxhighlight>
And a test program. Works with code from read ppm and write ppm to pipe tasks. For input, it uses a version of the test file converted by the Go solution to "Read an image through a pipe". For output it uses the trick from "PPM conversion through a pipe" to write the .png suitable for uploading to RC.
[[File:Go_flood.png|right]]
<langsyntaxhighlight lang="go">package main
 
import (
Line 1,329 ⟶ 1,523:
log.Fatal(err)
}
}</langsyntaxhighlight>
 
=={{header|Haskell}}==
This code uses the Bitmap and Bitmap.RGB modules defined [[Bitmap#Haskell|here]].
<langsyntaxhighlight Haskelllang="haskell">import Data.Array.ST
import Data.STRef
import Control.Monad
Line 1,443 ⟶ 1,636:
setSpanRight p False
scanWhileX b st p oldC newC (w, h) (Pixel (x, y + 1))
</syntaxhighlight>
</lang>
 
=={{header|HicEst}}==
HicEst color fill is via the [http://www.HicEst.com/DeCoRation.htm decoration option of WRITE()]
<langsyntaxhighlight HicEstlang="hicest">WINDOW(WINdowhandle=wh, BaCkcolor=0, TItle="Rosetta test image")
 
WRITE(WIN=wh, DeCoRation="EL=14, BC=14") ! color 14 == bright yellow
Line 1,454 ⟶ 1,646:
WRITE(WIN=wh, DeCoRation="L=1/4, R=1/2, T=1/4, B=1/2, EL=25, BC=25")
 
WINDOW(Kill=wh)</langsyntaxhighlight>
 
=={{header|J}}==
'''Solution:'''<br>
Uses <code>getPixels</code> and <code>setPixels</code> from [[Basic bitmap storage#J|Basic bitmap storage]].
<langsyntaxhighlight lang="j">NB. finds and labels contiguous areas with the same numbers
NB. ref: http://www.jsoftware.com/pipermail/general/2005-August/023886.html
findcontig=: (|."1@|:@:>. (* * 1&(|.!.0)))^:4^:_@(* >:@i.@$)
Line 1,468 ⟶ 1,659:
NB.*floodFill v Floods area, defined by point and color (x), of image (y)
NB. x is: 2-item list of (y x) ; (color)
floodFill=: (1&({::)@[ ;~ 0&({::)@[ getFloodpoints ]) setPixels ]</langsyntaxhighlight>
 
'''Example Usage:'''<br>
The following draws the same image as for the [[Flood fill#Tcl|Tcl example image]] below.<br>
Uses definitions from [[Basic bitmap storage#J|Basic bitmap storage]], [[Bresenham's line algorithm#J|Bresenham's line algorithm]] and [[Midpoint circle algorithm#J|Midpoint circle algorithm]].
<langsyntaxhighlight lang="j">'white blue yellow black orange red'=: 255 255 255,0 0 255,255 255 0,0 0 0,255 165 0,:255 0 0
myimg=: white makeRGB 50 70
lines=: _2]\^:2 ] 0 0 25 0 , 25 0 25 35 , 25 35 0 35 , 0 35 0 0
Line 1,481 ⟶ 1,672:
myimg=: (5 34;orange) floodFill myimg
myimg=: (5 36;red) floodFill myimg
viewRGB myimg</langsyntaxhighlight>
 
'''Alternative findcontig:'''<br>
The following alternative version of <code>findcontig</code> is less concise but is leaner, faster, works for n-dimensions and is not restricted to numerical arrays.
<langsyntaxhighlight lang="j">NB. ref: http://www.jsoftware.com/pipermail/general/2005-August/024174.html
eq=:[:}:"1 [:($$[:([:+/\1:,}:~:}.),) ,&_"1 NB. equal numbers for atoms of y connected in first direction
eq_nd=: i.@#@$(<"0@[([:, |:^:_1"0 _)&> [:EQ&.> <@|:"0 _)] NB. n-dimensional eq, gives an #@$,*/@$ shaped matrix
Line 1,491 ⟶ 1,682:
cnnct=: [: |:@({."1<.//.]) [: ; <@(,.<./)/.~
 
findcontig_nd=: 3 : '($y)${. ([:({.,~}:) ([ repl cnnct)/\.)^:([:+./@(~:/)2&{.)^:_ (,{.) eq_nd (i.~ ~.@,) y'</langsyntaxhighlight>
 
=={{header|Java}}==
Input is the image, the starting node (x, y), the target color we want to fill, and the replacement color that will replace the target color. It implements a 4-way flood fill algorithm. For large images, the performance can be improved by drawing the scanlines instead of setting each pixel to the replacement color, or by working directly on the databuffer.
<langsyntaxhighlight lang="java">import java.awt.Color;
import java.awt.Point;
import java.awt.image.BufferedImage;
Line 1,536 ⟶ 1,726:
}
}
}</langsyntaxhighlight>
And here is an example of how to replace the white color with red from the sample image (with starting node (50, 50)):
<langsyntaxhighlight lang="java">import java.io.IOException;
import java.awt.Color;
import java.awt.Point;
Line 1,555 ⟶ 1,745:
new Test();
}
}</langsyntaxhighlight>
=={{header|Julia}}==
{{works with|Julia|0.6}}
Inspired to [[#Python | Python]] version.
 
<syntaxhighlight lang="julia">using Images, FileIO
 
function floodfill!(img::Matrix{<:Color}, initnode::CartesianIndex{2}, target::Color, replace::Color)
img[initnode] != target && return img
# constants
north = CartesianIndex(-1, 0)
south = CartesianIndex( 1, 0)
east = CartesianIndex( 0, 1)
west = CartesianIndex( 0, -1)
 
queue = [initnode]
while !isempty(queue)
node = pop!(queue)
if img[node] == target
wnode = node
enode = node + east
end
# Move west until color of node does not match target color
while checkbounds(Bool, img, wnode) && img[wnode] == target
img[wnode] = replace
if checkbounds(Bool, img, wnode + north) && img[wnode + north] == target
push!(queue, wnode + north)
end
if checkbounds(Bool, img, wnode + south) && img[wnode + south] == target
push!(queue, wnode + south)
end
wnode += west
end
# Move east until color of node does not match target color
while checkbounds(Bool, img, enode) && img[enode] == target
img[enode] = replace
if checkbounds(Bool, img, enode + north) && img[enode + north] == target
push!(queue, enode + north)
end
if checkbounds(Bool, img, enode + south) && img[enode + south] == target
push!(queue, enode + south)
end
enode += east
end
end
return img
end
 
img = Gray{Bool}.(load("data/unfilledcircle.png"))
floodfill!(img, CartesianIndex(100, 100), Gray(false), Gray(true))
save("data/filledcircle.png", img)</syntaxhighlight>
=={{header|Kotlin}}==
{{trans|Java}}
<syntaxhighlight lang="scala">// version 1.1.4-3
 
import java.awt.Color
import java.awt.Point
import java.awt.image.BufferedImage
import java.util.LinkedList
import java.io.File
import javax.imageio.ImageIO
import javax.swing.JOptionPane
import javax.swing.JLabel
import javax.swing.ImageIcon
 
fun floodFill(image: BufferedImage, node: Point, targetColor: Color, replColor: Color) {
val target = targetColor.getRGB()
val replacement = replColor.getRGB()
if (target == replacement) return
val width = image.width
val height = image.height
val queue = LinkedList<Point>()
var nnode: Point? = node
 
do {
var x = nnode!!.x
val y = nnode.y
while (x > 0 && image.getRGB(x - 1, y) == target) x--
var spanUp = false
var spanDown = false
 
while (x < width && image.getRGB(x, y) == target) {
image.setRGB(x, y, replacement)
 
if (!spanUp && y > 0 && image.getRGB(x, y - 1) == target) {
queue.add(Point(x, y - 1))
spanUp = true
}
else if (spanUp && y > 0 && image.getRGB(x, y - 1) != target) {
spanUp = false
}
 
if (!spanDown && y < height - 1 && image.getRGB(x, y + 1) == target) {
queue.add(Point(x, y + 1))
spanDown = true
}
else if (spanDown && y < height - 1 && image.getRGB(x, y + 1) != target) {
spanDown = false
}
x++
}
nnode = queue.pollFirst()
}
while (nnode != null)
}
 
fun main(args: Array<String>) {
val image = ImageIO.read(File("Unfilledcirc.png"))
floodFill(image, Point(50, 50), Color.white, Color.yellow)
val title = "Floodfilledcirc.png"
ImageIO.write(image, "png", File(title))
JOptionPane.showMessageDialog(null, JLabel(ImageIcon(image)), title, JOptionPane.PLAIN_MESSAGE)
}</syntaxhighlight>
=={{header|Liberty BASIC}}==
<langsyntaxhighlight lang="lb">'This example requires the Windows API
NoMainWin
WindowWidth = 267.5
Line 1,646 ⟶ 1,947:
result = FloodFill(mouseXX, (mouseYY - 1), targetColor)
End If
End Function</langsyntaxhighlight>
 
=={{header|Lingo}}==
Lingo has built-in flood fill for image objects, so a custom implementation would be pointless:
<langsyntaxhighlight lang="lingo">img.floodFill(x, y, rgb(r,g,b))</langsyntaxhighlight>
=={{header|Lua}}==
Uses Bitmap class [[Bitmap#Lua|here]], with an RGB tuple pixel representation, then extending..
 
Preprocess with ImageMagick to simplify loading:
<syntaxhighlight lang="lua">$ magick unfilledcirc.png -depth 8 unfilledcirc.ppm</syntaxhighlight>
Some rudimentary PPM support:
<syntaxhighlight lang="lua">function Bitmap:loadPPM(filename)
local fp = io.open( filename, "rb" )
if fp == nil then return false end
local head, width, height, depth, tail = fp:read("*line", "*number", "*number", "*number", "*line")
self.width, self.height = width, height
self:alloc()
for y = 1, self.height do
for x = 1, self.width do
self.pixels[y][x] = { string.byte(fp:read(1)), string.byte(fp:read(1)), string.byte(fp:read(1)) }
end
end
fp:close()
end
 
function Bitmap:savePPM(filename)
local fp = io.open( filename, "wb" )
if fp == nil then return false end
fp:write(string.format("P6\n%d %d\n%d\n", self.width, self.height, 255))
for y = 1, self.height do
for x = 1, self.width do
local pix = self.pixels[y][x]
fp:write(string.char(pix[1]), string.char(pix[2]), string.char(pix[3]))
end
end
fp:close()
end</syntaxhighlight>
The task itself:
<syntaxhighlight lang="lua">function Bitmap:floodfill(x, y, c)
local b = self:get(x, y)
if not b then return end
local function matches(a)
if not a then return false end
-- this is where a "tolerance" could be implemented:
return a[1]==b[1] and a[2]==b[2] and a[3]==b[3]
end
local function ff(x, y)
if not matches(self:get(x, y)) then return end
self:set(x, y, c)
ff(x+1, y)
ff(x, y-1)
ff(x-1, y)
ff(x, y+1)
end
ff(x, y)
end</syntaxhighlight>
Demo:
<syntaxhighlight lang="lua">bitmap = Bitmap(0, 0)
bitmap:loadPPM("unfilledcirc.ppm")
bitmap:floodfill( 1, 1, { 255,0,0 }) -- fill exterior (except bottom right) with red
bitmap:floodfill( 50, 50, { 0,255,0 })-- fill larger circle with green
bitmap:floodfill( 100, 100, { 0,0,255 })-- fill smaller circle with blue
bitmap:savePPM("filledcirc.ppm")</syntaxhighlight>
=={{header|Mathematica}} / {{header|Wolfram Language}}==
<langsyntaxhighlight Mathematicalang="mathematica">createMask[img_, pos_, tol_] :=
RegionBinarize[img, Image[SparseArray[pos -> 1, ImageDimensions[img]]], tol];
floodFill[img_Image, pos_List, tol_Real, color_List] :=
Line 1,661 ⟶ 2,018:
Dilation[createMask[img, pos, tol],1]
]
]</langsyntaxhighlight>
 
{{out}}
Line 1,667 ⟶ 2,024:
<pre>floodFill[Import["http://rosettacode.org/mw/images/0/0f/Unfilledcirc.png"], {100, 100}, 0.01, {1, 0, 0}]</pre>
 
=={{header|MiniScript}}==
This implementation is for use with [http://miniscript.org/MiniMicro Mini Micro]. The first parameter can be either a PixelDisplay or Image object. Flooding only occurs if the color as well as the opacity matches.
<syntaxhighlight lang="miniscript">
floodFill = function(bmp, x, y, targetColor, replacementColor)
// Check if pixel is outside the bounds
if not(0 < x < bmp.width) or not(0 < y < bmp.height) then return
// Check the current pixel color
currentColor = bmp.pixel(x, y)
if currentColor != targetColor then return
// Replace the color
bmp.setPixel x, y, replacementColor
// Recursively apply to adjacent pixels
floodFill(bmp, x + 1, y, targetColor, replacementColor)
floodFill(bmp, x - 1, y, targetColor, replacementColor)
floodFill(bmp, x, y + 1, targetColor, replacementColor)
floodFill(bmp, x, y - 1, targetColor, replacementColor)
end function
clear
img = file.loadImage("Unfilledcirc.png")
gfx.drawImage img, 0, 0
floodFill gfx, 50, 50, "#FFFFFFFF", "#00FFFFFF"
floodFill gfx, 100, 125, "#000000FF", "#0000FFFF"
</syntaxhighlight>
 
=={{header|Nim}}==
{{Trans|Python}}
<syntaxhighlight lang="nim">import bitmap
 
proc floodFill*(img: Image; initPoint: Point; targetColor, replaceColor: Color) =
 
var stack: seq[Point]
let width = img.w
let height = img.h
 
if img[initPoint.x, initPoint.y] != targetColor:
return
 
stack.add(initPoint)
 
while stack.len > 0:
var w, e: Point
let pt = stack.pop()
if img[pt.x, pt.y] == targetColor:
w = pt
e = if pt.x + 1 < width: (pt.x + 1, pt.y) else: pt
else:
continue # Already processed.
 
# Move west until color of node does not match "targetColor".
while w.x >= 0 and img[w.x, w.y] == targetColor:
img[w.x, w.y] = replaceColor
if w.y + 1 < height and img[w.x, w.y + 1] == targetColor:
stack.add((w.x, w.y + 1))
if w.y - 1 >= 0 and img[w.x, w.y - 1] == targetColor:
stack.add((w.x, w.y - 1))
dec w.x
 
# Move east until color of node does not match "targetColor".
while e.x < width and img[e.x, e.y] == targetColor:
img[e.x, e.y] = replaceColor
if e.y + 1 < height and img[e.x, e.y + 1] == targetColor:
stack.add((e.x, e.y + 1))
if e.y - 1 >= 0 and img[e.x, e.y - 1] == targetColor:
stack.add((e.x, e.y - 1))
inc e.x
 
#———————————————————————————————————————————————————————————————————————————————————————————————————
 
when isMainModule:
 
import ppm_read, ppm_write
 
var img = readPPM("Unfilledcirc.ppm")
img.floodFill((30, 122), White, color(255, 0, 0))
img.writePPM("Unfilledcirc_red.ppm")</syntaxhighlight>
=={{header|OCaml}}==
{{Trans|C}}
<syntaxhighlight lang="ocaml">
let floodFill ~img (i, j) newColor =
let oldColor = get_pixel ~img ~pt:(i, j) in
let width, height = get_dims ~img in
 
let rec aux (i, j) =
if 0 <= i && i < height
&& 0 <= j && j < width
&& (get_pixel ~img ~pt:(i, j)) = oldColor
then begin
put_pixel img newColor i j;
aux (i-1, j);
aux (i+1, j);
aux (i, j-1);
aux (i, j+1);
end;
in
aux (i, j)</syntaxhighlight>
=={{header|Pascal}}==
{{trans|C#}}
<syntaxhighlight lang="pascal">
 
program FloodFillTest;
 
{$APPTYPE CONSOLE}
{$R *.res}
 
uses
Winapi.Windows,
System.SysUtils,
System.Generics.Collections,
vcl.Graphics;
 
procedure FloodFill(bmp: tBitmap; pt: TPoint; targetColor: TColor;
replacementColor: TColor);
var
q: TQueue<TPoint>;
n, w, e: TPoint;
begin
q := TQueue<TPoint>.Create;
 
q.Enqueue(pt);
 
while (q.Count > 0) do
begin
n := q.Dequeue;
if bmp.Canvas.Pixels[n.X, n.Y] <> targetColor then
Continue;
 
w := n;
e := TPoint.Create(n.X + 1, n.Y);
 
while ((w.X >= 0) and (bmp.Canvas.Pixels[w.X, w.Y] = targetColor)) do
begin
bmp.Canvas.Pixels[w.X, w.Y] := replacementColor;
if ((w.Y > 0) and (bmp.Canvas.Pixels[w.X, w.Y - 1] = targetColor)) then
q.Enqueue(TPoint.Create(w.X, w.Y - 1));
if ((w.Y < bmp.Height - 1) and (bmp.Canvas.Pixels[w.X, w.Y + 1] = targetColor)) then
q.Enqueue(TPoint.Create(w.X, w.Y + 1));
dec(w.X);
end;
 
while ((e.X <= bmp.Width - 1) and (bmp.Canvas.Pixels[e.X, e.Y] = targetColor)) do
begin
bmp.Canvas.Pixels[e.X, e.Y] := replacementColor;
if ((e.Y > 0) and (bmp.Canvas.Pixels[e.X, e.Y - 1] = targetColor)) then
q.Enqueue(TPoint.Create(e.X, e.Y - 1));
 
if ((e.Y < bmp.Height - 1) and (bmp.Canvas.Pixels[e.X, e.Y + 1] = targetColor)) then
q.Enqueue(TPoint.Create(e.X, e.Y + 1));
inc(e.X);
end;
end;
q.Free;
end;
 
var
bmp: TBitmap;
 
begin
bmp := TBitmap.Create;
try
bmp.LoadFromFile('Unfilledcirc.bmp');
FloodFill(bmp, TPoint.Create(200, 200), clWhite, clRed);
FloodFill(bmp, TPoint.Create(100, 100), clBlack, clBlue);
bmp.SaveToFile('Filledcirc.bmp');
finally
bmp.Free;
end;
 
end.
</syntaxhighlight>
=={{header|Perl}}==
 
Line 1,673 ⟶ 2,201:
The <tt>fill</tt> of the Perl package Image::Imlib2 is a flood fill (so the documentatin of Image::Imlib2 says). The target colour is the one of the starting point pixel; the color set with <tt>set_color</tt> is the fill colour.
 
<langsyntaxhighlight lang="perl">#! /usr/bin/perl
 
use strict;
Line 1,682 ⟶ 2,210:
$img->fill(100,100);
$img->save("filledcirc.jpg");
exit 0;</langsyntaxhighlight>
 
A homemade implementation can be:
 
<langsyntaxhighlight lang="perl">use strict;
use Image::Imlib2;
 
Line 1,733 ⟶ 2,261:
floodfill($img, 100,100, 0, 0, 0);
$img->save("filledcirc1.jpg");
exit 0;</langsyntaxhighlight>
 
This fills better than the Image::Imlib2 <tt>fill</tt> function the inner circle, since because of JPG compression and thanks to the <tt>$distparameter</tt>, it "sees" as black also pixel that are no more exactly black.
 
=={{header|Phix}}==
{{Trans|Go}}
Requires read_ppm() from [[Bitmap/Read_a_PPM_file#Phix|Read_a_PPM_fileRead a PPM file]], write_ppm() from [[Bitmap/Write_a_PPM_file#Phix|Write_a_PPM_fileWrite a PPM file]]. <br>
Uses the output of Bitmap_Circle.exw[[Bitmap/Midpoint_circle_algorithm#Phix|Midpoint circle algorithm]] (Circle.ppm), results may be verified with demo\rosetta\viewppm.exw
Working<syntaxhighlight program islang="phix">-- demo\rosetta\Bitmap_FloodFill.exw, results may(runnable be verified with demo\rosetta\viewppm.exwversion)
include ppm.e -- blue, green, read_ppm(), write_ppm() (covers above requirements)
<lang Phix>function ff(sequence img, integer x, integer y, integer colour, integer target)
 
if x>=1 and x<=length(img)
function ff(sequence img, integer x, y, colour, target)
if x>=1 and x<=length(img)
and y>=1 and y<=length(img[x])
and img[x][y]=target then
Line 1,755 ⟶ 2,284:
end function
 
function FloodFill(sequence img, integer x, integer y, integer colour)
integer target = img[x][y]
return ff(img,x,y,colour,target)
end function
 
sequence img = read_ppm("Circle.ppm")
img = FloodFill(img, 200, 100, blue)
write_ppm("FloodIn.ppm",img)
img = FloodFill(img, 10, 10, green)
write_ppm("FloodOut.ppm",img)</langsyntaxhighlight>
 
 
=={{header|PicoLisp}}==
Using the format of [[Bitmap#PicoLisp|Bitmap]], a minimal recursive solution:
<langsyntaxhighlight PicoLisplang="picolisp">(de ppmFloodFill (Ppm X Y Color)
(let Target (get Ppm Y X)
(recur (X Y)
Line 1,778 ⟶ 2,305:
(recurse X (dec Y))
(recurse X (inc Y)) ) ) )
Ppm )</langsyntaxhighlight>
Test using 'ppmRead' from [[Bitmap/Read a PPM file#PicoLisp]] and 'ppmWrite' from [[Bitmap/Write a PPM file#PicoLisp]], filling the white area with red:
<pre>(ppmWrite
(ppmFloodFill (ppmRead "Unfilledcirc.ppm") 192 128 (255 0 0))
"Filledcirc.ppm" )</pre>
 
=={{header|PL/I}}==
<langsyntaxhighlight PLlang="pl/Ii">fill: procedure (x, y, fill_color) recursive; /* 12 May 2010 */
declare (x, y) fixed binary;
declare fill_color bit (24) aligned;
Line 1,810 ⟶ 2,336:
if pixel_color = area_color then call fill (x, y+1, fill_color);
 
end fill;</langsyntaxhighlight>
The following PL/I statements change the color of the white area
of the sample image to red, and the central orb to green.
<syntaxhighlight lang="text">
/* Fill the white area of the suggested image with red color. */
area_color = (24)'1'b;
Line 1,821 ⟶ 2,347:
area_color = '0'b;
call fill (125, 125, '000000001111111100000000'b );
</syntaxhighlight>
</lang>
=={{header|Processing}}==
<syntaxhighlight lang="java">import java.awt.Point;
import java.util.Queue;
import java.util.LinkedList;
 
PImage img;
int tolerance;
color fill_color;
boolean allowed;
 
void setup() {
size(600, 400);
img = loadImage("image.png");
fill_color = color(250, 0, 0);
fill(0, 0, 100);
tolerance = 15;
image(img, 0, 0, width, height);
textSize(18);
text("Tolerance = "+tolerance+" (Use mouse wheel to change)", 100, height-30);
text("Right click to reset", 100, height-10);
}
 
void draw() {
if (allowed) {
image(img, 0, 0, width, height);
text("Tolerance = "+tolerance+" (Use mouse wheel to change)", 100, height-30);
text("Right click to reset", 100, height-10);
allowed = false;
}
}
 
void mousePressed() {
if (mouseButton == RIGHT) {
img = loadImage("image.png");
} else {
img.loadPixels();
flood(mouseX, mouseY);
img.updatePixels();
allowed = true;
}
}
 
void mouseWheel(MouseEvent event) {
float e = event.getCount();
tolerance += 2*e;
if (tolerance > 128) tolerance = 128;
if (tolerance < 0) tolerance = 0;
allowed = true;
}
 
void flood(int x, int y) {
color target_color = img.pixels[pixel_position(mouseX, mouseY)];
if (target_color != fill_color) {
Queue<Point> queue = new LinkedList<Point>();
queue.add(new Point(x, y));
while (!queue.isEmpty()) {
Point p = queue.remove();
if (check(p.x, p.y, target_color)) {
queue.add(new Point(p.x, p.y-1));
queue.add(new Point(p.x, p.y+1));
queue.add(new Point(p.x-1, p.y));
queue.add(new Point(p.x+1, p.y));
}
}
}
}
 
int pixel_position(int x, int y) {
return x + (y * img.width);
}
 
boolean check(int x, int y, color target_color) {
if (x < 0 || y < 0 || y >= img.height || x >= img.width) return false;
int pp = img.pixels[pixel_position(x, y)];
boolean test_tolerance = (abs(green(target_color)-green(pp)) < tolerance
&& abs( red(target_color)- red(pp)) < tolerance
&& abs( blue(target_color)- blue(pp)) < tolerance);
if (!test_tolerance) return false;
img.pixels[pixel_position(x, y)] = fill_color;
return true;
}</syntaxhighlight>
 
==={{header|Processing Python mode}}===
<syntaxhighlight lang="python">from collections import deque
 
image_file = "image.png"
fill_color = color(250, 0, 0)
tolerance = 15
allowed = False
 
def setup():
global img
size(600, 400)
img = loadImage(image_file)
fill(0, 0, 100)
textSize(18)
show()
def show():
image(img, 0, 0, width, height)
text("Tolerance = {} (Use mouse wheel to change)".format(tolerance),
100, height - 30)
text("Right click to reset", 100, height - 10)
def draw():
global allowed
if allowed:
show()
allowed = False
 
def mousePressed():
global allowed, img
if mouseButton == RIGHT:
img = loadImage(image_file)
else:
img.loadPixels()
flood(mouseX, mouseY)
img.updatePixels()
allowed = True
 
def mouseWheel(event):
global allowed, tolerance
e = event.getCount()
tolerance += 2 * e
if tolerance > 128:
tolerance = 128
if tolerance < 0:
tolerance = 0
allowed = True
 
def flood(x, y):
target_color = img.pixels[pixel_position(mouseX, mouseY)]
if target_color != fill_color:
queue = deque()
queue.append((x, y))
while len(queue) > 0:
p_x, p_y = queue.popleft()
if (check(p_x, p_y, target_color)):
queue.append((p_x, p_y - 1))
queue.append((p_x, p_y + 1))
queue.append((p_x - 1, p_y))
queue.append((p_x + 1, p_y))
 
def pixel_position(x, y):
return x + (y * img.width)
 
def check(x, y, target_color):
if x < 0 or y < 0 or y >= img.height or x >= img.width:
return False
pp = img.pixels[pixel_position(x, y)]
test_tolerance = (abs(green(target_color) - green(pp)) < tolerance
and abs(red(target_color) - red(pp)) < tolerance
and abs(blue(target_color) - blue(pp)) < tolerance)
if not test_tolerance:
return False
img.pixels[pixel_position(x, y)] = fill_color
return True</syntaxhighlight>
=={{header|PureBasic}}==
=== built-in ===
<langsyntaxhighlight PureBasiclang="purebasic">FillArea(0,0,-1,$ff)
; Fills an Area in red</langsyntaxhighlight>
 
=== Iterative ===
<langsyntaxhighlight PureBasiclang="purebasic"> Procedure Floodfill(x,y,new_color)
old_color = Point(x,y)
NewList stack.POINT()
Line 1,858 ⟶ 2,540:
Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow
EndIf</langsyntaxhighlight>
 
=={{header|Python}}==
<langsyntaxhighlight lang="python">
import Image
def FloodFill( fileName, initNode, targetColor, replaceColor ):
Line 1,906 ⟶ 2,587:
break
return img
</syntaxhighlight>
</lang>
 
===Usage example===
<langsyntaxhighlight lang="python">
# "FloodFillClean.png" is name of input file
# [55,55] the x,y coordinate where fill starts
Line 1,917 ⟶ 2,598:
#The resulting image is saved as Filled.png
img.save( "Filled.png" )
</syntaxhighlight>
</lang>
 
 
=={{header|R}}==
'''Stack-based recursive version'''
<syntaxhighlight lang="r">
<lang R>
library(png)
img <- readPNG("Unfilledcirc.png")
Line 1,946 ⟶ 2,625:
 
image(M, col = c(1, 0, 2))
</syntaxhighlight>
</lang>
'''Queue-based version (Forest Fire algorithm)'''
<syntaxhighlight lang="r">
<lang R>
library(png)
img <- readPNG("Unfilledcirc.png")
Line 1,986 ⟶ 2,665:
 
image(M, col = c(1, 0, 2, 3))
</syntaxhighlight>
</lang>
 
=={{header|Racket}}==
<langsyntaxhighlight lang="racket">
#lang racket
 
Line 2,072 ⟶ 2,750:
;; ... and after:
bm
</syntaxhighlight>
</lang>
=={{header|Raku}}==
(formerly Perl 6)
{{works with|Rakudo|2019.11}}
Using bits and pieces from various other bitmap tasks.
 
<syntaxhighlight lang="raku" line>class Pixel { has Int ($.R, $.G, $.B) }
class Bitmap {
has Int ($.width, $.height);
has Pixel @.data;
 
method pixel(
$i where ^$!width,
$j where ^$!height
--> Pixel
) is rw { @!data[$i + $j * $!width] }
}
 
role PPM {
method P6 returns Blob {
"P6\n{self.width} {self.height}\n255\n".encode('ascii')
~ Blob.new: flat map { .R, .G, .B }, self.data
}
}
 
sub load-ppm ( $ppm ) {
my $fh = $ppm.IO.open( :enc('ISO-8859-1') );
my $type = $fh.get;
my ($width, $height) = $fh.get.split: ' ';
my $depth = $fh.get;
Bitmap.new( width => $width.Int, height => $height.Int,
data => ( $fh.slurp.ords.rotor(3).map:
{ Pixel.new(R => $_[0], G => $_[1], B => $_[2]) } )
)
}
 
sub color-distance (Pixel $c1, Pixel $c2) {
sqrt( ( ($c1.R - $c2.R)² + ($c1.G - $c2.G)² + ($c1.B - $c2.B)² ) / ( 255 * sqrt(3) ) );
}
 
sub flood ($img, $x, $y, $c1) {
my $c2 = $img.pixel($x, $y);
my $max-distance = 10;
my @queue;
my %checked;
check($x, $y);
for @queue -> [$x, $y] {
$img.pixel($x, $y) = $c1.clone;
}
 
sub check ($x, $y) {
my $c3 = $img.pixel($x, $y);
 
if color-distance($c2, $c3) < $max-distance {
@queue.push: [$x,$y];
@queue.elems;
%checked{"$x,$y"} = 1;
check($x - 1, $y) if $x > 0 and %checked{"{$x - 1},$y"}:!exists;
check($x + 1, $y) if $x < $img.width - 1 and %checked{"{$x + 1},$y"}:!exists;
check($x, $y - 1) if $y > 0 and %checked{"$x,{$y - 1}"}:!exists;
check($x, $y + 1) if $y < $img.height - 1 and %checked{"$x,{$y + 1}"}:!exists;
}
}
}
 
my $infile = './Unfilled-Circle.ppm';
 
my Bitmap $b = load-ppm( $infile ) but PPM;
 
flood($b, 5, 5, Pixel.new(:255R, :0G, :0B));
flood($b, 5, 125, Pixel.new(:255R, :0G, :0B));
flood($b, 125, 5, Pixel.new(:255R, :0G, :0B));
flood($b, 125, 125, Pixel.new(:255R, :0G, :0B));
flood($b, 50, 50, Pixel.new(:0R, :0G, :255B));
 
my $outfile = open('./Bitmap-flood-perl6.ppm', :w, :bin);
 
$outfile.write: $b.P6;
</syntaxhighlight>
 
See output image [https://github.com/thundergnat/rc/blob/master/img/Bitmap-flood-perl6.png Bitmap-flood-perl6 ] (offsite image file, converted to PNG for ease of viewing)
=={{header|REXX}}==
{{trans|PL/I}}
<langsyntaxhighlight lang="rexx">/*REXX program demonstrates a method to perform a flood fill of an area. */
black= '000000000000000000000000'b /*define the black color (using bits).*/
red = '000000000000000011111111'b /* " " red " " " */
Line 2,084 ⟶ 2,839:
white= '111111111111111111111111'b /* " " white " " " */
/*image is defined to the test image. */
hx= 125; hy=125 hy= 125 /*define limits (X,Y) for the image. */
area= white; call fill 125, 25, red /*fill the white area in red. */
area= black; call fill 125, 125, green /*fill the center orb in green. */
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
fill: procedure expose image. hx hy area; parse arg x,y,fill_color /*obtain the args.*/
if x<1 | x>hx | y<1 | y>hy then return /*X or Y are outside of the image area*/
pixel= image.x.y /*obtain the color of the X,Y pixel. */
if pixel \== area then return /*the pixel has already been filled */
/*with the fill_color, or we are not */
/*within the area to be filled. */
image.x.y=fill_color fill_color /*color desired area with fill_color. */
pixel= @(x , y-1); if pixel==area then call fill x , y-1, fill_color /*north*/
pixel= @(x-1, y ); if pixel==area then call fill x-1, y , fill_color /*west */
pixel= @(x+1, y ); if pixel==area then call fill x+1, y , fill_color /*east */
pixel= @(x , y+1); if pixel==area then call fill x , y+1, fill_color /*south*/
return
/*──────────────────────────────────────────────────────────────────────────────────────*/
@: parse arg $x,$y; return image.$x.$y /*return with color of the X,Y pixel.*/</langsyntaxhighlight>
<br><br>
 
=={{header|Ruby}}==
 
Uses [[Raster graphics operations/Ruby]]
'''Note''' This code is not completely functional. Please add the remaining classes (Pixel, ..) and initializers. Or maybe a library to be included to make this work.
 
<syntaxhighlight lang="ruby"># frozen_string_literal: true
<lang ruby>class RGBColour
 
def ==(a_colour)
require_relative 'raster_graphics'
values == a_colour.values
 
class RGBColour
def ==(other)
values == other.values
end
end
 
class Queue < Array
alias_method :enqueue, :push
alias_method :dequeue, :shift
end
 
Line 2,124 ⟶ 2,877:
current_colour = self[pixel.x, pixel.y]
queue = Queue.new
queue.enqueueenq(pixel)
until queue.empty?
p = queue.dequeuepop
ifnext unless self[p.x, p.y] == current_colour
 
west = find_border(p, current_colour, :west)
eastwest = find_border(p, current_colour, :eastwest)
east = draw_linefind_border(westp, eastcurrent_colour, new_colour:east)
draw_line(west, east, q = westnew_colour)
while q.x <= east.xwest
while q.x <= east.x
[:north, :south].each do |direction|
%i[north south].each do n = neighbour(q, |direction)|
n = queue.enqueueneighbour(n) if self[n.xq, n.y] == current_colourdirection)
queue.enq(n) if self[n.x, n.y] == current_colour
end
q = neighbour(q, :east)
end
q = neighbour(q, :east)
end
end
Line 2,163 ⟶ 2,916:
 
bitmap = Pixmap.new(300, 300)
bitmap.draw_circle(Pixel[149, 149], 120, RGBColour::BLACK)
bitmap.draw_circle(Pixel[200, 100], 40, RGBColour::BLACK)
bitmap.flood_fill(Pixel[140, 160], RGBColour::BLUE)</lang>
bitmap.save_as_png('flood_fill.png')</syntaxhighlight>
 
{{libheader|RubyGems}}
{{libheader|JRubyArt}}
JRubyArt is a port of Processing to the ruby language
 
<syntaxhighlight lang="ruby"># holder for pixel coords
Pixel = Struct.new(:x, :y)
 
attr_reader :img, :fill_color, :queue, :value
 
def setup
sketch_title 'Flood Fill'
@img = load_image(data_path('image.png'))
@fill_color = color(250, 0, 0)
end
 
def draw
image(img, 0, 0, width, height)
no_loop
end
 
def mouse_clicked
img.load_pixels
flood(mouse_x, mouse_y)
img.update_pixels
redraw
end
 
def flood(x, y)
@queue = Queue.new
queue.enq(Pixel.new(x, y))
until queue.empty?
pix = queue.pop
next unless check(pix, color(255))
 
queue.enq(Pixel.new(pix.x, pix.y - 1))
queue.enq(Pixel.new(pix.x, pix.y + 1))
queue.enq(Pixel.new(pix.x - 1, pix.y))
queue.enq(Pixel.new(pix.x + 1, pix.y))
end
end
 
def check(pix, target_color)
unless (1...width).include?(pix.x) && (1...height).include?(pix.y)
return false
end
 
value = img.pixels[pix.x + (pix.y * img.width)]
return false if target_color != value
 
img.pixels[pix.x + (pix.y * img.width)] = fill_color
true
end
 
def settings
size(256, 256)
end
</syntaxhighlight>
=={{header|Rust}}==
 
<syntaxhighlight lang="rust">
/* Naive Rust implementation of RosettaCode's Bitmap/Flood fill excercise.
*
* For the sake of simplicity this code reads PPM files (format specification can be found here: http://netpbm.sourceforge.net/doc/ppm.html ).
* The program assumes that the image has been created by GIMP in PPM ASCII mode and panics at any error.
*
* Also this program expects the input file to be in the same directory as the executable and named
* "input.ppm" and outputs a file in the same directory under the name "output.ppm".
*
*/
 
use std::fs::File; // Used for creating/opening files.
use std::io::{BufReader, BufRead, Write}; // Used for reading/writing files.
 
fn read_image(filename: String) -> Vec<Vec<(u8,u8,u8)>> {
let file = File::open(filename).unwrap();
let reader = BufReader::new(file);
let mut lines = reader.lines();
 
let _ = lines.next().unwrap(); // Skip P3 signature.
let _ = lines.next().unwrap(); // Skip GIMP comment.
 
let dimensions: (usize, usize) = {
let line = lines.next().unwrap().unwrap();
let values = line.split_whitespace().collect::<Vec<&str>>();
 
// We turn the &str vector that holds the width & height of the image into an usize tuplet.
(values[0].parse::<usize>().unwrap(),values[1].parse::<usize>().unwrap())
};
 
let _ = lines.next().unwrap(); // Skip maximum color value (we assume 255).
 
let mut image_data = Vec::with_capacity(dimensions.1);
 
for y in 0..dimensions.1 {
image_data.push(Vec::new());
for _ in 0..dimensions.0 {
// We read the R, G and B components and put them in the image_data vector.
image_data[y].push((lines.next().unwrap().unwrap().parse::<u8>().unwrap(),
lines.next().unwrap().unwrap().parse::<u8>().unwrap(),
lines.next().unwrap().unwrap().parse::<u8>().unwrap()));
}
}
 
image_data
}
 
fn write_image(image_data: Vec<Vec<(u8,u8,u8)>>) {
let mut file = File::create(format!("./output.ppm")).unwrap();
 
// Signature, then width and height, then 255 as max color value.
write!(file, "P3\n{} {}\n255\n", image_data.len(), image_data[0].len()).unwrap();
 
for row in &image_data {
// For performance reasons, we reserve a String with the necessary length for a line and
// fill that up before writing it to the file.
 
let mut line = String::with_capacity(row.len()*6); // 6 = r(space)g(space)b(space)
for (r,g,b) in row {
 
// &* is used to turn a String into a &str as needed by push_str.
line.push_str(&*format!("{} {} {} ", r,g,b));
}
 
write!(file, "{}", line).unwrap();
}
 
}
 
fn flood_fill(x: usize, y: usize, target: &(u8,u8,u8), replacement: &(u8,u8,u8), image_data: &mut Vec<Vec<(u8,u8,u8)>>) {
if &image_data[y][x] == target {
image_data[y][x] = *replacement;
 
if y > 0 {flood_fill(x,y-1, &target, &replacement, image_data);}
if x > 0 {flood_fill(x-1,y, &target, &replacement, image_data);}
if y < image_data.len()-1 {flood_fill(x,y+1, &target, &replacement, image_data);}
if x < image_data[0].len()-1 {flood_fill(x+1,y, &target, &replacement, image_data);}
}
}
 
fn main() {
let mut data = read_image(String::from("./input.ppm"));
 
flood_fill(1,50, &(255,255,255), &(0,255,0), &mut data); // Fill the big white circle with green.
flood_fill(40,35, &(0,0,0), &(255,0,0), &mut data); // Fill the small black circle with red.
 
write_image(data);
 
}</syntaxhighlight>
=={{header|Scala}}==
 
Line 2,173 ⟶ 3,075:
See [[Basic_bitmap_storage#Scala|Basic Bitmap Storage]] for RgbBitmap class.
 
<langsyntaxhighlight lang="scala">import java.awt.Color
import scala.collection.mutable
 
Line 2,215 ⟶ 3,117:
}
}
}</langsyntaxhighlight>
 
=={{header|Standard ML}}==
This implementation is imperative, updating the pixels of the image as it goes.
Line 2,222 ⟶ 3,123:
data structures instead.
 
<langsyntaxhighlight lang="sml">(* For simplicity, we're going to fill black-and-white images. Nothing
* fundamental would change if we used more colors. *)
datatype color = Black | White
Line 2,270 ⟶ 3,171:
 
(* Fill the image with black starting at the center. *)
val () = fill test Black (3,3)</langsyntaxhighlight>
 
=={{header|Tcl}}==
{{libheader|Tk}}
{{tcllib|struct::queue}}
Using code from [[Basic bitmap storage#Tcl|Basic bitmap storage]], [[Bresenham's line algorithm#Tcl|Bresenham's line algorithm]] and [[Midpoint circle algorithm#Tcl|Midpoint circle algorithm]]
<langsyntaxhighlight lang="tcl">package require Tcl 8.5
package require Tk
package require struct::queue
Line 2,349 ⟶ 3,249:
toplevel .flood
label .flood.l -image $img
pack .flood.l</langsyntaxhighlight>
Results in:
 
[[Image:Tcl_flood_fill.png]]
=={{header|Wren}}==
{{libheader|DOME}}
This script uses the same 'flood fill' routine as the Go entry.
 
It draws 3 concentric squares on the canvas colored yellow, red and white.
 
When the up arrow is pressed, the red square changes to blue and when the down arrow is pressed the blue square turns back to red.
<syntaxhighlight lang="wren">import "graphics" for Canvas, ImageData, Color
import "dome" for Window
import "input" for Keyboard
 
class Bitmap {
construct new(name, size) {
Window.title = name
Window.resize(size, size)
Canvas.resize(size, size)
size = size / 2
_bmp = ImageData.create(name, size, size)
_size = size
_flooded = false
}
 
init() {
var s = _size
var hs = s / 2
var qs = s / 4
fill(0, 0, s, s, Color.yellow)
fill(qs, qs, 3 * qs, 3 * qs, Color.red)
fill(qs * 1.5, qs * 1.5, qs * 2.5, qs * 2.5, Color.white)
_bmp.draw(hs, hs)
}
 
fill(s, t, w, h, col) {
for (x in s...w) {
for (y in t...h) pset(x, y, col)
}
}
 
flood(x, y, repl) {
var target = pget(x, y)
var ff // recursive closure
ff = Fn.new { |x, y|
if (x >= 0 && x < _bmp.width && y >= 0 && y < _bmp.height) {
var p = pget(x, y)
if (p.r == target.r && p.g == target.g && p.b == target.b) {
pset(x, y, repl)
ff.call(x-1, y)
ff.call(x+1, y)
ff.call(x, y-1)
ff.call(x, y+1)
}
}
}
ff.call(x, y)
}
 
pset(x, y, col) { _bmp.pset(x, y, col) }
 
pget(x, y) { _bmp.pget(x, y) }
 
update() {
var hs = _size / 2
var qs = _size / 4
if (!_flooded && Keyboard.isKeyDown("up")) {
flood(qs, qs, Color.blue)
_bmp.draw(hs, hs)
_flooded = true
} else if (_flooded && Keyboard.isKeyDown("down")) {
flood(qs, qs, Color.red)
_bmp.draw(hs, hs)
_flooded = false
}
}
 
draw(alpha) {}
}
 
var Game = Bitmap.new("Bitmap - flood fill", 600)</syntaxhighlight>
 
=={{header|XPL0}}==
[[File:FloodXPL0.gif|right|Output]]
<langsyntaxhighlight XPL0lang="xpl0">include c:\cxpl\codes;
 
proc Flood(X, Y, C, C0); \Fill an area of color C0 with color C
Line 2,415 ⟶ 3,393:
if ChIn(1) then []; \wait for keystroke
SetVid(3); \restore normal text mode
]</langsyntaxhighlight>
 
=={{header|zkl}}==
[[file:Flood_before.zkl.jpg|right]][[file:Flood.zkl.jpg|right]]
Line 2,422 ⟶ 3,399:
Uses the PPM class from http://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#zkl
 
<langsyntaxhighlight lang="zkl">fcn flood(pixmap, x,y, repl){ // slow!
targ,h,w:=pixmap[x,y], pixmap.h,pixmap.w;
stack:=List(T(x,y));
Line 2,435 ⟶ 3,412:
}
}
}</langsyntaxhighlight>
<langsyntaxhighlight lang="zkl">pixmap:=PPM(250,302,0xFF|FF|FF);
pixmap.circle(101,200,100,0); pixmap.circle(75,100,25,0);
 
Line 2,443 ⟶ 3,420:
flood(pixmap, 75,100, 0x00|00|F0);
 
pixmap.writeJPGFile("flood.zkl.jpg");</langsyntaxhighlight>
 
{{omit from|AWK}}
{{omit from|Computer/zero Assembly|this language doesn't support video output and only has 32 bytes of RAM}}
{{omit from|Lotus 123 Macro Scripting}}
{{omit from|PARI/GP}}
Anonymous user