Home > Net >  Fill a section with color inside PictureBox
Fill a section with color inside PictureBox

Time:06-06

I have to fill a section inside PicureBox with solid color. I've managed to do it with this code:

private void fillForm(object sender, MouseEventArgs e)
        {
            MouseEventArgs me = (MouseEventArgs)e;
            Point coordinates = me.Location; // get mouse click coordinates
            Graphics graphics = Graphics.FromImage(imageSection.Image);
            fillDownRight(coordinates);
            fillUpLeft(new Point(coordinates.X - 1, coordinates.Y));
            fillUpRight(new Point(coordinates.X, coordinates.Y - 1));
            fillDownLeft(new Point(coordinates.X - 1, coordinates.Y   1));
            graphics.Dispose();
            imageSection.Refresh();
        }

        private void fillDownRight(Point coordinates)
        {
            Bitmap bitmap = ((Bitmap)imageSection.Image);

            if (coordinates.Y < bitmap.Height && coordinates.X   1 < bitmap.Width)
            {
                int pixelColor = bitmap.GetPixel(coordinates.X, coordinates.Y).ToArgb();
                if (pixelColor != Color.Black.ToArgb() && pixelColor != pen.Color.ToArgb())
                {
                    bitmap.SetPixel(coordinates.X, coordinates.Y, pen.Color);
                    fillDownRight(new Point(coordinates.X, coordinates.Y   1));
                    fillDownRight(new Point(coordinates.X   1, coordinates.Y));
                }
            }
        }
        private void fillUpLeft(Point coordinates)
        {
            Bitmap bitmap = ((Bitmap)imageSection.Image);

            if (coordinates.Y >= Constants.coordinatesZero && coordinates.X >= Constants.coordinatesZero)
            {
                int pixelColor = bitmap.GetPixel(coordinates.X, coordinates.Y).ToArgb();
                if (pixelColor != Color.Black.ToArgb() && pixelColor != pen.Color.ToArgb())
                {
                    bitmap.SetPixel(coordinates.X, coordinates.Y, pen.Color);
                    fillUpLeft(new Point(coordinates.X, coordinates.Y - 1));
                    fillUpLeft(new Point(coordinates.X - 1, coordinates.Y));
                }
            }
        }

        private void fillUpRight(Point coordinates)
        {
            Bitmap bitmap = ((Bitmap)imageSection.Image);


            if (coordinates.Y >= Constants.coordinatesZero && coordinates.X < bitmap.Width)
            {
                int pixelColor = bitmap.GetPixel(coordinates.X, coordinates.Y).ToArgb();
                if (pixelColor != Color.Black.ToArgb() && pixelColor != pen.Color.ToArgb())
                {
                    bitmap.SetPixel(coordinates.X, coordinates.Y, pen.Color);
                    fillUpRight(new Point(coordinates.X, coordinates.Y - 1));
                    fillUpRight(new Point(coordinates.X   1, coordinates.Y));
                }
            }
        }

        private void fillDownLeft(Point coordinates)
        {
            Bitmap bitmap = ((Bitmap)imageSection.Image);
            if (coordinates.Y < bitmap.Height && coordinates.X > Constants.coordinatesZero)
            {
                int pixelColor = bitmap.GetPixel(coordinates.X, coordinates.Y).ToArgb();
                if (pixelColor != Color.Black.ToArgb() && pixelColor != pen.Color.ToArgb())
                {
                    bitmap.SetPixel(coordinates.X, coordinates.Y, pen.Color);
                    fillDownLeft(new Point(coordinates.X - 1, coordinates.Y));
                    fillDownLeft(new Point(coordinates.X, coordinates.Y   1));
                }
            }
        }

So basically my code does the following:

  1. get the coordinates where I clicked
  2. then if fills recursively all "blank" pixels(that doesn't have a color) until it finds a colored/black pixel

My PictureBox kind of looks like this:

enter image description here

And if I click on the selected area: enter image description here

The PictureBox should look like this: enter image description here

I want to ask if there is a faster/better way to fill the section.

CodePudding user response:

I wrote code for flood-fill using LinkedList<>. Using Stack<> seems slower as it has to resize its inner array when it gets filled. (Source code of Stack<>)

static class FloodFill
{
    public static void Fill(this Bitmap bitmap, Color sourceColor,
             Color newColor, int x, int y)
    {
        var sourceArgb = sourceColor.ToArgb();
        var newArgb = newColor.ToArgb();
        if (sourceArgb == newArgb)
        {
            return;
        }
        LinkedList<Point> list = new LinkedList<Point>();
        list.AddLast(new Point(x, y));
        do
        {
            x = list.Last.Value.X;
            y = list.Last.Value.Y;
            list.RemoveLast();
            if (x < 0 || x >= bitmap.Width || y < 0 || y >= bitmap.Height)
            {
                list.RemoveLast();
                continue;
            }
            if (bitmap.GetPixel(x, y).ToArgb() == sourceArgb)
            {
                bitmap.SetPixel(x, y, newColor);
                list.AddLast(new Point(x   1, y));
                list.AddLast(new Point(x - 1, y));
                list.AddLast(new Point(x, y   1));
                list.AddLast(new Point(x, y - 1));
            }
        }
        while (list.Last != null);
    }
}

Client code is

private void PictureBox1_MouseClick(object sender, MouseEventArgs e)
{
    Bitmap bitmap = pictureBox1.Image as Bitmap;
    bitmap.Fill(bitmap.GetPixel(e.X, e.Y), Color.Blue, e.X, e.Y);
    pictureBox1.Invalidate();
}
  • Related