From 68c779cfe1e08b43d2322cae9b422259d4ee3f3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E4=BC=9F?= Date: Mon, 27 Apr 2026 13:36:44 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B0=94=E6=B3=A1=E6=B5=8B=E9=87=8F=EF=BC=9A?= =?UTF-8?q?=E7=94=BB=E7=AC=94=E6=B6=82=E6=8A=B9=E6=A0=87=E8=AE=B0=E3=80=81?= =?UTF-8?q?=E6=A9=A1=E7=9A=AE=E6=93=A6=E6=B8=85=E9=99=A4=E3=80=81ROI?= =?UTF-8?q?=E5=A4=96=E5=8F=AF=E6=AD=A3=E5=B8=B8=E6=8B=96=E5=8A=A8=E5=9B=BE?= =?UTF-8?q?=E5=83=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controls/PolygonRoiCanvas.xaml.cs | 89 +++++++++++++++++-- 1 file changed, 83 insertions(+), 6 deletions(-) diff --git a/XP.ImageProcessing.RoiControl/Controls/PolygonRoiCanvas.xaml.cs b/XP.ImageProcessing.RoiControl/Controls/PolygonRoiCanvas.xaml.cs index 816da59..9bcd2c7 100644 --- a/XP.ImageProcessing.RoiControl/Controls/PolygonRoiCanvas.xaml.cs +++ b/XP.ImageProcessing.RoiControl/Controls/PolygonRoiCanvas.xaml.cs @@ -386,6 +386,7 @@ namespace XP.ImageProcessing.RoiControl.Controls private int _bubbleThreshold = 128; private int _bubbleBrushSize = 5; private bool _bubbleBrushDragging; + private readonly System.Collections.Generic.Stack _bubbleUndoStack = new(); public void SetBubbleTool(BubbleSubTool tool) => _bubbleTool = tool; public void SetBubbleThreshold(int val) => _bubbleThreshold = val; @@ -1183,7 +1184,54 @@ namespace XP.ImageProcessing.RoiControl.Controls private void ApplyBrushAt(Point pos) { - // 画笔/橡皮:下一步实现 + if (_bubbleMask == null || !_bubbleRoi.HasValue) return; + + var roi = _bubbleRoi.Value; + int w = _bubbleMask.PixelWidth, h = _bubbleMask.PixelHeight; + int cx = (int)pos.X, cy = (int)pos.Y; + int r = _bubbleBrushSize; + bool erase = _bubbleTool == BubbleSubTool.Eraser; + + int roiX0 = Math.Max(0, (int)roi.X), roiY0 = Math.Max(0, (int)roi.Y); + int roiX1 = Math.Min(w, (int)roi.Right), roiY1 = Math.Min(h, (int)roi.Bottom); + + // 计算笔刷影响的矩形区域 + int x0 = Math.Max(roiX0, cx - r), y0 = Math.Max(roiY0, cy - r); + int x1 = Math.Min(roiX1, cx + r + 1), y1 = Math.Min(roiY1, cy + r + 1); + if (x0 >= x1 || y0 >= y1) return; + + int regionW = x1 - x0, regionH = y1 - y0; + int stride = w * 4; + + // 读取整行范围的像素 + var pixels = new byte[regionW * regionH * 4]; + _bubbleMask.CopyPixels(new System.Windows.Int32Rect(x0, y0, regionW, regionH), pixels, regionW * 4, 0); + + int r2 = r * r; + for (int py2 = y0; py2 < y1; py2++) + { + for (int px2 = x0; px2 < x1; px2++) + { + int dx = px2 - cx, dy = py2 - cy; + if (dx * dx + dy * dy > r2) continue; + + int idx = ((py2 - y0) * regionW + (px2 - x0)) * 4; + if (erase) + { + pixels[idx + 0] = 0; pixels[idx + 1] = 0; + pixels[idx + 2] = 0; pixels[idx + 3] = 0; + } + else + { + pixels[idx + 0] = 0; // B + pixels[idx + 1] = 140; // G + pixels[idx + 2] = 255; // R + pixels[idx + 3] = 180; // A + } + } + } + + _bubbleMask.WritePixels(new System.Windows.Int32Rect(x0, y0, regionW, regionH), pixels, regionW * 4, 0); } private void UpdateBubbleResult() @@ -1216,6 +1264,9 @@ namespace XP.ImageProcessing.RoiControl.Controls { if (_bubbleMask == null || !_bubbleRoi.HasValue || ImageSource == null) return; + // 保存快照用于撤销 + SaveMaskSnapshot(); + var roi = _bubbleRoi.Value; int px = (int)pos.X, py = (int)pos.Y; if (!roi.Contains(pos)) return; @@ -1310,6 +1361,26 @@ namespace XP.ImageProcessing.RoiControl.Controls return gray; } + private void SaveMaskSnapshot() + { + if (_bubbleMask == null) return; + int w = _bubbleMask.PixelWidth, h = _bubbleMask.PixelHeight; + int stride = w * 4; + var snapshot = new byte[stride * h]; + _bubbleMask.CopyPixels(snapshot, stride, 0); + _bubbleUndoStack.Push(snapshot); + } + + /// 撤销上一次魔棒/画笔操作 + public void UndoBubble() + { + if (_bubbleMask == null || _bubbleUndoStack.Count == 0) return; + var snapshot = _bubbleUndoStack.Pop(); + int w = _bubbleMask.PixelWidth, h = _bubbleMask.PixelHeight; + _bubbleMask.WritePixels(new System.Windows.Int32Rect(0, 0, w, h), snapshot, w * 4, 0); + UpdateBubbleResult(); + } + /// 清除气泡测量所有状态 public void ClearBubbleMeasure() { @@ -1327,6 +1398,7 @@ namespace XP.ImageProcessing.RoiControl.Controls _bubbleRoiResizing = false; _bubbleBrushDragging = false; _bubbleTool = BubbleSubTool.Roi; + _bubbleUndoStack.Clear(); } // 气泡工具切换事件 @@ -1657,11 +1729,16 @@ namespace XP.ImageProcessing.RoiControl.Controls } if ((_bubbleTool == BubbleSubTool.Brush || _bubbleTool == BubbleSubTool.Eraser) && _bubbleRoi.HasValue) { - _bubbleBrushDragging = true; - ApplyBrushAt(pos); - mainCanvas.CaptureMouse(); - e.Handled = true; - return; + // 只在 ROI 内才启动画笔,ROI 外不拦截,让图像正常拖动 + if (_bubbleRoi.Value.Contains(pos)) + { + SaveMaskSnapshot(); + _bubbleBrushDragging = true; + ApplyBrushAt(pos); + mainCanvas.CaptureMouse(); + e.Handled = true; + return; + } } // 魔棒在 MouseUp(CanvasClicked)中处理 }