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:
- get the coordinates where I clicked
- 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:
And if I click on the selected area:
The PictureBox
should look like this:
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();
}