Implement a 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.

To accomplish the task, you need to implement just one of the possible algorithms (examples are on Wikipedia). Variations on the theme are allowed (e.g. adding a tolerance parameter or argument for color-matching of the banks or target color).

 
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.

// 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)
}