add:基于IPC的IACore在net6的实现
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup useLegacyV2RuntimeActivationPolicy="true">
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
|
||||
</startup>
|
||||
</configuration>
|
||||
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||
<ProjectGuid>{B1A2C3D4-E5F6-7890-ABCD-EF1234567891}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>InkCanvas.IACoreHelper</RootNamespace>
|
||||
<AssemblyName>InkCanvas.IACoreHelper</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' Or '$(Platform)' == 'x64' Or '$(Platform)' == 'ARM64' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||
<DebugSymbols Condition=" '$(Configuration)' == 'Debug' ">true</DebugSymbols>
|
||||
<DebugType Condition=" '$(Configuration)' == 'Debug' ">full</DebugType>
|
||||
<DebugType Condition=" '$(Configuration)' != 'Debug' ">pdbonly</DebugType>
|
||||
<Optimize Condition=" '$(Configuration)' == 'Debug' ">false</Optimize>
|
||||
<Optimize Condition=" '$(Configuration)' != 'Debug' ">true</Optimize>
|
||||
<DefineConstants Condition=" '$(Configuration)' == 'Debug' ">DEBUG;TRACE</DefineConstants>
|
||||
<DefineConstants Condition=" '$(Configuration)' != 'Debug' ">TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
<Reference Include="WindowsBase" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="IAWinFX">
|
||||
<HintPath>..\Ink Canvas\Resources\IACore\IAWinFX.dll</HintPath>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="IpcProtocol.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -0,0 +1,133 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace InkCanvas.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Pipes;
|
||||
using System.Linq;
|
||||
using System.Windows.Ink;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace InkCanvas.IACoreHelper
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main(string[] args)
|
||||
{
|
||||
if (args.Length < 1 || !int.TryParse(args[0], out int parentPid))
|
||||
{
|
||||
Console.Error.WriteLine("Usage: IACoreHelper.exe <parentPid>");
|
||||
return;
|
||||
}
|
||||
|
||||
string pipeName = string.Format(IpcConstants.PipeName, parentPid);
|
||||
|
||||
try
|
||||
{
|
||||
RunPipeServer(pipeName);
|
||||
}
|
||||
catch (Exception 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
|
||||
{
|
||||
var strokes = BuildStrokeCollection(request);
|
||||
if (strokes.Count == 0)
|
||||
return new RecognizeResponse { Success = false, ShapeName = string.Empty };
|
||||
|
||||
return RecognizeCore(strokes);
|
||||
}
|
||||
catch (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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[assembly: AssemblyTitle("InkCanvas.IACoreHelper")]
|
||||
[assembly: AssemblyDescription("IACore 32-bit ink shape recognition helper process")]
|
||||
[assembly: AssemblyCompany("ICC CE")]
|
||||
[assembly: AssemblyProduct("InkCanvas.IACoreHelper")]
|
||||
[assembly: AssemblyCopyright("Copyright © ICC CE")]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
Reference in New Issue
Block a user