diff --git a/.gitignore b/.gitignore
index 954c28b..448ee79 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,10 @@
/InkCanvasForClass/bin
/InkCanvasForClassX/obj
/InkCanvasForClassX/bin
+/InkCanvasForClassPPTVsto/obj
+/InkCanvasForClassPPTVsto/bin
+/PeroInstaller/obj
+/PeroInstaller/bin
/CvtePaintDemo/obj
/CvtePaintDemo/bin
/.vs
diff --git a/Ink Canvas.sln b/Ink Canvas.sln
index feace4c..0c55082 100644
--- a/Ink Canvas.sln
+++ b/Ink Canvas.sln
@@ -3,16 +3,20 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.33530.505
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InkCanvasForClassX", "InkCanvasForClassX\InkCanvasForClassX.csproj", "{98DF6AA1-DD4D-4C70-A0A2-4B2974D97D51}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InkCanvasForClassX", "InkCanvasForClassX\InkCanvasForClassX.csproj", "{98DF6AA1-DD4D-4C70-A0A2-4B2974D97D51}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InkCanvasForClass", "InkCanvasForClass\InkCanvasForClass.csproj", "{2474F5B0-6FA7-4D70-8A00-167BBB03264D}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CvtePaintDemo", "CvtePaintDemo\CvtePaintDemo.csproj", "{26F0E9DD-A9DC-45D1-97B9-337C63863837}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CvtePaintDemo", "CvtePaintDemo\CvtePaintDemo.csproj", "{26F0E9DD-A9DC-45D1-97B9-337C63863837}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Demos", "Demos", "{0B6F0669-8945-4AC7-923D-145BF23C38A0}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Assets", "Assets", "{D31A4267-C13F-41FE-8516-3B633E3B1990}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InkCanvasForClassPPTVsto", "InkCanvasForClassPPTVsto\InkCanvasForClassPPTVsto.csproj", "{E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PeroInstaller", "PeroInstaller\PeroInstaller.csproj", "{AB1CC983-E30D-4597-A858-05DF7DF7664C}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -122,6 +126,66 @@ Global
{26F0E9DD-A9DC-45D1-97B9-337C63863837}.x86 Debug|x64.Build.0 = Debug|Any CPU
{26F0E9DD-A9DC-45D1-97B9-337C63863837}.x86 Debug|x86.ActiveCfg = Debug|Any CPU
{26F0E9DD-A9DC-45D1-97B9-337C63863837}.x86 Debug|x86.Build.0 = Debug|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.Debug|ARM.Build.0 = Debug|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.Debug|ARM64.ActiveCfg = Debug|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.Debug|ARM64.Build.0 = Debug|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.Debug|x64.Build.0 = Debug|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.Debug|x86.Build.0 = Debug|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.Release|ARM.ActiveCfg = Release|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.Release|ARM.Build.0 = Release|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.Release|ARM64.ActiveCfg = Release|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.Release|ARM64.Build.0 = Release|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.Release|x64.ActiveCfg = Release|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.Release|x64.Build.0 = Release|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.Release|x86.ActiveCfg = Release|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.Release|x86.Build.0 = Release|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.x86 Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.x86 Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.x86 Debug|ARM.ActiveCfg = Debug|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.x86 Debug|ARM.Build.0 = Debug|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.x86 Debug|ARM64.ActiveCfg = Debug|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.x86 Debug|ARM64.Build.0 = Debug|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.x86 Debug|x64.ActiveCfg = Debug|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.x86 Debug|x64.Build.0 = Debug|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.x86 Debug|x86.ActiveCfg = Debug|Any CPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}.x86 Debug|x86.Build.0 = Debug|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.Debug|ARM.Build.0 = Debug|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.Debug|ARM64.ActiveCfg = Debug|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.Debug|ARM64.Build.0 = Debug|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.Debug|x64.Build.0 = Debug|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.Debug|x86.Build.0 = Debug|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.Release|ARM.ActiveCfg = Release|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.Release|ARM.Build.0 = Release|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.Release|ARM64.ActiveCfg = Release|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.Release|ARM64.Build.0 = Release|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.Release|x64.ActiveCfg = Release|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.Release|x64.Build.0 = Release|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.Release|x86.ActiveCfg = Release|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.Release|x86.Build.0 = Release|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.x86 Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.x86 Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.x86 Debug|ARM.ActiveCfg = Debug|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.x86 Debug|ARM.Build.0 = Debug|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.x86 Debug|ARM64.ActiveCfg = Debug|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.x86 Debug|ARM64.Build.0 = Debug|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.x86 Debug|x64.ActiveCfg = Debug|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.x86 Debug|x64.Build.0 = Debug|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.x86 Debug|x86.ActiveCfg = Debug|Any CPU
+ {AB1CC983-E30D-4597-A858-05DF7DF7664C}.x86 Debug|x86.Build.0 = Debug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/InkCanvasForClass/MainWindow.xaml b/InkCanvasForClass/MainWindow.xaml
index 9a26a8d..5c00d67 100644
--- a/InkCanvasForClass/MainWindow.xaml
+++ b/InkCanvasForClass/MainWindow.xaml
@@ -1710,17 +1710,6 @@
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchAutoKillICA_Toggled" />
-
-
-
-
-
@@ -1876,7 +1865,12 @@
-
+
+
+
+
+
diff --git a/InkCanvasForClass/MainWindow_cs/MW_PPT.cs b/InkCanvasForClass/MainWindow_cs/MW_PPT.cs
index 8fa804e..2f0a8b0 100644
--- a/InkCanvasForClass/MainWindow_cs/MW_PPT.cs
+++ b/InkCanvasForClass/MainWindow_cs/MW_PPT.cs
@@ -375,6 +375,14 @@ namespace Ink_Canvas {
private void UpdatePPTBtnDisplaySettingsStatus() {
+ if (!Settings.PowerPointSettings.ShowPPTButton) {
+ LeftBottomPanelForPPTNavigation.Visibility = Visibility.Collapsed;
+ RightBottomPanelForPPTNavigation.Visibility = Visibility.Collapsed;
+ LeftSidePanelForPPTNavigation.Visibility = Visibility.Collapsed;
+ RightSidePanelForPPTNavigation.Visibility = Visibility.Collapsed;
+ return;
+ }
+
var lsp = Settings.PowerPointSettings.PPTLSButtonPosition;
LeftSidePanelForPPTNavigation.Margin = new Thickness(0, 0, 0, lsp*2);
var rsp = Settings.PowerPointSettings.PPTRSButtonPosition;
@@ -382,6 +390,7 @@ namespace Ink_Canvas {
var dopt = Settings.PowerPointSettings.PPTButtonsDisplayOption.ToString();
char[] doptc = dopt.ToCharArray();
+
if (doptc[0] == '2') AnimationsHelper.ShowWithFadeIn(LeftBottomPanelForPPTNavigation);
else LeftBottomPanelForPPTNavigation.Visibility = Visibility.Collapsed;
if (doptc[1] == '2') AnimationsHelper.ShowWithFadeIn(RightBottomPanelForPPTNavigation);
diff --git a/InkCanvasForClass/MainWindow_cs/MW_Settings.cs b/InkCanvasForClass/MainWindow_cs/MW_Settings.cs
index 0785d27..c146538 100644
--- a/InkCanvasForClass/MainWindow_cs/MW_Settings.cs
+++ b/InkCanvasForClass/MainWindow_cs/MW_Settings.cs
@@ -338,6 +338,7 @@ namespace Ink_Canvas {
if (!isLoaded) return;
Settings.PowerPointSettings.ShowPPTButton = ToggleSwitchShowPPTButton.IsOn;
SaveSettingsToFile();
+ if (BtnPPTSlideShowEnd.Visibility == Visibility.Visible) UpdatePPTBtnDisplaySettingsStatus();
UpdatePPTBtnPreview();
}
@@ -1121,19 +1122,19 @@ namespace Ink_Canvas {
timerKillProcess.Stop();
}
- private void ToggleSwitchAutoKillIDT_Toggled(object sender, RoutedEventArgs e)
- {
- if (!isLoaded) return;
- Settings.Automation.IsAutoKillIDT = ToggleSwitchAutoKillIDT.IsOn;
- SaveSettingsToFile();
- if (Settings.Automation.IsAutoKillEasiNote || Settings.Automation.IsAutoKillPptService ||
- Settings.Automation.IsAutoKillHiteAnnotation || Settings.Automation.IsAutoKillInkCanvas
- || Settings.Automation.IsAutoKillICA || Settings.Automation.IsAutoKillIDT || Settings.Automation.IsAutoKillVComYouJiao
- || Settings.Automation.IsAutoKillSeewoLauncher2DesktopAnnotation)
- timerKillProcess.Start();
- else
- timerKillProcess.Stop();
- }
+ //private void ToggleSwitchAutoKillIDT_Toggled(object sender, RoutedEventArgs e)
+ //{
+ // if (!isLoaded) return;
+ // Settings.Automation.IsAutoKillIDT = ToggleSwitchAutoKillIDT.IsOn;
+ // SaveSettingsToFile();
+ // if (Settings.Automation.IsAutoKillEasiNote || Settings.Automation.IsAutoKillPptService ||
+ // Settings.Automation.IsAutoKillHiteAnnotation || Settings.Automation.IsAutoKillInkCanvas
+ // || Settings.Automation.IsAutoKillICA || Settings.Automation.IsAutoKillIDT || Settings.Automation.IsAutoKillVComYouJiao
+ // || Settings.Automation.IsAutoKillSeewoLauncher2DesktopAnnotation)
+ // timerKillProcess.Start();
+ // else
+ // timerKillProcess.Stop();
+ //}
private void ToggleSwitchSaveScreenshotsInDateFolders_Toggled(object sender, RoutedEventArgs e) {
if (!isLoaded) return;
diff --git a/InkCanvasForClass/MainWindow_cs/MW_SettingsToLoad.cs b/InkCanvasForClass/MainWindow_cs/MW_SettingsToLoad.cs
index 42c3ecc..93b54bf 100644
--- a/InkCanvasForClass/MainWindow_cs/MW_SettingsToLoad.cs
+++ b/InkCanvasForClass/MainWindow_cs/MW_SettingsToLoad.cs
@@ -638,7 +638,7 @@ namespace Ink_Canvas {
ToggleSwitchAutoKillICA.IsOn = Settings.Automation.IsAutoKillICA;
- ToggleSwitchAutoKillIDT.IsOn = Settings.Automation.IsAutoKillIDT;
+ //ToggleSwitchAutoKillIDT.IsOn = Settings.Automation.IsAutoKillIDT;
ToggleSwitchAutoKillSeewoLauncher2DesktopAnnotation.IsOn =
Settings.Automation.IsAutoKillSeewoLauncher2DesktopAnnotation;
diff --git a/InkCanvasForClass/MainWindow_cs/MW_Timer.cs b/InkCanvasForClass/MainWindow_cs/MW_Timer.cs
index aa6f64b..e6eaa8b 100644
--- a/InkCanvasForClass/MainWindow_cs/MW_Timer.cs
+++ b/InkCanvasForClass/MainWindow_cs/MW_Timer.cs
@@ -121,16 +121,17 @@ namespace Ink_Canvas {
if (processes.Length > 0) arg += " /IM \"Ink Canvas.exe\"";
}
- if (Settings.Automation.IsAutoKillIDT) {
- var processes = Process.GetProcessesByName("智绘教");
- if (processes.Length > 0) arg += " /IM \"智绘教.exe\"";
- }
+ // 移除了IDT的查殺
+ //if (Settings.Automation.IsAutoKillIDT) {
+ // var processes = Process.GetProcessesByName("智绘教");
+ // if (processes.Length > 0) arg += " /IM \"智绘教.exe\"";
+ //}
- if (Settings.Automation.IsAutoKillSeewoLauncher2DesktopAnnotation) {
+ //if (Settings.Automation.IsAutoKillSeewoLauncher2DesktopAnnotation) {
//由于希沃桌面2.0提供的桌面批注是64位应用程序,32位程序无法访问,目前暂不做精准匹配,只匹配进程名称,后面会考虑封装一套基于P/Invoke和WMI的综合进程识别方案。
- var processes = Process.GetProcessesByName("DesktopAnnotation");
- if (processes.Length > 0) arg += " /IM DesktopAnnotation.exe";
- }
+ // var processes = Process.GetProcessesByName("DesktopAnnotation");
+ // if (processes.Length > 0) arg += " /IM DesktopAnnotation.exe";
+ //}
if (arg != "/F") {
var p = new Process();
@@ -162,11 +163,11 @@ namespace Ink_Canvas {
});
}
- if (arg.Contains("智绘教")) {
- Dispatcher.Invoke(() => {
- ShowNotification("“智绘教”已自动关闭");
- });
- }
+ //if (arg.Contains("智绘教")) {
+ // Dispatcher.Invoke(() => {
+ // ShowNotification("“智绘教”已自动关闭");
+ // });
+ //}
if (arg.Contains("VcomTeach"))
{
@@ -175,12 +176,12 @@ namespace Ink_Canvas {
});
}
- if (arg.Contains("DesktopAnnotation"))
- {
- Dispatcher.Invoke(() => {
- ShowNotification("“DesktopAnnotation”已自动关闭");
- });
- }
+ //if (arg.Contains("DesktopAnnotation"))
+ //{
+ // Dispatcher.Invoke(() => {
+ // ShowNotification("“DesktopAnnotation”已自动关闭");
+ // });
+ //}
}
}
catch {}
diff --git a/InkCanvasForClassPPTVsto/InkCanvasForClassPPTVsto.csproj b/InkCanvasForClassPPTVsto/InkCanvasForClassPPTVsto.csproj
new file mode 100644
index 0000000..b8ebce2
--- /dev/null
+++ b/InkCanvasForClassPPTVsto/InkCanvasForClassPPTVsto.csproj
@@ -0,0 +1,216 @@
+
+
+
+
+ {BAA0C2D2-18E2-41B9-852F-F413020CAA33};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ Debug
+ AnyCPU
+ {E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}
+ Library
+ false
+ InkCanvasForClassPPTVsto
+ InkCanvasForClassPPTVsto
+ 3
+ v4.7.2
+ VSTO40
+ true
+ HomeSite
+
+
+
+ False
+ Microsoft Visual Studio 2010 Tools for Office Runtime %28x86 and x64%29
+ true
+
+
+
+
+ PowerPoint
+
+
+
+ true
+ full
+ false
+ bin\Debug\
+ false
+ $(DefineConstants);DEBUG;TRACE
+ 4
+
+
+
+ pdbonly
+ true
+ bin\Release\
+ false
+ $(DefineConstants);TRACE
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+
+
+ False
+
+
+ False
+
+
+ False
+
+
+
+
+ True
+
+
+
+
+ False
+ true
+
+
+ False
+ true
+
+
+ False
+
+
+
+
+
+ Code
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+ Designer
+
+
+ True
+ Resources.resx
+
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+ True
+ Settings.settings
+
+
+ Code
+
+
+ ThisAddIn.cs
+
+
+ ThisAddIn.Designer.xml
+
+
+
+
+ 10.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+ true
+
+
+ InkCanvasForClassPPTVsto_TemporaryKey.pfx
+
+
+ E0DCEEAE8C0D178489A9D826E0280507E45B0283
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/InkCanvasForClassPPTVsto/InkCanvasForClassPPTVsto_TemporaryKey.pfx b/InkCanvasForClassPPTVsto/InkCanvasForClassPPTVsto_TemporaryKey.pfx
new file mode 100644
index 0000000..8833e31
Binary files /dev/null and b/InkCanvasForClassPPTVsto/InkCanvasForClassPPTVsto_TemporaryKey.pfx differ
diff --git a/InkCanvasForClassPPTVsto/Properties/AssemblyInfo.cs b/InkCanvasForClassPPTVsto/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..297cda3
--- /dev/null
+++ b/InkCanvasForClassPPTVsto/Properties/AssemblyInfo.cs
@@ -0,0 +1,38 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security;
+
+// 有关程序集的一般信息由以下
+// 控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("InkCanvasForClassPPTVsto")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("InkCanvasForClassPPTVsto")]
+[assembly: AssemblyCopyright("Copyright © 2024")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+//将 ComVisible 设置为 false 将使此程序集中的类型
+//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
+//请将此类型的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("cfac1b17-2ab3-422a-9a48-a2d01a63f52d")]
+
+// 程序集的版本信息由下列四个值组成:
+//
+// 主版本
+// 次版本
+// 生成号
+// 修订号
+//
+//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
+// 方法是按如下所示使用“*”: :
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+
diff --git a/InkCanvasForClassPPTVsto/Properties/Resources.Designer.cs b/InkCanvasForClassPPTVsto/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..e06741d
--- /dev/null
+++ b/InkCanvasForClassPPTVsto/Properties/Resources.Designer.cs
@@ -0,0 +1,62 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace InkCanvasForClassPPTVsto.Properties {
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("InkCanvasForClassPPTVsto.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/InkCanvasForClassPPTVsto/Properties/Resources.resx b/InkCanvasForClassPPTVsto/Properties/Resources.resx
new file mode 100644
index 0000000..af7dbeb
--- /dev/null
+++ b/InkCanvasForClassPPTVsto/Properties/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/InkCanvasForClassPPTVsto/Properties/Settings.Designer.cs b/InkCanvasForClassPPTVsto/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..1d49dc3
--- /dev/null
+++ b/InkCanvasForClassPPTVsto/Properties/Settings.Designer.cs
@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace InkCanvasForClassPPTVsto.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/InkCanvasForClassPPTVsto/Properties/Settings.settings b/InkCanvasForClassPPTVsto/Properties/Settings.settings
new file mode 100644
index 0000000..3964565
--- /dev/null
+++ b/InkCanvasForClassPPTVsto/Properties/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/InkCanvasForClassPPTVsto/ThisAddIn.Designer.cs b/InkCanvasForClassPPTVsto/ThisAddIn.Designer.cs
new file mode 100644
index 0000000..de7c25f
--- /dev/null
+++ b/InkCanvasForClassPPTVsto/ThisAddIn.Designer.cs
@@ -0,0 +1,231 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+#pragma warning disable 414
+namespace InkCanvasForClassPPTVsto {
+
+
+ ///
+ [Microsoft.VisualStudio.Tools.Applications.Runtime.StartupObjectAttribute(0)]
+ [global::System.Security.Permissions.PermissionSetAttribute(global::System.Security.Permissions.SecurityAction.Demand, Name="FullTrust")]
+ public sealed partial class ThisAddIn : Microsoft.Office.Tools.AddInBase {
+
+ internal Microsoft.Office.Tools.CustomTaskPaneCollection CustomTaskPanes;
+
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "17.0.0.0")]
+ private global::System.Object missing = global::System.Type.Missing;
+
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "17.0.0.0")]
+ internal Microsoft.Office.Interop.PowerPoint.Application Application;
+
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)]
+ public ThisAddIn(global::Microsoft.Office.Tools.Factory factory, global::System.IServiceProvider serviceProvider) :
+ base(factory, serviceProvider, "AddIn", "ThisAddIn") {
+ Globals.Factory = factory;
+ }
+
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "17.0.0.0")]
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)]
+ protected override void Initialize() {
+ base.Initialize();
+ this.Application = this.GetHostItem(typeof(Microsoft.Office.Interop.PowerPoint.Application), "Application");
+ Globals.ThisAddIn = this;
+ global::System.Windows.Forms.Application.EnableVisualStyles();
+ this.InitializeCachedData();
+ this.InitializeControls();
+ this.InitializeComponents();
+ this.InitializeData();
+ }
+
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "17.0.0.0")]
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)]
+ protected override void FinishInitialization() {
+ this.InternalStartup();
+ this.OnStartup();
+ }
+
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "17.0.0.0")]
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)]
+ protected override void InitializeDataBindings() {
+ this.BeginInitialization();
+ this.BindToData();
+ this.EndInitialization();
+ }
+
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "17.0.0.0")]
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)]
+ private void InitializeCachedData() {
+ if ((this.DataHost == null)) {
+ return;
+ }
+ if (this.DataHost.IsCacheInitialized) {
+ this.DataHost.FillCachedData(this);
+ }
+ }
+
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "17.0.0.0")]
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)]
+ private void InitializeData() {
+ }
+
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "17.0.0.0")]
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)]
+ private void BindToData() {
+ }
+
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ private void StartCaching(string MemberName) {
+ this.DataHost.StartCaching(this, MemberName);
+ }
+
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ private void StopCaching(string MemberName) {
+ this.DataHost.StopCaching(this, MemberName);
+ }
+
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ private bool IsCached(string MemberName) {
+ return this.DataHost.IsCached(this, MemberName);
+ }
+
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "17.0.0.0")]
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)]
+ private void BeginInitialization() {
+ this.BeginInit();
+ this.CustomTaskPanes.BeginInit();
+ }
+
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "17.0.0.0")]
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)]
+ private void EndInitialization() {
+ this.CustomTaskPanes.EndInit();
+ this.EndInit();
+ }
+
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "17.0.0.0")]
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)]
+ private void InitializeControls() {
+ this.CustomTaskPanes = Globals.Factory.CreateCustomTaskPaneCollection(null, null, "CustomTaskPanes", "CustomTaskPanes", this);
+ }
+
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "17.0.0.0")]
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)]
+ private void InitializeComponents() {
+ }
+
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ private bool NeedsFill(string MemberName) {
+ return this.DataHost.NeedsFill(this, MemberName);
+ }
+
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "17.0.0.0")]
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)]
+ protected override void OnShutdown() {
+ this.CustomTaskPanes.Dispose();
+ base.OnShutdown();
+ }
+ }
+
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "17.0.0.0")]
+ internal sealed partial class Globals {
+
+ ///
+ private Globals() {
+ }
+
+ private static ThisAddIn _ThisAddIn;
+
+ private static global::Microsoft.Office.Tools.Factory _factory;
+
+ private static ThisRibbonCollection _ThisRibbonCollection;
+
+ internal static ThisAddIn ThisAddIn {
+ get {
+ return _ThisAddIn;
+ }
+ set {
+ if ((_ThisAddIn == null)) {
+ _ThisAddIn = value;
+ }
+ else {
+ throw new System.NotSupportedException();
+ }
+ }
+ }
+
+ internal static global::Microsoft.Office.Tools.Factory Factory {
+ get {
+ return _factory;
+ }
+ set {
+ if ((_factory == null)) {
+ _factory = value;
+ }
+ else {
+ throw new System.NotSupportedException();
+ }
+ }
+ }
+
+ internal static ThisRibbonCollection Ribbons {
+ get {
+ if ((_ThisRibbonCollection == null)) {
+ _ThisRibbonCollection = new ThisRibbonCollection(_factory.GetRibbonFactory());
+ }
+ return _ThisRibbonCollection;
+ }
+ }
+ }
+
+ ///
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Tools.Office.ProgrammingModel.dll", "17.0.0.0")]
+ internal sealed partial class ThisRibbonCollection : Microsoft.Office.Tools.Ribbon.RibbonCollectionBase {
+
+ ///
+ internal ThisRibbonCollection(global::Microsoft.Office.Tools.Ribbon.RibbonFactory factory) :
+ base(factory) {
+ }
+ }
+}
diff --git a/InkCanvasForClassPPTVsto/ThisAddIn.Designer.xml b/InkCanvasForClassPPTVsto/ThisAddIn.Designer.xml
new file mode 100644
index 0000000..a7ebc31
--- /dev/null
+++ b/InkCanvasForClassPPTVsto/ThisAddIn.Designer.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/InkCanvasForClassPPTVsto/ThisAddIn.cs b/InkCanvasForClassPPTVsto/ThisAddIn.cs
new file mode 100644
index 0000000..02b897b
--- /dev/null
+++ b/InkCanvasForClassPPTVsto/ThisAddIn.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Xml.Linq;
+using PowerPoint = Microsoft.Office.Interop.PowerPoint;
+using Office = Microsoft.Office.Core;
+
+namespace InkCanvasForClassPPTVsto
+{
+ public partial class ThisAddIn
+ {
+ private void ThisAddIn_Startup(object sender, System.EventArgs e)
+ {
+ }
+
+ private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
+ {
+ }
+
+ #region VSTO 生成的代码
+
+ ///
+ /// 设计器支持所需的方法 - 不要修改
+ /// 使用代码编辑器修改此方法的内容。
+ ///
+ private void InternalStartup()
+ {
+ this.Startup += new System.EventHandler(ThisAddIn_Startup);
+ this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
+ }
+
+ #endregion
+ }
+}
diff --git a/InkCanvasForClassX/InkCanvasForClassX.csproj b/InkCanvasForClassX/InkCanvasForClassX.csproj
index 38425cb..77ad001 100644
--- a/InkCanvasForClassX/InkCanvasForClassX.csproj
+++ b/InkCanvasForClassX/InkCanvasForClassX.csproj
@@ -7,6 +7,7 @@
true
+
diff --git a/InkCanvasForClassX/Libraries/InkProjector.cs b/InkCanvasForClassX/Libraries/InkProjector.cs
index cf1ee1c..373ed5b 100644
--- a/InkCanvasForClassX/Libraries/InkProjector.cs
+++ b/InkCanvasForClassX/Libraries/InkProjector.cs
@@ -1,6 +1,9 @@
using System;
+using System.Collections.Generic;
+using System.Diagnostics;
using System.Windows;
using System.Windows.Ink;
+using System.Windows.Input;
using System.Windows.Media;
namespace InkCanvasForClassX.Libraries
@@ -12,6 +15,7 @@ namespace InkCanvasForClassX.Libraries
private VisualCollection _children;
private DrawingVisual _layer = new DrawingVisual();
private StrokeCollection _strokes;
+ private PerfectFreehandJint _perfectFreehandJint = new PerfectFreehandJint();
public InkProjector()
{
@@ -24,7 +28,7 @@ namespace InkCanvasForClassX.Libraries
get => _strokes;
set {
_strokes = value;
- DrawInk();
+ DrawPerfectInk();
}
}
@@ -41,5 +45,50 @@ namespace InkCanvasForClassX.Libraries
context.Close();
}
+ private void DrawPerfectInk() {
+ DrawingContext context = _layer.RenderOpen();
+ context.PushClip(new RectangleGeometry(new Rect(new Size(this.ActualWidth,this.ActualHeight))));
+ foreach (var stroke in _strokes) {
+ var stylusPtsList = new List();
+ foreach (var strokeStylusPoint in stroke.StylusPoints)
+ {
+ stylusPtsList.Add(new PerfectFreehandJint.StylusPointLite()
+ {
+ x = Math.Round(strokeStylusPoint.X, 2),
+ y = Math.Round(strokeStylusPoint.Y, 2),
+ pressure = strokeStylusPoint.PressureFactor,
+ });
+ }
+ context.DrawGeometry(new SolidColorBrush(Colors.Black), (System.Windows.Media.Pen)null, _perfectFreehandJint.GetGeometryStroke(stylusPtsList.ToArray(), new PerfectFreehandJint.StrokeOptions()
+ {
+ size = 2,
+ thinning = 0.5,
+ smoothing = 0.5,
+ streamline = 0.2,
+ simulatePressure = true,
+ easing = (x) => 1 - (1 - x) * (1 - x),
+ last = true,
+ start = new PerfectFreehandJint.StrokeCapOptions()
+ {
+ cap = true,
+ taper = 0,
+ easing = (x) => 1 - (1 - x) * (1 - x),
+ },
+ end = new PerfectFreehandJint.StrokeCapOptions()
+ {
+ cap = true,
+ taper = 0,
+ easing = (x) => 1 - (1 - x) * (1 - x),
+ },
+ }));
+ }
+ context.Pop();
+ context.Close();
+ }
+
+ protected override void OnMouseLeave(MouseEventArgs e) {
+ base.OnMouseLeave(e);
+ Trace.WriteLine("Mouse Move");
+ }
}
}
diff --git a/InkCanvasForClassX/Libraries/PerfectFreehand.cs b/InkCanvasForClassX/Libraries/PerfectFreehand.cs
index 41d97ba..7c62479 100644
--- a/InkCanvasForClassX/Libraries/PerfectFreehand.cs
+++ b/InkCanvasForClassX/Libraries/PerfectFreehand.cs
@@ -14,6 +14,42 @@ namespace InkCanvasForClassX.Libraries
///
public class PerfectFreehand {
+ private static double Average(double a, double b) {
+ return (a + b) / 2;
+ }
+
+ public static string ConvertVectorsToSVGPath(Vector[] points, bool closed = true)
+ {
+ int len = points.Length;
+
+ if (len < 4)
+ {
+ return string.Empty;
+ }
+
+ Vector a = points[0];
+ Vector b = points[1];
+ Vector c = points[2];
+
+ StringBuilder result = new StringBuilder();
+ result.AppendFormat("M{0:F2},{1:F2} Q{2:F2},{3:F2} {4:F2},{5:F2} T",
+ a.X, a.Y, b.X, b.Y, Average(b.X, c.X), Average(b.Y, c.Y));
+
+ for (int i = 2, max = len - 1; i < max; i++)
+ {
+ a = points[i];
+ b = points[i + 1];
+ result.AppendFormat("{0:F2},{1:F2} ", Average(a.X, b.X), Average(a.Y, b.Y));
+ }
+
+ if (closed)
+ {
+ result.Append("Z");
+ }
+
+ return result.ToString();
+ }
+
///
/// Get an array of points as objects with an adjusted point, pressure, vector, distance, and runningLength.
///
@@ -152,6 +188,360 @@ namespace InkCanvasForClassX.Libraries
}
return size * easing(0.5 - thinning * (0.5 - pressure));
}
+
+ // This is the rate of change for simulated pressure. It could be an option.
+ private const double RATE_OF_PRESSURE_CHANGE = 0.275;
+
+ private const double PI = Math.PI;
+ private const double FIXED_PI = PI + 0.0001;
+
+ ///
+ /// Get an array of points (as `[x, y]`) representing the outline of a stroke.
+ ///
+ /// An array of StrokePoints as returned from `getStrokePoints`.
+ /// An object with options.
+ ///
+ public static Vector[] GetStrokeOutlinePointsVectors(StrokePoint[] points, StrokeOptions options) {
+ var strokeOptions_Size = options.Size ?? 16;
+ var strokeOptions_Thinning = options.Thinning ?? 0.5;
+ var strokeOptions_Smoothing = options.Smoothing ?? 0.5;
+ var strokeOptions_SimulatePressure = options.SimulatePressure ?? true;
+ Func strokeOptions_Easing = (t) => t;
+ var strokeOptions_Start = options.Start;
+ var strokeOptions_End = options.End;
+ var isComplete = options.Last ?? false;
+
+ var capStart = strokeOptions_Start != null ? strokeOptions_Start.Cap : true;
+ Func taperStartEase = strokeOptions_Start != null
+ ? strokeOptions_Start.Easing
+ : (s) => s * (2 - s);
+
+ var capEnd = strokeOptions_End != null ? strokeOptions_End.Cap : true;
+ Func taperEndEase = strokeOptions_End != null
+ ? strokeOptions_End.Easing
+ : (t) => --t * t * t + 1;
+
+ // We can't do anything with an empty array or a stroke with negative size.
+ if (points.Length == 0 || strokeOptions_Size <= 0) {
+ return new Vector[] { };
+ }
+
+ // The total length of the line
+ var totalLength = points[points.Length - 1].RunningLength;
+
+ var taperStart = strokeOptions_Start != null ? strokeOptions_Start.IsTaper == false ? 0 :
+ strokeOptions_Start.IsTaper ? Math.Max(strokeOptions_Size, totalLength) :
+ strokeOptions_Start.Taper != null ? (double)strokeOptions_Start.Taper : 0 : Double.NaN;
+
+ var taperEnd = strokeOptions_End != null ? strokeOptions_End.IsTaper == false ? 0 :
+ strokeOptions_End.IsTaper ? Math.Max(strokeOptions_Size, totalLength) :
+ strokeOptions_End.Taper != null ? (double)strokeOptions_End.Taper : 0 : Double.NaN;
+
+ // The minimum allowed distance between points (squared)
+ var minDistance = Math.Pow(strokeOptions_Size * strokeOptions_Smoothing, 2);
+
+ // Our collected left and right points
+ var leftPts = new List();
+ var rightPts = new List();
+
+ // Previous pressure (start with average of first five pressures,
+ // in order to prevent fat starts for every line. Drawn lines
+ // almost always start slow!
+ var _prevPressure_arrseg = new ArraySegment(points, 0, 10);
+ var prevPressure = _prevPressure_arrseg.Aggregate(points[0].Pressure,
+ (acc, curr) => {
+ var pressure = curr.Pressure;
+
+ if (strokeOptions_SimulatePressure) {
+ // Speed of change - how fast should the the pressure changing?
+ var sp = Math.Min(1, curr.Distance / strokeOptions_Size);
+ // Rate of change - how much of a change is there?
+ var rp = Math.Min(1, 1 - sp);
+ pressure = Math.Min(1, acc + (rp - acc) * (sp * RATE_OF_PRESSURE_CHANGE));
+ }
+
+ return (acc + pressure) / 2;
+ });
+
+ // The current radius
+ var radius = GetStrokeRadius(strokeOptions_Size, strokeOptions_Thinning, points[points.Length - 1].Pressure,
+ strokeOptions_Easing);
+
+ // The radius of the first saved point
+ double firstRadius = Double.NaN;
+
+ // Previous vector
+ var prevVector = points[0].Vector;
+
+ // Previous left and right points
+ var pl = points[0].Point;
+ var pr = pl;
+
+ // Temporary left and right points
+ var tl = pl;
+ var tr = pr;
+
+ // Keep track of whether the previous point is a sharp corner
+ // ... so that we don't detect the same corner twice
+ var isPrevPointSharpCorner = false;
+
+ /*
+ Find the outline's left and right points
+
+ Iterating through the points and populate the rightPts and leftPts arrays,
+ skipping the first and last pointsm, which will get caps later on.
+ */
+ foreach (var _sp in points) {
+ var pressure = _sp.Pressure;
+ var point = _sp.Point;
+ var vector = _sp.Vector;
+ var distance = _sp.Distance;
+ var runningLength = _sp.RunningLength;
+
+ var i = Array.IndexOf(points, _sp);
+
+ // Removes noise from the end of the line
+ if (i < points.Length - 1 && totalLength - runningLength < 3) {
+ continue;
+ }
+
+ /*
+ Calculate the radius
+
+ If not thinning, the current point's radius will be half the size; or
+ otherwise, the size will be based on the current (real or simulated)
+ pressure.
+ */
+ if (strokeOptions_Thinning == Double.NaN) {
+ if (strokeOptions_SimulatePressure) {
+ // If we're simulating pressure, then do so based on the distance
+ // between the current point and the previous point, and the size
+ // of the stroke. Otherwise, use the input pressure.
+ var sp = Math.Min(1, distance / strokeOptions_Size);
+ var rp = Math.Min(1, 1 - sp);
+ pressure = Math.Min(1, prevPressure + (rp - prevPressure) * (sp * RATE_OF_PRESSURE_CHANGE));
+ }
+
+ radius = GetStrokeRadius(strokeOptions_Size, strokeOptions_Thinning, pressure,
+ strokeOptions_Easing);
+ } else {
+ radius = strokeOptions_Size / 2;
+ }
+
+ if (firstRadius == Double.NaN) firstRadius = radius;
+
+ /*
+ Apply tapering
+
+ If the current length is within the taper distance at either the
+ start or the end, calculate the taper strengths. Apply the smaller
+ of the two taper strengths to the radius.
+ */
+ var ts = runningLength < taperStart ? taperStartEase(runningLength / taperStart) : 1;
+ var te = runningLength < taperEnd ? taperEndEase(runningLength / taperEnd) : 1;
+
+ radius = Math.Max(0.01, radius * Math.Min(ts, te));
+
+ /* Add points to left and right */
+
+ /*
+ Handle sharp corners
+
+ Find the difference (dot product) between the current and next vector.
+ If the next vector is at more than a right angle to the current vector,
+ draw a cap at the current point.
+ */
+
+ var nextVector = (i < points.Length - 1 ? points[i + 1] : points[i]).Vector;
+ var nextDpr = i < points.Length - 1 ? Vector.DotVectors(vector, nextVector) : 1.0;
+ var prevDpr = Vector.DotVectors(vector, prevVector);
+
+ var isPointSharpCorner = prevDpr < 0 && !isPrevPointSharpCorner;
+ var isNextPointSharpCorner = nextDpr < 0;
+
+ if (isPointSharpCorner || isNextPointSharpCorner) {
+ // It's a sharp corner. Draw a rounded cap and move on to the next point
+ // Considering saving these and drawing them later? So that we can avoid
+ // crossing future points.
+
+ var offset = Vector.MultiplyVector(Vector.PerpendicularRotationVector(prevVector), radius);
+
+ double step = 1D / 13D;
+ double t = 0D;
+ for (; t <= 1D; t += step) {
+ tl = Vector.RotateVectors(Vector.SubtractVectors(point, offset), point, FIXED_PI * t);
+ leftPts.Add(tl);
+
+ tr = Vector.RotateVectors(Vector.AddVectors(point, offset), point, FIXED_PI * -t);
+ rightPts.Add(tr);
+ }
+
+ pl = tl;
+ pr = tr;
+
+ if (isNextPointSharpCorner) {
+ isPrevPointSharpCorner = true;
+ }
+ continue;
+ }
+
+ isPrevPointSharpCorner = false;
+
+ // Handle the last point
+ if (i == points.Length - 1) {
+ var offset = Vector.MultiplyVector(Vector.PerpendicularRotationVector(vector), radius);
+ leftPts.Add(Vector.SubtractVectors(point, offset));
+ rightPts.Add(Vector.AddVectors(point, offset));
+ continue;
+ }
+
+ /*
+ Add regular points
+
+ Project points to either side of the current point, using the
+ calculated size as a distance. If a point's distance to the
+ previous point on that side greater than the minimum distance
+ (or if the corner is kinda sharp), add the points to the side's
+ points array.
+ */
+ Vector _offset =
+ Vector.MultiplyVector(
+ Vector.PerpendicularRotationVector(Vector.InterpolateVectors(nextVector, vector, nextDpr)),
+ radius);
+
+ tl = Vector.SubtractVectors(point, _offset);
+
+ if (i <= 1 || Vector.DistLengthSquaredVectors(pl, tl) > minDistance) {
+ leftPts.Add(tl);
+ pl = tl;
+ }
+
+ tr = Vector.AddVectors(point, _offset);
+
+ if (i <= 1 || Vector.DistLengthSquaredVectors(pr, tr) > minDistance) {
+ rightPts.Add(tr);
+ pr = tr;
+ }
+
+ // Set variables for next iteration
+ prevPressure = pressure;
+ prevVector = vector;
+ }
+
+ /*
+ Drawing caps
+
+ Now that we have our points on either side of the line, we need to
+ draw caps at the start and end. Tapered lines don't have caps, but
+ may have dots for very short lines.
+ */
+ var firstPoint = points[0].Point;
+
+ var lastPoint = points.Length > 1
+ ? points[points.Length - 1].Point
+ : Vector.AddVectors(points[0].Point, new Vector(1, 1));
+
+ var startCap = new List();
+ var endCap = new List();
+
+ /*
+ Draw a dot for very short or completed strokes
+
+ If the line is too short to gather left or right points and if the line is
+ not tapered on either side, draw a dot. If the line is tapered, then only
+ draw a dot if the line is both very short and complete. If we draw a dot,
+ we can just return those points.
+ */
+ if (points.Length == 1) {
+ if (!((strokeOptions_Start != null && (taperStart != 0 && strokeOptions_Start.IsTaper)) || (strokeOptions_End != null &&
+ (taperEnd != 0 && strokeOptions_End.IsTaper))) || isComplete) {
+ var start = Vector.ProjectVectors(firstPoint,
+ Vector.UnitVector(
+ Vector.PerpendicularRotationVector(Vector.SubtractVectors(firstPoint, lastPoint))), !double.IsNaN(firstRadius) ? -firstRadius : -radius);
+ var dotPts = new List();
+ double step = 1D / 13D;
+ double t = step;
+ for (; t <= 1D; t += step) {
+ dotPts.Add(Vector.RotateVectors(start, firstPoint, FIXED_PI * 2 * t));
+ }
+
+ return dotPts.ToArray();
+ }
+ } else {
+ /*
+ Draw a start cap
+
+ Unless the line has a tapered start, or unless the line has a tapered end
+ and the line is very short, draw a start cap around the first point. Use
+ the distance between the second left and right point for the cap's radius.
+ Finally remove the first left and right points. :psyduck:
+ */
+
+ if ((strokeOptions_Start != null && (taperStart != 0 && strokeOptions_Start.IsTaper)) || ((strokeOptions_End != null &&
+ (taperEnd != 0 && strokeOptions_End.IsTaper)) && points.Length == 1)) {
+ // The start point is tapered, noop
+ } else if (capStart) {
+ // Draw the round cap - add thirteen points rotating the right point around the start point to the left point
+ double step = 1D / 13D;
+ double t = step;
+ for (; t <= 1D; t += step) {
+ var pt = Vector.RotateVectors(rightPts[0], firstPoint, FIXED_PI * t);
+ startCap.Add(pt);
+ }
+ } else {
+ // Draw the flat cap - add a point to the left and right of the start point
+ var cornersVector = Vector.SubtractVectors(leftPts[0], rightPts[0]);
+ var offsetA = Vector.MultiplyVector(cornersVector, 0.5);
+ var offsetB = Vector.MultiplyVector(cornersVector, 0.51);
+
+ startCap.Add(Vector.SubtractVectors(firstPoint, offsetA));
+ startCap.Add(Vector.SubtractVectors(firstPoint, offsetB));
+ startCap.Add(Vector.AddVectors(firstPoint, offsetA));
+ startCap.Add(Vector.AddVectors(firstPoint, offsetB));
+ }
+
+ /*
+ Draw an end cap
+
+ If the line does not have a tapered end, and unless the line has a tapered
+ start and the line is very short, draw a cap around the last point. Finally,
+ remove the last left and right points. Otherwise, add the last point. Note
+ that This cap is a full-turn-and-a-half: this prevents incorrect caps on
+ sharp end turns.
+ */
+ var direction =
+ Vector.PerpendicularRotationVector(Vector.NegateVector(points[points.Length - 1].Vector));
+
+ if ((strokeOptions_End != null &&
+ (taperEnd != 0 && strokeOptions_End.IsTaper)) ||
+ ((strokeOptions_Start != null && (taperStart != 0 && strokeOptions_Start.IsTaper)) && points.Length == 1)) {
+ // Tapered end - push the last point to the line
+ endCap.Add(lastPoint);
+ } else if (capEnd) {
+ // Draw the round end cap
+ var start = Vector.ProjectVectors(lastPoint, direction, radius);
+ double step = 1D / 29D;
+ double t = step;
+ for (; t < 1D; t += step) {
+ endCap.Add(Libraries.Vector.RotateVectors(start, lastPoint, FIXED_PI * 3 * t));
+ }
+ } else {
+ // Draw the flat end cap
+ endCap.Add(Vector.AddVectors(lastPoint, Vector.MultiplyVector(direction, radius)));
+ endCap.Add(Vector.AddVectors(lastPoint, Vector.MultiplyVector(direction, radius * 0.99)));
+ endCap.Add(Vector.SubtractVectors(lastPoint, Vector.MultiplyVector(direction, radius)));
+ endCap.Add(Vector.SubtractVectors(lastPoint, Vector.MultiplyVector(direction, radius * 0.99)));
+ }
+ }
+
+ /*
+ Return the points in the correct winding order: begin on the left side, then
+ continue around the end cap, then come back along the right side, and finally
+ complete the start cap.
+ */
+ rightPts.Reverse();
+ return leftPts.Concat(endCap).Concat(rightPts).Concat(startCap).ToArray();
+ }
}
namespace Stroke {
@@ -204,12 +594,14 @@ namespace InkCanvasForClassX.Libraries
///
/// Whether to apply a cap at the start/end of the line.
///
- public bool? Cap { get; set; }
+ public bool Cap { get; set; }
///
/// The taper value at the start/end of the line.
///
- public double? Taper { get; set; }
+ public double Taper { get; set; }
+
+ public bool IsTaper { get; set; }
///
/// An easing function to apply to the taper.
diff --git a/InkCanvasForClassX/Libraries/PerfectFreehandJint.cs b/InkCanvasForClassX/Libraries/PerfectFreehandJint.cs
new file mode 100644
index 0000000..07e8f45
--- /dev/null
+++ b/InkCanvasForClassX/Libraries/PerfectFreehandJint.cs
@@ -0,0 +1,74 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Media;
+using InkCanvasForClassX.Libraries.Stroke;
+using Jint;
+using Jint.Native;
+
+namespace InkCanvasForClassX.Libraries
+{
+ public class PerfectFreehandJint {
+ public class StylusPointLite
+ {
+ public double x;
+ public double y;
+ public double pressure;
+ }
+
+ public class StrokeOptions
+ {
+ public double? size { get; set; }
+ public double? thinning { get; set; }
+ public double? smoothing { get; set; }
+ public double? streamline { get; set; }
+ public Func easing { get; set; }
+ public bool? simulatePressure { get; set; }
+ public StrokeCapOptions start { get; set; }
+ public StrokeCapOptions end { get; set; }
+ public bool? last { get; set; }
+ }
+
+ public class StrokeCapOptions
+ {
+ public bool? cap { get; set; }
+ public double? taper { get; set; }
+ public Func easing { get; set; }
+ }
+
+ public class StrokePoint
+ {
+ public Array point { get; set; }
+ public double pressure { get; set; }
+ public double distance { get; set; }
+ public Array vector { get; set; }
+ public double runningLength { get; set; }
+ }
+
+ public readonly Engine JintEngine = new Engine();
+
+ public PerfectFreehandJint() {
+ // perfect-freehand
+ JintEngine.Execute("function neg(t){return[-t[0],-t[1]]}function add(t,n){return[t[0]+n[0],t[1]+n[1]]}function sub(t,n){return[t[0]-n[0],t[1]-n[1]]}function mul(t,n){return[t[0]*n,t[1]*n]}function div(t,n){return[t[0]/n,t[1]/n]}function per(t){return[t[1],-t[0]]}function dpr(t,n){return t[0]*n[0]+t[1]*n[1]}function isEqual(t,n){return t[0]===n[0]&&t[1]===n[1]}function len(t){return Math.hypot(t[0],t[1])}function len2(t){return t[0]*t[0]+t[1]*t[1]}function dist2(t,n){return len2(sub(t,n))}function uni(t){return div(t,len(t))}function dist(t,n){return Math.hypot(t[1]-n[1],t[0]-n[0])}function med(t,n){return mul(add(t,n),.5)}function rotAround(t,n,e){const r=Math.sin(e),u=Math.cos(e),i=t[0]-n[0],s=t[1]-n[1],o=i*r+s*u;return[i*u-s*r+n[0],o+n[1]]}function lrp(t,n,e){return add(t,mul(sub(n,t),e))}function prj(t,n,e){return add(t,mul(n,e))}function getStrokeRadius(t,n,e,r=(t=>t)){return t*r(.5-n*(.5-e))}function getStrokePoints(t,n={}){var e;const{streamline:r=.5,size:u=16,last:i=!1}=n;if(0===t.length)return[];const s=.15+.85*(1-r);let o=Array.isArray(t[0])?t:t.map((({x:t,y:n,pressure:e=.5})=>[t,n,e]));if(2===o.length){const t=o[1];o=o.slice(0,-1);for(let n=1;n<5;n++)o.push(lrp(o[0],t,n/4))}1===o.length&&(o=[...o,[...add(o[0],[1,1]),...o[0].slice(2)]]);const c=[{point:[o[0][0],o[0][1]],pressure:o[0][2]>=0?o[0][2]:.25,vector:[1,1],distance:0,runningLength:0}];let l=!1,p=0,a=c[0];const d=o.length-1;for(let t=1;t=0?o[t][2]:.5,vector:uni(sub(a.point,n)),distance:e,runningLength:p},c.push(a)}return c[0].vector=(null===(e=c[1])||void 0===e?void 0:e.vector)||[0,0],c}const{min:min,PI:PI}=Math,RATE_OF_PRESSURE_CHANGE=.275,FIXED_PI=PI+1e-4;function getStrokeOutlinePoints(t,n={}){const{size:e=16,smoothing:r=.5,thinning:u=.5,simulatePressure:i=!0,easing:s=(t=>t),start:o={},end:c={},last:l=!1}=n,{cap:p=!0,easing:a=(t=>t*(2-t))}=o,{cap:d=!0,easing:h=(t=>--t*t*t+1)}=c;if(0===t.length||e<=0)return[];const f=t[t.length-1].runningLength,g=!1===o.taper?0:!0===o.taper?Math.max(e,f):o.taper,m=!1===c.taper?0:!0===c.taper?Math.max(e,f):c.taper,E=Math.pow(e*r,2),P=[],v=[];let I,_=t.slice(0,10).reduce(((t,n)=>{let r=n.pressure;if(i){const u=min(1,n.distance/e),i=min(1,1-u);r=min(1,t+u*RATE_OF_PRESSURE_CHANGE*(i-t))}return(t+r)/2}),t[0].pressure),A=getStrokeRadius(e,u,t[t.length-1].pressure,s),S=t[0].vector,b=t[0].point,R=b,M=b,F=R,k=!1;for(let n=0;nE)&&(P.push(M),b=M),F=add(o,x),(n<=1||dist2(R,F)>E)&&(v.push(F),R=F),_=r,S=c}const D=t[0].point.slice(0,2),X=t.length>1?t[t.length-1].point.slice(0,2):add(t[0].point,[1,1]),y=[],O=[];if(1===t.length){if(!g&&!m||l){const t=prj(D,uni(per(sub(D,X))),-(I||A)),n=[];for(let e=1/13,r=e;r<=1;r+=e)n.push(rotAround(t,D,2*FIXED_PI*r));return n}}else{if(g||m&&1===t.length);else if(p)for(let t=1/13,n=t;n<=1;n+=t){const t=rotAround(v[0],D,FIXED_PI*n);y.push(t)}else{const t=sub(P[0],v[0]),n=mul(t,.5),e=mul(t,.51);y.push(sub(D,n),sub(D,e),add(D,e),add(D,n))}const n=per(neg(t[t.length-1].vector));if(m||g&&1===t.length)O.push(X);else if(d){const t=prj(X,n,A);for(let n=1/29,e=n;e<1;e+=n)O.push(rotAround(t,X,3*FIXED_PI*e))}else O.push(add(X,mul(n,A)),add(X,mul(n,.99*A)),sub(X,mul(n,.99*A)),sub(X,mul(n,A)))}return P.concat(O,v.reverse(),y)}function getStroke(t,n={}){return getStrokeOutlinePoints(getStrokePoints(t,n),n)}");
+ // getSvgPathFromStroke
+ JintEngine.Execute(
+ "const average=(e,t)=>(e+t)/2;function getSvgPathFromStroke(e,t=!0){const o=e.length;if(o<4)return\"\";let r=e[0],a=e[1];const i=e[2];let F=`M${r[0].toFixed(2)},${r[1].toFixed(2)} Q${a[0].toFixed(2)},${a[1].toFixed(2)} ${average(a[0],i[0]).toFixed(2)},${average(a[1],i[1]).toFixed(2)} T`;for(let t=2,i=o-1;t
- /// 將該向量點乘另一個向量
+ /// 提供兩個Vector,返回兩個Vector點乘後的数值
///
- public Vector Dot(Vector vec)
+ public static double DotVectors(Vector vec1, Vector vec2)
{
- _x = _x * vec.X;
- _y = _y * vec.Y;
- return this;
- }
-
- ///
- /// 提供兩個Vector,返回兩個Vector點乘後的Vector
- ///
- public static Vector DotVectors(Vector vec1, Vector vec2)
- {
- return new Vector(vec1.X * vec2.X, vec1.Y * vec2.Y);
+ return vec1.X * vec2.X + vec1.Y * vec2.Y;
}
///
diff --git a/InkCanvasForClassX/MainWindow.xaml b/InkCanvasForClassX/MainWindow.xaml
index f60adcd..e02e873 100644
--- a/InkCanvasForClassX/MainWindow.xaml
+++ b/InkCanvasForClassX/MainWindow.xaml
@@ -10,5 +10,9 @@
+
+
+
+
diff --git a/InkCanvasForClassX/MainWindow.xaml.cs b/InkCanvasForClassX/MainWindow.xaml.cs
index aadf517..266215d 100644
--- a/InkCanvasForClassX/MainWindow.xaml.cs
+++ b/InkCanvasForClassX/MainWindow.xaml.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@@ -7,11 +8,14 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
+using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
+using InkCanvasForClassX.Libraries;
+using InkCanvasForClassX.Libraries.Stroke;
namespace InkCanvasForClassX
{
@@ -20,12 +24,129 @@ namespace InkCanvasForClassX
///
public partial class MainWindow : Window
{
+
+
+
+ public static StylusPointCollection GenerateStylusPoints(int numberOfPoints, int maxX, int maxY)
+ {
+ Random random = new Random();
+ StylusPointCollection points = new StylusPointCollection();
+
+ for (int i = 0; i < numberOfPoints; i++)
+ {
+ double x = random.NextDouble() * maxX;
+ double y = random.NextDouble() * maxY;
+ float pressureFactor = 0.5F;
+
+ StylusPoint point = new StylusPoint(x, y, pressureFactor);
+ points.Add(point);
+ }
+
+ return points;
+ }
+
+ private bool isDragging = false;
+ private Point startPoint;
public MainWindow()
{
InitializeComponent();
InkC.StrokeCollected += (object sender, InkCanvasStrokeCollectedEventArgs e) => {
InkP.Strokes = InkC.Strokes;
+ var stylusPtsList = new List();
+ foreach (var strokeStylusPoint in e.Stroke.StylusPoints) {
+ stylusPtsList.Add(new PerfectFreehandJint.StylusPointLite()
+ {
+ x = Math.Round(strokeStylusPoint.X,2) ,
+ y = Math.Round(strokeStylusPoint.Y,2),
+ pressure = strokeStylusPoint.PressureFactor,
+ });
+ }
+ var aaa = new PerfectFreehandJint();
+ var ccc = aaa.GetSVGPathStroke(stylusPtsList.ToArray(), new PerfectFreehandJint.StrokeOptions() {
+ size = 16,
+ thinning = 0.5,
+ smoothing = 0.5,
+ streamline = 0.5,
+ simulatePressure = true,
+ easing = (t)=>t,
+ last = true,
+ start = new PerfectFreehandJint.StrokeCapOptions() {
+ cap = true,
+ taper = 0,
+ easing = (t)=>t,
+ },
+ end = new PerfectFreehandJint.StrokeCapOptions()
+ {
+ cap = true,
+ taper = 0,
+ easing = (t) => t,
+ },
+ });
+ Trace.WriteLine(ccc);
};
+
+ InkC.MouseRightButtonDown += Inkcanv_MouseRightButtonDown;
+ InkC.MouseRightButtonUp += Inkcanv_MouseRightButtonUp;
+ InkC.MouseMove += Inkcanv_MouseMove;
+ var a = GenerateStylusPoints(10, 1920, 1080);
+ foreach (var strokePoint in a)
+ {
+ Trace.WriteLine($"point x:{strokePoint.X} point y:{strokePoint.Y}");
+ }
+ var c = PerfectFreehand.GetStrokePoints(a, new StrokeOptions() {
+ Size = 16,
+ Thinning = 0.5,
+ Smoothing = 0.5,
+ SimulatePressure = true,
+ });
+ var s = PerfectFreehand.GetStrokeOutlinePointsVectors(c, new StrokeOptions() {
+ Size = 16,
+ Thinning = 0.5,
+ Smoothing = 0.5,
+ SimulatePressure = true,
+ });
+ foreach (var strokePoint in c) {
+ Trace.WriteLine($"point x:{strokePoint.Vector.X.ToString()} point y:{strokePoint.Vector.Y.ToString()}");
+ }
+ Trace.WriteLine(PerfectFreehand.ConvertVectorsToSVGPath(s));
+ }
+
+ private void Inkcanv_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
+ {
+ isDragging = true;
+ startPoint = e.GetPosition(InkC);
+ InkC.CaptureMouse();
+ }
+
+ private void Inkcanv_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
+ {
+ isDragging = false;
+ InkC.ReleaseMouseCapture();
+ }
+
+ private void Inkcanv_MouseMove(object sender, MouseEventArgs e)
+ {
+ if (isDragging && e.RightButton == MouseButtonState.Pressed)
+ {
+ Point currentPoint = e.GetPosition(InkC);
+ System.Windows.Vector delta = currentPoint - startPoint;
+
+ foreach (Stroke stroke in InkC.Strokes)
+ {
+ stroke.Transform(new Matrix(1, 0, 0, 1, delta.X, delta.Y), false);
+ }
+ InkP.Strokes = InkC.Strokes;
+
+ startPoint = currentPoint;
+ }
+ }
+
+ private void ButtonBase1_OnClick(object sender, RoutedEventArgs e) {
+ InkC.EditingMode = InkCanvasEditingMode.None;
+ }
+
+ private void ButtonBase2_OnClick(object sender, RoutedEventArgs e) {
+ InkC.EditingMode = InkCanvasEditingMode.Ink;
}
}
}
diff --git a/PeroInstaller/App.xaml b/PeroInstaller/App.xaml
new file mode 100644
index 0000000..853bd24
--- /dev/null
+++ b/PeroInstaller/App.xaml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/PeroInstaller/App.xaml.cs b/PeroInstaller/App.xaml.cs
new file mode 100644
index 0000000..958933f
--- /dev/null
+++ b/PeroInstaller/App.xaml.cs
@@ -0,0 +1,13 @@
+using System.Configuration;
+using System.Data;
+using System.Windows;
+
+namespace PeroInstaller
+{
+ ///
+ /// Interaction logic for App.xaml
+ ///
+ public partial class App : Application
+ {
+ }
+}
\ No newline at end of file
diff --git a/PeroInstaller/AssemblyInfo.cs b/PeroInstaller/AssemblyInfo.cs
new file mode 100644
index 0000000..b0ec827
--- /dev/null
+++ b/PeroInstaller/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
diff --git a/PeroInstaller/InstallerConfig.xaml b/PeroInstaller/InstallerConfig.xaml
new file mode 100644
index 0000000..6bb2206
--- /dev/null
+++ b/PeroInstaller/InstallerConfig.xaml
@@ -0,0 +1,9 @@
+
+ InkCanvasForClass 安装向导
+ InkCanvasForClass
+ 开源的简单易用小巧强大的屏幕批注软件
+ 20240710V1P1
+
+
\ No newline at end of file
diff --git a/PeroInstaller/MainWindow.xaml b/PeroInstaller/MainWindow.xaml
new file mode 100644
index 0000000..daec3cb
--- /dev/null
+++ b/PeroInstaller/MainWindow.xaml
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+
+
+ 基于PeroInstaller包装,打包版本:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 安装
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 卸载
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 更新
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 修改
+
+
+
+
+
+
+
+
+
diff --git a/PeroInstaller/MainWindow.xaml.cs b/PeroInstaller/MainWindow.xaml.cs
new file mode 100644
index 0000000..e2f78bd
--- /dev/null
+++ b/PeroInstaller/MainWindow.xaml.cs
@@ -0,0 +1,24 @@
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace PeroInstaller
+{
+ ///
+ /// Interaction logic for MainWindow.xaml
+ ///
+ public partial class MainWindow : Window
+ {
+ public MainWindow()
+ {
+ InitializeComponent();
+ }
+ }
+}
\ No newline at end of file
diff --git a/PeroInstaller/PeroInstaller - Backup (1).csproj b/PeroInstaller/PeroInstaller - Backup (1).csproj
new file mode 100644
index 0000000..32194a3
--- /dev/null
+++ b/PeroInstaller/PeroInstaller - Backup (1).csproj
@@ -0,0 +1,17 @@
+
+
+
+ WinExe
+ net6.0-windows10.0.19041.0
+ enable
+ enable
+ true
+ 7.0
+
+
+
+
+
+
+
+
diff --git a/PeroInstaller/PeroInstaller - Backup.csproj b/PeroInstaller/PeroInstaller - Backup.csproj
new file mode 100644
index 0000000..b25f853
--- /dev/null
+++ b/PeroInstaller/PeroInstaller - Backup.csproj
@@ -0,0 +1,16 @@
+
+
+
+ WinExe
+ net6.0-windows10.0.18362.0
+ enable
+ enable
+ true
+
+
+
+
+
+
+
+
diff --git a/PeroInstaller/PeroInstaller.csproj b/PeroInstaller/PeroInstaller.csproj
new file mode 100644
index 0000000..7a9958b
--- /dev/null
+++ b/PeroInstaller/PeroInstaller.csproj
@@ -0,0 +1,25 @@
+
+
+
+ WinExe
+ net6.0-windows10.0.18362.0
+ enable
+ enable
+ true
+ 7.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/PeroInstaller/PeroInstaller.csproj.user b/PeroInstaller/PeroInstaller.csproj.user
new file mode 100644
index 0000000..27618fc
--- /dev/null
+++ b/PeroInstaller/PeroInstaller.csproj.user
@@ -0,0 +1,19 @@
+
+
+
+ <_LastSelectedProfileId>D:\vs\ica\PeroInstaller\Properties\PublishProfiles\FolderProfile.pubxml
+
+
+
+ Designer
+
+
+
+
+ Designer
+
+
+ Designer
+
+
+
\ No newline at end of file
diff --git a/PeroInstaller/Properties/PublishProfiles/FolderProfile.pubxml b/PeroInstaller/Properties/PublishProfiles/FolderProfile.pubxml
new file mode 100644
index 0000000..f4b2696
--- /dev/null
+++ b/PeroInstaller/Properties/PublishProfiles/FolderProfile.pubxml
@@ -0,0 +1,18 @@
+
+
+
+
+ Release
+ Any CPU
+ bin\dist\
+ FileSystem
+ <_TargetId>Folder
+ net6.0-windows
+ win-x86
+ true
+ true
+ true
+
+
\ No newline at end of file
diff --git a/PeroInstaller/Properties/PublishProfiles/FolderProfile.pubxml.user b/PeroInstaller/Properties/PublishProfiles/FolderProfile.pubxml.user
new file mode 100644
index 0000000..c09c61c
--- /dev/null
+++ b/PeroInstaller/Properties/PublishProfiles/FolderProfile.pubxml.user
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/PeroInstaller/resources/icc.png b/PeroInstaller/resources/icc.png
new file mode 100644
index 0000000..99017b9
Binary files /dev/null and b/PeroInstaller/resources/icc.png differ