Flood fill
というやつですね。昔はペイントルーチンなどと呼んだりしていましたが、グラフィックスをVRAM直描きしていた頃はよく作ったものです。
Windows APIのExtFloodFill
関数がまさにそれなのですが、なぜか.NET Frameworkには同様の機能がありません。C#からAPI呼び出ししてみましたがうまく使えませんでした。
ということで、アルゴリズム自体は単純なので昔を思い出しながら作ってみました。検索すればいろいろ見つかると思います。
クラスにしていますが、体裁や効率、エラー処理などはあまり考えていないので、適宜改良・改造してください。
C#
1class FloodFill
2{
3 private Bitmap mBitmap;
4 private int mWidth;
5 private int mHeight;
6 private Color mFillColor;
7 private Color mSeedColor;
8 Queue<Point> mQueue = new Queue<Point>();
9
10 public FloodFill(Bitmap iImage)
11 {
12 mBitmap = iImage;
13 mWidth = mBitmap.Width;
14 mHeight = mBitmap.Height;
15 }
16
17 public void Fill(int iStartX, int iStartY, Color iColor)
18 {
19 mFillColor = iColor;
20 mSeedColor = mBitmap.GetPixel(iStartX, iStartY);
21 mQueue.Enqueue(new Point(iStartX, iStartY));
22 while(mQueue.Count != 0)
23 {
24 Point pos = mQueue.Dequeue();
25 scanLine(pos);
26 }
27 }
28
29 private void scanLine(Point iPos)
30 {
31 if(!isFillArea(iPos.X, iPos.Y))
32 return;
33 // 指定位置から右方向に塗って右端を覚えておく
34 int x = iPos.X;
35 while(x < mWidth && isFillArea(x, iPos.Y))
36 {
37 mBitmap.SetPixel(x, iPos.Y, mFillColor);
38 x++;
39 }
40 int right = x - 1;
41 // 指定位置から左方向に塗って左端を覚えておく
42 x = iPos.X - 1;
43 while(x >= 0 && isFillArea(x, iPos.Y))
44 {
45 mBitmap.SetPixel(x, iPos.Y, mFillColor);
46 x--;
47 }
48 int left = x + 1;
49
50 // 左端から右端の上下のラインをスキャンして塗りつぶし位置をキューに入れる
51 bool upperFound = false;
52 bool lowerFound = false;
53 for(x = left; x <= right; x++)
54 {
55 bool scan = isFillArea(x, iPos.Y - 1);
56 if(!upperFound)
57 {
58 if(scan)
59 {
60 mQueue.Enqueue(new Point(x, iPos.Y - 1));
61 upperFound = true;
62 }
63 }
64 else
65 {
66 if(!scan)
67 {
68 upperFound = false;
69 }
70 }
71 scan = isFillArea(x, iPos.Y + 1);
72 if(!lowerFound)
73 {
74 if(scan)
75 {
76 mQueue.Enqueue(new Point(x, iPos.Y + 1));
77 lowerFound = true;
78 }
79 }
80 else
81 {
82 if(!scan)
83 {
84 lowerFound = false;
85 }
86 }
87 }
88 }
89
90 private bool isFillArea(int iX, int iY)
91 {
92 if(iY < 0 || iY >= mHeight)
93 return false;
94 return mBitmap.GetPixel(iX, iY) == mSeedColor;
95 }
96}
Fill
メソッドに塗りつぶしの開始座標と色を渡せば、その座標と同じ色の領域を指定した色で塗りつぶします。
分断された領域には届かないので、ドーナツの外側と内側の2回塗りつぶしを実行することになります。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/06/07 08:31
2016/06/07 08:42
2016/06/07 10:00
2016/06/07 14:39