From 870440a6a2b3ee7c405e04fe713f43a1cc0acaf7 Mon Sep 17 00:00:00 2001 From: kriastans Date: Mon, 8 Jul 2024 20:29:57 +0800 Subject: [PATCH] =?UTF-8?q?[update]=20=E6=9B=B4=E6=96=B0InkCanvasForClassX?= =?UTF-8?q?=E7=9A=84=E6=BA=90=E4=BB=A3=E7=A2=BC=EF=BC=8C=E4=BD=BF=E7=94=A8?= =?UTF-8?q?Jint=E5=AF=A6=E7=8F=BE=E4=BA=86perfect-freehand=E7=9A=84C#?= =?UTF-8?q?=E5=8C=85=E8=A3=9D=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 + Ink Canvas.sln | 68 ++- InkCanvasForClass/MainWindow.xaml | 18 +- InkCanvasForClass/MainWindow_cs/MW_PPT.cs | 9 + .../MainWindow_cs/MW_Settings.cs | 27 +- .../MainWindow_cs/MW_SettingsToLoad.cs | 2 +- InkCanvasForClass/MainWindow_cs/MW_Timer.cs | 39 +- .../InkCanvasForClassPPTVsto.csproj | 216 ++++++++++ .../InkCanvasForClassPPTVsto_TemporaryKey.pfx | Bin 0 -> 1692 bytes .../Properties/AssemblyInfo.cs | 38 ++ .../Properties/Resources.Designer.cs | 62 +++ .../Properties/Resources.resx | 117 ++++++ .../Properties/Settings.Designer.cs | 26 ++ .../Properties/Settings.settings | 7 + .../ThisAddIn.Designer.cs | 231 ++++++++++ .../ThisAddIn.Designer.xml | 4 + InkCanvasForClassPPTVsto/ThisAddIn.cs | 35 ++ InkCanvasForClassX/InkCanvasForClassX.csproj | 1 + InkCanvasForClassX/Libraries/InkProjector.cs | 51 ++- .../Libraries/PerfectFreehand.cs | 396 +++++++++++++++++- .../Libraries/PerfectFreehandJint.cs | 74 ++++ InkCanvasForClassX/Libraries/Vector.cs | 16 +- InkCanvasForClassX/MainWindow.xaml | 4 + InkCanvasForClassX/MainWindow.xaml.cs | 121 ++++++ PeroInstaller/App.xaml | 17 + PeroInstaller/App.xaml.cs | 13 + PeroInstaller/AssemblyInfo.cs | 10 + PeroInstaller/InstallerConfig.xaml | 9 + PeroInstaller/MainWindow.xaml | 118 ++++++ PeroInstaller/MainWindow.xaml.cs | 24 ++ .../PeroInstaller - Backup (1).csproj | 17 + PeroInstaller/PeroInstaller - Backup.csproj | 16 + PeroInstaller/PeroInstaller.csproj | 25 ++ PeroInstaller/PeroInstaller.csproj.user | 19 + .../PublishProfiles/FolderProfile.pubxml | 18 + .../PublishProfiles/FolderProfile.pubxml.user | 6 + PeroInstaller/resources/icc.png | Bin 0 -> 36906 bytes 37 files changed, 1795 insertions(+), 63 deletions(-) create mode 100644 InkCanvasForClassPPTVsto/InkCanvasForClassPPTVsto.csproj create mode 100644 InkCanvasForClassPPTVsto/InkCanvasForClassPPTVsto_TemporaryKey.pfx create mode 100644 InkCanvasForClassPPTVsto/Properties/AssemblyInfo.cs create mode 100644 InkCanvasForClassPPTVsto/Properties/Resources.Designer.cs create mode 100644 InkCanvasForClassPPTVsto/Properties/Resources.resx create mode 100644 InkCanvasForClassPPTVsto/Properties/Settings.Designer.cs create mode 100644 InkCanvasForClassPPTVsto/Properties/Settings.settings create mode 100644 InkCanvasForClassPPTVsto/ThisAddIn.Designer.cs create mode 100644 InkCanvasForClassPPTVsto/ThisAddIn.Designer.xml create mode 100644 InkCanvasForClassPPTVsto/ThisAddIn.cs create mode 100644 InkCanvasForClassX/Libraries/PerfectFreehandJint.cs create mode 100644 PeroInstaller/App.xaml create mode 100644 PeroInstaller/App.xaml.cs create mode 100644 PeroInstaller/AssemblyInfo.cs create mode 100644 PeroInstaller/InstallerConfig.xaml create mode 100644 PeroInstaller/MainWindow.xaml create mode 100644 PeroInstaller/MainWindow.xaml.cs create mode 100644 PeroInstaller/PeroInstaller - Backup (1).csproj create mode 100644 PeroInstaller/PeroInstaller - Backup.csproj create mode 100644 PeroInstaller/PeroInstaller.csproj create mode 100644 PeroInstaller/PeroInstaller.csproj.user create mode 100644 PeroInstaller/Properties/PublishProfiles/FolderProfile.pubxml create mode 100644 PeroInstaller/Properties/PublishProfiles/FolderProfile.pubxml.user create mode 100644 PeroInstaller/resources/icc.png 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 0000000000000000000000000000000000000000..8833e31e0d6892959498045eee7fe38727ffa021 GIT binary patch literal 1692 zcmZWodpOf=82;^NHi^k;3(2_?YRfc-&)4R3E$50*4vmOZ&NNAkS+Sf_4kJWFAu=U7 z6~eSRR0>%tNv%SYF6{ID>iWLAzU#Z5>v`Y%zMtoLulJAV#?lbEAWRHPLpUSWY)d95 zFG|CZuwoj*3Qj|iAlVE{6KniWNvr}+6Dx(}A}Cpiwf{^>Ny5Nl8rX=Xf%Vu82+4nC z=y4QWLQd%lzQ9uRIS3*L;50D9^jV!0$7~|@MtL>w;*xx5w5$4$A`{C0r-tHYmZQAu7tb>EI;T5?1%O(f9iDPmuBPEzc%d*gJ zlP5Ig`Ut-C*eb7a^pm(PjKzHL$Tm)&+|9RKd|ug*@#dXck}bDDk;<^}Be9vP;$sY9153DSbfo^GDp^8rrMe1peSW9{mcV>KgYKI5QNxUz-K zEuSYj*$G;(ik&u2N&|igx$1}a*y9fyH6I!qEnk31qhPM!1KIM>rosNJi0w`lgv*EMA;BD1o*QCPm? zg`36#Rm})E-c@scSf}kn#kNMR>1Fk6@ojQXqGCApl2Ltw1zQI+Dy>yQbE4C@0fs3x z8Kgk2e)OyRS9zkdoMPW56?7*c5XgQp@bI8zRYTRwceXt@Pa9%dXeW?oy97b zV&krC+aw|dRi|IpCTV2*&c6j6xyi?ZSQaMN?eQNvG`{7$36T;kg~i2LzHDo&!}VxS zx4z?|>5SU-(qXOxioBu13jq>d)1%+qjuXk}Ws$m@YRqk(ffHn70has=!+# z4sR1$tJvMqEWIWH!{0fT7r>hE52;Az9_FghIVn?!z>N*!?e*%t+|BY+59?eQ`CtS8~KZlra4dM6Zof`>UP4N_*r!<#*EfIM=AXaek-KTd`RXf>o<4-v(rKASyjzV;W|b*r?8Op+0{yB<$+ z+t+2b?j3MnN=s8~9zr9Xzr|BG>A7K?UQK<+mn@7-F)`awp8lcbxd3Ne`${}z2kvQc zXq?D<)v-6xF`M0fKzDpDBbeGtKXFLQV#d_?2q{>OEy^@rnZAN+N0Ip((W2d_{v0;n zc~f5DoUG`3LEHEjI(^FYS?WMv>7L#mG-=UwGzeaKBWP_`5T(U6vS(sYimmq{pRsaE zwiM0Rlk`pWZK~U|6eFKcAZm;^#d~f-h#pt*QlqmH&3rINbsj9YqU1aH?9jVwjnai_ z*kYO2y+&T_PbPWH1n|WllqP4wyTJFdr2uHk=r5DC3Z8nMo$j4_nd^!(VZlvjnL`U2 zYFoea^0sJYt<4U^Fs~sg)k2~5F75l-i<}lUWR6g!wXe1AQuw4D3sXl%)s#FWC@Jo6 zy`z^|EumEx!eLe?nJid_085nTi&BlP=>T5&qdUAo2OIhhLNEmdV zS-2}?*j4doirDN#FDab~g4rn66sv|sBE)r3VxTfy;a%;v`c9Fi_~!Vbn~d1wJJ%N$ fJ%THUP59}!n-1-u$NF?0)35ChPAZ7`v3P$2c52>3 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..99017b97421bd92b4351de1b8fe72e18476d70bc GIT binary patch literal 36906 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