add:WinRT墨迹识别

This commit is contained in:
2026-03-28 18:40:18 +08:00
parent dc9fb26260
commit 97bdf78b08
5 changed files with 121 additions and 49 deletions
+23 -6
View File
@@ -40,14 +40,19 @@ namespace Ink_Canvas.Helpers
{
try
{
_isModernSystemAvailable = Environment.Is64BitProcess;
if (_isModernSystemAvailable)
var tryModern = WinRtInkShapeRecognizer.IsApiAvailable
&& (Environment.Is64BitProcess || Environment.Is64BitOperatingSystem);
_isModernSystemAvailable = false;
if (tryModern)
{
try
{
_modernProcessor = new ModernInkProcessor();
_modernAnalyzer = new ModernInkAnalyzer();
LogHelper.WriteLogToFile("墨迹识别管理器:使用64位现代化墨迹识别系统");
_isModernSystemAvailable = true;
LogHelper.WriteLogToFile(
$"墨迹识别管理器:使用现代化墨迹识别系统 (WinRT) - 进程64位: {Environment.Is64BitProcess}, OS64位: {Environment.Is64BitOperatingSystem}");
}
catch (Exception ex)
{
@@ -80,10 +85,9 @@ namespace Ink_Canvas.Helpers
try
{
if (ShapeRecognitionRouter.ResolveUseWinRt(mode)
&& _isModernSystemAvailable
&& _modernProcessor != null)
&& WinRtInkShapeRecognizer.IsApiAvailable)
{
return _modernProcessor.RecognizeShapeAsync(strokes);
return RunWinRtOrLogAsync(strokes);
}
var legacy = InkRecognizeHelper.RecognizeShapeIACore(strokes);
@@ -96,6 +100,19 @@ namespace Ink_Canvas.Helpers
}
}
private static async Task<InkShapeRecognitionResult> RunWinRtOrLogAsync(StrokeCollection strokes)
{
try
{
return await WinRtInkShapeRecognizer.RecognizeShapeAsync(strokes).ConfigureAwait(true);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile("WinRT 墨迹形状识别异常: " + ex, LogHelper.LogType.Error);
return InkShapeRecognitionResult.Empty;
}
}
public Task<StrokeCollection> CorrectInkAsync(
StrokeCollection strokes,
ShapeRecognitionEngineMode mode)
+18 -6
View File
@@ -26,19 +26,29 @@ namespace Ink_Canvas.Helpers
var alternates = analyzer.GetAlternates();
if (alternates.Count > 0)
{
while ((!alternates[0].Strokes.Contains(strokes.Last()) ||
!IsContainShapeType(((InkDrawingNode)alternates[0].AlternateNodes[0]).GetShapeName()))
&& strokesCount >= 2)
while (strokesCount >= 2)
{
var alt0 = alternates[0];
if (alt0?.AlternateNodes == null || alt0.AlternateNodes.Count == 0)
break;
var drawNode = alt0.AlternateNodes[0] as InkDrawingNode;
if (drawNode == null)
break;
var shapeOk = IsContainShapeType(drawNode.GetShapeName());
if (alt0.Strokes.Contains(strokes.Last()) && shapeOk)
break;
analyzer.RemoveStroke(strokes[strokes.Count - strokesCount]);
strokesCount--;
sfsaf = analyzer.Analyze();
if (sfsaf.Successful)
{
alternates = analyzer.GetAlternates();
}
else
break;
if (alternates.Count == 0)
break;
}
analysisAlternate = alternates[0];
if (alternates.Count > 0)
analysisAlternate = alternates[0];
}
}
@@ -47,6 +57,8 @@ namespace Ink_Canvas.Helpers
if (analysisAlternate != null && analysisAlternate.AlternateNodes.Count > 0)
{
var node = analysisAlternate.AlternateNodes[0] as InkDrawingNode;
if (node == null)
return default;
return new ShapeRecognizeResult(node.Centroid, node.HotPoints, analysisAlternate, node);
}
+67 -33
View File
@@ -46,41 +46,70 @@ namespace Ink_Canvas.Helpers
/// <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)
if (!IsApiAvailable || strokes == null || strokes.Count == 0)
return InkShapeRecognitionResult.Empty;
try
{
var inkStroke = CreateInkStrokeFromWpf(s);
if (inkStroke == null)
continue;
var analyzer = new WinRtInkAnalyzer();
var added = 0;
foreach (Stroke s in strokes)
{
var inkStroke = CreateInkStrokeFromWpf(s);
if (inkStroke == null)
continue;
analyzer.AddDataForStroke(inkStroke);
analyzer.SetStrokeDataKind(
inkStroke.Id,
global::Windows.UI.Input.Inking.Analysis.InkAnalysisStrokeKind.Drawing);
analyzer.AddDataForStroke(inkStroke);
analyzer.SetStrokeDataKind(
inkStroke.Id,
global::Windows.UI.Input.Inking.Analysis.InkAnalysisStrokeKind.Drawing);
added++;
}
if (added == 0)
{
LogHelper.WriteLogToFile(
"WinRT 形状识别:未能从 WPF 笔迹生成 InkStroke(检查 StylusPoints/DrawingAttributes)。",
LogHelper.LogType.Warning);
return InkShapeRecognitionResult.Empty;
}
await analyzer.AnalyzeAsync().AsTask().ConfigureAwait(true);
var drawing = FindPrimaryDrawing(analyzer);
if (drawing == null)
{
LogHelper.WriteLogToFile("WinRT 形状识别:分析完成但未找到 InkAnalysisInkDrawing 节点。", LogHelper.LogType.Trace);
return InkShapeRecognitionResult.Empty;
}
if (drawing.DrawingKind == global::Windows.UI.Input.Inking.Analysis.InkAnalysisDrawingKind.Drawing)
{
LogHelper.WriteLogToFile("WinRT 形状识别:结果为 Drawing(未识别为规则形状)。", LogHelper.LogType.Trace);
return InkShapeRecognitionResult.Empty;
}
var name = MapDrawingKindToShapeName(drawing.DrawingKind);
if (string.IsNullOrEmpty(name) || name == "Drawing")
return InkShapeRecognitionResult.Empty;
var winPts = CopyWinRtPoints(drawing);
var hot = ToWpfPointCollection(winPts);
var c = drawing.Center;
var centroid = new SysPoint(c.X, c.Y);
BoundsFromPoints(winPts, out double w, out double h);
var toRemove = new StrokeCollection();
foreach (Stroke s in strokes)
toRemove.Add(s);
return new InkShapeRecognitionResult(name, centroid, hot, w, h, toRemove);
}
await analyzer.AnalyzeAsync().AsTask().ConfigureAwait(true);
var drawing = FindPrimaryDrawing(analyzer);
if (drawing == null ||
drawing.DrawingKind == global::Windows.UI.Input.Inking.Analysis.InkAnalysisDrawingKind.Drawing)
catch (Exception ex)
{
LogHelper.WriteLogToFile("WinRtInkShapeRecognizer 异常: " + ex, LogHelper.LogType.Error);
return InkShapeRecognitionResult.Empty;
var name = MapDrawingKindToShapeName(drawing.DrawingKind);
if (string.IsNullOrEmpty(name) || name == "Drawing")
return InkShapeRecognitionResult.Empty;
var winPts = CopyWinRtPoints(drawing);
var hot = ToWpfPointCollection(winPts);
var c = drawing.Center;
var centroid = new SysPoint(c.X, c.Y);
BoundsFromPoints(winPts, out double w, out double h);
var toRemove = new StrokeCollection();
foreach (Stroke s in strokes)
toRemove.Add(s);
return new InkShapeRecognitionResult(name, centroid, hot, w, h, toRemove);
}
}
private static global::Windows.UI.Input.Inking.InkStroke CreateInkStrokeFromWpf(Stroke stroke)
@@ -117,7 +146,8 @@ namespace Ink_Canvas.Helpers
{
global::Windows.UI.Input.Inking.Analysis.InkAnalysisInkDrawing best = null;
double bestArea = -1;
Visit(analyzer.AnalysisRoot);
if (analyzer?.AnalysisRoot != null)
Visit(analyzer.AnalysisRoot);
return best;
void Visit(global::Windows.UI.Input.Inking.Analysis.IInkAnalysisNode node)
@@ -135,7 +165,11 @@ namespace Ink_Canvas.Helpers
}
}
foreach (var child in node.Children)
// WinRT IInkAnalysisNode.Children 可能为 null,不可直接 foreach。
var children = node.Children;
if (children == null) return;
foreach (var child in children)
Visit(child);
}
}
+3 -3
View File
@@ -30,17 +30,17 @@
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugType>embedded</DebugType>
<OutputPath>bin\$(Configuration)\</OutputPath>
<Prefer32Bit>True</Prefer32Bit>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x86 Debug|AnyCPU'">
<DebugType>embedded</DebugType>
<OutputPath>bin\$(Configuration)\</OutputPath>
<Prefer32Bit>True</Prefer32Bit>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>embedded</DebugType>
<OutputPath>bin\$(Configuration)\</OutputPath>
<Prefer32Bit>True</Prefer32Bit>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>Resources\icc.ico</ApplicationIcon>
@@ -3,6 +3,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
@@ -39,6 +40,9 @@ namespace Ink_Canvas
/// </summary>
private List<Circle> circles = new List<Circle>();
/// <summary>串行执行墨迹转形状(尤其 WinRT 异步延后),避免多笔 BeginInvoke 交错修改 newStrokes。</summary>
private static readonly SemaphoreSlim InkToShapeSerial = new SemaphoreSlim(1, 1);
/// <summary>
@@ -390,6 +394,7 @@ namespace Ink_Canvas
{
async Task InkToShapeProcessCoreAsync()
{
await InkToShapeSerial.WaitAsync().ConfigureAwait(true);
try
{
newStrokes.Add(e.Stroke);
@@ -713,6 +718,10 @@ namespace Ink_Canvas
}
}
catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex); }
finally
{
InkToShapeSerial.Release();
}
}
void InkToShapeProcess()
@@ -730,7 +739,7 @@ namespace Ink_Canvas
{
System.Diagnostics.Debug.WriteLine(ex);
}
}), DispatcherPriority.Background);
}), DispatcherPriority.Normal);
return;
}