今回は自由曲線によって選択された部分の移動をおこないます。
Contents
マウスがクリックされたときの処理
まず範囲選択がされている状態でクリックされた場合を考えます。
移動範囲は矩形ではないのでちょっと面倒です。Bitmapと同じサイズのビットマップを別に作成し、先に取得したborderPointsをつかって黒い線を描画します。そしてクリックされた座標に対応する部分を赤で塗りつぶします。そして赤い部分を集めればそれが選択された点の集合ということになります。
その点に対応する色を取得してColorPointのリストをつくります。ColorPointクラスはこのようになっています。
ColorPointクラス
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
public class ColorPoint { public ColorPoint(int x, int y, Color color) { X = x; Y = y; Color = color; } public int X { get; set; } = 0; public int Y { get; set; } = 0; public Color Color { get; set; } } |
ColorPointのリストに座標と色を格納したら、これをもとに移動元のビットマップを作成します。
移動元のビットマップの幅はcolorPointsの最大値と最小値から求めることができます。そして移動元のビットマップにSetPixelメソッドをつかって描画していきます。
それから移動するわけですから移動元は白抜きになります。そのためにCreateBlankBitmapメソッドを自作しています。
CreateBlankBitmapメソッド
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public partial class UserControlImage : UserControl { List<ColorPoint> blankColorPoints = null; void CreateBlankBitmap(List<ColorPoint> pts) { blankColorPoints = new List<ColorPoint>(); foreach(ColorPoint cp in pts) { Color color = cp.Color; if(color != Color.FromArgb(0, 0, 0, 0)) color = Color.White; blankColorPoints.Add(new ColorPoint(cp.X, cp.Y, color)); } } } |
次に範囲選択がされている状態でクリックされた場合の処理は以下のようになります。
OnMouseDownForMoveFreeLineSelectionメソッド
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
public partial class UserControlImage : UserControl { void OnMouseDownForMoveFreeLineSelection(Point bitmapPoint) { Bitmap temp = new Bitmap(Bitmap.Width, Bitmap.Height); foreach(Point pt in borderPoints) temp.SetPixel(pt.X, pt.Y, Color.Black); FillColor(temp, bitmapPoint, Color.Red); List<ColorPoint> colorPoints = new List<ColorPoint>(); for(int x =0; x< Bitmap.Width; x++) { for(int y = 0; y < Bitmap.Height; y++) { Color color = temp.GetPixel(x, y); if(color.ToArgb() == Color.Red.ToArgb()) { colorPoints.Add(new ColorPoint(x, y, Bitmap.GetPixel(x, y))); } } } int pCount = borderPoints.Count; borderPoints.Clear(); // 自由曲線が閉じていない場合は全体が選択されてしまう。 // この場合はなにもしないで処理を終了する if(colorPoints.Count == Bitmap.Width * Bitmap.Height - pCount) { colorPoints.Clear(); ShowBitmap(Bitmap); return; } // 移動元は白(ただし透明部分は透明)にする if(colorPoints != null && colorPoints.Count > 0) { isMouseDownForMove = true; freeLineSelectionMoveStartLocationX = bitmapPoint.X; freeLineSelectionMoveStartLocationY = bitmapPoint.Y; CreateBlankBitmap(colorPoints); } // 移動元になるビットマップを作成する int minX = colorPoints.Min(x => x.X); int maxX = colorPoints.Max(x => x.X); int minY = colorPoints.Min(x => x.Y); int maxY = colorPoints.Max(x => x.Y); Bitmap bitmap = new Bitmap(maxX - minX + 1, maxY - minY +1); foreach(var cp in colorPoints) { bitmap.SetPixel(cp.X- minX, cp.Y- minY, cp.Color); } // 移動元になるビットマップが作成できたらBitmapRectangleにセットする BitmapRectangle = new BitmapRectangle(bitmap, new Rectangle(new Point(minX, minY), new Size(maxX-minX, maxY - minY))); this.rectangleMoveStartMousePosX = bitmapPoint.X; this.rectangleMoveStartMousePosY = bitmapPoint.Y; this.rectangleMoveStartLocationX = minX; this.rectangleMoveStartLocationY = minY; } } |
マウスを動かしたときの処理
次に選択された部分が移動しているときの処理を考えます。
まずBitmapRectangleを移動させます。そしてblankColorPointsが存在する場合、その部分を白く描画します。そしてBitmapRectangleに格納されたデータを描画します。
OnMouseMoveForMoveFreeLineSelectionメソッド
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public partial class UserControlImage : UserControl { void OnMouseMoveForMoveFreeLineSelection(Point bitmapPoint) { int xMove = bitmapPoint.X - rectangleMoveStartMousePosX; int yMove = bitmapPoint.Y - rectangleMoveStartMousePosY; BitmapRectangle.X = rectangleMoveStartLocationX + xMove; BitmapRectangle.Y = rectangleMoveStartLocationY + yMove; Bitmap newBitmap = new Bitmap(Bitmap); Graphics g = Graphics.FromImage(newBitmap); if(blankColorPoints != null) { foreach(var cp in blankColorPoints) newBitmap.SetPixel(cp.X, cp.Y, cp.Color); } g.DrawImage(BitmapRectangle.Bitmap, BitmapRectangle.Location); g.Dispose(); ShowBitmap(DrawBoderRectangle(newBitmap)); } } |
マウスボタンが離されたときの処理
そしてマウスボタンが離されたらOnMouseUpForMoveFreeLineSelectionメソッドが呼ばれます。isMouseDownForMoveフラグをクリアして、BitmapRectangle.UpdatePositionメソッドをよびます。ここは矩形の移動と同じです。
1 2 3 4 5 6 7 8 9 |
public partial class UserControlImage : UserControl { void OnMouseUpForMoveFreeLineSelection(Point bitmapPoint) { isMouseDownForMove = false; if(BitmapRectangle != null) BitmapRectangle.UpdatePosition(); } } |
UniteBitmapRectangleメソッドの修正
最後に移動したあと矩形以外の部分でマウスがクリックされるとUniteBitmapRectangleメソッドが呼ばれます。フィールド変数 blankColorPointsがあるので、このための処理を追加する必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
public partial class UserControlImage : UserControl { void UniteBitmapRectangle(Point mouseDownPoint) { Bitmap bitmap1 = new Bitmap(Bitmap); Graphics g = Graphics.FromImage(bitmap1); if(blankBitmap != null) { g.DrawImage(blankBitmap.Bitmap, blankBitmap.Location); blankBitmap.Dispose(); blankBitmap = null; } if(blankColorPoints != null) { foreach(var cp in blankColorPoints) bitmap1.SetPixel(cp.X, cp.Y, cp.Color); blankColorPoints.Clear(); } if(BitmapRectangle != null) { g.DrawImage(BitmapRectangle.Bitmap, BitmapRectangle.Location); g.Dispose(); BitmapRectangle.Dispose(); BitmapRectangle = null; } Bitmap = bitmap1; startPoint = new Point(-1, -1); endPoint = new Point(-1, -1); } } |
初期化にかんする処理
移動の途中で新しくファイルを読み込んだときのことも考えて、移動のときに使用したフィールド変数などをクリアしておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public partial class UserControlImage : UserControl { public void Init() { // スクロールに関する値をリセット ClearScrollInfo(); // BitmapRectangleをクリア ClearBitmapRectangle(); // UndoBufをクリア ClearUndoBufs(); if(borderPoints != null) borderPoints.Clear(); if(blankBitmap != null) blankBitmap.Dispose(); if(blankColorPoints != null) blankColorPoints.Clear(); EditMode = EditMode.Selection; } } |