2025-07-26 19:03:07 +08:00
|
|
|
using System;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using System.Windows.Ink;
|
2025-07-28 14:40:44 +08:00
|
|
|
using System.Windows.Media;
|
2025-07-26 19:03:07 +08:00
|
|
|
using System.Windows.Threading;
|
|
|
|
|
|
|
|
|
|
namespace Ink_Canvas.Helpers
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 统一的墨迹平滑管理器,整合异步处理和硬件加速
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class InkSmoothingManager : IDisposable
|
|
|
|
|
{
|
|
|
|
|
private readonly AsyncAdvancedBezierSmoothing _asyncSmoothing;
|
|
|
|
|
private readonly HardwareAcceleratedInkProcessor _hardwareProcessor;
|
|
|
|
|
private readonly InkSmoothingPerformanceMonitor _performanceMonitor;
|
|
|
|
|
private readonly InkSmoothingConfig _config;
|
|
|
|
|
private readonly Dispatcher _uiDispatcher;
|
2025-07-28 14:40:44 +08:00
|
|
|
private bool _disposed;
|
2025-07-26 19:03:07 +08:00
|
|
|
|
|
|
|
|
public InkSmoothingManager(Dispatcher uiDispatcher)
|
|
|
|
|
{
|
|
|
|
|
_uiDispatcher = uiDispatcher;
|
|
|
|
|
_config = InkSmoothingConfig.FromSettings();
|
|
|
|
|
_config.ApplyQualitySettings();
|
2025-08-03 16:46:33 +08:00
|
|
|
|
2025-07-26 19:03:07 +08:00
|
|
|
_asyncSmoothing = new AsyncAdvancedBezierSmoothing(uiDispatcher)
|
|
|
|
|
{
|
|
|
|
|
SmoothingStrength = _config.SmoothingStrength,
|
|
|
|
|
ResampleInterval = _config.ResampleInterval,
|
|
|
|
|
InterpolationSteps = _config.InterpolationSteps,
|
|
|
|
|
UseHardwareAcceleration = _config.UseHardwareAcceleration,
|
|
|
|
|
MaxConcurrentTasks = _config.MaxConcurrentTasks
|
|
|
|
|
};
|
2025-08-03 16:46:33 +08:00
|
|
|
|
2025-07-26 19:03:07 +08:00
|
|
|
_hardwareProcessor = new HardwareAcceleratedInkProcessor();
|
|
|
|
|
_performanceMonitor = new InkSmoothingPerformanceMonitor();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 平滑笔画(自动选择最佳方法)
|
|
|
|
|
/// </summary>
|
2025-08-03 16:46:33 +08:00
|
|
|
public async Task<Stroke> SmoothStrokeAsync(Stroke originalStroke,
|
2025-07-26 19:03:07 +08:00
|
|
|
Action<Stroke, Stroke> 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)
|
|
|
|
|
{
|
2025-07-28 14:40:44 +08:00
|
|
|
Debug.WriteLine($"墨迹平滑失败: {ex.Message}");
|
2025-07-26 19:03:07 +08:00
|
|
|
result = originalStroke;
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
stopwatch.Stop();
|
|
|
|
|
_performanceMonitor.RecordProcessingTime(stopwatch.Elapsed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 同步平滑笔画(用于向后兼容)
|
|
|
|
|
/// </summary>
|
|
|
|
|
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)
|
|
|
|
|
{
|
2025-07-28 14:40:44 +08:00
|
|
|
Debug.WriteLine($"同步墨迹平滑失败: {ex.Message}");
|
2025-07-26 19:03:07 +08:00
|
|
|
result = originalStroke;
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
stopwatch.Stop();
|
|
|
|
|
_performanceMonitor.RecordProcessingTime(stopwatch.Elapsed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 更新配置
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void UpdateConfig()
|
|
|
|
|
{
|
|
|
|
|
var newConfig = InkSmoothingConfig.FromSettings();
|
|
|
|
|
newConfig.ApplyQualitySettings();
|
2025-08-03 16:46:33 +08:00
|
|
|
|
2025-07-26 19:03:07 +08:00
|
|
|
_asyncSmoothing.SmoothingStrength = newConfig.SmoothingStrength;
|
|
|
|
|
_asyncSmoothing.ResampleInterval = newConfig.ResampleInterval;
|
|
|
|
|
_asyncSmoothing.InterpolationSteps = newConfig.InterpolationSteps;
|
|
|
|
|
_asyncSmoothing.UseHardwareAcceleration = newConfig.UseHardwareAcceleration;
|
|
|
|
|
_asyncSmoothing.MaxConcurrentTasks = newConfig.MaxConcurrentTasks;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取性能统计信息
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string GetPerformanceStats()
|
|
|
|
|
{
|
|
|
|
|
return $"平均处理时间: {_performanceMonitor.GetAverageProcessingTimeMs():F2}ms, " +
|
|
|
|
|
$"最大处理时间: {_performanceMonitor.GetMaxProcessingTimeMs():F2}ms, " +
|
|
|
|
|
$"样本数: {_performanceMonitor.GetSampleCount()}";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 取消所有正在进行的任务
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void CancelAllTasks()
|
|
|
|
|
{
|
|
|
|
|
_asyncSmoothing?.CancelAllTasks();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 检查系统是否支持硬件加速
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static bool IsHardwareAccelerationSupported()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2025-07-28 14:40:44 +08:00
|
|
|
return RenderCapability.Tier >= 0x00020000;
|
2025-07-26 19:03:07 +08:00
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取推荐的配置
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static InkSmoothingConfig GetRecommendedConfig()
|
|
|
|
|
{
|
|
|
|
|
var config = new InkSmoothingConfig();
|
2025-08-03 16:46:33 +08:00
|
|
|
|
2025-07-26 19:03:07 +08:00
|
|
|
// 根据系统性能调整配置
|
|
|
|
|
var processorCount = Environment.ProcessorCount;
|
|
|
|
|
var isHardwareAccelerated = IsHardwareAccelerationSupported();
|
2025-08-03 16:46:33 +08:00
|
|
|
|
2025-07-29 09:02:03 +08:00
|
|
|
if (processorCount >= 4 && isHardwareAccelerated)
|
2025-07-26 19:03:07 +08:00
|
|
|
{
|
2025-07-29 09:02:03 +08:00
|
|
|
// 降低高质量模式的门槛,4核以上且支持硬件加速就使用高质量
|
2025-08-30 22:54:16 +08:00
|
|
|
config.Quality = (InkSmoothingConfig.SmoothingQuality)InkSmoothingConfig.InkSmoothingQuality.HighQuality;
|
2025-07-26 19:03:07 +08:00
|
|
|
config.UseHardwareAcceleration = true;
|
|
|
|
|
config.UseAsyncProcessing = true;
|
|
|
|
|
config.MaxConcurrentTasks = Math.Min(processorCount, 8);
|
|
|
|
|
}
|
2025-07-29 09:02:03 +08:00
|
|
|
else if (processorCount >= 2)
|
2025-07-26 19:03:07 +08:00
|
|
|
{
|
2025-07-29 09:02:03 +08:00
|
|
|
// 2核以上使用平衡模式
|
2025-08-30 22:54:16 +08:00
|
|
|
config.Quality = (InkSmoothingConfig.SmoothingQuality)InkSmoothingConfig.InkSmoothingQuality.Balanced;
|
2025-07-26 19:03:07 +08:00
|
|
|
config.UseHardwareAcceleration = isHardwareAccelerated;
|
|
|
|
|
config.UseAsyncProcessing = true;
|
|
|
|
|
config.MaxConcurrentTasks = Math.Min(processorCount, 4);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2025-07-29 09:02:03 +08:00
|
|
|
// 单核或性能较低的设备使用高性能模式
|
2025-08-30 22:54:16 +08:00
|
|
|
config.Quality = (InkSmoothingConfig.SmoothingQuality)InkSmoothingConfig.InkSmoothingQuality.HighPerformance;
|
2025-07-26 19:03:07 +08:00
|
|
|
config.UseHardwareAcceleration = false;
|
|
|
|
|
config.UseAsyncProcessing = false;
|
|
|
|
|
config.MaxConcurrentTasks = 1;
|
|
|
|
|
}
|
2025-08-03 16:46:33 +08:00
|
|
|
|
2025-07-26 19:03:07 +08:00
|
|
|
config.ApplyQualitySettings();
|
|
|
|
|
return config;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 应用推荐配置到设置
|
|
|
|
|
/// </summary>
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 墨迹平滑事件参数
|
|
|
|
|
/// </summary>
|
|
|
|
|
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; }
|
|
|
|
|
}
|
|
|
|
|
}
|