diff --git a/Ink Canvas/Helpers/InkRecognitionManager.cs b/Ink Canvas/Helpers/InkRecognitionManager.cs
index 881b7ed6..8c30d975 100644
--- a/Ink Canvas/Helpers/InkRecognitionManager.cs
+++ b/Ink Canvas/Helpers/InkRecognitionManager.cs
@@ -11,7 +11,6 @@ namespace Ink_Canvas.Helpers
private readonly object _initSync = new object();
private ModernInkProcessor _modernProcessor;
- private ModernInkAnalyzer _modernAnalyzer;
private bool _isModernSystemAvailable;
private bool _isInitialized;
@@ -41,7 +40,7 @@ namespace Ink_Canvas.Helpers
try
{
// 启动阶段只做能力探测,不做 WinRT 组件实例化(避免冷启动延迟)
- _isModernSystemAvailable = WinRtInkShapeRecognizer.IsApiAvailable && Environment.Is64BitProcess;
+ _isModernSystemAvailable = WinRtInkShapeRecognizer.IsApiAvailable;
_isInitialized = true;
}
catch (Exception ex)
@@ -63,22 +62,20 @@ namespace Ink_Canvas.Helpers
private void EnsureModernAnalyzerInitialized()
{
- if (_modernAnalyzer != null || !_isModernSystemAvailable) return;
+ if (_modernProcessor != null || !_isModernSystemAvailable) return;
lock (_initSync)
{
- if (_modernAnalyzer != null || !_isModernSystemAvailable) return;
+ if (_modernProcessor != null || !_isModernSystemAvailable) return;
try
{
_modernProcessor ??= new ModernInkProcessor();
- _modernAnalyzer = new ModernInkAnalyzer();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile("WinRT 墨迹模块懒加载失败: " + ex.Message, LogHelper.LogType.Warning);
_isModernSystemAvailable = false;
_modernProcessor = null;
- _modernAnalyzer = null;
}
}
}
@@ -156,19 +153,11 @@ namespace Ink_Canvas.Helpers
return Task.FromResult(strokes);
}
- if (!Environment.Is64BitProcess)
- {
- LogHelper.WriteLogToFile(
- "[手写体] CorrectInkAsync 跳过:非 64 位进程,WinRT 手写体替换不可用。笔画数=" + strokes.Count,
- LogHelper.LogType.Info);
- return Task.FromResult(strokes);
- }
-
EnsureModernAnalyzerInitialized();
- if (_modernAnalyzer == null)
+ if (_modernProcessor == null)
{
LogHelper.WriteLogToFile(
- "[手写体] CorrectInkAsync 跳过:ModernInkAnalyzer 未就绪(WinRT 初始化失败?)。笔画数=" +
+ "[手写体] CorrectInkAsync 跳过:ModernInkProcessor 未就绪(WinRT 初始化失败?)。笔画数=" +
strokes.Count,
LogHelper.LogType.Warning);
return Task.FromResult(strokes);
@@ -178,7 +167,7 @@ namespace Ink_Canvas.Helpers
"[手写体] CorrectInkAsync 开始:笔画数=" + strokes.Count +
",字体=" + (string.IsNullOrWhiteSpace(handwritingFontFamilyList) ? "(默认)" : handwritingFontFamilyList.Trim()),
LogHelper.LogType.Info);
- return _modernAnalyzer.AnalyzeAndCorrectAsync(strokes, handwritingFontFamilyList);
+ return WinRtHandwritingRecognizer.ConvertRecognizedTextToHandwritingInkAsync(strokes, handwritingFontFamilyList);
}
catch (Exception ex)
{
@@ -188,7 +177,7 @@ namespace Ink_Canvas.Helpers
}
///
- /// WinRT 手写体识别(需 64 位进程、Windows 10+ 及系统手写识别组件)。返回分词候选与包围框,供剪贴板或插件使用。
+ /// WinRT 手写体识别(需 Windows 10+ 及系统手写识别组件)。返回分词候选与包围框,供剪贴板或插件使用。
///
public Task RecognizeHandwritingAsync(
StrokeCollection strokes,
@@ -200,8 +189,7 @@ namespace Ink_Canvas.Helpers
try
{
- if (!Environment.Is64BitProcess
- || !ShapeRecognitionRouter.ResolveUseWinRt(mode)
+ if (!ShapeRecognitionRouter.ResolveUseWinRt(mode)
|| !WinRtHandwritingRecognizer.IsApiAvailable)
return Task.FromResult(HandwritingRecognitionResult.Empty);
@@ -227,14 +215,13 @@ namespace Ink_Canvas.Helpers
public string GetSystemInfo()
{
return _isModernSystemAvailable
- ? $"现代化64位墨迹识别系统 (Windows Runtime API) - 进程架构: {Environment.Is64BitProcess}"
+ ? $"现代化墨迹识别系统 (Windows Runtime API) - 进程架构: {Environment.Is64BitProcess}"
: $"传统墨迹识别系统 (IACore) - 进程架构: {Environment.Is64BitProcess}";
}
public void Dispose()
{
_modernProcessor?.Dispose();
- _modernAnalyzer?.Dispose();
_isInitialized = false;
}
}
@@ -256,20 +243,4 @@ namespace Ink_Canvas.Helpers
{
}
}
-
- internal sealed class ModernInkAnalyzer : IDisposable
- {
- public Task AnalyzeAndCorrectAsync(
- StrokeCollection strokes,
- string handwritingFontFamilyList)
- {
- return WinRtHandwritingRecognizer.ConvertRecognizedTextToHandwritingInkAsync(
- strokes,
- handwritingFontFamilyList);
- }
-
- public void Dispose()
- {
- }
- }
}
diff --git a/Ink Canvas/Helpers/InkRecognizeHelper.cs b/Ink Canvas/Helpers/InkRecognizeHelper.cs
index 9f3018c7..ed56e693 100644
--- a/Ink Canvas/Helpers/InkRecognizeHelper.cs
+++ b/Ink Canvas/Helpers/InkRecognizeHelper.cs
@@ -117,7 +117,7 @@ namespace Ink_Canvas.Helpers
}
}
- /// WinRT 手写识别(64 位 + Windows 10+)。
+ /// WinRT 手写识别(Windows 10+)。
public static Task RecognizeHandwritingUnifiedAsync(
StrokeCollection strokes,
ShapeRecognitionEngineMode mode) =>
diff --git a/Ink Canvas/Helpers/InkShapeRecognition.cs b/Ink Canvas/Helpers/InkShapeRecognition.cs
index 0d04c0cf..987a9aee 100644
--- a/Ink Canvas/Helpers/InkShapeRecognition.cs
+++ b/Ink Canvas/Helpers/InkShapeRecognition.cs
@@ -17,13 +17,13 @@ namespace Ink_Canvas.Helpers
public static class ShapeRecognitionRouter
{
///
- /// 自动模式:按当前进程位数选择——64 位进程用 WinRT,32 位进程(含 x86 目标在 WOW64 下运行)用 IACore。
+ /// 自动模式:在 Windows 10 及以上系统默认使用 WinRT,否则使用 IACore。
///
public static bool ResolveUseWinRt(ShapeRecognitionEngineMode mode)
{
if (mode == ShapeRecognitionEngineMode.WinRT) return true;
if (mode == ShapeRecognitionEngineMode.IACore) return false;
- return Environment.Is64BitProcess;
+ return OSVersion.GetOperatingSystem() >= OSVersionExtension.OperatingSystem.Windows10;
}
public static bool ShouldRunShapeRecognition(bool inkToShapeEnabled, ShapeRecognitionEngineMode mode)
@@ -31,7 +31,7 @@ namespace Ink_Canvas.Helpers
if (!inkToShapeEnabled) return false;
if (ResolveUseWinRt(mode))
return OSVersion.GetOperatingSystem() >= OSVersionExtension.OperatingSystem.Windows10;
- return !Environment.Is64BitProcess;
+ return true;
}
public static ShapeRecognitionEngineMode FromSettingsInt(int value)
diff --git a/Ink Canvas/Helpers/WinRtInkShapeRecognizer.cs b/Ink Canvas/Helpers/WinRtInkShapeRecognizer.cs
index 687d6980..8ad74c69 100644
--- a/Ink Canvas/Helpers/WinRtInkShapeRecognizer.cs
+++ b/Ink Canvas/Helpers/WinRtInkShapeRecognizer.cs
@@ -1,6 +1,7 @@
using OSVersionExtension;
using System;
using System.Collections.Generic;
+using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Ink;
@@ -11,6 +12,128 @@ using WinRtInkAnalyzer = global::Windows.UI.Input.Inking.Analysis.InkAnalyzer;
namespace Ink_Canvas.Helpers
{
+ internal class ModernInkAnalyzer : IDisposable
+ {
+ public static readonly Guid ShapeStrokePropertyGuid = new Guid("11111111-2222-3333-4444-555555555555");
+
+ private global::Windows.UI.Input.Inking.Analysis.InkAnalyzer _internalAnalyzer;
+ private readonly Dictionary _strokeIdMap = new Dictionary();
+ private readonly Dictionary _reverseIdMap = new Dictionary();
+ private readonly object _syncLock = new object();
+
+ public ModernInkAnalyzer()
+ {
+ if (!WinRtInkShapeRecognizer.IsApiAvailable)
+ return;
+
+ _internalAnalyzer = new global::Windows.UI.Input.Inking.Analysis.InkAnalyzer();
+ }
+
+ private void AddStrokeInternal(Stroke stroke)
+ {
+ if (stroke.ContainsPropertyData(ShapeStrokePropertyGuid))
+ return;
+
+ var inkStroke = WinRtInkShapeRecognizer.CreateInkStrokeFromWpf(stroke);
+ if (inkStroke == null) return;
+
+ _internalAnalyzer.AddDataForStroke(inkStroke);
+ _internalAnalyzer.SetStrokeDataKind(
+ inkStroke.Id,
+ global::Windows.UI.Input.Inking.Analysis.InkAnalysisStrokeKind.Drawing);
+
+ _strokeIdMap[stroke] = inkStroke.Id;
+ _reverseIdMap[inkStroke.Id] = stroke;
+ }
+
+ private CancellationTokenSource _cts;
+
+ public async Task AnalyzeAsync(StrokeCollection strokes)
+ {
+ if (_internalAnalyzer == null || strokes == null || strokes.Count == 0)
+ return InkShapeRecognitionResult.Empty;
+
+ _cts?.Cancel();
+ _cts = new CancellationTokenSource();
+ var token = _cts.Token;
+
+ try
+ {
+ lock (_syncLock)
+ {
+ _internalAnalyzer.ClearDataForAllStrokes();
+ _strokeIdMap.Clear();
+ _reverseIdMap.Clear();
+
+ foreach (var stroke in strokes)
+ {
+ AddStrokeInternal(stroke);
+ }
+ }
+
+ if (_strokeIdMap.Count == 0)
+ return InkShapeRecognitionResult.Empty;
+
+ var result = await _internalAnalyzer.AnalyzeAsync().AsTask(token).ConfigureAwait(true);
+
+ if (token.IsCancellationRequested) return InkShapeRecognitionResult.Empty;
+
+ // Use the internal method from WinRtInkShapeRecognizer to find the primary drawing
+ var drawing = WinRtInkShapeRecognizer.FindPrimaryDrawing(_internalAnalyzer);
+ if (drawing == null)
+ return InkShapeRecognitionResult.Empty;
+
+ if (drawing.DrawingKind == global::Windows.UI.Input.Inking.Analysis.InkAnalysisDrawingKind.Drawing)
+ return InkShapeRecognitionResult.Empty;
+
+ var name = WinRtInkShapeRecognizer.MapDrawingKindToShapeName(drawing.DrawingKind);
+ if (string.IsNullOrEmpty(name) || name == "Drawing")
+ return InkShapeRecognitionResult.Empty;
+
+ var winPts = WinRtInkShapeRecognizer.CopyWinRtPoints(drawing);
+ var hot = WinRtInkShapeRecognizer.ToWpfPointCollection(winPts);
+ var c = drawing.Center;
+ var centroid = new SysPoint(c.X, c.Y);
+ WinRtInkShapeRecognizer.BoundsFromPoints(winPts, out double w, out double h);
+
+ var toRemove = new StrokeCollection();
+ lock (_syncLock)
+ {
+ foreach (var id in drawing.GetStrokeIds())
+ {
+ if (_reverseIdMap.TryGetValue(id, out var stroke))
+ {
+ toRemove.Add(stroke);
+ }
+ }
+ }
+
+ if (toRemove.Count == 0)
+ return InkShapeRecognitionResult.Empty;
+
+ return new InkShapeRecognitionResult(name, centroid, hot, w, h, toRemove);
+ }
+ catch (Exception)
+ {
+ return InkShapeRecognitionResult.Empty;
+ }
+ }
+
+ public Task AnalyzeAndCorrectAsync(
+ StrokeCollection strokes,
+ string handwritingFontFamilyList)
+ {
+ return WinRtHandwritingRecognizer.ConvertRecognizedTextToHandwritingInkAsync(
+ strokes,
+ handwritingFontFamilyList);
+ }
+
+ public void Dispose()
+ {
+ _internalAnalyzer = null;
+ }
+ }
+
/// 基于 Windows.UI.Input.Inking.Analysis 的形状识别(适用于 64 位进程等场景)。
internal static class WinRtInkShapeRecognizer
{
@@ -150,8 +273,8 @@ namespace Ink_Canvas.Helpers
return builder.CreateStroke(points);
}
- private static global::Windows.UI.Input.Inking.Analysis.InkAnalysisInkDrawing FindPrimaryDrawing(
- WinRtInkAnalyzer analyzer)
+ internal static global::Windows.UI.Input.Inking.Analysis.InkAnalysisInkDrawing FindPrimaryDrawing(
+ global::Windows.UI.Input.Inking.Analysis.InkAnalyzer analyzer)
{
global::Windows.UI.Input.Inking.Analysis.InkAnalysisInkDrawing best = null;
double bestArea = -1;
@@ -190,7 +313,7 @@ namespace Ink_Canvas.Helpers
return w * h;
}
- private static global::Windows.Foundation.Point[] CopyWinRtPoints(
+ internal static global::Windows.Foundation.Point[] CopyWinRtPoints(
global::Windows.UI.Input.Inking.Analysis.InkAnalysisInkDrawing drawing)
{
var src = drawing?.Points;
@@ -207,7 +330,7 @@ namespace Ink_Canvas.Helpers
return arr;
}
- private static void BoundsFromPoints(
+ internal static void BoundsFromPoints(
System.Collections.Generic.IReadOnlyList points,
out double w,
out double h)
@@ -232,7 +355,7 @@ namespace Ink_Canvas.Helpers
h = Math.Max(0, maxY - minY);
}
- private static PointCollection ToWpfPointCollection(
+ internal static PointCollection ToWpfPointCollection(
System.Collections.Generic.IReadOnlyList points)
{
var hot = new PointCollection();
@@ -246,7 +369,7 @@ namespace Ink_Canvas.Helpers
return hot;
}
- private static string MapDrawingKindToShapeName(
+ internal static string MapDrawingKindToShapeName(
global::Windows.UI.Input.Inking.Analysis.InkAnalysisDrawingKind kind)
{
switch (kind)
diff --git a/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs b/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs
index 5cddb40b..a81d2ada 100644
--- a/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs
+++ b/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs
@@ -30,6 +30,10 @@ namespace Ink_Canvas
///
public partial class MainWindow : Window
{
+ private Helpers.ModernInkAnalyzer _modernInkAnalyzer;
+ private Helpers.ModernInkAnalyzer ModernInkAnalyzer =>
+ _modernInkAnalyzer ??= new Helpers.ModernInkAnalyzer();
+
///
/// 存储新的笔画集合,用于形状识别
///
@@ -564,6 +568,7 @@ namespace Ink_Canvas
{
DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone()
};
+ straightStroke.AddPropertyData(Helpers.ModernInkAnalyzer.ShapeStrokePropertyGuid, true);
// Replace the original stroke with the straightened one
SetNewBackupOfStroke();
@@ -617,17 +622,26 @@ namespace Ink_Canvas
ProcessRectangleGuideLines(e.Stroke);
var shapeMode = ShapeRecognitionRouter.FromSettingsInt(Settings.InkToShape.ShapeRecognitionEngine);
- var strokeReco = new StrokeCollection();
- var result = await InkRecognizeHelper.RecognizeShapeUnifiedAsync(newStrokes, shapeMode);
- for (var i = newStrokes.Count - 1; i >= 0; i--)
+ InkShapeRecognitionResult result = InkShapeRecognitionResult.Empty;
+
+ if (ShapeRecognitionRouter.ResolveUseWinRt(shapeMode) && Helpers.WinRtInkShapeRecognizer.IsApiAvailable)
{
- strokeReco.Add(newStrokes[i]);
- var newResult = await InkRecognizeHelper.RecognizeShapeUnifiedAsync(strokeReco, shapeMode);
- if (newResult.IsSuccess &&
- (newResult.ShapeName == "Circle" || newResult.ShapeName == "Ellipse"))
+ result = await ModernInkAnalyzer.AnalyzeAsync(newStrokes);
+ }
+ else
+ {
+ var strokeReco = new StrokeCollection();
+ result = await InkRecognizeHelper.RecognizeShapeUnifiedAsync(newStrokes, shapeMode);
+ for (var i = newStrokes.Count - 1; i >= 0; i--)
{
- result = newResult;
- break;
+ strokeReco.Add(newStrokes[i]);
+ var newResult = await InkRecognizeHelper.RecognizeShapeUnifiedAsync(strokeReco, shapeMode);
+ if (newResult.IsSuccess &&
+ (newResult.ShapeName == "Circle" || newResult.ShapeName == "Ellipse"))
+ {
+ result = newResult;
+ break;
+ }
}
}
@@ -687,6 +701,7 @@ namespace Ink_Canvas
{
DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone()
};
+ stroke.AddPropertyData(Helpers.ModernInkAnalyzer.ShapeStrokePropertyGuid, true);
circles.Add(new Circle(result.Centroid, result.ShapeWidth / 2.0, stroke));
SetNewBackupOfStroke();
_currentCommitType = CommitReason.ShapeRecognition;
@@ -790,6 +805,7 @@ namespace Ink_Canvas
{
DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone()
};
+ _stroke.AddPropertyData(Helpers.ModernInkAnalyzer.ShapeStrokePropertyGuid, true);
var _dashedLineStroke =
GenerateDashedLineEllipseStrokeCollection(iniP, endP, true, false);
var strokes = new StrokeCollection {
@@ -836,6 +852,7 @@ namespace Ink_Canvas
{
DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone()
};
+ stroke.AddPropertyData(Helpers.ModernInkAnalyzer.ShapeStrokePropertyGuid, true);
if (needRotation)
{
@@ -883,6 +900,7 @@ namespace Ink_Canvas
{
DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone()
};
+ stroke.AddPropertyData(Helpers.ModernInkAnalyzer.ShapeStrokePropertyGuid, true);
SetNewBackupOfStroke();
_currentCommitType = CommitReason.ShapeRecognition;
inkCanvas.Strokes.Remove(result.StrokesToRemove);
@@ -928,6 +946,7 @@ namespace Ink_Canvas
{
DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone()
};
+ stroke.AddPropertyData(Helpers.ModernInkAnalyzer.ShapeStrokePropertyGuid, true);
SetNewBackupOfStroke();
_currentCommitType = CommitReason.ShapeRecognition;
inkCanvas.Strokes.Remove(result.StrokesToRemove);
@@ -2835,6 +2854,7 @@ namespace Ink_Canvas
{
DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone()
};
+ rectangleStroke.AddPropertyData(Helpers.ModernInkAnalyzer.ShapeStrokePropertyGuid, true);
// 移除原有的四条直线
SetNewBackupOfStroke();
diff --git a/Ink Canvas/Properties/Strings.resx b/Ink Canvas/Properties/Strings.resx
index 27aa9e9e..ea3fb82c 100644
--- a/Ink Canvas/Properties/Strings.resx
+++ b/Ink Canvas/Properties/Strings.resx
@@ -568,7 +568,7 @@
WinRT识别转手写体字形
- #开启后,调用墨迹纠正API时:先WinRT识别手写词,再将识别成功的文字用手写风格字体(默认Ink Free/楷体等,可在设置JSON的handwritingCorrectionFontFamily调整)转成字形轮廓墨迹替换原笔画。需64位与WinRT。
+ #开启后,调用墨迹纠正API时:先WinRT识别手写词,再将识别成功的文字用手写风格字体(默认Ink Free/楷体等,可在设置JSON的handwritingCorrectionFontFamily调整)转成字形轮廓墨迹替换原笔画。需WinRT。
识别引擎