add:WinRT墨迹识别
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Ink;
|
||||
|
||||
namespace Ink_Canvas.Helpers
|
||||
{
|
||||
public sealed class InkRecognitionManager
|
||||
{
|
||||
private static InkRecognitionManager _instance;
|
||||
private static readonly object _lock = new object();
|
||||
|
||||
private ModernInkProcessor _modernProcessor;
|
||||
private ModernInkAnalyzer _modernAnalyzer;
|
||||
private bool _isModernSystemAvailable;
|
||||
private bool _isInitialized;
|
||||
|
||||
public static InkRecognitionManager Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (_instance == null)
|
||||
_instance = new InkRecognitionManager();
|
||||
}
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private InkRecognitionManager()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
_isModernSystemAvailable = Environment.Is64BitProcess;
|
||||
if (_isModernSystemAvailable)
|
||||
{
|
||||
try
|
||||
{
|
||||
_modernProcessor = new ModernInkProcessor();
|
||||
_modernAnalyzer = new ModernInkAnalyzer();
|
||||
LogHelper.WriteLogToFile("墨迹识别管理器:使用64位现代化墨迹识别系统");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile("WinRT API不可用,回退到IACore: " + ex.Message, LogHelper.LogType.Warning);
|
||||
_isModernSystemAvailable = false;
|
||||
_modernProcessor = null;
|
||||
_modernAnalyzer = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_isModernSystemAvailable)
|
||||
LogHelper.WriteLogToFile("墨迹识别管理器:使用IACore墨迹识别系统");
|
||||
|
||||
_isInitialized = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile("墨迹识别管理器初始化失败: " + ex.Message, LogHelper.LogType.Error);
|
||||
_isInitialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
public Task<InkShapeRecognitionResult> RecognizeShapeAsync(
|
||||
StrokeCollection strokes,
|
||||
ShapeRecognitionEngineMode mode)
|
||||
{
|
||||
if (!_isInitialized || strokes == null || strokes.Count == 0)
|
||||
return Task.FromResult(InkShapeRecognitionResult.Empty);
|
||||
|
||||
try
|
||||
{
|
||||
if (ShapeRecognitionRouter.ResolveUseWinRt(mode)
|
||||
&& _isModernSystemAvailable
|
||||
&& _modernProcessor != null)
|
||||
{
|
||||
return _modernProcessor.RecognizeShapeAsync(strokes);
|
||||
}
|
||||
|
||||
var legacy = InkRecognizeHelper.RecognizeShapeIACore(strokes);
|
||||
return Task.FromResult(InkRecognizeHelper.FromIACoreOrEmpty(legacy));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile("墨迹形状识别失败: " + ex.Message, LogHelper.LogType.Error);
|
||||
return Task.FromResult(InkShapeRecognitionResult.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public Task<StrokeCollection> CorrectInkAsync(
|
||||
StrokeCollection strokes,
|
||||
ShapeRecognitionEngineMode mode)
|
||||
{
|
||||
if (!_isInitialized || strokes == null || strokes.Count == 0)
|
||||
return Task.FromResult(strokes);
|
||||
|
||||
try
|
||||
{
|
||||
if (ShapeRecognitionRouter.ResolveUseWinRt(mode) && _modernAnalyzer != null)
|
||||
return _modernAnalyzer.AnalyzeAndCorrectAsync(strokes);
|
||||
|
||||
return Task.FromResult(strokes);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile("墨迹纠正失败: " + ex.Message, LogHelper.LogType.Error);
|
||||
return Task.FromResult(strokes);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsValidShapeType(string shapeName)
|
||||
{
|
||||
return !string.IsNullOrEmpty(shapeName)
|
||||
&& (shapeName.Contains("Triangle") || shapeName.Contains("Circle")
|
||||
|| shapeName.Contains("Rectangle") || shapeName.Contains("Diamond")
|
||||
|| shapeName.Contains("Parallelogram") || shapeName.Contains("Square")
|
||||
|| shapeName.Contains("Ellipse") || shapeName.Contains("Line")
|
||||
|| shapeName.Contains("Arrow"));
|
||||
}
|
||||
|
||||
public string GetSystemInfo()
|
||||
{
|
||||
return _isModernSystemAvailable
|
||||
? $"现代化64位墨迹识别系统 (Windows Runtime API) - 进程架构: {Environment.Is64BitProcess}"
|
||||
: $"传统墨迹识别系统 (IACore) - 进程架构: {Environment.Is64BitProcess}";
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_modernProcessor?.Dispose();
|
||||
_modernAnalyzer?.Dispose();
|
||||
_isInitialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class ModernInkProcessor : IDisposable
|
||||
{
|
||||
public ModernInkProcessor()
|
||||
{
|
||||
if (!WinRtInkShapeRecognizer.IsApiAvailable)
|
||||
throw new InvalidOperationException("WinRT 墨迹分析需要 Windows 10 及以上。");
|
||||
}
|
||||
|
||||
public Task<InkShapeRecognitionResult> RecognizeShapeAsync(StrokeCollection strokes)
|
||||
{
|
||||
return WinRtInkShapeRecognizer.RecognizeShapeAsync(strokes);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class ModernInkAnalyzer : IDisposable
|
||||
{
|
||||
public Task<StrokeCollection> AnalyzeAndCorrectAsync(StrokeCollection strokes)
|
||||
{
|
||||
return Task.FromResult(strokes);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Ink;
|
||||
using System.Windows.Media;
|
||||
@@ -56,7 +57,7 @@ namespace Ink_Canvas.Helpers
|
||||
public static ShapeRecognizeResult RecognizeShape(StrokeCollection strokes) =>
|
||||
RecognizeShapeIACore(strokes);
|
||||
|
||||
/// <summary>按设置选择 WinRT 或 IACore,返回统一识别结果。</summary>
|
||||
/// <summary>按设置选择 WinRT(<see cref="InkRecognitionManager"/>)或 IACore;WinRT 请用 <see cref="RecognizeShapeUnifiedAsync"/>。</summary>
|
||||
public static InkShapeRecognitionResult RecognizeShapeUnified(
|
||||
StrokeCollection strokes,
|
||||
ShapeRecognitionEngineMode mode)
|
||||
@@ -65,16 +66,28 @@ namespace Ink_Canvas.Helpers
|
||||
return InkShapeRecognitionResult.Empty;
|
||||
|
||||
if (ShapeRecognitionRouter.ResolveUseWinRt(mode))
|
||||
return WinRtInkShapeRecognizer.RecognizeShape(strokes);
|
||||
return InkShapeRecognitionResult.Empty;
|
||||
|
||||
var legacy = RecognizeShapeIACore(strokes);
|
||||
return FromIACoreOrEmpty(legacy);
|
||||
}
|
||||
|
||||
/// <summary>与 CE 反编译版 <c>InkRecognitionManager.RecognizeShapeAsync</c> 对齐的统一入口。</summary>
|
||||
public static Task<InkShapeRecognitionResult> RecognizeShapeUnifiedAsync(
|
||||
StrokeCollection strokes,
|
||||
ShapeRecognitionEngineMode mode)
|
||||
{
|
||||
if (strokes == null || strokes.Count == 0)
|
||||
return Task.FromResult(InkShapeRecognitionResult.Empty);
|
||||
|
||||
return InkRecognitionManager.Instance.RecognizeShapeAsync(strokes, mode);
|
||||
}
|
||||
|
||||
public static void WarmupShapeRecognition(ShapeRecognitionEngineMode mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
_ = InkRecognitionManager.Instance;
|
||||
if (ShapeRecognitionRouter.ResolveUseWinRt(mode))
|
||||
WinRtInkShapeRecognizer.Warmup();
|
||||
else
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Ink;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
@@ -22,7 +23,19 @@ namespace Ink_Canvas.Helpers
|
||||
if (!IsApiAvailable) return;
|
||||
try
|
||||
{
|
||||
RecognizeShape(new StrokeCollection());
|
||||
var d = Application.Current?.Dispatcher;
|
||||
if (d == null) return;
|
||||
d.BeginInvoke(new Action(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await RecognizeShapeAsync(new StrokeCollection());
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}));
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -30,23 +43,8 @@ namespace Ink_Canvas.Helpers
|
||||
}
|
||||
}
|
||||
|
||||
public static InkShapeRecognitionResult RecognizeShape(StrokeCollection strokes)
|
||||
{
|
||||
if (!IsApiAvailable || strokes == null || strokes.Count == 0)
|
||||
return InkShapeRecognitionResult.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
return RecognizeShapeAsync(strokes).GetAwaiter().GetResult();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(ex);
|
||||
return InkShapeRecognitionResult.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<InkShapeRecognitionResult> RecognizeShapeAsync(StrokeCollection strokes)
|
||||
/// <summary>由 <see cref="ModernInkProcessor"/> / <see cref="InkRecognitionManager"/> 在 UI 上 await(勿在收笔回调中同步阻塞)。</summary>
|
||||
internal static async Task<InkShapeRecognitionResult> RecognizeShapeAsync(StrokeCollection strokes)
|
||||
{
|
||||
var analyzer = new WinRtInkAnalyzer();
|
||||
foreach (Stroke s in strokes)
|
||||
@@ -61,7 +59,7 @@ namespace Ink_Canvas.Helpers
|
||||
global::Windows.UI.Input.Inking.Analysis.InkAnalysisStrokeKind.Drawing);
|
||||
}
|
||||
|
||||
await analyzer.AnalyzeAsync().AsTask().ConfigureAwait(false);
|
||||
await analyzer.AnalyzeAsync().AsTask().ConfigureAwait(true);
|
||||
|
||||
var drawing = FindPrimaryDrawing(analyzer);
|
||||
if (drawing == null ||
|
||||
|
||||
@@ -388,7 +388,7 @@ namespace Ink_Canvas
|
||||
Settings.InkToShape.IsInkToShapeEnabled,
|
||||
ShapeRecognitionRouter.FromSettingsInt(Settings.InkToShape.ShapeRecognitionEngine)))
|
||||
{
|
||||
void InkToShapeProcess()
|
||||
async Task InkToShapeProcessCoreAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -407,11 +407,11 @@ namespace Ink_Canvas
|
||||
|
||||
var shapeMode = ShapeRecognitionRouter.FromSettingsInt(Settings.InkToShape.ShapeRecognitionEngine);
|
||||
var strokeReco = new StrokeCollection();
|
||||
var result = InkRecognizeHelper.RecognizeShapeUnified(newStrokes, shapeMode);
|
||||
var result = await InkRecognizeHelper.RecognizeShapeUnifiedAsync(newStrokes, shapeMode);
|
||||
for (var i = newStrokes.Count - 1; i >= 0; i--)
|
||||
{
|
||||
strokeReco.Add(newStrokes[i]);
|
||||
var newResult = InkRecognizeHelper.RecognizeShapeUnified(strokeReco, shapeMode);
|
||||
var newResult = await InkRecognizeHelper.RecognizeShapeUnifiedAsync(strokeReco, shapeMode);
|
||||
if (newResult.IsSuccess &&
|
||||
(newResult.ShapeName == "Circle" || newResult.ShapeName == "Ellipse"))
|
||||
{
|
||||
@@ -715,6 +715,28 @@ namespace Ink_Canvas
|
||||
catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex); }
|
||||
}
|
||||
|
||||
void InkToShapeProcess()
|
||||
{
|
||||
var engineMode = ShapeRecognitionRouter.FromSettingsInt(Settings.InkToShape.ShapeRecognitionEngine);
|
||||
if (ShapeRecognitionRouter.ResolveUseWinRt(engineMode))
|
||||
{
|
||||
Dispatcher.BeginInvoke(new Action(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await InkToShapeProcessCoreAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(ex);
|
||||
}
|
||||
}), DispatcherPriority.Background);
|
||||
return;
|
||||
}
|
||||
|
||||
InkToShapeProcessCoreAsync().GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
InkToShapeProcess();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user