diff --git a/Ink Canvas/Helpers/MultiTouchInput.cs b/Ink Canvas/Helpers/MultiTouchInput.cs
index 40391fc0..f1a745b1 100644
--- a/Ink Canvas/Helpers/MultiTouchInput.cs
+++ b/Ink Canvas/Helpers/MultiTouchInput.cs
@@ -111,6 +111,14 @@ namespace Ink_Canvas.Helpers
///
/// 绘制点段到新的DrawingVisual
///
+ private static double PressureToVisualScale(float pressureFactor, bool ignorePressure)
+ {
+ if (ignorePressure)
+ return 1.0;
+ // 与 WPF 墨迹观感接近:0.5 为标称,压低变细、抬高变粗(预览此前固定 Pen 宽,等同忽略压感)
+ return Math.Max(0.22, Math.Min(2.1, 0.42 + 1.16 * pressureFactor));
+ }
+
private void DrawSegmentToNewVisual(int startIndex, int endIndex)
{
if (Stroke == null || Stroke.StylusPoints.Count == 0 || _visualCanvas == null) return;
@@ -118,6 +126,7 @@ namespace Ink_Canvas.Helpers
var points = Stroke.StylusPoints;
var drawingAttributes = Stroke.DrawingAttributes;
+ var ignorePressure = drawingAttributes.IgnorePressure;
// 创建新的DrawingVisual用于绘制这个点段
var segmentVisual = new DrawingVisual();
@@ -128,11 +137,6 @@ namespace Ink_Canvas.Helpers
using (var dc = segmentVisual.RenderOpen())
{
- var pen = new Pen(new SolidColorBrush(drawingAttributes.Color), drawingAttributes.Width);
- pen.StartLineCap = PenLineCap.Round;
- pen.EndLineCap = PenLineCap.Round;
- pen.LineJoin = PenLineJoin.Round;
-
// 绘制指定范围内的点段
if (endIndex - startIndex >= 2)
{
@@ -141,6 +145,15 @@ namespace Ink_Canvas.Helpers
{
var startPoint = new Point(points[i].X, points[i].Y);
var endPoint = new Point(points[i + 1].X, points[i + 1].Y);
+ var s0 = PressureToVisualScale(points[i].PressureFactor, ignorePressure);
+ var s1 = PressureToVisualScale(points[i + 1].PressureFactor, ignorePressure);
+ var thickness = Math.Max(0.35, (drawingAttributes.Width * s0 + drawingAttributes.Width * s1) / 2.0);
+ var pen = new Pen(new SolidColorBrush(drawingAttributes.Color), thickness)
+ {
+ StartLineCap = PenLineCap.Round,
+ EndLineCap = PenLineCap.Round,
+ LineJoin = PenLineJoin.Round
+ };
dc.DrawLine(pen, startPoint, endPoint);
}
}
@@ -149,8 +162,9 @@ namespace Ink_Canvas.Helpers
// 只有一个点,绘制圆点
var brush = new SolidColorBrush(drawingAttributes.Color);
var point = points[startIndex];
+ var s = PressureToVisualScale(point.PressureFactor, ignorePressure);
dc.DrawEllipse(brush, null, new Point(point.X, point.Y),
- drawingAttributes.Width / 2, drawingAttributes.Height / 2);
+ drawingAttributes.Width * s / 2, drawingAttributes.Height * s / 2);
}
}
diff --git a/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs b/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs
index f0220b3c..48155dcf 100644
--- a/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs
+++ b/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs
@@ -180,16 +180,12 @@ namespace Ink_Canvas
var speed = GetPointSpeed(e.Stroke.StylusPoints[Math.Max(i - 1, 0)].ToPoint(),
e.Stroke.StylusPoints[i].ToPoint(),
e.Stroke.StylusPoints[Math.Min(i + 1, n)].ToPoint());
- var point = new StylusPoint();
- if (speed >= 0.25)
- point.PressureFactor = (float)(0.5 - 0.3 * (Math.Min(speed, 1.5) - 0.3) / 1.2);
- else if (speed >= 0.05)
- point.PressureFactor = (float)0.5;
- else
- point.PressureFactor = (float)(0.5 + 0.4 * (0.05 - speed) / 0.05);
-
- point.X = e.Stroke.StylusPoints[i].X;
- point.Y = e.Stroke.StylusPoints[i].Y;
+ var point = new StylusPoint
+ {
+ PressureFactor = RateBasedPressureFactorFromPointSpeed(speed),
+ X = e.Stroke.StylusPoints[i].X,
+ Y = e.Stroke.StylusPoints[i].Y
+ };
stylusPoints.Add(point);
}
@@ -423,16 +419,12 @@ namespace Ink_Canvas
var speed = GetPointSpeed(e.Stroke.StylusPoints[Math.Max(i - 1, 0)].ToPoint(),
e.Stroke.StylusPoints[i].ToPoint(),
e.Stroke.StylusPoints[Math.Min(i + 1, n)].ToPoint());
- var point = new StylusPoint();
- if (speed >= 0.25)
- point.PressureFactor = (float)(0.5 - 0.3 * (Math.Min(speed, 1.5) - 0.3) / 1.2);
- else if (speed >= 0.05)
- point.PressureFactor = (float)0.5;
- else
- point.PressureFactor = (float)(0.5 + 0.4 * (0.05 - speed) / 0.05);
-
- point.X = e.Stroke.StylusPoints[i].X;
- point.Y = e.Stroke.StylusPoints[i].Y;
+ var point = new StylusPoint
+ {
+ PressureFactor = RateBasedPressureFactorFromPointSpeed(speed),
+ X = e.Stroke.StylusPoints[i].X,
+ Y = e.Stroke.StylusPoints[i].Y
+ };
stylusPoints.Add(point);
}
@@ -498,7 +490,6 @@ namespace Ink_Canvas
// 会导致不进入逻辑或进入后渲染仍忽略 PressureFactor;具体在 ApplyVelocityBrushTipFromSpeed 内关闭。
if (Settings.Canvas.InkStyle == 3
&& !touchPressureSimulationApplied
- && !Settings.Canvas.DisablePressure
&& penType != 1
&& e.Stroke?.DrawingAttributes != null
&& !e.Stroke.DrawingAttributes.IsHighlighter
@@ -2124,8 +2115,49 @@ namespace Ink_Canvas
/ 20;
}
+ private static float RateBasedPressureFactorFromPointSpeed(double speed)
+ {
+ if (speed >= 0.25)
+ return (float)(0.5 - 0.3 * (Math.Min(speed, 1.5) - 0.3) / 1.2);
+ if (speed >= 0.05)
+ return 0.5f;
+ return (float)(0.5 + 0.4 * (0.05 - speed) / 0.05);
+ }
+
+ private static float RealtimeBrushTipMixRatePressureFromSpeed(double speed)
+ {
+ if (speed < 0) speed = 0;
+ const double slowRef = 0.012;
+ const double fastRef = 0.5;
+ var t = (speed - slowRef) / (fastRef - slowRef);
+ if (t < 0) t = 0;
+ else if (t > 1) t = 1;
+ t = t * t * (3.0 - 2.0 * t);
+ const double pThick = 0.9;
+ const double pThin = 0.22;
+ var p = pThick + (pThin - pThick) * t;
+ return (float)Math.Max(0.08, Math.Min(1.0, p));
+ }
+
+ private static bool IsStrokePressureApproximatelyConstant(StylusPointCollection pts, out float meanPf)
+ {
+ meanPf = 0.5f;
+ if (pts == null || pts.Count == 0) return true;
+ double sum = 0;
+ foreach (StylusPoint p in pts) sum += p.PressureFactor;
+ meanPf = (float)(sum / pts.Count);
+ const float tol = 0.04f;
+ foreach (StylusPoint p in pts)
+ {
+ if (Math.Abs(p.PressureFactor - meanPf) > tol)
+ return false;
+ }
+
+ return true;
+ }
+
///
- /// 将沿线速度映射为压感并与硬件压感混合,快写略细、慢写略粗;与 Inkeys 中 RTSSpeed 驱动的笔锋类似,在落笔后统一施加。
+ /// 将沿线速度映射为压感并与硬件压感混合,快写略细、慢写略粗;在落笔时(及手写笔移动时由调用方)统一施加。
/// 无压感设备上系统可能将 置为 true,此处强制关闭以便粗细随合成压感变化(与「屏蔽压感」无关:调用方已保证未屏蔽)。
///
private void ApplyVelocityBrushTipFromSpeed(Stroke stroke)
@@ -2142,6 +2174,10 @@ namespace Ink_Canvas
var pts = stroke.StylusPoints;
if (pts.Count < 3) return;
+ var effectiveMix = (float)mix;
+ if (IsStrokePressureApproximatelyConstant(pts, out _))
+ effectiveMix = Math.Max(effectiveMix, 0.78f);
+
var n = pts.Count - 1;
var stylusPoints = new StylusPointCollection();
@@ -2152,18 +2188,10 @@ namespace Ink_Canvas
pts[i].ToPoint(),
pts[Math.Min(i + 1, n)].ToPoint());
- float speedPressure;
- if (speed >= 0.25)
- speedPressure = (float)(0.5 - 0.3 * (Math.Min(speed, 1.5) - 0.3) / 1.2);
- else if (speed >= 0.05)
- speedPressure = 0.5f;
- else
- speedPressure = (float)(0.5 + 0.4 * (0.05 - speed) / 0.05);
-
- speedPressure = (float)Math.Max(0.08, Math.Min(1.0, speedPressure));
+ var speedPressure = RealtimeBrushTipMixRatePressureFromSpeed(speed);
var basePf = pts[i].PressureFactor;
- var blended = (float)((1.0 - mix) * basePf + mix * speedPressure);
+ var blended = (1.0f - effectiveMix) * basePf + effectiveMix * speedPressure;
blended = (float)Math.Max(0.08, Math.Min(1.0, blended));
var p = new StylusPoint(pts[i].X, pts[i].Y, blended);
diff --git a/Ink Canvas/MainWindow_cs/MW_TouchEvents.cs b/Ink Canvas/MainWindow_cs/MW_TouchEvents.cs
index 48f46d7e..7f44331e 100644
--- a/Ink Canvas/MainWindow_cs/MW_TouchEvents.cs
+++ b/Ink Canvas/MainWindow_cs/MW_TouchEvents.cs
@@ -542,7 +542,23 @@ namespace Ink_Canvas
var stylusPointCollection = e.GetStylusPoints(this);
foreach (var stylusPoint in stylusPointCollection)
strokeVisual.Add(new StylusPoint(stylusPoint.X, stylusPoint.Y, stylusPoint.PressureFactor));
- strokeVisual.Redraw();
+
+ // 实时笔锋:在绘制过程中更新压感并整笔重绘预览;否则预览层固定线宽,收笔后改点集也看不到笔锋变化。
+ var committedStroke = strokeVisual.Stroke;
+ if (committedStroke != null
+ && Settings.Canvas.InkStyle == 3
+ && penType == 0
+ && committedStroke.DrawingAttributes != null
+ && !committedStroke.DrawingAttributes.IsHighlighter
+ && committedStroke.StylusPoints.Count >= 3)
+ {
+ ApplyVelocityBrushTipFromSpeed(committedStroke);
+ strokeVisual.ForceRedraw();
+ }
+ else
+ {
+ strokeVisual.Redraw();
+ }
}
catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex); }
}
diff --git a/Ink Canvas/Resources/Settings.cs b/Ink Canvas/Resources/Settings.cs
index 88eef9c6..303d5102 100644
--- a/Ink Canvas/Resources/Settings.cs
+++ b/Ink Canvas/Resources/Settings.cs
@@ -147,7 +147,7 @@ namespace Ink_Canvas
[JsonProperty("eraserAutoSwitchBackDelaySeconds")]
public int EraserAutoSwitchBackDelaySeconds { get; set; } = 10; // 默认10秒
[JsonProperty("velocityBrushTipMix")]
- public double VelocityBrushTipMix { get; set; } = 0.22;
+ public double VelocityBrushTipMix { get; set; } = 0.45;
[JsonProperty("enableVelocityBrushTip")]
public bool EnableVelocityBrushTip { get; set; }