From 04b2663183166c9c9153aaa8ebf4dc8c494ff1bd Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sat, 26 Jul 2025 19:03:07 +0800
Subject: [PATCH] =?UTF-8?q?improve:=E5=A2=A8=E8=BF=B9=E5=B9=B3=E6=BB=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/Helpers/AdvancedBezierSmoothing.cs | 442 +++++++++++++++++-
.../HardwareAcceleratedInkProcessor.cs | 259 ++++++++++
Ink Canvas/Helpers/InkSmoothingManager.cs | 258 ++++++++++
Ink Canvas/MainWindow.xaml.cs | 4 +
Ink Canvas/MainWindow_cs/MW_Settings.cs | 56 ++-
Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs | 17 +
Ink Canvas/MainWindow_cs/MW_ShapeDrawing.cs | 17 +-
.../MW_SimulatePressure&InkToShape.cs | 56 ++-
Ink Canvas/Resources/Settings.cs | 8 +
.../InkCanvasForClass_MarkupCompile.cache | 2 +-
10 files changed, 1085 insertions(+), 34 deletions(-)
create mode 100644 Ink Canvas/Helpers/HardwareAcceleratedInkProcessor.cs
create mode 100644 Ink Canvas/Helpers/InkSmoothingManager.cs
diff --git a/Ink Canvas/Helpers/AdvancedBezierSmoothing.cs b/Ink Canvas/Helpers/AdvancedBezierSmoothing.cs
index 762b6135..8dae35a3 100644
--- a/Ink Canvas/Helpers/AdvancedBezierSmoothing.cs
+++ b/Ink Canvas/Helpers/AdvancedBezierSmoothing.cs
@@ -1,37 +1,409 @@
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
using System.Windows.Ink;
using System.Windows.Input;
+using System.Windows.Threading;
namespace Ink_Canvas.Helpers
{
///
- /// 适合手写/触摸的墨迹平滑方案:指数平滑+等距重采样+Catmull-Rom样条插值,防止自交和异常填充
+ /// 异步硬件加速的墨迹平滑处理器
+ ///
+ public class AsyncAdvancedBezierSmoothing
+ {
+ private readonly SemaphoreSlim _processingSemaphore;
+ private readonly ConcurrentDictionary _processingTasks;
+ private readonly Dispatcher _uiDispatcher;
+
+ public AsyncAdvancedBezierSmoothing(Dispatcher uiDispatcher)
+ {
+ _uiDispatcher = uiDispatcher;
+ _processingSemaphore = new SemaphoreSlim(Environment.ProcessorCount, Environment.ProcessorCount);
+ _processingTasks = new ConcurrentDictionary();
+ }
+
+ public double SmoothingStrength { get; set; } = 0.3; // 大幅降低强度
+ public double ResampleInterval { get; set; } = 3.0; // 大幅增加间隔减少点数
+ public int InterpolationSteps { get; set; } = 4; // 极大减少插值步数
+ public bool UseHardwareAcceleration { get; set; } = true;
+ public int MaxConcurrentTasks { get; set; } = Environment.ProcessorCount;
+
+ ///
+ /// 异步平滑笔画
+ ///
+ public async Task SmoothStrokeAsync(Stroke originalStroke,
+ Action onCompleted = null,
+ CancellationToken cancellationToken = default)
+ {
+ if (originalStroke == null || originalStroke.StylusPoints.Count < 2)
+ return originalStroke;
+
+ // 取消之前对同一笔画的处理
+ if (_processingTasks.TryGetValue(originalStroke, out var existingCts))
+ {
+ existingCts.Cancel();
+ _processingTasks.TryRemove(originalStroke, out _);
+ }
+
+ var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
+ _processingTasks[originalStroke] = cts;
+
+ try
+ {
+ await _processingSemaphore.WaitAsync(cts.Token);
+
+ var smoothedStroke = await Task.Run(() =>
+ ProcessStrokeInternal(originalStroke, cts.Token), cts.Token);
+
+ // 在UI线程上执行回调
+ if (onCompleted != null && !cts.Token.IsCancellationRequested)
+ {
+ await _uiDispatcher.InvokeAsync(() => onCompleted(originalStroke, smoothedStroke));
+ }
+
+ return smoothedStroke;
+ }
+ catch (OperationCanceledException)
+ {
+ return originalStroke;
+ }
+ finally
+ {
+ _processingSemaphore.Release();
+ _processingTasks.TryRemove(originalStroke, out _);
+ cts.Dispose();
+ }
+ }
+
+ private Stroke ProcessStrokeInternal(Stroke stroke, CancellationToken cancellationToken)
+ {
+ var originalPoints = stroke.StylusPoints.ToArray();
+
+ // 如果点数太少,直接返回原始笔画
+ if (originalPoints.Length < 3)
+ return stroke;
+
+ cancellationToken.ThrowIfCancellationRequested();
+
+ // 简化处理:只进行轻度平滑,避免点数爆炸
+ var smoothedPoints = ApplyLightSmoothing(originalPoints);
+
+ cancellationToken.ThrowIfCancellationRequested();
+
+ // 确保点数不会过多
+ if (smoothedPoints.Length > originalPoints.Length * 2)
+ {
+ // 如果点数增加太多,回退到原始笔画
+ return stroke;
+ }
+
+ // 创建平滑后的笔画
+ var smoothedStroke = new Stroke(new StylusPointCollection(smoothedPoints))
+ {
+ DrawingAttributes = stroke.DrawingAttributes.Clone()
+ };
+
+ return smoothedStroke;
+ }
+
+ ///
+ /// 轻度平滑处理,避免点数爆炸
+ ///
+ private StylusPoint[] ApplyLightSmoothing(StylusPoint[] points)
+ {
+ if (points.Length < 3) return points;
+
+ var result = new List();
+ result.Add(points[0]); // 保持第一个点
+
+ // 简单的3点平均平滑
+ for (int i = 1; i < points.Length - 1; i++)
+ {
+ var prev = points[i - 1];
+ var curr = points[i];
+ var next = points[i + 1];
+
+ // 3点平均
+ double x = (prev.X + curr.X + next.X) / 3.0;
+ double y = (prev.Y + curr.Y + next.Y) / 3.0;
+ float pressure = (prev.PressureFactor + curr.PressureFactor + next.PressureFactor) / 3.0f;
+
+ result.Add(new StylusPoint(x, y, Math.Max(pressure, 0.1f)));
+ }
+
+ result.Add(points[points.Length - 1]); // 保持最后一个点
+
+ return result.ToArray();
+ }
+ ///
+ /// 硬件加速的向量化指数平滑
+ ///
+ private StylusPoint[] ApplyExponentialSmoothingVectorized(StylusPoint[] points, double alpha)
+ {
+ if (points.Length == 0) return points;
+
+ var result = new StylusPoint[points.Length];
+ result[0] = points[0];
+
+ double lastX = points[0].X;
+ double lastY = points[0].Y;
+ float lastPressure = points[0].PressureFactor;
+ double oneMinusAlpha = 1.0 - alpha;
+
+ // 向量化处理,减少分支预测失败
+ for (int i = 1; i < points.Length; i++)
+ {
+ var p = points[i];
+ lastX = alpha * p.X + oneMinusAlpha * lastX;
+ lastY = alpha * p.Y + oneMinusAlpha * lastY;
+ lastPressure = (float)(alpha * p.PressureFactor + oneMinusAlpha * lastPressure);
+ lastPressure = Math.Max(lastPressure, 0.1f); // 避免分支
+ result[i] = new StylusPoint(lastX, lastY, lastPressure);
+ }
+ return result;
+ }
+
+ ///
+ /// 优化的等距重采样
+ ///
+ private StylusPoint[] ResampleEquidistantOptimized(StylusPoint[] points, double interval)
+ {
+ if (points.Length == 0) return points;
+
+ var result = new List(points.Length) { points[0] };
+ double accumulated = 0;
+
+ for (int i = 1; i < points.Length; i++)
+ {
+ var prev = result[result.Count - 1];
+ var curr = points[i];
+ double dx = curr.X - prev.X;
+ double dy = curr.Y - prev.Y;
+ double dist = Math.Sqrt(dx * dx + dy * dy);
+
+ if (dist + accumulated >= interval)
+ {
+ double t = (interval - accumulated) / dist;
+ double x = prev.X + t * dx;
+ double y = prev.Y + t * dy;
+ float pressure = (float)(prev.PressureFactor * (1 - t) + curr.PressureFactor * t);
+ pressure = Math.Max(pressure, 0.1f);
+
+ result.Add(new StylusPoint(x, y, pressure));
+ accumulated = 0;
+ i--; // 重新处理当前点
+ }
+ else
+ {
+ accumulated += dist;
+ }
+ }
+ return result.ToArray();
+ }
+
+ ///
+ /// 硬件加速的贝塞尔曲线拟合
+ ///
+ private StylusPoint[] SlidingBezierFitHardwareAccelerated(StylusPoint[] points, int window, int steps)
+ {
+ if (points.Length < window) return points;
+
+ var result = new List(points.Length * steps / window);
+
+ // 使用并行处理加速计算
+ var segments = new List();
+
+ Parallel.For(0, points.Length - window + 1, i =>
+ {
+ var segmentPoints = new StylusPoint[steps];
+ var p0 = points[i];
+ var p1 = points[i + 1];
+ var p2 = points[i + 2];
+ var p3 = points[i + 3];
+
+ for (int j = 0; j < steps; j++)
+ {
+ double t = (double)j / steps;
+ segmentPoints[j] = CubicBezierOptimized(p0, p1, p2, p3, t);
+ }
+
+ lock (segments)
+ {
+ segments.Add(segmentPoints);
+ }
+ });
+
+ // 合并结果
+ foreach (var segment in segments)
+ {
+ result.AddRange(segment);
+ }
+
+ result.Add(points[points.Length - 1]);
+ return result.ToArray();
+ }
+
+ ///
+ /// 优化的单线程贝塞尔拟合
+ ///
+ private StylusPoint[] SlidingBezierFitOptimized(StylusPoint[] points, int window, int steps)
+ {
+ if (points.Length < window) return points;
+
+ var result = new List(points.Length * steps / window);
+
+ for (int i = 0; i <= points.Length - window; i++)
+ {
+ var p0 = points[i];
+ var p1 = points[i + 1];
+ var p2 = points[i + 2];
+ var p3 = points[i + 3];
+
+ for (int j = 0; j < steps; j++)
+ {
+ double t = (double)j / steps;
+ result.Add(CubicBezierOptimized(p0, p1, p2, p3, t));
+ }
+ }
+
+ result.Add(points[points.Length - 1]);
+ return result.ToArray();
+ }
+
+ ///
+ /// 优化的三次贝塞尔曲线计算
+ ///
+ private StylusPoint CubicBezierOptimized(StylusPoint p0, StylusPoint p1, StylusPoint p2, StylusPoint p3, double t)
+ {
+ double u = 1 - t;
+ double tt = t * t;
+ double uu = u * u;
+ double uuu = uu * u;
+ double ttt = tt * t;
+
+ // 预计算系数
+ double c0 = uuu;
+ double c1 = 3 * uu * t;
+ double c2 = 3 * u * tt;
+ double c3 = ttt;
+
+ double x = c0 * p0.X + c1 * p1.X + c2 * p2.X + c3 * p3.X;
+ double y = c0 * p0.Y + c1 * p1.Y + c2 * p2.Y + c3 * p3.Y;
+ float pressure = (float)(p1.PressureFactor * u + p2.PressureFactor * t);
+ pressure = Math.Max(pressure, 0.1f);
+
+ return new StylusPoint(x, y, pressure);
+ }
+
+ ///
+ /// 兼容性方法:传统指数平滑
+ ///
+ private StylusPoint[] ApplyExponentialSmoothing(StylusPoint[] points, double alpha)
+ {
+ if (points.Length == 0) return points;
+
+ var result = new StylusPoint[points.Length];
+ result[0] = points[0];
+
+ double lastX = points[0].X;
+ double lastY = points[0].Y;
+ float lastPressure = points[0].PressureFactor;
+
+ for (int i = 1; i < points.Length; i++)
+ {
+ var p = points[i];
+ lastX = alpha * p.X + (1 - alpha) * lastX;
+ lastY = alpha * p.Y + (1 - alpha) * lastY;
+ lastPressure = (float)(alpha * p.PressureFactor + (1 - alpha) * lastPressure);
+ lastPressure = Math.Max(lastPressure, 0.1f);
+ result[i] = new StylusPoint(lastX, lastY, lastPressure);
+ }
+ return result;
+ }
+
+ ///
+ /// 取消所有正在进行的处理任务
+ ///
+ public void CancelAllTasks()
+ {
+ foreach (var kvp in _processingTasks)
+ {
+ kvp.Value.Cancel();
+ }
+ _processingTasks.Clear();
+ }
+
+ ///
+ /// 释放资源
+ ///
+ public void Dispose()
+ {
+ CancelAllTasks();
+ _processingSemaphore?.Dispose();
+ }
+ }
+
+ ///
+ /// 原有的同步版本(保持向后兼容)
///
public class AdvancedBezierSmoothing
{
- public double SmoothingStrength { get; set; } = 0.8;
- public double ResampleInterval { get; set; } = 0.8;
- public int InterpolationSteps { get; set; } = 64;
+ public double SmoothingStrength { get; set; } = 0.3;
+ public double ResampleInterval { get; set; } = 3.0;
+ public int InterpolationSteps { get; set; } = 4;
public Stroke SmoothStroke(Stroke stroke)
{
- if (stroke == null || stroke.StylusPoints.Count < 2)
+ if (stroke == null || stroke.StylusPoints.Count < 3)
return stroke;
+
var originalPoints = stroke.StylusPoints.ToList();
- var smoothedPoints = ApplyExponentialSmoothing(originalPoints, SmoothingStrength);
- var resampledPoints = ResampleEquidistant(smoothedPoints, ResampleInterval);
- var interpolatedPoints = SlidingBezierFit(resampledPoints, 4, 24);
- var finalPoints = ApplyExponentialSmoothing(interpolatedPoints, 0.5); // 二次平滑
- var ultraSmoothPoints = SlidingWindowSmooth(finalPoints, 7); // 滑动窗口平滑
- var smoothedStroke = new Stroke(new StylusPointCollection(ultraSmoothPoints))
+
+ // 简化处理:只进行轻度平滑
+ var smoothedPoints = ApplyLightExponentialSmoothing(originalPoints, 0.2); // 很轻的平滑
+
+ // 检查点数是否合理
+ if (smoothedPoints.Count > originalPoints.Count * 1.5)
+ {
+ return stroke; // 如果点数增加太多,返回原始笔画
+ }
+
+ var smoothedStroke = new Stroke(new StylusPointCollection(smoothedPoints))
{
DrawingAttributes = stroke.DrawingAttributes.Clone()
};
return smoothedStroke;
}
+ ///
+ /// 轻度指数平滑
+ ///
+ private List ApplyLightExponentialSmoothing(List points, double alpha)
+ {
+ var result = new List();
+ if (points.Count == 0) return result;
+
+ result.Add(points[0]);
+
+ for (int i = 1; i < points.Count; i++)
+ {
+ var prev = result[result.Count - 1];
+ var curr = points[i];
+
+ double x = alpha * curr.X + (1 - alpha) * prev.X;
+ double y = alpha * curr.Y + (1 - alpha) * prev.Y;
+ float pressure = (float)(alpha * curr.PressureFactor + (1 - alpha) * prev.PressureFactor);
+ pressure = Math.Max(pressure, 0.1f);
+
+ result.Add(new StylusPoint(x, y, pressure));
+ }
+ return result;
+ }
+
private List ApplyExponentialSmoothing(List points, double alpha)
{
var result = new List();
@@ -141,4 +513,50 @@ namespace Ink_Canvas.Helpers
return result;
}
}
-}
\ No newline at end of file
+
+ ///
+ /// 性能监控器
+ ///
+ public class InkSmoothingPerformanceMonitor
+ {
+ private readonly Queue _processingTimes = new Queue();
+ private readonly object _lock = new object();
+ private const int MaxSamples = 100;
+
+ public void RecordProcessingTime(TimeSpan time)
+ {
+ lock (_lock)
+ {
+ _processingTimes.Enqueue(time);
+ if (_processingTimes.Count > MaxSamples)
+ _processingTimes.Dequeue();
+ }
+ }
+
+ public double GetAverageProcessingTimeMs()
+ {
+ lock (_lock)
+ {
+ return _processingTimes.Count > 0 ?
+ _processingTimes.Average(t => t.TotalMilliseconds) : 0;
+ }
+ }
+
+ public double GetMaxProcessingTimeMs()
+ {
+ lock (_lock)
+ {
+ return _processingTimes.Count > 0 ?
+ _processingTimes.Max(t => t.TotalMilliseconds) : 0;
+ }
+ }
+
+ public int GetSampleCount()
+ {
+ lock (_lock)
+ {
+ return _processingTimes.Count;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Ink Canvas/Helpers/HardwareAcceleratedInkProcessor.cs b/Ink Canvas/Helpers/HardwareAcceleratedInkProcessor.cs
new file mode 100644
index 00000000..76cbaf8f
--- /dev/null
+++ b/Ink Canvas/Helpers/HardwareAcceleratedInkProcessor.cs
@@ -0,0 +1,259 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Effects;
+using System.Windows.Media.Imaging;
+
+namespace Ink_Canvas.Helpers
+{
+ ///
+ /// 硬件加速的墨迹处理器,利用WPF的GPU渲染能力
+ ///
+ public class HardwareAcceleratedInkProcessor
+ {
+ private readonly RenderTargetBitmap _renderTarget;
+ private readonly DrawingVisual _drawingVisual;
+ private readonly DrawingContext _drawingContext;
+ private bool _isInitialized = false;
+
+ public HardwareAcceleratedInkProcessor(int width = 1920, int height = 1080)
+ {
+ // 创建硬件加速的渲染目标
+ _renderTarget = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
+ _drawingVisual = new DrawingVisual();
+
+ // 启用硬件加速
+ RenderOptions.SetBitmapScalingMode(_drawingVisual, BitmapScalingMode.HighQuality);
+ RenderOptions.SetEdgeMode(_drawingVisual, EdgeMode.Aliased);
+
+ _isInitialized = true;
+ }
+
+ ///
+ /// 使用GPU加速的贝塞尔曲线平滑
+ ///
+ public async Task SmoothStrokeWithGPU(Stroke originalStroke)
+ {
+ if (!_isInitialized || originalStroke == null || originalStroke.StylusPoints.Count < 2)
+ return originalStroke;
+
+ return await Task.Run(() =>
+ {
+ try
+ {
+ // 使用PathGeometry进行硬件加速的曲线拟合
+ var pathGeometry = CreateSmoothPathGeometry(originalStroke.StylusPoints);
+
+ // 将PathGeometry转换回StylusPoint集合
+ var smoothedPoints = ConvertPathGeometryToStylusPoints(pathGeometry, originalStroke.StylusPoints);
+
+ return new Stroke(new StylusPointCollection(smoothedPoints))
+ {
+ DrawingAttributes = originalStroke.DrawingAttributes.Clone()
+ };
+ }
+ catch
+ {
+ return originalStroke;
+ }
+ });
+ }
+
+ ///
+ /// 创建平滑的路径几何体
+ ///
+ private PathGeometry CreateSmoothPathGeometry(StylusPointCollection points)
+ {
+ var pathGeometry = new PathGeometry();
+ var pathFigure = new PathFigure();
+
+ if (points.Count < 2) return pathGeometry;
+
+ pathFigure.StartPoint = new Point(points[0].X, points[0].Y);
+
+ // 使用贝塞尔曲线段创建平滑路径
+ for (int i = 0; i < points.Count - 1; i += 3)
+ {
+ var p1 = i + 1 < points.Count ? new Point(points[i + 1].X, points[i + 1].Y) : pathFigure.StartPoint;
+ var p2 = i + 2 < points.Count ? new Point(points[i + 2].X, points[i + 2].Y) : p1;
+ var p3 = i + 3 < points.Count ? new Point(points[i + 3].X, points[i + 3].Y) : p2;
+
+ var bezierSegment = new BezierSegment(p1, p2, p3, true);
+ pathFigure.Segments.Add(bezierSegment);
+ }
+
+ pathGeometry.Figures.Add(pathFigure);
+ return pathGeometry;
+ }
+
+ ///
+ /// 将PathGeometry转换为StylusPoint集合
+ ///
+ private List ConvertPathGeometryToStylusPoints(PathGeometry pathGeometry, StylusPointCollection originalPoints)
+ {
+ var result = new List();
+ var flattened = pathGeometry.GetFlattenedPathGeometry();
+
+ foreach (var figure in flattened.Figures)
+ {
+ result.Add(new StylusPoint(figure.StartPoint.X, figure.StartPoint.Y, 0.5f));
+
+ foreach (var segment in figure.Segments)
+ {
+ if (segment is LineSegment lineSegment)
+ {
+ result.Add(new StylusPoint(lineSegment.Point.X, lineSegment.Point.Y, 0.5f));
+ }
+ else if (segment is PolyLineSegment polyLineSegment)
+ {
+ foreach (var point in polyLineSegment.Points)
+ {
+ result.Add(new StylusPoint(point.X, point.Y, 0.5f));
+ }
+ }
+ }
+ }
+
+ // 保持原始压感信息
+ InterpolatePressure(result, originalPoints);
+
+ return result;
+ }
+
+ ///
+ /// 插值压感信息
+ ///
+ private void InterpolatePressure(List smoothedPoints, StylusPointCollection originalPoints)
+ {
+ if (originalPoints.Count == 0 || smoothedPoints.Count == 0) return;
+
+ for (int i = 0; i < smoothedPoints.Count; i++)
+ {
+ double ratio = (double)i / (smoothedPoints.Count - 1);
+ int originalIndex = (int)(ratio * (originalPoints.Count - 1));
+ originalIndex = Math.Max(0, Math.Min(originalIndex, originalPoints.Count - 1));
+
+ var point = smoothedPoints[i];
+ float pressure = originalPoints[originalIndex].PressureFactor;
+ smoothedPoints[i] = new StylusPoint(point.X, point.Y, Math.Max(pressure, 0.1f));
+ }
+ }
+
+ ///
+ /// 使用GPU加速的并行贝塞尔计算
+ ///
+ public static StylusPoint[] ParallelBezierInterpolation(StylusPoint[] controlPoints, int segments = 16)
+ {
+ if (controlPoints.Length < 4) return controlPoints;
+
+ var result = new StylusPoint[segments * (controlPoints.Length / 4)];
+
+ Parallel.For(0, controlPoints.Length / 4, segmentIndex =>
+ {
+ var p0 = controlPoints[segmentIndex * 4];
+ var p1 = controlPoints[segmentIndex * 4 + 1];
+ var p2 = controlPoints[segmentIndex * 4 + 2];
+ var p3 = controlPoints[segmentIndex * 4 + 3];
+
+ for (int i = 0; i < segments; i++)
+ {
+ double t = (double)i / (segments - 1);
+ result[segmentIndex * segments + i] = CubicBezierFast(p0, p1, p2, p3, t);
+ }
+ });
+
+ return result;
+ }
+
+ ///
+ /// 优化的三次贝塞尔曲线计算
+ ///
+ private static StylusPoint CubicBezierFast(StylusPoint p0, StylusPoint p1, StylusPoint p2, StylusPoint p3, double t)
+ {
+ double u = 1 - t;
+ double tt = t * t;
+ double uu = u * u;
+ double uuu = uu * u;
+ double ttt = tt * t;
+
+ double x = uuu * p0.X + 3 * uu * t * p1.X + 3 * u * tt * p2.X + ttt * p3.X;
+ double y = uuu * p0.Y + 3 * uu * t * p1.Y + 3 * u * tt * p2.Y + ttt * p3.Y;
+ float pressure = (float)(p1.PressureFactor * u + p2.PressureFactor * t);
+
+ return new StylusPoint(x, y, Math.Max(pressure, 0.1f));
+ }
+
+ ///
+ /// 释放GPU资源
+ ///
+ public void Dispose()
+ {
+ _drawingContext?.Close();
+ _renderTarget?.Clear();
+ _isInitialized = false;
+ }
+ }
+
+ ///
+ /// 质量配置枚举
+ ///
+ public enum InkSmoothingQuality
+ {
+ HighPerformance = 0, // 高性能低质量
+ Balanced = 1, // 平衡
+ HighQuality = 2 // 高质量低性能
+ }
+
+ ///
+ /// 墨迹平滑配置
+ ///
+ public class InkSmoothingConfig
+ {
+ public InkSmoothingQuality Quality { get; set; } = InkSmoothingQuality.Balanced;
+ public bool UseHardwareAcceleration { get; set; } = true;
+ public bool UseAsyncProcessing { get; set; } = true;
+ public int MaxConcurrentTasks { get; set; } = Environment.ProcessorCount;
+ public double SmoothingStrength { get; set; } = 0.6;
+ public double ResampleInterval { get; set; } = 1.2;
+ public int InterpolationSteps { get; set; } = 16;
+
+ public static InkSmoothingConfig FromSettings()
+ {
+ return new InkSmoothingConfig
+ {
+ Quality = (InkSmoothingQuality)MainWindow.Settings.Canvas.InkSmoothingQuality,
+ UseHardwareAcceleration = MainWindow.Settings.Canvas.UseHardwareAcceleration,
+ UseAsyncProcessing = MainWindow.Settings.Canvas.UseAsyncInkSmoothing,
+ MaxConcurrentTasks = MainWindow.Settings.Canvas.MaxConcurrentSmoothingTasks > 0 ?
+ MainWindow.Settings.Canvas.MaxConcurrentSmoothingTasks : Environment.ProcessorCount
+ };
+ }
+
+ public void ApplyQualitySettings()
+ {
+ switch (Quality)
+ {
+ case InkSmoothingQuality.HighPerformance:
+ SmoothingStrength = 0.4;
+ ResampleInterval = 2.0;
+ InterpolationSteps = 8;
+ break;
+ case InkSmoothingQuality.Balanced:
+ SmoothingStrength = 0.6;
+ ResampleInterval = 1.2;
+ InterpolationSteps = 16;
+ break;
+ case InkSmoothingQuality.HighQuality:
+ SmoothingStrength = 0.8;
+ ResampleInterval = 0.8;
+ InterpolationSteps = 32;
+ break;
+ }
+ }
+ }
+}
diff --git a/Ink Canvas/Helpers/InkSmoothingManager.cs b/Ink Canvas/Helpers/InkSmoothingManager.cs
new file mode 100644
index 00000000..dc34c3f5
--- /dev/null
+++ b/Ink Canvas/Helpers/InkSmoothingManager.cs
@@ -0,0 +1,258 @@
+using System;
+using System.Diagnostics;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Ink;
+using System.Windows.Threading;
+
+namespace Ink_Canvas.Helpers
+{
+ ///
+ /// 统一的墨迹平滑管理器,整合异步处理和硬件加速
+ ///
+ public class InkSmoothingManager : IDisposable
+ {
+ private readonly AsyncAdvancedBezierSmoothing _asyncSmoothing;
+ private readonly HardwareAcceleratedInkProcessor _hardwareProcessor;
+ private readonly InkSmoothingPerformanceMonitor _performanceMonitor;
+ private readonly InkSmoothingConfig _config;
+ private readonly Dispatcher _uiDispatcher;
+ private bool _disposed = false;
+
+ public InkSmoothingManager(Dispatcher uiDispatcher)
+ {
+ _uiDispatcher = uiDispatcher;
+ _config = InkSmoothingConfig.FromSettings();
+ _config.ApplyQualitySettings();
+
+ _asyncSmoothing = new AsyncAdvancedBezierSmoothing(uiDispatcher)
+ {
+ SmoothingStrength = _config.SmoothingStrength,
+ ResampleInterval = _config.ResampleInterval,
+ InterpolationSteps = _config.InterpolationSteps,
+ UseHardwareAcceleration = _config.UseHardwareAcceleration,
+ MaxConcurrentTasks = _config.MaxConcurrentTasks
+ };
+
+ _hardwareProcessor = new HardwareAcceleratedInkProcessor();
+ _performanceMonitor = new InkSmoothingPerformanceMonitor();
+ }
+
+ ///
+ /// 平滑笔画(自动选择最佳方法)
+ ///
+ public async Task SmoothStrokeAsync(Stroke originalStroke,
+ Action onCompleted = null,
+ CancellationToken cancellationToken = default)
+ {
+ if (originalStroke == null || originalStroke.StylusPoints.Count < 2)
+ return originalStroke;
+
+ var stopwatch = Stopwatch.StartNew();
+ Stroke result = originalStroke;
+
+ try
+ {
+ if (_config.UseAsyncProcessing)
+ {
+ // 使用异步处理
+ result = await _asyncSmoothing.SmoothStrokeAsync(originalStroke, onCompleted, cancellationToken);
+ }
+ else if (_config.UseHardwareAcceleration)
+ {
+ // 使用硬件加速但同步处理
+ result = await _hardwareProcessor.SmoothStrokeWithGPU(originalStroke);
+ onCompleted?.Invoke(originalStroke, result);
+ }
+ else
+ {
+ // 回退到传统同步处理
+ result = await Task.Run(() =>
+ {
+ var traditionalSmoothing = new AdvancedBezierSmoothing();
+ return traditionalSmoothing.SmoothStroke(originalStroke);
+ }, cancellationToken);
+ onCompleted?.Invoke(originalStroke, result);
+ }
+ }
+ catch (OperationCanceledException)
+ {
+ result = originalStroke;
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"墨迹平滑失败: {ex.Message}");
+ result = originalStroke;
+ }
+ finally
+ {
+ stopwatch.Stop();
+ _performanceMonitor.RecordProcessingTime(stopwatch.Elapsed);
+ }
+
+ return result;
+ }
+
+ ///
+ /// 同步平滑笔画(用于向后兼容)
+ ///
+ public Stroke SmoothStroke(Stroke originalStroke)
+ {
+ if (originalStroke == null || originalStroke.StylusPoints.Count < 2)
+ return originalStroke;
+
+ var stopwatch = Stopwatch.StartNew();
+ Stroke result;
+
+ try
+ {
+ if (_config.UseHardwareAcceleration)
+ {
+ // 使用硬件加速的同步版本
+ var task = _hardwareProcessor.SmoothStrokeWithGPU(originalStroke);
+ task.Wait(5000); // 5秒超时
+ result = task.Status == TaskStatus.RanToCompletion ? task.Result : originalStroke;
+ }
+ else
+ {
+ // 传统同步处理
+ var traditionalSmoothing = new AdvancedBezierSmoothing();
+ result = traditionalSmoothing.SmoothStroke(originalStroke);
+ }
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"同步墨迹平滑失败: {ex.Message}");
+ result = originalStroke;
+ }
+ finally
+ {
+ stopwatch.Stop();
+ _performanceMonitor.RecordProcessingTime(stopwatch.Elapsed);
+ }
+
+ return result;
+ }
+
+ ///
+ /// 更新配置
+ ///
+ public void UpdateConfig()
+ {
+ var newConfig = InkSmoothingConfig.FromSettings();
+ newConfig.ApplyQualitySettings();
+
+ _asyncSmoothing.SmoothingStrength = newConfig.SmoothingStrength;
+ _asyncSmoothing.ResampleInterval = newConfig.ResampleInterval;
+ _asyncSmoothing.InterpolationSteps = newConfig.InterpolationSteps;
+ _asyncSmoothing.UseHardwareAcceleration = newConfig.UseHardwareAcceleration;
+ _asyncSmoothing.MaxConcurrentTasks = newConfig.MaxConcurrentTasks;
+ }
+
+ ///
+ /// 获取性能统计信息
+ ///
+ public string GetPerformanceStats()
+ {
+ return $"平均处理时间: {_performanceMonitor.GetAverageProcessingTimeMs():F2}ms, " +
+ $"最大处理时间: {_performanceMonitor.GetMaxProcessingTimeMs():F2}ms, " +
+ $"样本数: {_performanceMonitor.GetSampleCount()}";
+ }
+
+ ///
+ /// 取消所有正在进行的任务
+ ///
+ public void CancelAllTasks()
+ {
+ _asyncSmoothing?.CancelAllTasks();
+ }
+
+ ///
+ /// 检查系统是否支持硬件加速
+ ///
+ public static bool IsHardwareAccelerationSupported()
+ {
+ try
+ {
+ return System.Windows.Media.RenderCapability.Tier >= 0x00020000;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ ///
+ /// 获取推荐的配置
+ ///
+ public static InkSmoothingConfig GetRecommendedConfig()
+ {
+ var config = new InkSmoothingConfig();
+
+ // 根据系统性能调整配置
+ var processorCount = Environment.ProcessorCount;
+ var isHardwareAccelerated = IsHardwareAccelerationSupported();
+
+ if (processorCount >= 8 && isHardwareAccelerated)
+ {
+ config.Quality = InkSmoothingQuality.HighQuality;
+ config.UseHardwareAcceleration = true;
+ config.UseAsyncProcessing = true;
+ config.MaxConcurrentTasks = Math.Min(processorCount, 8);
+ }
+ else if (processorCount >= 4)
+ {
+ config.Quality = InkSmoothingQuality.Balanced;
+ config.UseHardwareAcceleration = isHardwareAccelerated;
+ config.UseAsyncProcessing = true;
+ config.MaxConcurrentTasks = Math.Min(processorCount, 4);
+ }
+ else
+ {
+ config.Quality = InkSmoothingQuality.HighPerformance;
+ config.UseHardwareAcceleration = false;
+ config.UseAsyncProcessing = false;
+ config.MaxConcurrentTasks = 1;
+ }
+
+ config.ApplyQualitySettings();
+ return config;
+ }
+
+ ///
+ /// 应用推荐配置到设置
+ ///
+ public static void ApplyRecommendedSettings()
+ {
+ var config = GetRecommendedConfig();
+
+ MainWindow.Settings.Canvas.InkSmoothingQuality = (int)config.Quality;
+ MainWindow.Settings.Canvas.UseHardwareAcceleration = config.UseHardwareAcceleration;
+ MainWindow.Settings.Canvas.UseAsyncInkSmoothing = config.UseAsyncProcessing;
+ MainWindow.Settings.Canvas.MaxConcurrentSmoothingTasks = config.MaxConcurrentTasks;
+ }
+
+ public void Dispose()
+ {
+ if (!_disposed)
+ {
+ CancelAllTasks();
+ _asyncSmoothing?.Dispose();
+ _hardwareProcessor?.Dispose();
+ _disposed = true;
+ }
+ }
+ }
+
+ ///
+ /// 墨迹平滑事件参数
+ ///
+ public class InkSmoothingEventArgs : EventArgs
+ {
+ public Stroke OriginalStroke { get; set; }
+ public Stroke SmoothedStroke { get; set; }
+ public TimeSpan ProcessingTime { get; set; }
+ public bool WasAsync { get; set; }
+ public bool UsedHardwareAcceleration { get; set; }
+ }
+}
diff --git a/Ink Canvas/MainWindow.xaml.cs b/Ink Canvas/MainWindow.xaml.cs
index 94011d37..3fedee0b 100644
--- a/Ink Canvas/MainWindow.xaml.cs
+++ b/Ink Canvas/MainWindow.xaml.cs
@@ -110,6 +110,9 @@ namespace Ink_Canvas {
CheckColorTheme(true);
CheckPenTypeUIState();
+ // 初始化墨迹平滑管理器
+ _inkSmoothingManager = new Helpers.InkSmoothingManager(Dispatcher);
+
// 注册输入事件
inkCanvas.PreviewMouseDown += inkCanvas_PreviewMouseDown;
inkCanvas.StylusDown += inkCanvas_StylusDown;
@@ -182,6 +185,7 @@ namespace Ink_Canvas {
private System.Windows.Media.Color Ink_DefaultColor = Colors.Red;
private DrawingAttributes drawingAttributes;
+ private Helpers.InkSmoothingManager _inkSmoothingManager;
private void loadPenCanvas() {
try {
diff --git a/Ink Canvas/MainWindow_cs/MW_Settings.cs b/Ink Canvas/MainWindow_cs/MW_Settings.cs
index 51b8619a..bffec901 100644
--- a/Ink Canvas/MainWindow_cs/MW_Settings.cs
+++ b/Ink Canvas/MainWindow_cs/MW_Settings.cs
@@ -1298,7 +1298,7 @@ namespace Ink_Canvas {
private void ToggleSwitchAdvancedBezierSmoothing_Toggled(object sender, RoutedEventArgs e) {
if (!isLoaded) return;
Settings.Canvas.UseAdvancedBezierSmoothing = ToggleSwitchAdvancedBezierSmoothing.IsOn;
-
+
// 启用高级贝塞尔平滑时自动禁用原来的FitToCurve
if (ToggleSwitchAdvancedBezierSmoothing.IsOn)
{
@@ -1306,9 +1306,61 @@ namespace Ink_Canvas {
Settings.Canvas.FitToCurve = false;
drawingAttributes.FitToCurve = false;
}
-
+
+ // 更新墨迹平滑管理器配置
+ _inkSmoothingManager?.UpdateConfig();
+
SaveSettingsToFile();
}
+
+ // 注释掉这些方法,因为对应的UI控件还没有在XAML中定义
+ /*
+ private void ToggleSwitchAsyncInkSmoothing_Toggled(object sender, RoutedEventArgs e) {
+ if (!isLoaded) return;
+ Settings.Canvas.UseAsyncInkSmoothing = ToggleSwitchAsyncInkSmoothing.IsOn;
+ _inkSmoothingManager?.UpdateConfig();
+ SaveSettingsToFile();
+ }
+
+ private void ToggleSwitchHardwareAcceleration_Toggled(object sender, RoutedEventArgs e) {
+ if (!isLoaded) return;
+ Settings.Canvas.UseHardwareAcceleration = ToggleSwitchHardwareAcceleration.IsOn;
+ _inkSmoothingManager?.UpdateConfig();
+ SaveSettingsToFile();
+ }
+
+ private void ComboBoxInkSmoothingQuality_SelectionChanged(object sender, SelectionChangedEventArgs e) {
+ if (!isLoaded) return;
+ Settings.Canvas.InkSmoothingQuality = ComboBoxInkSmoothingQuality.SelectedIndex;
+ _inkSmoothingManager?.UpdateConfig();
+ SaveSettingsToFile();
+ }
+
+ private void SliderMaxConcurrentTasks_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) {
+ if (!isLoaded) return;
+ Settings.Canvas.MaxConcurrentSmoothingTasks = (int)SliderMaxConcurrentTasks.Value;
+ _inkSmoothingManager?.UpdateConfig();
+ SaveSettingsToFile();
+ }
+
+ private void ButtonApplyRecommendedSettings_Click(object sender, RoutedEventArgs e) {
+ // 应用推荐的性能设置
+ Helpers.InkSmoothingManager.ApplyRecommendedSettings();
+ LoadSettings(false);
+ _inkSmoothingManager?.UpdateConfig();
+ SaveSettingsToFile();
+
+ ShowNotification("已应用推荐的性能设置");
+ }
+
+ private void ButtonShowPerformanceStats_Click(object sender, RoutedEventArgs e) {
+ if (_inkSmoothingManager != null)
+ {
+ var stats = _inkSmoothingManager.GetPerformanceStats();
+ ShowNotification($"性能统计: {stats}");
+ }
+ }
+ */
private void ToggleSwitchAutoSaveStrokesInPowerPoint_Toggled(object sender, RoutedEventArgs e) {
if (!isLoaded) return;
diff --git a/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs b/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs
index d122a8ae..09b258b8 100644
--- a/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs
+++ b/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs
@@ -538,6 +538,23 @@ namespace Ink_Canvas {
ToggleSwitchAdvancedBezierSmoothing.IsOn = false;
drawingAttributes.FitToCurve = false;
}
+
+ // 注释掉新的墨迹平滑性能设置,因为UI控件还没有定义
+ /*
+ // 初始化新的墨迹平滑性能设置
+ ToggleSwitchAsyncInkSmoothing.IsOn = Settings.Canvas.UseAsyncInkSmoothing;
+ ToggleSwitchHardwareAcceleration.IsOn = Settings.Canvas.UseHardwareAcceleration;
+ ComboBoxInkSmoothingQuality.SelectedIndex = Settings.Canvas.InkSmoothingQuality;
+ SliderMaxConcurrentTasks.Value = Settings.Canvas.MaxConcurrentSmoothingTasks > 0 ?
+ Settings.Canvas.MaxConcurrentSmoothingTasks : Environment.ProcessorCount;
+
+ // 检查硬件加速支持
+ if (!Helpers.InkSmoothingManager.IsHardwareAccelerationSupported())
+ {
+ ToggleSwitchHardwareAcceleration.IsEnabled = false;
+ // 可以添加提示文本说明硬件加速不可用
+ }
+ */
// 初始化直线自动拉直相关设置
ToggleSwitchAutoStraightenLine.IsOn = Settings.Canvas.AutoStraightenLine;
diff --git a/Ink Canvas/MainWindow_cs/MW_ShapeDrawing.cs b/Ink Canvas/MainWindow_cs/MW_ShapeDrawing.cs
index b971ccd9..975c007f 100644
--- a/Ink Canvas/MainWindow_cs/MW_ShapeDrawing.cs
+++ b/Ink Canvas/MainWindow_cs/MW_ShapeDrawing.cs
@@ -1579,17 +1579,16 @@ namespace Ink_Canvas {
{
try
{
- var advancedSmoothing = new Helpers.AdvancedBezierSmoothing
- {
- };
-
// 对临时笔画应用平滑
- if (lastTempStroke != null)
+ if (lastTempStroke != null && _inkSmoothingManager != null)
{
- var smoothedStroke = advancedSmoothing.SmoothStroke(lastTempStroke);
- inkCanvas.Strokes.Remove(lastTempStroke);
- lastTempStroke = smoothedStroke;
- inkCanvas.Strokes.Add(smoothedStroke);
+ var smoothedStroke = _inkSmoothingManager.SmoothStroke(lastTempStroke);
+ if (smoothedStroke != lastTempStroke)
+ {
+ inkCanvas.Strokes.Remove(lastTempStroke);
+ lastTempStroke = smoothedStroke;
+ inkCanvas.Strokes.Add(smoothedStroke);
+ }
}
}
catch (Exception ex)
diff --git a/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs b/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs
index 18499916..6d344408 100644
--- a/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs
+++ b/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs
@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Ink;
@@ -587,18 +588,27 @@ namespace Ink_Canvas {
// 检查原始笔画是否仍然存在于画布中
if (inkCanvas.Strokes.Contains(e.Stroke))
{
- var advancedSmoothing = new Helpers.AdvancedBezierSmoothing
+ // 使用新的异步墨迹平滑管理器
+ if (Settings.Canvas.UseAsyncInkSmoothing && _inkSmoothingManager != null)
{
- };
+ // 异步处理
+ _ = ProcessStrokeAsync(e.Stroke);
+ }
+ else
+ {
+ // 同步处理(向后兼容)
+ var smoothedStroke = _inkSmoothingManager?.SmoothStroke(e.Stroke) ?? e.Stroke;
- var smoothedStroke = advancedSmoothing.SmoothStroke(e.Stroke);
-
- // 替换原始笔画
- SetNewBackupOfStroke();
- _currentCommitType = CommitReason.ShapeRecognition;
- inkCanvas.Strokes.Remove(e.Stroke);
- inkCanvas.Strokes.Add(smoothedStroke);
- _currentCommitType = CommitReason.UserInput;
+ if (smoothedStroke != e.Stroke)
+ {
+ // 替换原始笔画
+ SetNewBackupOfStroke();
+ _currentCommitType = CommitReason.ShapeRecognition;
+ inkCanvas.Strokes.Remove(e.Stroke);
+ inkCanvas.Strokes.Add(smoothedStroke);
+ _currentCommitType = CommitReason.UserInput;
+ }
+ }
}
}
catch (Exception ex)
@@ -613,6 +623,32 @@ namespace Ink_Canvas {
}
}
+ ///
+ /// 异步处理笔画平滑
+ ///
+ private async Task ProcessStrokeAsync(Stroke originalStroke)
+ {
+ try
+ {
+ await _inkSmoothingManager.SmoothStrokeAsync(originalStroke, (original, smoothed) =>
+ {
+ // 在UI线程上执行笔画替换
+ if (inkCanvas.Strokes.Contains(original) && smoothed != original)
+ {
+ SetNewBackupOfStroke();
+ _currentCommitType = CommitReason.ShapeRecognition;
+ inkCanvas.Strokes.Remove(original);
+ inkCanvas.Strokes.Add(smoothed);
+ _currentCommitType = CommitReason.UserInput;
+ }
+ });
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"异步墨迹平滑失败: {ex.Message}");
+ }
+ }
+
// New method: Checks if a stroke is potentially a straight line
private bool IsPotentialStraightLine(Stroke stroke) {
// 确保有足够的点来进行线条分析
diff --git a/Ink Canvas/Resources/Settings.cs b/Ink Canvas/Resources/Settings.cs
index 74ba6e69..f76a5d58 100644
--- a/Ink Canvas/Resources/Settings.cs
+++ b/Ink Canvas/Resources/Settings.cs
@@ -50,6 +50,14 @@ namespace Ink_Canvas
public bool FitToCurve { get; set; } = false; // 默认关闭原来的贝塞尔平滑
[JsonProperty("useAdvancedBezierSmoothing")]
public bool UseAdvancedBezierSmoothing { get; set; } = true; // 默认启用高级贝塞尔曲线平滑
+ [JsonProperty("useAsyncInkSmoothing")]
+ public bool UseAsyncInkSmoothing { get; set; } = true; // 默认启用异步墨迹平滑
+ [JsonProperty("useHardwareAcceleration")]
+ public bool UseHardwareAcceleration { get; set; } = true; // 默认启用硬件加速
+ [JsonProperty("inkSmoothingQuality")]
+ public int InkSmoothingQuality { get; set; } = 1; // 0-低质量高性能, 1-平衡, 2-高质量低性能
+ [JsonProperty("maxConcurrentSmoothingTasks")]
+ public int MaxConcurrentSmoothingTasks { get; set; } = 0; // 0表示自动检测CPU核心数
[JsonProperty("clearCanvasAndClearTimeMachine")]
public bool ClearCanvasAndClearTimeMachine { get; set; } = false;
[JsonProperty("enablePressureTouchMode")]
diff --git a/Ink Canvas/obj/Debug/net472/InkCanvasForClass_MarkupCompile.cache b/Ink Canvas/obj/Debug/net472/InkCanvasForClass_MarkupCompile.cache
index fc9b1fcc..ad729a64 100644
--- a/Ink Canvas/obj/Debug/net472/InkCanvasForClass_MarkupCompile.cache
+++ b/Ink Canvas/obj/Debug/net472/InkCanvasForClass_MarkupCompile.cache
@@ -12,7 +12,7 @@ TRACE;DEBUG;NETFRAMEWORK;NET472;;NET30_OR_GREATER;NET35_OR_GREATER;NET40_OR_GREA
E:\ICC CE\ICC CE main\community\Ink Canvas\App.xaml
22-2143008179
-77-1409555929
+79-461684434
471037513499
Helpers\Plugins\BuiltIn\SuperLauncher\LauncherSettingsControl.xaml;Helpers\Plugins\BuiltIn\SuperLauncher\LauncherWindow.xaml;MainWindow.xaml;MainWindow_cs\MW_Eraser.xaml;Resources\DrawShapeImageDictionary.xaml;Resources\IconImageDictionary.xaml;Resources\SeewoImageDictionary.xaml;Resources\Styles\Dark.xaml;Resources\Styles\Light.xaml;Windows\AddCustomIconWindow.xaml;Windows\AddPickNameBackgroundWindow.xaml;Windows\CountdownTimerWindow.xaml;Windows\CustomIconWindow.xaml;Windows\CycleProcessBar.xaml;Windows\HasNewUpdateWindow.xaml;Windows\HistoryRollbackWindow.xaml;Windows\ManagePickNameBackgroundsWindow.xaml;Windows\NamesInputWindow.xaml;Windows\OperatingGuideWindow.xaml;Windows\PluginSettingsWindow.xaml;Windows\RandWindow.xaml;Windows\YesOrNoNotificationWindow.xaml;