From 9fb18e020e6da4fa5986ebf4436a270d42e6542d Mon Sep 17 00:00:00 2001
From: PrefacedCorg <1876568293@qq.com>
Date: Fri, 1 May 2026 23:03:20 +0800
Subject: [PATCH 1/4] =?UTF-8?q?```=20fix(ui):=20=E4=BF=AE=E5=A4=8D?=
=?UTF-8?q?=E7=94=BB=E5=B8=83=E7=95=8C=E9=9D=A2=E5=85=83=E7=B4=A0=E5=B8=83?=
=?UTF-8?q?=E5=B1=80=E5=92=8C=E9=97=B4=E8=B7=9D=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 修复背景设置面板的位置偏移问题,调整Margin值从-115,-360,-55,50到-189,-360,-55,50
- 为各个工具面板添加设计时可见性属性(d:Visibility="Visible")以便预览
- 修复多个堆叠面板的Spacing属性,将负值改为正值以正确显示元素间距
- 在各个工具菜单区域添加中文注释标识(如, 等)
- 调整了工具面板中的Spacing属性从-2到2,解决元素重叠问题
```
---
Ink Canvas/MainWindow.xaml | 347 ++++++++++++++++++-------------------
1 file changed, 168 insertions(+), 179 deletions(-)
diff --git a/Ink Canvas/MainWindow.xaml b/Ink Canvas/MainWindow.xaml
index a91db569..89a6f0ab 100644
--- a/Ink Canvas/MainWindow.xaml
+++ b/Ink Canvas/MainWindow.xaml
@@ -1089,137 +1089,137 @@
Label="{i18n:I18n Key=Board_Background}"
IconGeometry="F0 M24,24z M0,0z M4.71815,3.98345C6.64142,2.23541 9.19629,1.17001 12,1.17001 17.9812,1.17001 22.83,6.01877 22.83,12 22.83,17.9813 17.9812,22.83 12,22.83 11.6262,22.83 11.2568,22.8111 10.8927,22.7741 5.8167,22.2586 1.77699,18.2377 1.2325,13.1703 1.22536,13.1039 1.21882,13.0373 1.21289,12.9705 1.20871,12.9234 1.20483,12.8762 1.20125,12.8289 1.18054,12.5553 1.17,12.2789 1.17,12 1.17,9.41057 2.07878,7.03339 3.59479,5.17001 3.9391,4.74681 4.31473,4.35011 4.71815,3.98345z M12,20.83C16.8767,20.83 20.83,16.8767 20.83,12 20.83,7.12334 16.8767,3.17001 12,3.17001L12,20.83z"
ButtonMouseUp="BoardChangeBackgroundColorBtn_MouseUp" />
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+ Foreground="{DynamicResource TextForeground}"
+ FontSize="10" FontWeight="Bold"
+ HorizontalAlignment="Center"
+ Margin="0,4,0,8" />
+ Width="60" Height="30"
+ Background="#2563eb"
+ CornerRadius="4"
+ Margin="0,0,8,0"
+ MouseUp="WhiteboardModeBtn_MouseUp">
+ Foreground="White"
+ HorizontalAlignment="Center"
+ VerticalAlignment="Center" />
+ Width="60" Height="30"
+ Background="LightGray"
+ CornerRadius="4"
+ MouseUp="BlackboardModeBtn_MouseUp">
+ Foreground="Black"
+ HorizontalAlignment="Center"
+ VerticalAlignment="Center" />
+ Background="{DynamicResource SettingsPageBorderBrush}"
+ Margin="0,12,0,12" />
+ Foreground="{DynamicResource TextForeground}"
+ FontSize="10" FontWeight="Bold"
+ HorizontalAlignment="Center"
+ Margin="0,4,0,8" />
+ Width="100" Height="40"
+ BorderThickness="1"
+ BorderBrush="{DynamicResource SettingsPageBorderBrush}"
+ Background="White"
+ CornerRadius="4"
+ Margin="0,0,0,10"
+ HorizontalAlignment="Center" />
-
+ Foreground="{DynamicResource TextForeground}" />
+
+ Text="255" Width="30"
+ VerticalAlignment="Center"
+ TextAlignment="Right"
+ Foreground="{DynamicResource TextForeground}" />
-
+ Foreground="{DynamicResource TextForeground}" />
+
+ Text="255" Width="30"
+ VerticalAlignment="Center"
+ TextAlignment="Right"
+ Foreground="{DynamicResource TextForeground}" />
-
+ Foreground="{DynamicResource TextForeground}" />
+
+ Text="255" Width="30"
+ VerticalAlignment="Center"
+ TextAlignment="Right"
+ Foreground="{DynamicResource TextForeground}" />
+ Content="应用颜色"
+ Margin="0,10,0,0"
+ Padding="10,5,10,5"
+ Background="#2563eb"
+ Foreground="White"
+ BorderThickness="0"
+ HorizontalAlignment="Center"
+ Click="ApplyBackgroundColorBtn_Click" />
-
-
-
-
+
+
+
+
@@ -1234,18 +1234,11 @@
Label="{i18n:I18n Key=Board_Pen}"
IconGeometry="F1 M24,24z M0,0z M20.4786,1.42438C19.9985,1.23743 19.4847,1.15194 18.9698,1.17319 18.4549,1.19444 17.9499,1.32197 17.4869,1.54789 17.0368,1.76752 16.6358,2.07554 16.3083,2.45361L3.85516,14.9067 9.08243,20.134 21.5311,7.68529C21.9113,7.36382 22.223,6.96912 22.447,6.52438 22.6786,6.06462 22.8113,5.56167 22.8365,5.04763 22.8616,4.5336 22.7787,4.02012 22.593,3.54002 22.4073,3.05994 22.1232,2.62403 21.759,2.25988 21.3949,1.89574 20.9587,1.61132 20.4786,1.42438z M7.28056,21.1605L2.8286,16.7086 1.15912,22.83 7.28056,21.1605z"
ButtonMouseUp="PenIcon_Click" />
+
-
-
-
-
-
-
-
-
-
@@ -1560,17 +1553,10 @@
Label="{i18n:I18n Key=Board_Eraser}"
IconGeometry="F1 M24,24z M0,0z M15.6314,20.7262L22.7921,13.5655C24.3494,12.141,24.2819,9.81776,22.8105,8.34633L16.7793,2.31508C15.3547,0.757753,13.0315,0.825236,11.5601,2.29666L4.38099,9.47574 15.6314,20.7262z M14.2172,22.1404L2.96677,10.89 1.20761,12.6491C-0.34971,14.0737,-0.281711,16.3974,1.18971,17.8688L6.15089,22.83 13.5276,22.83 14.2172,22.1404z"
ButtonMouseUp="BoardEraserIcon_Click" />
+
-
-
-
-
-
-
-
-
-
+
-
+
@@ -1911,6 +1898,7 @@
Label="{i18n:I18n Key=Board_InsertImage}"
IconGeometry="F1 M24,24z M0,0z M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2-0.9 2-2V5C21,3.9 20.1,3 19,3zM19,19H5V5h14V19z M17,7c-1.1,0-2,0.9-2,2s0.9,2 2,2 2-0.9 2-2S18.1,7 17,7zM7,17l2.5-3.01 1.96,2.36 2.54-3.21L17,17H7z"
ButtonMouseUp="InsertImageOptions_MouseUp" />
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
From 2a17ea1bd15a32c73c29b06b20608e3837c09e14 Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Fri, 1 May 2026 23:54:24 +0800
Subject: [PATCH 2/4] =?UTF-8?q?add:=E5=9F=BA=E4=BA=8EIPC=E7=9A=84IACore?=
=?UTF-8?q?=E5=9C=A8net6=E7=9A=84=E5=AE=9E=E7=8E=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas.sln | 22 ++
Ink Canvas/App.xaml.cs | 18 ++
Ink Canvas/Helpers/InkRecognitionManager.cs | 14 +-
Ink Canvas/Helpers/InkRecognizeHelper.cs | 244 +-------------
Ink Canvas/Helpers/IpcIACoreClient.cs | 302 ++++++++++++++++++
Ink Canvas/InkCanvasForClass.csproj | 25 +-
InkCanvasForClass.IACoreHelper/App.config | 6 +
.../InkCanvasForClass.IACoreHelper.csproj | 56 ++++
InkCanvasForClass.IACoreHelper/IpcProtocol.cs | 133 ++++++++
InkCanvasForClass.IACoreHelper/Program.cs | 222 +++++++++++++
.../Properties/AssemblyInfo.cs | 11 +
11 files changed, 806 insertions(+), 247 deletions(-)
create mode 100644 Ink Canvas/Helpers/IpcIACoreClient.cs
create mode 100644 InkCanvasForClass.IACoreHelper/App.config
create mode 100644 InkCanvasForClass.IACoreHelper/InkCanvasForClass.IACoreHelper.csproj
create mode 100644 InkCanvasForClass.IACoreHelper/IpcProtocol.cs
create mode 100644 InkCanvasForClass.IACoreHelper/Program.cs
create mode 100644 InkCanvasForClass.IACoreHelper/Properties/AssemblyInfo.cs
diff --git a/Ink Canvas.sln b/Ink Canvas.sln
index 0bf57c17..7907e2c2 100644
--- a/Ink Canvas.sln
+++ b/Ink Canvas.sln
@@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InkCanvas.PluginSdk", "InkC
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InkCanvas.Controls", "InkCanvas.Controls\InkCanvas.Controls.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InkCanvasForClass.IACoreHelper", "InkCanvasForClass.IACoreHelper\InkCanvasForClass.IACoreHelper.csproj", "{B1A2C3D4-E5F6-7890-ABCD-EF1234567891}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -83,6 +85,26 @@ Global
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x64.Build.0 = Release|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x86.ActiveCfg = Release|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x86.Build.0 = Release|Any CPU
+ {B1A2C3D4-E5F6-7890-ABCD-EF1234567891}.Debug|Any CPU.ActiveCfg = Debug|x86
+ {B1A2C3D4-E5F6-7890-ABCD-EF1234567891}.Debug|Any CPU.Build.0 = Debug|x86
+ {B1A2C3D4-E5F6-7890-ABCD-EF1234567891}.Debug|ARM.ActiveCfg = Debug|x86
+ {B1A2C3D4-E5F6-7890-ABCD-EF1234567891}.Debug|ARM.Build.0 = Debug|x86
+ {B1A2C3D4-E5F6-7890-ABCD-EF1234567891}.Debug|ARM64.ActiveCfg = Debug|x86
+ {B1A2C3D4-E5F6-7890-ABCD-EF1234567891}.Debug|ARM64.Build.0 = Debug|x86
+ {B1A2C3D4-E5F6-7890-ABCD-EF1234567891}.Debug|x64.ActiveCfg = Debug|x86
+ {B1A2C3D4-E5F6-7890-ABCD-EF1234567891}.Debug|x64.Build.0 = Debug|x86
+ {B1A2C3D4-E5F6-7890-ABCD-EF1234567891}.Debug|x86.ActiveCfg = Debug|x86
+ {B1A2C3D4-E5F6-7890-ABCD-EF1234567891}.Debug|x86.Build.0 = Debug|x86
+ {B1A2C3D4-E5F6-7890-ABCD-EF1234567891}.Release|Any CPU.ActiveCfg = Release|x86
+ {B1A2C3D4-E5F6-7890-ABCD-EF1234567891}.Release|Any CPU.Build.0 = Release|x86
+ {B1A2C3D4-E5F6-7890-ABCD-EF1234567891}.Release|ARM.ActiveCfg = Release|x86
+ {B1A2C3D4-E5F6-7890-ABCD-EF1234567891}.Release|ARM.Build.0 = Release|x86
+ {B1A2C3D4-E5F6-7890-ABCD-EF1234567891}.Release|ARM64.ActiveCfg = Release|x86
+ {B1A2C3D4-E5F6-7890-ABCD-EF1234567891}.Release|ARM64.Build.0 = Release|x86
+ {B1A2C3D4-E5F6-7890-ABCD-EF1234567891}.Release|x64.ActiveCfg = Release|x86
+ {B1A2C3D4-E5F6-7890-ABCD-EF1234567891}.Release|x64.Build.0 = Release|x86
+ {B1A2C3D4-E5F6-7890-ABCD-EF1234567891}.Release|x86.ActiveCfg = Release|x86
+ {B1A2C3D4-E5F6-7890-ABCD-EF1234567891}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Ink Canvas/App.xaml.cs b/Ink Canvas/App.xaml.cs
index c2d05853..905abd75 100644
--- a/Ink Canvas/App.xaml.cs
+++ b/Ink Canvas/App.xaml.cs
@@ -1202,6 +1202,17 @@ namespace Ink_Canvas
LogHelper.WriteLogToFile($"释放IACore DLL时出错: {ex.Message}", LogHelper.LogType.Error);
}
+ try
+ {
+ LogHelper.WriteLogToFile("启动 IACore IPC 辅助进程");
+ bool ipcStarted = IpcIACoreClient.Instance.Start();
+ LogHelper.WriteLogToFile($"IACore IPC 辅助进程{(ipcStarted ? "启动成功" : "启动失败(将使用本地 IACore 回退)")}");
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"启动 IACore IPC 辅助进程时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+
try
{
LogHelper.WriteLogToFile("开始注册.icstk文件关联");
@@ -1577,6 +1588,13 @@ namespace Ink_Canvas
private void App_Exit(object sender, ExitEventArgs e)
{
CleanupTerminationMonitoring();
+
+ try
+ {
+ IpcIACoreClient.Instance.Dispose();
+ }
+ catch { }
+
// 卸载所有插件
try
{
diff --git a/Ink Canvas/Helpers/InkRecognitionManager.cs b/Ink Canvas/Helpers/InkRecognitionManager.cs
index 8c30d975..40b794ab 100644
--- a/Ink Canvas/Helpers/InkRecognitionManager.cs
+++ b/Ink Canvas/Helpers/InkRecognitionManager.cs
@@ -96,8 +96,10 @@ namespace Ink_Canvas.Helpers
return RecognizeShapeWinRtOnDispatcherContext(strokes);
}
- var legacy = InkRecognizeHelper.RecognizeShapeIACore(strokes);
- return Task.FromResult(InkRecognizeHelper.FromIACoreOrEmpty(legacy));
+ // IACore 必须走 IPC 辅助进程(x86/.NET 4.7.2)。
+ // 在 .NET 6 x64 主进程中本地加载 IAWinFX 会失败,故不再本地回退。
+ var ipcResult = IpcIACoreClient.Instance.Recognize(strokes);
+ return Task.FromResult(ipcResult);
}
catch (Exception ex)
{
@@ -214,9 +216,11 @@ namespace Ink_Canvas.Helpers
public string GetSystemInfo()
{
- return _isModernSystemAvailable
- ? $"现代化墨迹识别系统 (Windows Runtime API) - 进程架构: {Environment.Is64BitProcess}"
- : $"传统墨迹识别系统 (IACore) - 进程架构: {Environment.Is64BitProcess}";
+ if (_isModernSystemAvailable)
+ return $"现代化墨迹识别系统 (Windows Runtime API) - 进程架构: {Environment.Is64BitProcess}";
+ if (IpcIACoreClient.Instance.IsAvailable)
+ return $"传统墨迹识别系统 (IACore via IPC) - 进程架构: {Environment.Is64BitProcess}";
+ return $"传统墨迹识别系统 (IACore 本地) - 进程架构: {Environment.Is64BitProcess}";
}
public void Dispose()
diff --git a/Ink Canvas/Helpers/InkRecognizeHelper.cs b/Ink Canvas/Helpers/InkRecognizeHelper.cs
index ed56e693..35d5be84 100644
--- a/Ink Canvas/Helpers/InkRecognizeHelper.cs
+++ b/Ink Canvas/Helpers/InkRecognizeHelper.cs
@@ -1,79 +1,15 @@
-using System.Linq;
using System.Threading.Tasks;
-using System.Windows;
using System.Windows.Ink;
-using System.Windows.Media;
namespace Ink_Canvas.Helpers
{
+ ///
+ /// 墨迹形状/手写识别的对外门面。
+ /// IACore 路径通过 IPC 调用 x86 辅助进程;WinRT 路径在主进程内直接调用。
+ /// 主进程 (.NET 6 x64) 不再直接引用 IAWinFX 类型。
+ ///
public class InkRecognizeHelper
{
- /// IACore / IAWinFX 形状识别(典型用于 32 位进程)。
- public static ShapeRecognizeResult RecognizeShapeIACore(StrokeCollection strokes)
- {
- if (strokes == null || strokes.Count == 0)
- return default;
-
- var analyzer = new InkAnalyzer();
- analyzer.AddStrokes(strokes);
- analyzer.SetStrokesType(strokes, StrokeType.Drawing);
-
- AnalysisAlternate analysisAlternate = null;
- int strokesCount = strokes.Count;
- var sfsaf = analyzer.Analyze();
- if (sfsaf.Successful)
- {
- var alternates = analyzer.GetAlternates();
- if (alternates.Count > 0)
- {
- 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;
- }
- if (alternates.Count > 0)
- {
- var altFinal = alternates[0];
- if (altFinal?.AlternateNodes != null && altFinal.AlternateNodes.Count > 0)
- analysisAlternate = altFinal;
- }
- }
- }
-
- analyzer.Dispose();
-
- if (analysisAlternate != null && analysisAlternate.AlternateNodes != 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);
- }
-
- return default;
- }
-
- /// 兼容旧调用:等价于 。
- public static ShapeRecognizeResult RecognizeShape(StrokeCollection strokes) =>
- RecognizeShapeIACore(strokes);
-
- /// 按设置选择 WinRT()或 IACore;WinRT 请用 。
public static InkShapeRecognitionResult RecognizeShapeUnified(
StrokeCollection strokes,
ShapeRecognitionEngineMode mode)
@@ -84,11 +20,9 @@ namespace Ink_Canvas.Helpers
if (ShapeRecognitionRouter.ResolveUseWinRt(mode))
return InkShapeRecognitionResult.Empty;
- var legacy = RecognizeShapeIACore(strokes);
- return FromIACoreOrEmpty(legacy);
+ return IpcIACoreClient.Instance.Recognize(strokes);
}
- /// 与 CE 反编译版 InkRecognitionManager.RecognizeShapeAsync 对齐的统一入口。
public static Task RecognizeShapeUnifiedAsync(
StrokeCollection strokes,
ShapeRecognitionEngineMode mode)
@@ -109,7 +43,9 @@ namespace Ink_Canvas.Helpers
WinRtHandwritingRecognizer.Warmup();
}
else
- RecognizeShapeIACore(new StrokeCollection());
+ {
+ IpcIACoreClient.Instance.Start();
+ }
}
catch
{
@@ -117,13 +53,11 @@ namespace Ink_Canvas.Helpers
}
}
- /// WinRT 手写识别(Windows 10+)。
public static Task RecognizeHandwritingUnifiedAsync(
StrokeCollection strokes,
ShapeRecognitionEngineMode mode) =>
InkRecognitionManager.Instance.RecognizeHandwritingAsync(strokes, mode);
- /// WinRT 下将识别成功的词替换为手写体字形墨迹;是否应用由设置「WinRT 识别转手写体字形」控制。
public static Task CorrectHandwritingStrokesUnifiedAsync(
StrokeCollection strokes,
ShapeRecognitionEngineMode mode) =>
@@ -133,7 +67,6 @@ namespace Ink_Canvas.Helpers
MainWindow.Settings?.InkToShape?.EnableWinRtHandwritingStrokeBeautify ?? false,
MainWindow.Settings?.InkToShape?.HandwritingCorrectionFontFamily);
- /// 显式指定是否应用手写体字形替换(忽略开关);字体仍从设置读取。
public static Task CorrectHandwritingStrokesUnifiedAsync(
StrokeCollection strokes,
ShapeRecognitionEngineMode mode,
@@ -144,53 +77,18 @@ namespace Ink_Canvas.Helpers
applyHandwritingBeautify,
MainWindow.Settings?.InkToShape?.HandwritingCorrectionFontFamily);
- internal static InkShapeRecognitionResult FromIACoreOrEmpty(ShapeRecognizeResult legacy)
- {
- if (legacy?.InkDrawingNode == null)
- return InkShapeRecognitionResult.Empty;
-
- var node = legacy.InkDrawingNode;
- var shape = node.GetShape();
- if (shape == null)
- return InkShapeRecognitionResult.Empty;
-
- var hot = ClonePointCollection(node.HotPoints);
- return new InkShapeRecognitionResult(
- node.GetShapeName(),
- legacy.Centroid,
- hot,
- shape.Width,
- shape.Height,
- node.Strokes);
- }
-
- private static PointCollection ClonePointCollection(PointCollection src)
- {
- var dst = new PointCollection();
- if (src == null) return dst;
- foreach (System.Windows.Point p in src)
- dst.Add(p);
- return dst;
- }
-
public static bool IsContainShapeType(string name)
{
if (string.IsNullOrEmpty(name))
return false;
- if (name.Contains("Triangle") || name.Contains("Circle") ||
- name.Contains("Rectangle") || name.Contains("Diamond") ||
- name.Contains("Parallelogram") || name.Contains("Square")
- || name.Contains("Ellipse"))
- {
- return true;
- }
- return false;
+ return name.Contains("Triangle") || name.Contains("Circle") ||
+ name.Contains("Rectangle") || name.Contains("Diamond") ||
+ name.Contains("Parallelogram") || name.Contains("Square") ||
+ name.Contains("Ellipse");
}
}
- //Recognizer 的实现
-
public enum RecognizeLanguage
{
SimplifiedChinese = 0x0804,
@@ -198,127 +96,17 @@ namespace Ink_Canvas.Helpers
English = 0x0809
}
- public class ShapeRecognizeResult
- {
- public ShapeRecognizeResult(Point centroid, PointCollection hotPoints, AnalysisAlternate analysisAlternate, InkDrawingNode node)
- {
- Centroid = centroid;
- HotPoints = hotPoints;
- AnalysisAlternate = analysisAlternate;
- InkDrawingNode = node;
- }
-
- public AnalysisAlternate AnalysisAlternate { get; }
-
- public Point Centroid { get; set; }
-
- public PointCollection HotPoints { get; }
-
- public InkDrawingNode InkDrawingNode { get; }
- }
-
- ///
- /// 图形识别类
- ///
- //public class ShapeRecogniser
- //{
- // public InkAnalyzer _inkAnalyzer = null;
-
- // private ShapeRecogniser()
- // {
- // this._inkAnalyzer = new InkAnalyzer
- // {
- // AnalysisModes = AnalysisModes.AutomaticReconciliationEnabled
- // };
- // }
-
- // ///
- // /// 根据笔迹集合返回图形名称字符串
- // ///
- // ///
- // ///
- // public InkDrawingNode Recognition(StrokeCollection strokeCollection)
- // {
- // if (strokeCollection == null)
- // {
- // //MessageBox.Show("dddddd");
- // return null;
- // }
-
- // InkDrawingNode result = null;
- // try
- // {
- // this._inkAnalyzer.AddStrokes(strokeCollection);
- // if (this._inkAnalyzer.Analyze().Successful)
- // {
- // result = _internalAnalyzer(this._inkAnalyzer);
- // this._inkAnalyzer.RemoveStrokes(strokeCollection);
- // }
- // }
- // catch (System.Exception ex)
- // {
- // //result = ex.Message;
- // System.Diagnostics.Debug.WriteLine(ex.Message);
- // }
-
- // return result;
- // }
-
- // ///
- // /// 实现笔迹的分析,返回图形对应的字符串
- // /// 你在实际的应用中根据返回的字符串来生成对应的Shape
- // ///
- // ///
- // ///
- // private InkDrawingNode _internalAnalyzer(InkAnalyzer ink)
- // {
- // try
- // {
- // ContextNodeCollection nodecollections = ink.FindNodesOfType(ContextNodeType.InkDrawing);
- // foreach (ContextNode node in nodecollections)
- // {
- // InkDrawingNode drawingNode = node as InkDrawingNode;
- // if (drawingNode != null)
- // {
- // return drawingNode;//.GetShapeName();
- // }
- // }
- // }
- // catch (System.Exception ex)
- // {
- // System.Diagnostics.Debug.WriteLine(ex.Message);
- // }
-
- // return null;
- // }
-
-
- // private static ShapeRecogniser instance = null;
- // public static ShapeRecogniser Instance
- // {
- // get
- // {
- // return instance == null ? (instance = new ShapeRecogniser()) : instance;
- // }
- // }
- //}
-
-
- //用于自动控制其他形状相对于圆的位置
-
public class Circle
{
- public Circle(Point centroid, double r, Stroke stroke)
+ public Circle(System.Windows.Point centroid, double r, Stroke stroke)
{
Centroid = centroid;
R = r;
Stroke = stroke;
}
- public Point Centroid { get; set; }
-
+ public System.Windows.Point Centroid { get; set; }
public double R { get; set; }
-
public Stroke Stroke { get; set; }
}
-}
+}
\ No newline at end of file
diff --git a/Ink Canvas/Helpers/IpcIACoreClient.cs b/Ink Canvas/Helpers/IpcIACoreClient.cs
new file mode 100644
index 00000000..9910c6f0
--- /dev/null
+++ b/Ink Canvas/Helpers/IpcIACoreClient.cs
@@ -0,0 +1,302 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.IO.Pipes;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Ink;
+using System.Windows.Media;
+
+namespace Ink_Canvas.Helpers
+{
+ ///
+ /// 通过 Named Pipe IPC 调用 32 位辅助进程 InkCanvasForClass.IACoreHelper.exe 进行 IACore 形状识别。
+ /// 单例,线程安全,辅助进程崩溃后自动重启。
+ ///
+ public sealed class IpcIACoreClient : IDisposable
+ {
+ // ── 单例 ──────────────────────────────────────────────────────────────
+ private static IpcIACoreClient _instance;
+ private static readonly object _instanceLock = new object();
+
+ public static IpcIACoreClient Instance
+ {
+ get
+ {
+ if (_instance == null)
+ lock (_instanceLock)
+ if (_instance == null)
+ _instance = new IpcIACoreClient();
+ return _instance;
+ }
+ }
+
+ // ── 状态 ──────────────────────────────────────────────────────────────
+ private Process _helperProcess;
+ private readonly object _pipeLock = new object();
+ private bool _disposed;
+ private bool _available;
+
+ // 辅助进程 EXE 的路径(与主 EXE 同目录)
+ private static string HelperExePath =>
+ Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "InkCanvasForClass.IACoreHelper.exe");
+
+ // Named Pipe 名称(含主进程 PID,保证唯一)
+ private string PipeName =>
+ string.Format("ICC_IACoreHelper_{0}", Process.GetCurrentProcess().Id);
+
+ private IpcIACoreClient() { }
+
+ // ── 公开 API ──────────────────────────────────────────────────────────
+
+ /// 启动辅助进程,返回是否成功。
+ public bool Start()
+ {
+ if (_disposed) return false;
+
+ // 已运行则无需重启,避免 Warmup + App 两处调用导致重复启动
+ if (IsAvailable) return true;
+
+ if (!File.Exists(HelperExePath))
+ {
+ LogHelper.WriteLogToFile($"[IACoreIPC] 辅助进程不存在: {HelperExePath}", LogHelper.LogType.Warning);
+ _available = false;
+ return false;
+ }
+
+ return LaunchHelper();
+ }
+
+ /// 是否就绪(辅助进程运行中)。
+ public bool IsAvailable => _available && _helperProcess != null && !_helperProcess.HasExited;
+
+ ///
+ /// 发送笔画到辅助进程进行 IACore 形状识别。
+ /// 超时或失败时返回 。
+ ///
+ public InkShapeRecognitionResult Recognize(StrokeCollection strokes)
+ {
+ if (strokes == null || strokes.Count == 0)
+ return InkShapeRecognitionResult.Empty;
+
+ EnsureHelperAlive();
+ if (!IsAvailable)
+ {
+ LogHelper.WriteLogToFile($"[IACoreIPC] Recognize 跳过:辅助进程不可用(strokes={strokes.Count})", LogHelper.LogType.Warning);
+ return InkShapeRecognitionResult.Empty;
+ }
+
+ lock (_pipeLock)
+ {
+ try
+ {
+ LogHelper.WriteLogToFile($"[IACoreIPC] Recognize 请求:strokes={strokes.Count}");
+ var result = SendRecognizeRequest(strokes);
+ LogHelper.WriteLogToFile(
+ $"[IACoreIPC] Recognize 响应:IsSuccess={result.IsSuccess}, Shape={result.ShapeName}, StrokesToRemove={result.StrokesToRemove?.Count ?? 0}");
+ return result;
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"[IACoreIPC] 识别失败: {ex.GetType().Name}: {ex.Message}", LogHelper.LogType.Error);
+ KillHelper();
+ return InkShapeRecognitionResult.Empty;
+ }
+ }
+ }
+
+ // ── 内部实现 ──────────────────────────────────────────────────────────
+
+ private bool LaunchHelper()
+ {
+ try
+ {
+ KillHelper();
+
+ var psi = new ProcessStartInfo
+ {
+ FileName = HelperExePath,
+ Arguments = Process.GetCurrentProcess().Id.ToString(),
+ UseShellExecute = false,
+ CreateNoWindow = true,
+ WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory
+ };
+ _helperProcess = Process.Start(psi);
+ if (_helperProcess == null)
+ {
+ _available = false;
+ return false;
+ }
+ _helperProcess.EnableRaisingEvents = true;
+ _helperProcess.Exited += OnHelperExited;
+
+ // 等待 Pipe 就绪(最多 3 s)
+ bool pipeReady = WaitForPipe(3000);
+ _available = pipeReady;
+
+ LogHelper.WriteLogToFile($"[IACoreIPC] 辅助进程启动{(pipeReady ? "成功" : "失败(Pipe 未就绪)")},PID={_helperProcess?.Id}");
+ return pipeReady;
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"[IACoreIPC] 启动辅助进程失败: {ex.Message}", LogHelper.LogType.Error);
+ _available = false;
+ return false;
+ }
+ }
+
+ private bool WaitForPipe(int timeoutMs)
+ {
+ int elapsed = 0;
+ while (elapsed < timeoutMs)
+ {
+ if (_helperProcess == null || _helperProcess.HasExited)
+ return false;
+
+ try
+ {
+ using (var probe = new NamedPipeClientStream(".", PipeName, PipeDirection.InOut))
+ {
+ probe.Connect(200);
+ // 连接成功后立即断开,下次 Recognize 会重新连接
+ return true;
+ }
+ }
+ catch
+ {
+ Thread.Sleep(100);
+ elapsed += 300;
+ }
+ }
+ return false;
+ }
+
+ private InkShapeRecognitionResult SendRecognizeRequest(StrokeCollection strokes)
+ {
+ using (var client = new NamedPipeClientStream(".", PipeName, PipeDirection.InOut))
+ {
+ client.Connect(IpcTimeoutMs);
+
+ using (var writer = new BinaryWriter(client, System.Text.Encoding.UTF8, leaveOpen: true))
+ using (var reader = new BinaryReader(client, System.Text.Encoding.UTF8, leaveOpen: true))
+ {
+ // 序列化请求
+ writer.Write(CmdRecognize);
+ writer.Write(strokes.Count);
+ foreach (var stroke in strokes)
+ {
+ var pts = stroke.StylusPoints;
+ writer.Write(pts.Count);
+ foreach (var pt in pts)
+ {
+ writer.Write((float)pt.X);
+ writer.Write((float)pt.Y);
+ writer.Write(pt.PressureFactor);
+ }
+ }
+ writer.Flush();
+
+ // 读取响应
+ bool success = reader.ReadBoolean();
+ string shape = reader.ReadString();
+ float cx = reader.ReadSingle();
+ float cy = reader.ReadSingle();
+ float width = reader.ReadSingle();
+ float height = reader.ReadSingle();
+
+ int hotLen = reader.ReadInt32();
+ var hotPoints = new PointCollection();
+ for (int i = 0; i < hotLen; i++)
+ hotPoints.Add(new Point(reader.ReadSingle(), reader.ReadSingle()));
+
+ int idxLen = reader.ReadInt32();
+ var indices = new int[idxLen];
+ for (int i = 0; i < idxLen; i++)
+ indices[i] = reader.ReadInt32();
+
+ if (!success || string.IsNullOrEmpty(shape))
+ return InkShapeRecognitionResult.Empty;
+
+ // 根据下标还原参与识别的笔画子集
+ var recognized = new StrokeCollection();
+ foreach (int idx in indices)
+ if (idx >= 0 && idx < strokes.Count)
+ recognized.Add(strokes[idx]);
+
+ return new InkShapeRecognitionResult(
+ shape,
+ new Point(cx, cy),
+ hotPoints,
+ width,
+ height,
+ recognized);
+ }
+ }
+ }
+
+ private void EnsureHelperAlive()
+ {
+ if (!IsAvailable)
+ {
+ LogHelper.WriteLogToFile("[IACoreIPC] 辅助进程不可用,尝试重启...", LogHelper.LogType.Warning);
+ LaunchHelper();
+ }
+ }
+
+ private void OnHelperExited(object sender, EventArgs e)
+ {
+ _available = false;
+ LogHelper.WriteLogToFile("[IACoreIPC] 辅助进程意外退出", LogHelper.LogType.Warning);
+ }
+
+ private void KillHelper()
+ {
+ if (_helperProcess == null) return;
+ try
+ {
+ // 先解除事件订阅,避免主动 Kill 时触发 OnHelperExited 误报
+ try { _helperProcess.Exited -= OnHelperExited; } catch { }
+
+ if (!_helperProcess.HasExited)
+ {
+ // 发送优雅关闭命令
+ try
+ {
+ using (var client = new NamedPipeClientStream(".", PipeName, PipeDirection.InOut))
+ {
+ client.Connect(500);
+ using (var w = new BinaryWriter(client))
+ w.Write(CmdShutdown);
+ }
+ }
+ catch { /* 忽略,下面直接 Kill */ }
+
+ if (!_helperProcess.WaitForExit(800))
+ _helperProcess.Kill();
+ }
+ }
+ catch { }
+ finally
+ {
+ _helperProcess?.Dispose();
+ _helperProcess = null;
+ _available = false;
+ }
+ }
+
+ public void Dispose()
+ {
+ if (_disposed) return;
+ _disposed = true;
+ KillHelper();
+ }
+
+ // ── 协议常量(与 IACoreHelper/IpcProtocol.cs 保持一致) ─────────────
+ private const int IpcTimeoutMs = 5000;
+ private const byte CmdRecognize = 0x01;
+ private const byte CmdShutdown = 0xFF;
+ }
+}
\ No newline at end of file
diff --git a/Ink Canvas/InkCanvasForClass.csproj b/Ink Canvas/InkCanvasForClass.csproj
index 6dc1f47a..2721fa3e 100644
--- a/Ink Canvas/InkCanvasForClass.csproj
+++ b/Ink Canvas/InkCanvasForClass.csproj
@@ -101,20 +101,6 @@
x64
false
-
-
- .\IACore.dll
- False
-
-
- .\IALoader.dll
- False
-
-
- .\IAWinFX.dll
- False
-
-
@@ -153,6 +139,10 @@
+
+ false
+ false
+
@@ -668,4 +658,11 @@
+
+
+
+
+
+
+
diff --git a/InkCanvasForClass.IACoreHelper/App.config b/InkCanvasForClass.IACoreHelper/App.config
new file mode 100644
index 00000000..1dc0cb08
--- /dev/null
+++ b/InkCanvasForClass.IACoreHelper/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/InkCanvasForClass.IACoreHelper/InkCanvasForClass.IACoreHelper.csproj b/InkCanvasForClass.IACoreHelper/InkCanvasForClass.IACoreHelper.csproj
new file mode 100644
index 00000000..96bb9909
--- /dev/null
+++ b/InkCanvasForClass.IACoreHelper/InkCanvasForClass.IACoreHelper.csproj
@@ -0,0 +1,56 @@
+
+
+
+
+ Debug
+ x86
+ {B1A2C3D4-E5F6-7890-ABCD-EF1234567891}
+ Exe
+ InkCanvasForClass.IACoreHelper
+ InkCanvasForClass.IACoreHelper
+ v4.7.2
+ 512
+ true
+ true
+
+
+ x86
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ x86
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+ ..\Ink Canvas\Resources\IACore\IAWinFX.dll
+ false
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/InkCanvasForClass.IACoreHelper/IpcProtocol.cs b/InkCanvasForClass.IACoreHelper/IpcProtocol.cs
new file mode 100644
index 00000000..ed93f411
--- /dev/null
+++ b/InkCanvasForClass.IACoreHelper/IpcProtocol.cs
@@ -0,0 +1,133 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace InkCanvasForClass.IACoreHelper
+{
+ // Named Pipe 名称,主进程和辅助进程共用
+ internal static class IpcConstants
+ {
+ public const string PipeName = "ICC_IACoreHelper_{0}"; // {0} = 主进程 PID
+ public const int RequestTimeout = 5000; // ms
+ public const byte CmdRecognize = 0x01;
+ public const byte CmdShutdown = 0xFF;
+ }
+
+ // 单个 StylusPoint 的轻量传输结构
+ internal struct StylusPointDto
+ {
+ public float X;
+ public float Y;
+ public float Pressure;
+ }
+
+ // 单条笔画
+ internal class StrokeDto
+ {
+ public StylusPointDto[] Points;
+ }
+
+ // 识别请求(主进程 → 辅助进程)
+ internal class RecognizeRequest
+ {
+ public StrokeDto[] Strokes;
+
+ public void WriteTo(BinaryWriter w)
+ {
+ w.Write(IpcConstants.CmdRecognize);
+ w.Write(Strokes.Length);
+ foreach (var stroke in Strokes)
+ {
+ w.Write(stroke.Points.Length);
+ foreach (var pt in stroke.Points)
+ {
+ w.Write(pt.X);
+ w.Write(pt.Y);
+ w.Write(pt.Pressure);
+ }
+ }
+ }
+
+ public static RecognizeRequest ReadFrom(BinaryReader r)
+ {
+ int strokeCount = r.ReadInt32();
+ var strokes = new StrokeDto[strokeCount];
+ for (int i = 0; i < strokeCount; i++)
+ {
+ int ptCount = r.ReadInt32();
+ var pts = new StylusPointDto[ptCount];
+ for (int j = 0; j < ptCount; j++)
+ pts[j] = new StylusPointDto { X = r.ReadSingle(), Y = r.ReadSingle(), Pressure = r.ReadSingle() };
+ strokes[i] = new StrokeDto { Points = pts };
+ }
+ return new RecognizeRequest { Strokes = strokes };
+ }
+ }
+
+ // 识别响应(辅助进程 → 主进程)
+ internal class RecognizeResponse
+ {
+ public bool Success;
+ public string ShapeName; // e.g. "Circle", "Rectangle", "Triangle" ...
+ public float CentroidX;
+ public float CentroidY;
+ public float ShapeWidth;
+ public float ShapeHeight;
+ public float[] HotPointsX;
+ public float[] HotPointsY;
+ public int[] StrokeIndices; // 参与识别的笔画在原始数组中的下标
+
+ public void WriteTo(BinaryWriter w)
+ {
+ w.Write(Success);
+ w.Write(ShapeName ?? string.Empty);
+ w.Write(CentroidX);
+ w.Write(CentroidY);
+ w.Write(ShapeWidth);
+ w.Write(ShapeHeight);
+
+ int hotLen = HotPointsX != null ? HotPointsX.Length : 0;
+ w.Write(hotLen);
+ for (int i = 0; i < hotLen; i++)
+ {
+ w.Write(HotPointsX[i]);
+ w.Write(HotPointsY[i]);
+ }
+
+ int idxLen = StrokeIndices != null ? StrokeIndices.Length : 0;
+ w.Write(idxLen);
+ for (int i = 0; i < idxLen; i++)
+ w.Write(StrokeIndices[i]);
+ }
+
+ public static RecognizeResponse ReadFrom(BinaryReader r)
+ {
+ var resp = new RecognizeResponse
+ {
+ Success = r.ReadBoolean(),
+ ShapeName = r.ReadString(),
+ CentroidX = r.ReadSingle(),
+ CentroidY = r.ReadSingle(),
+ ShapeWidth = r.ReadSingle(),
+ ShapeHeight = r.ReadSingle()
+ };
+
+ int hotLen = r.ReadInt32();
+ resp.HotPointsX = new float[hotLen];
+ resp.HotPointsY = new float[hotLen];
+ for (int i = 0; i < hotLen; i++)
+ {
+ resp.HotPointsX[i] = r.ReadSingle();
+ resp.HotPointsY[i] = r.ReadSingle();
+ }
+
+ int idxLen = r.ReadInt32();
+ resp.StrokeIndices = new int[idxLen];
+ for (int i = 0; i < idxLen; i++)
+ resp.StrokeIndices[i] = r.ReadInt32();
+
+ return resp;
+ }
+ }
+}
\ No newline at end of file
diff --git a/InkCanvasForClass.IACoreHelper/Program.cs b/InkCanvasForClass.IACoreHelper/Program.cs
new file mode 100644
index 00000000..5b701235
--- /dev/null
+++ b/InkCanvasForClass.IACoreHelper/Program.cs
@@ -0,0 +1,222 @@
+using System;
+using System.IO;
+using System.IO.Pipes;
+using System.Linq;
+using System.Windows;
+using System.Windows.Ink;
+using System.Windows.Input;
+
+namespace InkCanvasForClass.IACoreHelper
+{
+ internal static class Program
+ {
+ private static readonly string LogPath = Path.Combine(
+ AppDomain.CurrentDomain.BaseDirectory, "IACoreHelper.log");
+
+ private static void Log(string msg)
+ {
+ try { File.AppendAllText(LogPath, $"{DateTime.Now:HH:mm:ss.fff} {msg}{Environment.NewLine}"); }
+ catch { }
+ }
+
+ [STAThread]
+ static void Main(string[] args)
+ {
+ Log($"=== Helper started, args=[{string.Join(",", args)}], cwd={Environment.CurrentDirectory}, baseDir={AppDomain.CurrentDomain.BaseDirectory} ===");
+
+ if (args.Length < 1 || !int.TryParse(args[0], out int parentPid))
+ {
+ Console.Error.WriteLine("Usage: IACoreHelper.exe ");
+ Log("Missing parentPid argument, exiting");
+ return;
+ }
+
+ string pipeName = string.Format(IpcConstants.PipeName, parentPid);
+ Log($"Pipe name: {pipeName}");
+
+ try
+ {
+ RunPipeServer(pipeName);
+ }
+ catch (Exception ex)
+ {
+ Log($"FATAL: {ex}");
+ Console.Error.WriteLine("IACoreHelper fatal: " + ex.Message);
+ }
+ }
+
+ private static void RunPipeServer(string pipeName)
+ {
+ while (true)
+ {
+ using (var server = new NamedPipeServerStream(
+ pipeName,
+ PipeDirection.InOut,
+ 1,
+ PipeTransmissionMode.Byte,
+ PipeOptions.WriteThrough))
+ {
+ server.WaitForConnection();
+
+ try
+ {
+ using (var reader = new BinaryReader(server, System.Text.Encoding.UTF8, leaveOpen: true))
+ using (var writer = new BinaryWriter(server, System.Text.Encoding.UTF8, leaveOpen: true))
+ {
+ byte cmd = reader.ReadByte();
+
+ if (cmd == IpcConstants.CmdShutdown)
+ return;
+
+ if (cmd == IpcConstants.CmdRecognize)
+ {
+ var request = RecognizeRequest.ReadFrom(reader);
+ var response = HandleRecognize(request);
+ response.WriteTo(writer);
+ writer.Flush();
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.Error.WriteLine("IACoreHelper pipe error: " + ex.Message);
+ }
+ }
+ // 每次连接后重新监听,支持多次调用
+ }
+ }
+
+ private static RecognizeResponse HandleRecognize(RecognizeRequest request)
+ {
+ try
+ {
+ Log($"HandleRecognize: strokes={request.Strokes?.Length ?? 0}");
+ var strokes = BuildStrokeCollection(request);
+ Log($"Built StrokeCollection: count={strokes.Count}");
+ if (strokes.Count == 0)
+ return new RecognizeResponse { Success = false, ShapeName = string.Empty };
+
+ var result = RecognizeCore(strokes);
+ Log($"RecognizeCore result: success={result.Success}, shape={result.ShapeName}");
+ return result;
+ }
+ catch (Exception ex)
+ {
+ Log($"HandleRecognize EXCEPTION: {ex}");
+ Console.Error.WriteLine("IACoreHelper recognize error: " + ex.Message);
+ return new RecognizeResponse { Success = false, ShapeName = string.Empty };
+ }
+ }
+
+ private static StrokeCollection BuildStrokeCollection(RecognizeRequest request)
+ {
+ var sc = new StrokeCollection();
+ foreach (var strokeDto in request.Strokes)
+ {
+ if (strokeDto.Points == null || strokeDto.Points.Length == 0)
+ continue;
+
+ var stylusPoints = new StylusPointCollection();
+ foreach (var pt in strokeDto.Points)
+ stylusPoints.Add(new StylusPoint(pt.X, pt.Y, pt.Pressure));
+
+ sc.Add(new Stroke(stylusPoints));
+ }
+ return sc;
+ }
+
+ private static RecognizeResponse RecognizeCore(StrokeCollection strokes)
+ {
+ var analyzer = new InkAnalyzer();
+ analyzer.AddStrokes(strokes);
+ analyzer.SetStrokesType(strokes, StrokeType.Drawing);
+
+ AnalysisAlternate analysisAlternate = null;
+ int strokesCount = strokes.Count;
+ var analysisStatus = analyzer.Analyze();
+
+ if (analysisStatus.Successful)
+ {
+ var alternates = analyzer.GetAlternates();
+ if (alternates.Count > 0)
+ {
+ 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;
+ bool shapeOk = IsContainShapeType(drawNode.GetShapeName());
+ if (alt0.Strokes.Contains(strokes.Last()) && shapeOk)
+ break;
+ analyzer.RemoveStroke(strokes[strokes.Count - strokesCount]);
+ strokesCount--;
+ analysisStatus = analyzer.Analyze();
+ if (analysisStatus.Successful)
+ alternates = analyzer.GetAlternates();
+ else
+ break;
+ if (alternates.Count == 0)
+ break;
+ }
+
+ if (alternates.Count > 0)
+ {
+ var altFinal = alternates[0];
+ if (altFinal?.AlternateNodes != null && altFinal.AlternateNodes.Count > 0)
+ analysisAlternate = altFinal;
+ }
+ }
+ }
+
+ analyzer.Dispose();
+
+ if (analysisAlternate?.AlternateNodes == null || analysisAlternate.AlternateNodes.Count == 0)
+ return new RecognizeResponse { Success = false, ShapeName = string.Empty };
+
+ var node = analysisAlternate.AlternateNodes[0] as InkDrawingNode;
+ if (node == null)
+ return new RecognizeResponse { Success = false, ShapeName = string.Empty };
+
+ var shape = node.GetShape();
+ var center = node.Centroid;
+ var hot = node.HotPoints;
+
+ float[] hotX = new float[hot?.Count ?? 0];
+ float[] hotY = new float[hot?.Count ?? 0];
+ if (hot != null)
+ for (int i = 0; i < hot.Count; i++) { hotX[i] = (float)hot[i].X; hotY[i] = (float)hot[i].Y; }
+
+ // 计算参与识别的笔画在原始集合中的下标
+ var participatingStrokes = analysisAlternate.Strokes;
+ int[] strokeIndices = new int[participatingStrokes?.Count ?? 0];
+ if (participatingStrokes != null)
+ for (int i = 0; i < participatingStrokes.Count; i++)
+ strokeIndices[i] = strokes.IndexOf(participatingStrokes[i]);
+
+ return new RecognizeResponse
+ {
+ Success = true,
+ ShapeName = node.GetShapeName() ?? string.Empty,
+ CentroidX = (float)center.X,
+ CentroidY = (float)center.Y,
+ ShapeWidth = shape != null ? (float)shape.Width : 0f,
+ ShapeHeight = shape != null ? (float)shape.Height : 0f,
+ HotPointsX = hotX,
+ HotPointsY = hotY,
+ StrokeIndices = strokeIndices
+ };
+ }
+
+ private static bool IsContainShapeType(string name)
+ {
+ if (string.IsNullOrEmpty(name)) return false;
+ return name.Contains("Triangle") || name.Contains("Circle") ||
+ name.Contains("Rectangle") || name.Contains("Diamond") ||
+ name.Contains("Parallelogram") || name.Contains("Square") ||
+ name.Contains("Ellipse");
+ }
+ }
+}
\ No newline at end of file
diff --git a/InkCanvasForClass.IACoreHelper/Properties/AssemblyInfo.cs b/InkCanvasForClass.IACoreHelper/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..51bf9aa3
--- /dev/null
+++ b/InkCanvasForClass.IACoreHelper/Properties/AssemblyInfo.cs
@@ -0,0 +1,11 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("InkCanvasForClass.IACoreHelper")]
+[assembly: AssemblyDescription("IACore 32-bit ink shape recognition helper process")]
+[assembly: AssemblyCompany("ICC CE")]
+[assembly: AssemblyProduct("InkCanvasForClass.IACoreHelper")]
+[assembly: AssemblyCopyright("Copyright © ICC CE")]
+[assembly: ComVisible(false)]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
\ No newline at end of file
From 07ebbfbd242a34a4083caa429131da95eeeddd80 Mon Sep 17 00:00:00 2001
From: PrefacedCorg <1876568293@qq.com>
Date: Fri, 1 May 2026 23:54:31 +0800
Subject: [PATCH 3/4] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=20BoardMenuF?=
=?UTF-8?q?rame=20=E6=8E=A7=E4=BB=B6=E5=B9=B6=E5=86=85=E8=81=94=E5=AE=9E?=
=?UTF-8?q?=E7=8E=B0=E5=9B=BE=E5=83=8F=E9=80=89=E9=A1=B9=E9=9D=A2=E6=9D=BF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
将 BoardMenuFrame 自定义控件及其样式从项目中移除,改为直接在 MainWindow.xaml 中内联实现图像选项面板的布局和样式,以简化代码结构并减少自定义控件的使用
---
Ink Canvas/Controls/BoardMenuFrame.cs | 141 -----------------------
Ink Canvas/MainWindow.xaml | 156 +++++++++++++++-----------
Ink Canvas/Themes/Generic.xaml | 61 ----------
3 files changed, 88 insertions(+), 270 deletions(-)
delete mode 100644 Ink Canvas/Controls/BoardMenuFrame.cs
delete mode 100644 Ink Canvas/Themes/Generic.xaml
diff --git a/Ink Canvas/Controls/BoardMenuFrame.cs b/Ink Canvas/Controls/BoardMenuFrame.cs
deleted file mode 100644
index cadefa70..00000000
--- a/Ink Canvas/Controls/BoardMenuFrame.cs
+++ /dev/null
@@ -1,141 +0,0 @@
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Controls.Primitives;
-using System.Windows.Input;
-using System.Windows.Media;
-
-namespace Ink_Canvas.Controls
-{
- [TemplatePart(Name = PartCloseImage, Type = typeof(UIElement))]
- [TemplatePart(Name = PartAnimationRoot, Type = typeof(UIElement))]
- public class BoardMenuFrame : ContentControl
- {
- private const string PartCloseImage = "PART_CloseImage";
- private const string PartAnimationRoot = "PART_AnimationRoot";
-
- public static readonly DependencyProperty TitleProperty =
- DependencyProperty.Register(nameof(Title), typeof(object), typeof(BoardMenuFrame), new PropertyMetadata(null));
-
- public static readonly DependencyProperty TitleFontSizeProperty =
- DependencyProperty.Register(nameof(TitleFontSize), typeof(double), typeof(BoardMenuFrame), new PropertyMetadata(11d));
-
- public static readonly DependencyProperty HeaderHeightProperty =
- DependencyProperty.Register(nameof(HeaderHeight), typeof(double), typeof(BoardMenuFrame), new PropertyMetadata(48d));
-
- public static readonly DependencyProperty PanelCornerRadiusProperty =
- DependencyProperty.Register(nameof(PanelCornerRadius), typeof(CornerRadius), typeof(BoardMenuFrame), new PropertyMetadata(new CornerRadius(5)));
-
- public static readonly DependencyProperty HeaderCornerRadiusProperty =
- DependencyProperty.Register(nameof(HeaderCornerRadius), typeof(CornerRadius), typeof(BoardMenuFrame), new PropertyMetadata(new CornerRadius(6, 6, 0, 0)));
-
- public static readonly DependencyProperty PanelBackgroundProperty =
- DependencyProperty.Register(nameof(PanelBackground), typeof(Brush), typeof(BoardMenuFrame), new PropertyMetadata(null));
-
- public static readonly DependencyProperty HeaderBackgroundProperty =
- DependencyProperty.Register(nameof(HeaderBackground), typeof(Brush), typeof(BoardMenuFrame),
- new PropertyMetadata(new SolidColorBrush((Color)ColorConverter.ConvertFromString("#2563eb"))));
-
- public static readonly DependencyProperty HeaderBorderBrushProperty =
- DependencyProperty.Register(nameof(HeaderBorderBrush), typeof(Brush), typeof(BoardMenuFrame),
- new PropertyMetadata(new SolidColorBrush((Color)ColorConverter.ConvertFromString("#1e3a8a"))));
-
- public static readonly DependencyProperty IsOpenProperty =
- DependencyProperty.Register(nameof(IsOpen), typeof(bool), typeof(BoardMenuFrame), new PropertyMetadata(false));
-
- public static readonly DependencyProperty PlacementTargetProperty =
- DependencyProperty.Register(nameof(PlacementTarget), typeof(UIElement), typeof(BoardMenuFrame), new PropertyMetadata(null));
-
- public static readonly DependencyProperty PlacementProperty =
- DependencyProperty.Register(nameof(Placement), typeof(PlacementMode), typeof(BoardMenuFrame), new PropertyMetadata(PlacementMode.Custom));
-
- public static readonly DependencyProperty CustomPopupPlacementCallbackProperty =
- DependencyProperty.Register(nameof(CustomPopupPlacementCallback), typeof(CustomPopupPlacementCallback), typeof(BoardMenuFrame),
- new PropertyMetadata((CustomPopupPlacementCallback)PlaceCenteredAbove));
-
- private static CustomPopupPlacement[] PlaceCenteredAbove(Size popupSize, Size targetSize, Point offset)
- {
- return new[]
- {
- new CustomPopupPlacement(
- new Point((targetSize.Width - popupSize.Width) / 2 + offset.X,
- -popupSize.Height + offset.Y),
- PopupPrimaryAxis.Horizontal),
- new CustomPopupPlacement(
- new Point((targetSize.Width - popupSize.Width) / 2 + offset.X,
- targetSize.Height - offset.Y),
- PopupPrimaryAxis.Horizontal)
- };
- }
-
- public static readonly DependencyProperty PopupHorizontalOffsetProperty =
- DependencyProperty.Register(nameof(PopupHorizontalOffset), typeof(double), typeof(BoardMenuFrame), new PropertyMetadata(0d));
-
- public static readonly DependencyProperty PopupVerticalOffsetProperty =
- DependencyProperty.Register(nameof(PopupVerticalOffset), typeof(double), typeof(BoardMenuFrame), new PropertyMetadata(-4d));
-
- public object Title { get => GetValue(TitleProperty); set => SetValue(TitleProperty, value); }
- public double TitleFontSize { get => (double)GetValue(TitleFontSizeProperty); set => SetValue(TitleFontSizeProperty, value); }
- public double HeaderHeight { get => (double)GetValue(HeaderHeightProperty); set => SetValue(HeaderHeightProperty, value); }
- public CornerRadius PanelCornerRadius { get => (CornerRadius)GetValue(PanelCornerRadiusProperty); set => SetValue(PanelCornerRadiusProperty, value); }
- public CornerRadius HeaderCornerRadius { get => (CornerRadius)GetValue(HeaderCornerRadiusProperty); set => SetValue(HeaderCornerRadiusProperty, value); }
- public Brush PanelBackground { get => (Brush)GetValue(PanelBackgroundProperty); set => SetValue(PanelBackgroundProperty, value); }
- public Brush HeaderBackground { get => (Brush)GetValue(HeaderBackgroundProperty); set => SetValue(HeaderBackgroundProperty, value); }
- public Brush HeaderBorderBrush { get => (Brush)GetValue(HeaderBorderBrushProperty); set => SetValue(HeaderBorderBrushProperty, value); }
- public bool IsOpen { get => (bool)GetValue(IsOpenProperty); set => SetValue(IsOpenProperty, value); }
- public UIElement PlacementTarget { get => (UIElement)GetValue(PlacementTargetProperty); set => SetValue(PlacementTargetProperty, value); }
- public PlacementMode Placement { get => (PlacementMode)GetValue(PlacementProperty); set => SetValue(PlacementProperty, value); }
- public CustomPopupPlacementCallback CustomPopupPlacementCallback
- {
- get => (CustomPopupPlacementCallback)GetValue(CustomPopupPlacementCallbackProperty);
- set => SetValue(CustomPopupPlacementCallbackProperty, value);
- }
- public double PopupHorizontalOffset { get => (double)GetValue(PopupHorizontalOffsetProperty); set => SetValue(PopupHorizontalOffsetProperty, value); }
- public double PopupVerticalOffset { get => (double)GetValue(PopupVerticalOffsetProperty); set => SetValue(PopupVerticalOffsetProperty, value); }
-
- public event MouseButtonEventHandler CloseMouseDown;
- public event MouseButtonEventHandler CloseMouseUp;
-
- public UIElement AnimationTarget { get; private set; }
-
- private UIElement _closeImage;
-
- static BoardMenuFrame()
- {
- DefaultStyleKeyProperty.OverrideMetadata(typeof(BoardMenuFrame), new FrameworkPropertyMetadata(typeof(BoardMenuFrame)));
- VisibilityProperty.OverrideMetadata(typeof(BoardMenuFrame),
- new FrameworkPropertyMetadata(Visibility.Collapsed, OnVisibilityChanged));
- }
-
- private static void OnVisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- ((BoardMenuFrame)d).IsOpen = (Visibility)e.NewValue == Visibility.Visible;
- }
-
- public override void OnApplyTemplate()
- {
- base.OnApplyTemplate();
- if (_closeImage != null)
- {
- _closeImage.MouseDown -= CloseImage_MouseDown;
- _closeImage.MouseUp -= CloseImage_MouseUp;
- }
- _closeImage = GetTemplateChild(PartCloseImage) as UIElement;
- if (_closeImage != null)
- {
- _closeImage.MouseDown += CloseImage_MouseDown;
- _closeImage.MouseUp += CloseImage_MouseUp;
- }
- AnimationTarget = GetTemplateChild(PartAnimationRoot) as UIElement;
- }
-
- private void CloseImage_MouseDown(object sender, MouseButtonEventArgs e)
- {
- CloseMouseDown?.Invoke(sender, e);
- }
-
- private void CloseImage_MouseUp(object sender, MouseButtonEventArgs e)
- {
- CloseMouseUp?.Invoke(sender, e);
- }
- }
-}
\ No newline at end of file
diff --git a/Ink Canvas/MainWindow.xaml b/Ink Canvas/MainWindow.xaml
index 89a6f0ab..02aa2dac 100644
--- a/Ink Canvas/MainWindow.xaml
+++ b/Ink Canvas/MainWindow.xaml
@@ -1899,76 +1899,96 @@
IconGeometry="F1 M24,24z M0,0z M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2-0.9 2-2V5C21,3.9 20.1,3 19,3zM19,19H5V5h14V19z M17,7c-1.1,0-2,0.9-2,2s0.9,2 2,2 2-0.9 2-2S18.1,7 17,7zM7,17l2.5-3.01 1.96,2.36 2.54-3.21L17,17H7z"
ButtonMouseUp="InsertImageOptions_MouseUp" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
\ No newline at end of file
From 94142ec8a57a1592edfac4623b56f11e6e293f19 Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sat, 2 May 2026 00:40:49 +0800
Subject: [PATCH 4/4] =?UTF-8?q?add:=E5=9F=BA=E4=BA=8EIPC=E7=9A=84IACore?=
=?UTF-8?q?=E5=9C=A8net6=E7=9A=84=E5=AE=9E=E7=8E=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/App.xaml.cs | 11 +++--
Ink Canvas/Helpers/AnimationsHelper.cs | 11 +----
Ink Canvas/Helpers/IpcIACoreClient.cs | 55 ++---------------------
Ink Canvas/Properties/Strings.resx | 2 +-
InkCanvasForClass.IACoreHelper/Program.cs | 24 +---------
5 files changed, 15 insertions(+), 88 deletions(-)
diff --git a/Ink Canvas/App.xaml.cs b/Ink Canvas/App.xaml.cs
index 905abd75..4e771ab7 100644
--- a/Ink Canvas/App.xaml.cs
+++ b/Ink Canvas/App.xaml.cs
@@ -1204,9 +1204,14 @@ namespace Ink_Canvas
try
{
- LogHelper.WriteLogToFile("启动 IACore IPC 辅助进程");
- bool ipcStarted = IpcIACoreClient.Instance.Start();
- LogHelper.WriteLogToFile($"IACore IPC 辅助进程{(ipcStarted ? "启动成功" : "启动失败(将使用本地 IACore 回退)")}");
+ var shapeMode = ShapeRecognitionRouter.FromSettingsInt(
+ Ink_Canvas.Windows.SettingsViews.Helpers.SettingsManager.Settings?.InkToShape?.ShapeRecognitionEngine ?? 0);
+ if (!ShapeRecognitionRouter.ResolveUseWinRt(shapeMode))
+ {
+ LogHelper.WriteLogToFile("启动 IACore IPC 辅助进程");
+ bool ipcStarted = IpcIACoreClient.Instance.Start();
+ LogHelper.WriteLogToFile($"IACore IPC 辅助进程{(ipcStarted ? "启动成功" : "启动失败")}");
+ }
}
catch (Exception ex)
{
diff --git a/Ink Canvas/Helpers/AnimationsHelper.cs b/Ink Canvas/Helpers/AnimationsHelper.cs
index 076bd4fd..c7a36a8c 100644
--- a/Ink Canvas/Helpers/AnimationsHelper.cs
+++ b/Ink Canvas/Helpers/AnimationsHelper.cs
@@ -1,4 +1,3 @@
-using Ink_Canvas.Controls;
using System;
using System.Windows;
using System.Windows.Media;
@@ -8,15 +7,7 @@ namespace Ink_Canvas.Helpers
{
internal class AnimationsHelper
{
- private static UIElement ResolveAnimationTarget(UIElement element)
- {
- if (element is BoardMenuFrame frame)
- {
- frame.ApplyTemplate();
- return frame.AnimationTarget ?? element;
- }
- return element;
- }
+ private static UIElement ResolveAnimationTarget(UIElement element) => element;
public static void ShowWithFadeIn(UIElement element, double duration = 0.15)
{
diff --git a/Ink Canvas/Helpers/IpcIACoreClient.cs b/Ink Canvas/Helpers/IpcIACoreClient.cs
index 9910c6f0..e320b80a 100644
--- a/Ink Canvas/Helpers/IpcIACoreClient.cs
+++ b/Ink Canvas/Helpers/IpcIACoreClient.cs
@@ -1,24 +1,16 @@
using System;
-using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
-using System.Linq;
using System.Threading;
-using System.Threading.Tasks;
using System.Windows;
using System.Windows.Ink;
using System.Windows.Media;
namespace Ink_Canvas.Helpers
{
- ///
- /// 通过 Named Pipe IPC 调用 32 位辅助进程 InkCanvasForClass.IACoreHelper.exe 进行 IACore 形状识别。
- /// 单例,线程安全,辅助进程崩溃后自动重启。
- ///
public sealed class IpcIACoreClient : IDisposable
{
- // ── 单例 ──────────────────────────────────────────────────────────────
private static IpcIACoreClient _instance;
private static readonly object _instanceLock = new object();
@@ -34,35 +26,26 @@ namespace Ink_Canvas.Helpers
}
}
- // ── 状态 ──────────────────────────────────────────────────────────────
private Process _helperProcess;
private readonly object _pipeLock = new object();
private bool _disposed;
private bool _available;
- // 辅助进程 EXE 的路径(与主 EXE 同目录)
private static string HelperExePath =>
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "InkCanvasForClass.IACoreHelper.exe");
- // Named Pipe 名称(含主进程 PID,保证唯一)
private string PipeName =>
string.Format("ICC_IACoreHelper_{0}", Process.GetCurrentProcess().Id);
private IpcIACoreClient() { }
- // ── 公开 API ──────────────────────────────────────────────────────────
-
- /// 启动辅助进程,返回是否成功。
public bool Start()
{
if (_disposed) return false;
-
- // 已运行则无需重启,避免 Warmup + App 两处调用导致重复启动
if (IsAvailable) return true;
if (!File.Exists(HelperExePath))
{
- LogHelper.WriteLogToFile($"[IACoreIPC] 辅助进程不存在: {HelperExePath}", LogHelper.LogType.Warning);
_available = false;
return false;
}
@@ -70,13 +53,8 @@ namespace Ink_Canvas.Helpers
return LaunchHelper();
}
- /// 是否就绪(辅助进程运行中)。
public bool IsAvailable => _available && _helperProcess != null && !_helperProcess.HasExited;
- ///
- /// 发送笔画到辅助进程进行 IACore 形状识别。
- /// 超时或失败时返回 。
- ///
public InkShapeRecognitionResult Recognize(StrokeCollection strokes)
{
if (strokes == null || strokes.Count == 0)
@@ -84,32 +62,22 @@ namespace Ink_Canvas.Helpers
EnsureHelperAlive();
if (!IsAvailable)
- {
- LogHelper.WriteLogToFile($"[IACoreIPC] Recognize 跳过:辅助进程不可用(strokes={strokes.Count})", LogHelper.LogType.Warning);
return InkShapeRecognitionResult.Empty;
- }
lock (_pipeLock)
{
try
{
- LogHelper.WriteLogToFile($"[IACoreIPC] Recognize 请求:strokes={strokes.Count}");
- var result = SendRecognizeRequest(strokes);
- LogHelper.WriteLogToFile(
- $"[IACoreIPC] Recognize 响应:IsSuccess={result.IsSuccess}, Shape={result.ShapeName}, StrokesToRemove={result.StrokesToRemove?.Count ?? 0}");
- return result;
+ return SendRecognizeRequest(strokes);
}
- catch (Exception ex)
+ catch
{
- LogHelper.WriteLogToFile($"[IACoreIPC] 识别失败: {ex.GetType().Name}: {ex.Message}", LogHelper.LogType.Error);
KillHelper();
return InkShapeRecognitionResult.Empty;
}
}
}
- // ── 内部实现 ──────────────────────────────────────────────────────────
-
private bool LaunchHelper()
{
try
@@ -133,16 +101,12 @@ namespace Ink_Canvas.Helpers
_helperProcess.EnableRaisingEvents = true;
_helperProcess.Exited += OnHelperExited;
- // 等待 Pipe 就绪(最多 3 s)
bool pipeReady = WaitForPipe(3000);
_available = pipeReady;
-
- LogHelper.WriteLogToFile($"[IACoreIPC] 辅助进程启动{(pipeReady ? "成功" : "失败(Pipe 未就绪)")},PID={_helperProcess?.Id}");
return pipeReady;
}
- catch (Exception ex)
+ catch
{
- LogHelper.WriteLogToFile($"[IACoreIPC] 启动辅助进程失败: {ex.Message}", LogHelper.LogType.Error);
_available = false;
return false;
}
@@ -161,7 +125,6 @@ namespace Ink_Canvas.Helpers
using (var probe = new NamedPipeClientStream(".", PipeName, PipeDirection.InOut))
{
probe.Connect(200);
- // 连接成功后立即断开,下次 Recognize 会重新连接
return true;
}
}
@@ -183,7 +146,6 @@ namespace Ink_Canvas.Helpers
using (var writer = new BinaryWriter(client, System.Text.Encoding.UTF8, leaveOpen: true))
using (var reader = new BinaryReader(client, System.Text.Encoding.UTF8, leaveOpen: true))
{
- // 序列化请求
writer.Write(CmdRecognize);
writer.Write(strokes.Count);
foreach (var stroke in strokes)
@@ -199,7 +161,6 @@ namespace Ink_Canvas.Helpers
}
writer.Flush();
- // 读取响应
bool success = reader.ReadBoolean();
string shape = reader.ReadString();
float cx = reader.ReadSingle();
@@ -220,7 +181,6 @@ namespace Ink_Canvas.Helpers
if (!success || string.IsNullOrEmpty(shape))
return InkShapeRecognitionResult.Empty;
- // 根据下标还原参与识别的笔画子集
var recognized = new StrokeCollection();
foreach (int idx in indices)
if (idx >= 0 && idx < strokes.Count)
@@ -240,16 +200,12 @@ namespace Ink_Canvas.Helpers
private void EnsureHelperAlive()
{
if (!IsAvailable)
- {
- LogHelper.WriteLogToFile("[IACoreIPC] 辅助进程不可用,尝试重启...", LogHelper.LogType.Warning);
LaunchHelper();
- }
}
private void OnHelperExited(object sender, EventArgs e)
{
_available = false;
- LogHelper.WriteLogToFile("[IACoreIPC] 辅助进程意外退出", LogHelper.LogType.Warning);
}
private void KillHelper()
@@ -257,12 +213,10 @@ namespace Ink_Canvas.Helpers
if (_helperProcess == null) return;
try
{
- // 先解除事件订阅,避免主动 Kill 时触发 OnHelperExited 误报
try { _helperProcess.Exited -= OnHelperExited; } catch { }
if (!_helperProcess.HasExited)
{
- // 发送优雅关闭命令
try
{
using (var client = new NamedPipeClientStream(".", PipeName, PipeDirection.InOut))
@@ -272,7 +226,7 @@ namespace Ink_Canvas.Helpers
w.Write(CmdShutdown);
}
}
- catch { /* 忽略,下面直接 Kill */ }
+ catch { }
if (!_helperProcess.WaitForExit(800))
_helperProcess.Kill();
@@ -294,7 +248,6 @@ namespace Ink_Canvas.Helpers
KillHelper();
}
- // ── 协议常量(与 IACoreHelper/IpcProtocol.cs 保持一致) ─────────────
private const int IpcTimeoutMs = 5000;
private const byte CmdRecognize = 0x01;
private const byte CmdShutdown = 0xFF;
diff --git a/Ink Canvas/Properties/Strings.resx b/Ink Canvas/Properties/Strings.resx
index 594af26d..03da96e4 100644
--- a/Ink Canvas/Properties/Strings.resx
+++ b/Ink Canvas/Properties/Strings.resx
@@ -589,7 +589,7 @@
识别引擎
- 自动:64 位进程使用 WinRT(Windows 10+),32 位使用 IACore。可强制指定 IACore 或 WinRT。
+ 自动:在 Windows 10+ 使用 WinRT,否则使用 IACore。可强制指定 IACore 或 WinRT。IACore 通过 IPC 辅助进程运行,在 32/64 位主进程下均可用。
自动
diff --git a/InkCanvasForClass.IACoreHelper/Program.cs b/InkCanvasForClass.IACoreHelper/Program.cs
index 5b701235..640606f5 100644
--- a/InkCanvasForClass.IACoreHelper/Program.cs
+++ b/InkCanvasForClass.IACoreHelper/Program.cs
@@ -2,7 +2,6 @@ using System;
using System.IO;
using System.IO.Pipes;
using System.Linq;
-using System.Windows;
using System.Windows.Ink;
using System.Windows.Input;
@@ -10,29 +9,16 @@ namespace InkCanvasForClass.IACoreHelper
{
internal static class Program
{
- private static readonly string LogPath = Path.Combine(
- AppDomain.CurrentDomain.BaseDirectory, "IACoreHelper.log");
-
- private static void Log(string msg)
- {
- try { File.AppendAllText(LogPath, $"{DateTime.Now:HH:mm:ss.fff} {msg}{Environment.NewLine}"); }
- catch { }
- }
-
[STAThread]
static void Main(string[] args)
{
- Log($"=== Helper started, args=[{string.Join(",", args)}], cwd={Environment.CurrentDirectory}, baseDir={AppDomain.CurrentDomain.BaseDirectory} ===");
-
if (args.Length < 1 || !int.TryParse(args[0], out int parentPid))
{
Console.Error.WriteLine("Usage: IACoreHelper.exe ");
- Log("Missing parentPid argument, exiting");
return;
}
string pipeName = string.Format(IpcConstants.PipeName, parentPid);
- Log($"Pipe name: {pipeName}");
try
{
@@ -40,7 +26,6 @@ namespace InkCanvasForClass.IACoreHelper
}
catch (Exception ex)
{
- Log($"FATAL: {ex}");
Console.Error.WriteLine("IACoreHelper fatal: " + ex.Message);
}
}
@@ -82,7 +67,6 @@ namespace InkCanvasForClass.IACoreHelper
Console.Error.WriteLine("IACoreHelper pipe error: " + ex.Message);
}
}
- // 每次连接后重新监听,支持多次调用
}
}
@@ -90,19 +74,14 @@ namespace InkCanvasForClass.IACoreHelper
{
try
{
- Log($"HandleRecognize: strokes={request.Strokes?.Length ?? 0}");
var strokes = BuildStrokeCollection(request);
- Log($"Built StrokeCollection: count={strokes.Count}");
if (strokes.Count == 0)
return new RecognizeResponse { Success = false, ShapeName = string.Empty };
- var result = RecognizeCore(strokes);
- Log($"RecognizeCore result: success={result.Success}, shape={result.ShapeName}");
- return result;
+ return RecognizeCore(strokes);
}
catch (Exception ex)
{
- Log($"HandleRecognize EXCEPTION: {ex}");
Console.Error.WriteLine("IACoreHelper recognize error: " + ex.Message);
return new RecognizeResponse { Success = false, ShapeName = string.Empty };
}
@@ -189,7 +168,6 @@ namespace InkCanvasForClass.IACoreHelper
if (hot != null)
for (int i = 0; i < hot.Count; i++) { hotX[i] = (float)hot[i].X; hotY[i] = (float)hot[i].Y; }
- // 计算参与识别的笔画在原始集合中的下标
var participatingStrokes = analysisAlternate.Strokes;
int[] strokeIndices = new int[participatingStrokes?.Count ?? 0];
if (participatingStrokes != null)