(1 item) |
|
(1 item) |
|
(5 items) |
|
(1 item) |
|
(1 item) |
|
(2 items) |
|
(2 items) |
|
(4 items) |
|
(1 item) |
|
(6 items) |
|
(2 items) |
|
(4 items) |
|
(1 item) |
|
(4 items) |
|
(2 items) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(2 items) |
|
(2 items) |
|
(5 items) |
|
(3 items) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(3 items) |
|
(1 item) |
|
(1 item) |
|
(2 items) |
|
(8 items) |
|
(2 items) |
|
(7 items) |
|
(2 items) |
|
(2 items) |
|
(1 item) |
|
(2 items) |
|
(1 item) |
|
(2 items) |
|
(4 items) |
|
(1 item) |
|
(5 items) |
|
(1 item) |
|
(3 items) |
|
(2 items) |
|
(2 items) |
|
(8 items) |
|
(7 items) |
|
(3 items) |
|
(7 items) |
|
(6 items) |
|
(1 item) |
|
(2 items) |
|
(5 items) |
|
(5 items) |
|
(7 items) |
|
(3 items) |
|
(7 items) |
|
(16 items) |
|
(10 items) |
|
(27 items) |
|
(15 items) |
|
(15 items) |
|
(13 items) |
|
(16 items) |
|
(15 items) |
From time to time, people ask what the GDI+ equivalent of certain GDI operations are. Sometimes there is no equivalent, and it's usually for a good reason. For example, I've already written about why XOR isn't supported. More recently, someone asked about how to do a flood fill in GDI+ on the DOTNET-WINFORMS mailing list.
He was hoping to be able to convert a GDI+ Brush
object into a GDI32 HBRUSH
. If such a thing
were possible, that would have solved the problem, because GDI32 has the ExtFloodFill
API. However,
a GDI+ brush is a different kind of a thing from a GDI32 brush, so there's no way of converting between them.
Adrian Martin came up with a pragmatic solution to the problem. He suggested creating a bitmap containing the required fill pattern,
and then using that bitmap to create a bitmap-based GDI32 HBRUSH
. That's almost certainly the best solution, but I
was curious to see if an alternative solution was possible.
So I've written a function that generates a Region
object representing
the region that would be filled if a flood fill were done. This means you can write this kind of code:
Region r = FloodFill.FloodFillUtils.GetRegionForFloodFill(originalImage, e.X, e.Y); Bitmap bmp = new Bitmap(originalImage); using (Graphics g = Graphics.FromImage(bmp)) { using (Brush b = new LinearGradientBrush(new Rectangle(new Point(), bmp.Size), Color.Red, Color.Magenta, LinearGradientMode.Vertical)) { g.FillRegion(b, r); } }
Since the Graphcs.FillRegion
lets you use any GDI+ Brush
, I think this solves the original
problem - it lets you flood fill an area with any GDI+ Brush.
.
The following image illustrates why you probably don't want to do that in practice:
This was generated using the snippet above. And as you can see it looks rather ropey - it appears not to have gone quite up to the edge of the interior of the circle. The reason for this is that the circle in question was drawn with anti-aliasing enabled. Flood fills are essentially fundamentally incompatible with antialiasing. This is because flood fills use pixel colours to determine boundaries, while anti-aliasing works by messing with pixel colours at the boundaries. And since antialiasing is essential for high quality imagery, this pretty much relegates the simple pixel-oriented single-colour-based flood fill to the history books - it is not a useful technique in the modern world.
That's not to say that the notion of filling a bounded area is useless. It's just that you need a vector-oriented equivalent instead, and the algorithms involved for that are rather different. (It would also be possible to implement a much more sophisticated pixel-based flood fill that knew all about anti-aliasing and took it into account I suppose.)
Despite its essential uselessness, the code required to achieve it illustrates some potentially interesting techniques for mixing and matching GDI+ and GDI32. And there will doubtless be situations in which some people will want a flood fill despite its intrinsic problems, so here's the code.