fix.inkcanvas修复

This commit is contained in:
lincube
2026-07-10 10:01:27 +09:00
parent 96c6bde474
commit 0f56c33edd
2 changed files with 122 additions and 23 deletions

View File

@@ -77,11 +77,13 @@ public class InkCanvas : Control
}
var args = ToArgs(e);
var wasDuringInput = IsDuringInput;
_inputDictionary[e.Pointer.Id] = new InputInfo(args.StylusPoint);
e.Pointer.Capture(this);
if (EditingMode == InkCanvasEditingMode.Ink)
{
if (!IsDuringInput)
if (!wasDuringInput)
{
AvaloniaSkiaInkCanvas.WritingStart();
}
@@ -110,7 +112,6 @@ public class InkCanvas : Control
}
var args = ToArgs(e, inputInfo);
inputInfo.LastStylusPoint = args.StylusPoint;
if (EditingMode == InkCanvasEditingMode.Ink)
{
@@ -121,6 +122,7 @@ public class InkCanvas : Control
EraserMode.EraserMove(in args);
}
inputInfo.LastStylusPoint = args.StylusPoint;
base.OnPointerMoved(e);
}
@@ -137,7 +139,7 @@ public class InkCanvas : Control
return;
}
var args = ToArgs(e);
var args = ToArgs(e, inputInfo);
inputInfo.LastStylusPoint = args.StylusPoint;
if (EditingMode == InkCanvasEditingMode.Ink)
@@ -154,9 +156,33 @@ public class InkCanvas : Control
EraserMode.EraserUp(in args);
}
e.Pointer.Capture(null);
base.OnPointerReleased(e);
}
protected override void OnPointerCaptureLost(PointerCaptureLostEventArgs e)
{
if (_inputDictionary.Remove(e.Pointer.Id, out var inputInfo))
{
var args = new InkingModeInputArgs(e.Pointer.Id, inputInfo.LastStylusPoint, 0);
if (EditingMode == InkCanvasEditingMode.Ink)
{
AvaloniaSkiaInkCanvas.WritingUp(in args);
if (!IsDuringInput)
{
AvaloniaSkiaInkCanvas.WritingCompleted();
}
}
else if (EditingMode == InkCanvasEditingMode.EraseByPoint)
{
EraserMode.EraserUp(in args);
}
}
base.OnPointerCaptureLost(e);
}
class InputInfo
{
public InputInfo(InkStylusPoint lastStylusPoint)
@@ -173,42 +199,55 @@ public class InkCanvas : Control
private InkingModeInputArgs ToArgs(PointerEventArgs args, InputInfo? inputInfo = null)
{
PointerPoint currentPoint = args.GetCurrentPoint(AvaloniaSkiaInkCanvas);
var inkStylusPoint = ToInkStylusPoint(currentPoint);
InkStylusPoint? lastStylusPoint = inputInfo?.LastStylusPoint;
IReadOnlyList<InkStylusPoint>? stylusPointList = null;
var list = args.GetIntermediatePoints(AvaloniaSkiaInkCanvas);
if (list.Count > 1)
List<InkStylusPoint>? stylusPointList = null;
var intermediatePointList = args.GetIntermediatePoints(AvaloniaSkiaInkCanvas);
if (intermediatePointList.Count > 0)
{
stylusPointList = list.Select(ToInkStylusPoint)
.ToList();
var orderedIntermediatePointList = OrderIntermediatePoints(intermediatePointList, lastStylusPoint);
stylusPointList = new List<InkStylusPoint>(orderedIntermediatePointList.Count + 1);
foreach (var intermediatePoint in orderedIntermediatePointList)
{
var stylusPoint = ToInkStylusPoint(intermediatePoint, lastStylusPoint);
AddDistinctPoint(stylusPointList, stylusPoint);
lastStylusPoint = stylusPoint;
}
}
var inkStylusPoint = ToInkStylusPoint(currentPoint, lastStylusPoint);
if (stylusPointList is not null)
{
AddDistinctPoint(stylusPointList, inkStylusPoint);
}
return new InkingModeInputArgs(args.Pointer.Id, inkStylusPoint, args.Timestamp)
{
StylusPointList = stylusPointList,
StylusPointList = stylusPointList is { Count: > 0 } ? stylusPointList : null,
};
InkStylusPoint ToInkStylusPoint(PointerPoint point)
InkStylusPoint ToInkStylusPoint(PointerPoint point, InkStylusPoint? previousPoint)
{
var pressure = EnsurePressure(currentPoint.Properties.Pressure);
var contactRect = currentPoint.Properties.ContactRect;
var pressure = EnsurePressure(point.Properties.Pressure, previousPoint);
var contactRect = point.Properties.ContactRect;
var width = contactRect.Width;
var height = contactRect.Height;
if (inputInfo is not null)
if (previousPoint is not null)
{
if (width == 0 && inputInfo.LastStylusPoint.Width is { } lastWidth)
if (width == 0 && previousPoint.Value.Width is { } lastWidth)
{
width = lastWidth;
}
if (height == 0 && inputInfo.LastStylusPoint.Height is { } lastHeight)
if (height == 0 && previousPoint.Value.Height is { } lastHeight)
{
height = lastHeight;
}
}
var stylusPoint = new InkStylusPoint(currentPoint.Position.ToPoint2D(), pressure)
var stylusPoint = new InkStylusPoint(point.Position.ToPoint2D(), pressure)
{
Width = width != 0 ? width : null,
Height = height != 0 ? height : null,
@@ -217,20 +256,65 @@ public class InkCanvas : Control
return stylusPoint;
}
float EnsurePressure(float pressure)
float EnsurePressure(float pressure, InkStylusPoint? previousPoint)
{
// 这是一个修复补丁。在 Linux X11 上,如果前后两个点的压力是相同的,则后点将不会报告压力,此时 Avalonia 上将使用默认压力值 0.5 来填充压力值
// 为了避免压力值抖动,将压力值修正为上一个点的压力值
const float defaultPressure = InkStylusPoint.DefaultPressure;
if (inputInfo != null && (pressure == 0 || Math.Abs(pressure - defaultPressure) < 0.00001))
if (previousPoint is not null && (pressure == 0 || Math.Abs(pressure - defaultPressure) < 0.00001))
{
return inputInfo.LastStylusPoint.Pressure;
return previousPoint.Value.Pressure;
}
return pressure;
}
}
private static IReadOnlyList<PointerPoint> OrderIntermediatePoints(
IReadOnlyList<PointerPoint> intermediatePointList,
InkStylusPoint? previousPoint)
{
if (previousPoint is null || intermediatePointList.Count <= 1)
{
return intermediatePointList;
}
var firstDistance = GetDistanceSquared(previousPoint.Value, intermediatePointList[0]);
var lastDistance = GetDistanceSquared(previousPoint.Value, intermediatePointList[^1]);
if (lastDistance >= firstDistance)
{
return intermediatePointList;
}
var orderedList = intermediatePointList.ToList();
orderedList.Reverse();
return orderedList;
}
private static double GetDistanceSquared(InkStylusPoint point, PointerPoint pointerPoint)
{
var dx = point.X - pointerPoint.Position.X;
var dy = point.Y - pointerPoint.Position.Y;
return dx * dx + dy * dy;
}
private static void AddDistinctPoint(List<InkStylusPoint> pointList, InkStylusPoint point)
{
if (pointList.Count > 0 && AreSamePosition(pointList[^1], point))
{
return;
}
pointList.Add(point);
}
private static bool AreSamePosition(InkStylusPoint first, InkStylusPoint second)
{
const double tolerance = 0.001d;
return Math.Abs(first.X - second.X) < tolerance &&
Math.Abs(first.Y - second.Y) < tolerance;
}
#endregion
internal void AddChild(Control childControl)
@@ -279,4 +363,3 @@ public class InkCanvas : Control
}

View File

@@ -17,6 +17,7 @@ using SkiaSharp;
using System.Diagnostics;
using DotNetCampus.Inking.Interactives;
using DotNetCampus.Inking.Primitive;
using DotNetCampus.Inking.Utils;
using InkTransformContext = (DotNetCampus.Numerics.Geometry.BoundingBox2D VisibleBounds, DotNetCampus.Numerics.Geometry.SimilarityTransformation2D TransformToRoot);
@@ -134,7 +135,7 @@ public class AvaloniaSkiaInkCanvas : Control
if (_contextDictionary.TryGetValue(args.Id, out var context))
{
context.Stroke.AddPoint(args.StylusPoint);
context.Stroke.AddPoints(EnumerateStylusPoints(args));
InvalidateVisual();
}
}
@@ -145,7 +146,7 @@ public class AvaloniaSkiaInkCanvas : Control
if (_contextDictionary.Remove(args.Id, out var context))
{
context.Stroke.AddPoint(args.StylusPoint);
context.Stroke.AddPoints(EnumerateStylusPoints(args));
//_staticStrokeDictionary[context.Stroke.Id] = context.Stroke;
context.Stroke.SetAsStatic();
_staticStrokeList.Add(context.Stroke);
@@ -155,6 +156,21 @@ public class AvaloniaSkiaInkCanvas : Control
InvalidateVisual();
}
private static IEnumerable<InkStylusPoint> EnumerateStylusPoints(InkingModeInputArgs args)
{
if (args.StylusPointList is { Count: > 0 } stylusPointList)
{
foreach (var stylusPoint in stylusPointList)
{
yield return stylusPoint;
}
}
else
{
yield return args.StylusPoint;
}
}
public event EventHandler<AvaloniaSkiaInkCanvasStrokeCollectedEventArgs>? StrokeCollected;
public void WritingCompleted()