气泡测量:画笔涂抹标记、橡皮擦清除、ROI外可正常拖动图像

This commit is contained in:
李伟
2026-04-27 13:36:44 +08:00
parent 179a6a6755
commit 68c779cfe1
@@ -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<byte[]> _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);
}
/// <summary>撤销上一次魔棒/画笔操作</summary>
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();
}
/// <summary>清除气泡测量所有状态</summary>
public void ClearBubbleMeasure()
{
@@ -1327,6 +1398,7 @@ namespace XP.ImageProcessing.RoiControl.Controls
_bubbleRoiResizing = false;
_bubbleBrushDragging = false;
_bubbleTool = BubbleSubTool.Roi;
_bubbleUndoStack.Clear();
}
// 气泡工具切换事件
@@ -1657,12 +1729,17 @@ namespace XP.ImageProcessing.RoiControl.Controls
}
if ((_bubbleTool == BubbleSubTool.Brush || _bubbleTool == BubbleSubTool.Eraser) && _bubbleRoi.HasValue)
{
// 只在 ROI 内才启动画笔,ROI 外不拦截,让图像正常拖动
if (_bubbleRoi.Value.Contains(pos))
{
SaveMaskSnapshot();
_bubbleBrushDragging = true;
ApplyBrushAt(pos);
mainCanvas.CaptureMouse();
e.Handled = true;
return;
}
}
// 魔棒在 MouseUpCanvasClicked)中处理
}