[update] 更新InkCanvasForClassX的源代碼,使用Jint實現了perfect-freehand的C#包裝。

This commit is contained in:
Dubi906w 2024-07-08 20:29:57 +08:00
parent bfa1936794
commit 870440a6a2
37 changed files with 1795 additions and 63 deletions

4
.gitignore vendored
View File

@ -2,6 +2,10 @@
/InkCanvasForClass/bin
/InkCanvasForClassX/obj
/InkCanvasForClassX/bin
/InkCanvasForClassPPTVsto/obj
/InkCanvasForClassPPTVsto/bin
/PeroInstaller/obj
/PeroInstaller/bin
/CvtePaintDemo/obj
/CvtePaintDemo/bin
/.vs

View File

@ -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

View File

@ -1710,17 +1710,6 @@
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchAutoKillICA_Toggled" />
</ui:SimpleStackPanel>
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<Image Source="/Resources/Icons-png/idt.png" Margin="0,0,6,0"
Width="28"
Height="28" VerticalAlignment="Center" />
<TextBlock Foreground="#fafafa" Text="自动查杀“智绘教”" VerticalAlignment="Center"
FontSize="14" Margin="0,0,16,0" />
<ui:ToggleSwitch OnContent="" OffContent=""
Name="ToggleSwitchAutoKillIDT"
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchAutoKillIDT_Toggled" />
</ui:SimpleStackPanel>
<Line HorizontalAlignment="Center" X1="0" Y1="0" X2="400" Y2="0" Stroke="#3f3f46"
StrokeThickness="1" Margin="0,4,0,4" />
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
@ -1876,7 +1865,12 @@
</GroupBox.Header>
<ui:SimpleStackPanel Spacing="12">
<ui:SimpleStackPanel Orientation="Horizontal">
<TextBlock FontSize="18" FontWeight="Bold" Text="Version" />
<TextBlock FontSize="18" FontWeight="Bold" Text="Release Version" />
<TextBlock FontSize="18" FontWeight="Bold" FontFamily="Consolas"
Text="20240710V1P1" />
</ui:SimpleStackPanel>
<ui:SimpleStackPanel Orientation="Horizontal">
<TextBlock FontSize="18" FontWeight="Bold" Text="Bundle Version" />
<TextBlock x:Name="AppVersionTextBlock" FontSize="18" FontWeight="Bold"
Text="5.X.X.X" />
</ui:SimpleStackPanel>

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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 {}

View File

@ -0,0 +1,216 @@
<Project ToolsVersion="17.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<!--
This section defines project-level properties.
AssemblyName
Name of the output assembly.
Configuration
Specifies a default value for debug.
OutputType
Must be "Library" for VSTO.
Platform
Specifies what CPU the output of this project can run on.
NoStandardLibraries
Set to "false" for VSTO.
RootNamespace
In C#, this specifies the namespace given to new files. In VB, all objects are
wrapped in this namespace at runtime.
-->
<PropertyGroup>
<ProjectTypeGuids>{BAA0C2D2-18E2-41B9-852F-F413020CAA33};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{E494CFFE-D2EC-4BAD-82D9-C92FE29616A7}</ProjectGuid>
<OutputType>Library</OutputType>
<NoStandardLibraries>false</NoStandardLibraries>
<RootNamespace>InkCanvasForClassPPTVsto</RootNamespace>
<AssemblyName>InkCanvasForClassPPTVsto</AssemblyName>
<LoadBehavior>3</LoadBehavior>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<DefineConstants>VSTO40</DefineConstants>
<BootstrapperEnabled>true</BootstrapperEnabled>
<BootstrapperComponentsLocation>HomeSite</BootstrapperComponentsLocation>
</PropertyGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.VSTORuntime.4.0">
<Visible>False</Visible>
<ProductName>Microsoft Visual Studio 2010 Tools for Office Runtime %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<PropertyGroup>
<!--
OfficeApplication
Add-in host application
-->
<OfficeApplication>PowerPoint</OfficeApplication>
</PropertyGroup>
<!--
This section defines properties that are set when the "Debug" configuration is selected.
DebugSymbols
If "true", create symbols (.pdb). If "false", do not create symbols.
DefineConstants
Constants defined for the preprocessor.
EnableUnmanagedDebugging
If "true", starting the debugger will attach both managed and unmanaged debuggers.
Optimize
If "true", optimize the build output. If "false", do not optimize.
OutputPath
Output path of project relative to the project file.
WarningLevel
Warning level for the compiler.
-->
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
<DefineConstants>$(DefineConstants);DEBUG;TRACE</DefineConstants>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<!--
This section defines properties that are set when the "Release" configuration is selected.
DebugSymbols
If "true", create symbols (.pdb). If "false", do not create symbols.
DefineConstants
Constants defined for the preprocessor.
EnableUnmanagedDebugging
If "true", starting the debugger will attach both managed and unmanaged debuggers.
Optimize
If "true", optimize the build output. If "false", do not optimize.
OutputPath
Output path of project relative to the project file.
WarningLevel
Warning level for the compiler.
-->
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
<DefineConstants>$(DefineConstants);TRACE</DefineConstants>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<!--
This section specifies references for the project.
-->
<ItemGroup>
<Reference Include="Accessibility" />
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.Office.Tools.v4.0.Framework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.Tools.Applications.Runtime, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.Office.Tools, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.Office.Tools.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.Office.Tools.Common.v4.0.Utilities, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Reference Include="Office, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c">
<Private>False</Private>
<EmbedInteropTypes>true</EmbedInteropTypes>
</Reference>
<Reference Include="Microsoft.Office.Interop.PowerPoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c">
<Private>False</Private>
<EmbedInteropTypes>true</EmbedInteropTypes>
</Reference>
<Reference Include="stdole, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<Private>False</Private>
</Reference>
</ItemGroup>
<!--
This section defines the user source files that are part of the project.
A "Compile" element specifies a source file to compile.
An "EmbeddedResource" element specifies an .resx file for embedded resources.
A "None" element specifies a file that is not to be passed to the compiler (for instance,
a text file or XML file).
The "AppDesigner" element specifies the directory where the application properties files
can be found.
-->
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="InkCanvasForClassPPTVsto_TemporaryKey.pfx" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
</Compile>
<Compile Include="ThisAddIn.cs">
<SubType>Code</SubType>
</Compile>
<None Include="ThisAddIn.Designer.xml">
<DependentUpon>ThisAddIn.cs</DependentUpon>
</None>
<Compile Include="ThisAddIn.Designer.cs">
<DependentUpon>ThisAddIn.Designer.xml</DependentUpon>
</Compile>
<AppDesigner Include="Properties\" />
</ItemGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<PropertyGroup>
<SignManifests>true</SignManifests>
</PropertyGroup>
<PropertyGroup>
<ManifestKeyFile>InkCanvasForClassPPTVsto_TemporaryKey.pfx</ManifestKeyFile>
</PropertyGroup>
<PropertyGroup>
<ManifestCertificateThumbprint>E0DCEEAE8C0D178489A9D826E0280507E45B0283</ManifestCertificateThumbprint>
</PropertyGroup>
<!-- Include the build rules for a C# project. -->
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- Include additional build rules for an Office application add-in. -->
<Import Project="$(VSToolsPath)\OfficeTools\Microsoft.VisualStudio.Tools.Office.targets" Condition="'$(VSToolsPath)' != ''" />
<!-- This section defines VSTO properties that describe the host-changeable project properties. -->
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{BAA0C2D2-18E2-41B9-852F-F413020CAA33}">
<ProjectProperties HostName="PowerPoint" HostPackage="{29A7B9D7-A7F1-4328-8EF0-6B2D1A56B2C1}" OfficeVersion="15.0" VstxVersion="4.0" ApplicationType="PowerPoint" Language="cs" TemplatesPath="" DebugInfoExeName="#Software\Microsoft\Office\16.0\PowerPoint\InstallRoot\Path#powerpnt.exe" AddItemTemplatesGuid="{51063C3A-E220-4D12-8922-BDA915ACD783}" />
<Host Name="PowerPoint" GeneratedCodeNamespace="InkCanvasForClassPPTVsto" IconIndex="0">
<HostItem Name="ThisAddIn" Code="ThisAddIn.cs" CanonicalName="AddIn" CanActivate="false" IconIndex="1" Blueprint="ThisAddIn.Designer.xml" GeneratedCode="ThisAddIn.Designer.cs" />
</Host>
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
</Project>

View File

@ -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")]

View File

@ -0,0 +1,62 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 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.
// </auto-generated>
//------------------------------------------------------------------------------
namespace InkCanvasForClassPPTVsto.Properties {
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// 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() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[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;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 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.
// </auto-generated>
//------------------------------------------------------------------------------
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;
}
}
}
}

View File

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@ -0,0 +1,231 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 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.
// </auto-generated>
//------------------------------------------------------------------------------
#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<Microsoft.Office.Interop.PowerPoint.Application>(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) {
}
}
}

View File

@ -0,0 +1,4 @@
<hostitem:hostItem hostitem:baseType="Microsoft.Office.Tools.AddInBase" hostitem:namespace="InkCanvasForClassPPTVsto" hostitem:className="ThisAddIn" hostitem:identifier="ThisAddIn" hostitem:primaryCookie="AddIn" hostitem:master="true" hostitem:factoryType="Microsoft.Office.Tools.Factory" hostitem:startupIndex="0" xmlns:hostitem="http://schemas.microsoft.com/2004/VisualStudio/Tools/Applications/HostItem.xsd">
<hostitem:hostObject hostitem:name="Application" hostitem:identifier="Application" hostitem:type="Microsoft.Office.Interop.PowerPoint.Application" hostitem:cookie="Application" hostitem:modifier="Internal" />
<hostitem:hostControl hostitem:name="CustomTaskPanes" hostitem:identifier="CustomTaskPanes" hostitem:type="Microsoft.Office.Tools.CustomTaskPaneCollection" hostitem:primaryCookie="CustomTaskPanes" hostitem:modifier="Internal" />
</hostitem:hostItem>

View File

@ -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
/// <summary>
/// 设计器支持所需的方法 - 不要修改
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
#endregion
}
}

View File

@ -7,6 +7,7 @@
<ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Jint" Version="3.1.4" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
<PackageReference Include="System.Runtime" Version="4.3.1" />

View File

@ -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<PerfectFreehandJint.StylusPointLite>();
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");
}
}
}

View File

@ -14,6 +14,42 @@ namespace InkCanvasForClassX.Libraries
/// </summary>
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();
}
/// <summary>
/// Get an array of points as objects with an adjusted point, pressure, vector, distance, and runningLength.
/// </summary>
@ -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;
/// <summary>
/// Get an array of points (as `[x, y]`) representing the outline of a stroke.
/// </summary>
/// <param name="points">An array of StrokePoints as returned from `getStrokePoints`.</param>
/// <param name="options">An object with options.</param>
/// <returns></returns>
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<double,double> 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<double, double> taperStartEase = strokeOptions_Start != null
? strokeOptions_Start.Easing
: (s) => s * (2 - s);
var capEnd = strokeOptions_End != null ? strokeOptions_End.Cap : true;
Func<double, double> 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<Vector>();
var rightPts = new List<Vector>();
// 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<StrokePoint>(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<StrokePoint>(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<Vector>();
var endCap = new List<Vector>();
/*
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<Vector>();
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
/// <summary>
/// Whether to apply a cap at the start/end of the line.
/// </summary>
public bool? Cap { get; set; }
public bool Cap { get; set; }
/// <summary>
/// The taper value at the start/end of the line.
/// </summary>
public double? Taper { get; set; }
public double Taper { get; set; }
public bool IsTaper { get; set; }
/// <summary>
/// An easing function to apply to the taper.

View File

@ -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<double, double> 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<double, double> 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<o.length;t++){const n=i&&t===d?o[t].slice(0,2):lrp(a.point,o[t],s);if(isEqual(a.point,n))continue;const e=dist(n,a.point);if(p+=e,t<d&&!l){if(p<u)continue;l=!0}a={point:n,pressure:o[t][2]>=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;n<t.length;n++){let{pressure:r}=t[n];const{point:o,vector:c,distance:l,runningLength:p}=t[n];if(n<t.length-1&&f-p<3)continue;if(u){if(i){const t=min(1,l/e),n=min(1,1-t);r=min(1,_+t*RATE_OF_PRESSURE_CHANGE*(n-_))}A=getStrokeRadius(e,u,r,s)}else A=e/2;void 0===I&&(I=A);const d=p<g?a(p/g):1,D=f-p<m?h((f-p)/m):1;A=Math.max(.01,A*Math.min(d,D));const X=(n<t.length-1?t[n+1]:t[n]).vector,y=n<t.length-1?dpr(c,X):1,O=null!==y&&y<0;if(dpr(c,S)<0&&!k||O){const t=mul(per(S),A);for(let n=1/13,e=0;e<=1;e+=n)M=rotAround(sub(o,t),o,FIXED_PI*e),P.push(M),F=rotAround(add(o,t),o,FIXED_PI*-e),v.push(F);b=M,R=F,O&&(k=!0);continue}if(k=!1,n===t.length-1){const t=mul(per(c),A);P.push(sub(o,t)),v.push(add(o,t));continue}const x=mul(per(lrp(X,c,y)),A);M=sub(o,x),(n<=1||dist2(b,M)>E)&&(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<i;t++)r=e[t],a=e[t+1],F+=`${average(r[0],a[0]).toFixed(2)},${average(r[1],a[1]).toFixed(2)} `;return t&&(F+=\"Z\"),F}");
// getSvgPathStroke
JintEngine.Execute("function getSvgPathStroke(points,options,closed=true){return getSvgPathFromStroke(getStroke(points,options),closed)}");
}
public JsArray GetStroke(StylusPointLite[] points, StrokeOptions options ) {
return (JsArray)JintEngine.Invoke("getStrokePoints", points, options);
}
public string GetSVGPathStroke(StylusPointLite[] points, StrokeOptions options, bool closed = true) {
return ((JsString)JintEngine.Invoke("getSvgPathStroke", points, options, true)).ToString();
}
public Geometry GetGeometryStroke(StylusPointLite[] points, StrokeOptions options, bool closed = true) {
return Geometry.Parse("F1 "+((JsString)JintEngine.Invoke("getSvgPathStroke", points, options, true)).ToString());
}
}
}

View File

@ -154,21 +154,11 @@ namespace InkCanvasForClassX.Libraries
}
/// <summary>
/// 將該向量點乘另一個向量
/// 提供兩個<c>Vector</c>,返回兩個<c>Vector</c>點乘後的数值
/// </summary>
public Vector Dot(Vector vec)
public static double DotVectors(Vector vec1, Vector vec2)
{
_x = _x * vec.X;
_y = _y * vec.Y;
return this;
}
/// <summary>
/// 提供兩個<c>Vector</c>,返回兩個<c>Vector</c>點乘後的<c>Vector</c>
/// </summary>
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;
}
/// <summary>

View File

@ -10,5 +10,9 @@
<Grid>
<libraries:InkProjector Width="600" Height="600" x:Name="InkP" Margin="0,0,0,600"/>
<InkCanvas Height="600" Width="600" Name="InkC" Margin="0,600,0,0" Background="Wheat"></InkCanvas>
<StackPanel>
<Button Click="ButtonBase1_OnClick">Change to None</Button>
<Button Click="ButtonBase2_OnClick">Change to Pen</Button>
</StackPanel>
</Grid>
</Window>

View File

@ -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
/// </summary>
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<PerfectFreehandJint.StylusPointLite>();
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;
}
}
}

17
PeroInstaller/App.xaml Normal file
View File

@ -0,0 +1,17 @@
<Application x:Class="PeroInstaller.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
xmlns:local="clr-namespace:PeroInstaller"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ui:ThemeResources/>
<ui:XamlControlsResources/>
<ResourceDictionary Source="InstallerConfig.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

13
PeroInstaller/App.xaml.cs Normal file
View File

@ -0,0 +1,13 @@
using System.Configuration;
using System.Data;
using System.Windows;
namespace PeroInstaller
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}

View File

@ -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)
)]

View File

@ -0,0 +1,9 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=System.Runtime">
<system:String x:Key="InstallerWindowTitle">InkCanvasForClass 安装向导</system:String>
<system:String x:Key="ProductName">InkCanvasForClass</system:String>
<system:String x:Key="ProductSlogan">开源的简单易用小巧强大的屏幕批注软件</system:String>
<system:String x:Key="ProductBundleVersion">20240710V1P1</system:String>
<BitmapImage x:Key="ProductIcon" UriSource="pack://application:,,,/resources/icc.png"/>
</ResourceDictionary>

View File

@ -0,0 +1,118 @@
<Window x:Class="PeroInstaller.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:PeroInstaller"
xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
mc:Ignorable="d"
ui:ThemeManager.RequestedTheme="Light"
ResizeMode="NoResize"
Title="{StaticResource InstallerWindowTitle}" Height="600" Width="400">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.5*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<ui:SimpleStackPanel Grid.Row="0" Orientation="Vertical" Margin="8">
<Image Source="{StaticResource ProductIcon}" Width="64" Height="64" Margin="0,6,0,0"/>
<TextBlock FontSize="22" FontWeight="Bold" TextAlignment="Center" Margin="0,4,0,0" Text="{StaticResource ProductName}"/>
<TextBlock FontSize="14" TextAlignment="Center" Opacity="0.6" Text="{StaticResource ProductSlogan}"/>
<Line
X1="0" Y1="0"
X2="250" Y2="0"
Stroke="#a1a1aa"
StrokeThickness="1"
Margin="0,16,0,6"
HorizontalAlignment="Center"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"/>
<TextBlock FontSize="10" TextAlignment="Center" Opacity="0.6">基于PeroInstaller包装打包版本<Run Text="{StaticResource ProductBundleVersion}"></Run></TextBlock>
</ui:SimpleStackPanel>
<Grid Grid.Row="1">
<TabControl ui:TabControlHelper.IsAddTabButtonVisible="False">
<TabItem Name="InstallTab" Width="78" MinWidth="0" ui:TabItemHelper.Icon="{x:Null}">
<TabItem.Header>
<ui:SimpleStackPanel HorizontalAlignment="Center" Orientation="Horizontal" Spacing="3" Margin="-5,0,0,0">
<Image Width="20" Height="20">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V24 H24 V0 H0 Z">
<GeometryDrawing Brush="#FF000000" Geometry="F0 M24,24z M0,0z M13,4C13,3.44772 12.5523,3 12,3 11.4477,3 11,3.44772 11,4L11,13.5858 7.70711,10.2929C7.31658,9.90237 6.68342,9.90237 6.29289,10.2929 5.90237,10.6834 5.90237,11.3166 6.29289,11.7071L11.2922,16.7064C11.2946,16.7088 11.297,16.7112 11.2995,16.7136 11.3938,16.8063 11.502,16.8764 11.6172,16.9241 11.7343,16.9727 11.8625,16.9996 11.997,17 11.998,17 11.999,17 12,17 12.001,17 12.002,17 12.003,17 12.2746,16.9992 12.5208,16.8901 12.7005,16.7136 12.703,16.7112 12.7054,16.7088 12.7078,16.7064L17.7071,11.7071C18.0976,11.3166 18.0976,10.6834 17.7071,10.2929 17.3166,9.90237 16.6834,9.90237 16.2929,10.2929L13,13.5858 13,4z M4,16C4.55228,16,5,16.4477,5,17L5,19C5,19.2652 5.10536,19.5196 5.29289,19.7071 5.48043,19.8946 5.73478,20 6,20L18,20C18.2652,20 18.5196,19.8946 18.7071,19.7071 18.8946,19.5196 19,19.2652 19,19L19,17C19,16.4477 19.4477,16 20,16 20.5523,16 21,16.4477 21,17L21,19C21,19.7957 20.6839,20.5587 20.1213,21.1213 19.5587,21.6839 18.7957,22 18,22L6,22C5.20435,22 4.44129,21.6839 3.87868,21.1213 3.31607,20.5587 3,19.7957 3,19L3,17C3,16.4477,3.44772,16,4,16z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
<TextBlock VerticalAlignment="Center">安装</TextBlock>
</ui:SimpleStackPanel>
</TabItem.Header>
<TextBlock Text="Content 1" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</TabItem>
<TabItem Name="RemoveTab" Width="78" MinWidth="0" ui:TabItemHelper.Icon="{x:Null}">
<TabItem.Header>
<ui:SimpleStackPanel HorizontalAlignment="Center" Orientation="Horizontal" Spacing="3" Margin="-5,0,0,0">
<Image Width="20" Height="20">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V24 H24 V0 H0 Z">
<GeometryDrawing Brush="#FF000000" Geometry="F0 M24,24z M0,0z M10,2C9.46957,2 8.96086,2.21071 8.58579,2.58579 8.21071,2.96086 8,3.46957 8,4L8,6 4,6C3.44772,6 3,6.44772 3,7 3,7.55228 3.44772,8 4,8L4.07992,8 5.0004,19.0458C5.01228,19.8249 5.32693,20.5696 5.87874,21.1214 6.44134,21.684 7.20441,22.0001 8.00006,22.0001L16.0001,22.0001C16.7957,22.0001 17.5588,21.684 18.1214,21.1214 18.6732,20.5696 18.9878,19.8249 18.9997,19.0458L19.9202,8 20,8C20.5523,8 21,7.55228 21,7 21,6.44772 20.5523,6 20,6L16,6 16,4C16,3.46957 15.7893,2.96086 15.4142,2.58579 15.0391,2.21071 14.5304,2 14,2L10,2z M14,6L14,4 10,4 10,6 14,6z M9,8L6.08685,8 6.9966,18.917C6.9989,18.9446 7.00006,18.9723 7.00006,19.0001 7.00006,19.2653 7.10541,19.5196 7.29295,19.7072 7.48049,19.8947 7.73484,20.0001 8.00006,20.0001L16.0001,20.0001C16.2653,20.0001 16.5196,19.8947 16.7072,19.7072 16.8947,19.5196 17.0001,19.2653 17.0001,19.0001 17.0001,18.9723 17.0012,18.9446 17.0035,18.917L17.9133,8 15,8 9,8z M10,10C10.5523,10,11,10.4477,11,11L11,17C11,17.5523 10.5523,18 10,18 9.44772,18 9,17.5523 9,17L9,11C9,10.4477,9.44772,10,10,10z M15,11C15,10.4477 14.5523,10 14,10 13.4477,10 13,10.4477 13,11L13,17C13,17.5523 13.4477,18 14,18 14.5523,18 15,17.5523 15,17L15,11z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
<TextBlock VerticalAlignment="Center">卸载</TextBlock>
</ui:SimpleStackPanel>
</TabItem.Header>
<TextBlock Text="Content 2" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</TabItem>
<TabItem Name="UpdateTab" Width="78" MinWidth="0" ui:TabItemHelper.Icon="{x:Null}">
<TabItem.Header>
<ui:SimpleStackPanel HorizontalAlignment="Center" Orientation="Horizontal" Spacing="3" Margin="-5,0,0,0">
<Image Width="20" Height="20">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V24 H24 V0 H0 Z">
<GeometryDrawing Brush="#FF000000" Geometry="F0 M24,24z M0,0z M13.1418,3.08997C11.1621,2.83453 9.15344,3.23706 7.42509,4.23555 6.49773,4.7713 5.67868,5.46268 5.00012,6.27306L5.00012,5.0002C5.00012,4.44791 4.55241,4.0002 4.00012,4.0002 3.44784,4.0002 3.00012,4.44791 3.00012,5.0002L3.00012,9.0002C3.00012,9.55248,3.44784,10.0002,4.00012,10.0002L4.47695,10.0002C4.49216,10.0005,4.50734,10.0005,4.52249,10.0002L8.00012,10.0002C8.55241,10.0002 9.00012,9.55248 9.00012,9.0002 9.00012,8.44791 8.55241,8.0002 8.00012,8.0002L6.19127,8.0002C6.77809,7.17511 7.53828,6.47992 8.42556,5.96733 9.77405,5.18829 11.3413,4.87423 12.8858,5.07353 14.4304,5.27282 15.8665,5.97442 16.9731,7.07024 18.0797,8.16607 18.7953,9.59532 19.0096,11.1378 19.0857,11.6849 19.5907,12.0667 20.1378,11.9907 20.6848,11.9147 21.0666,11.4096 20.9906,10.8625 20.7159,8.88551 19.7987,7.05365 18.3804,5.64914 16.9621,4.24464 15.1214,3.34541 13.1418,3.08997z M4.9906,12.8624C4.91458,12.3153 4.4095,11.9335 3.86247,12.0095 3.31545,12.0855 2.93362,12.5906 3.00964,13.1376 3.28439,15.1147 4.20155,16.9466 5.61984,18.3511 7.03812,19.7556 8.87885,20.6548 10.8585,20.9102 12.8381,21.1657 14.8468,20.7631 16.5752,19.7646 17.5025,19.2289 18.3216,18.5375 19.0001,17.7271L19.0001,19C19.0001,19.5523 19.4478,20 20.0001,20 20.5524,20 21.0001,19.5523 21.0001,19L21.0001,15C21.0001,14.4477,20.5524,14,20.0001,14L19.5233,14C19.5081,13.9997,19.4929,13.9997,19.4778,14L16.0001,14C15.4478,14 15.0001,14.4477 15.0001,15 15.0001,15.5523 15.4478,16 16.0001,16L17.809,16C17.2222,16.8251 16.462,17.5203 15.5747,18.0329 14.2262,18.8119 12.659,19.126 11.1144,18.9267 9.56988,18.7274 8.1337,18.0258 7.02713,16.93 5.92056,15.8341 5.20497,14.4049 4.9906,12.8624z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
<TextBlock VerticalAlignment="Center">更新</TextBlock>
</ui:SimpleStackPanel>
</TabItem.Header>
<TextBlock Text="Content 3" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</TabItem>
<TabItem Name="ModifyTab" Width="78" MinWidth="0" ui:TabItemHelper.Icon="{x:Null}">
<TabItem.Header>
<ui:SimpleStackPanel HorizontalAlignment="Center" Orientation="Horizontal" Spacing="3" Margin="-5,0,0,0">
<Image Width="20" Height="20">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V24 H24 V0 H0 Z">
<GeometryDrawing Brush="#FF000000" Geometry="F0 M24,24z M0,0z M8.37853,3.96432L10.707,6.29275C10.8945,6.48028,10.9999,6.73464,10.9999,6.99986L10.9999,9.99986C10.9999,10.5521,10.5521,10.9999,9.99986,10.9999L6.99986,10.9999C6.73464,10.9999,6.48028,10.8945,6.29275,10.707L3.96432,8.37853C3.89111,8.89104 3.89749,9.41483 3.98608,9.93115 4.16092,10.9502 4.64741,11.89 5.37853,12.6212 6.10966,13.3523 7.04948,13.8388 8.06856,14.0136 9.08764,14.1885 10.1359,14.0431 11.0689,13.5975 11.4513,13.4149 11.9073,13.4931 12.207,13.7927L18.207,19.7927C18.4172,20.003 18.7025,20.1212 18.9999,20.1212 19.2972,20.1212 19.5825,20.003 19.7927,19.7927 20.003,19.5825 20.1212,19.2972 20.1212,18.9999 20.1212,18.7025 20.003,18.4172 19.7927,18.207L13.7927,12.207C13.4931,11.9073 13.4149,11.4513 13.5975,11.0689 14.0431,10.1359 14.1885,9.08764 14.0136,8.06856 13.8388,7.04948 13.3523,6.10966 12.6212,5.37853 11.89,4.64741 10.9502,4.16092 9.93115,3.98608 9.41483,3.89749 8.89104,3.89111 8.37853,3.96432z M6.06889,2.59749C7.37513,1.97364 8.84264,1.77009 10.2694,2.01488 11.6961,2.25966 13.0118,2.94074 14.0354,3.96432 15.059,4.9879 15.74,6.30364 15.9848,7.73035 16.1888,8.91918 16.0815,10.1363 15.6791,11.2649L21.207,16.7927C21.7923,17.3781 22.1212,18.172 22.1212,18.9999 22.1212,19.8277 21.7923,20.6216 21.207,21.207 20.6216,21.7923 19.8277,22.1212 18.9999,22.1212 18.172,22.1212 17.3781,21.7923 16.7927,21.207L11.2649,15.6791C10.1363,16.0815 8.91918,16.1888 7.73035,15.9848 6.30364,15.74 4.9879,15.059 3.96432,14.0354 2.94074,13.0118 2.25966,11.6961 2.01488,10.2694 1.77009,8.84264 1.97364,7.37513 2.59749,6.06889 2.73739,5.77595 3.01079,5.56915 3.33075,5.51426 3.65071,5.45936 3.97741,5.5632 4.20696,5.79275L7.41407,8.99986 8.99986,8.99986 8.99986,7.41407 5.79275,4.20696C5.5632,3.97741 5.45936,3.65071 5.51426,3.33075 5.56915,3.01079 5.77595,2.73739 6.06889,2.59749z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
<TextBlock VerticalAlignment="Center">修改</TextBlock>
</ui:SimpleStackPanel>
</TabItem.Header>
<TextBlock Text="Content 4" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</TabItem>
</TabControl>
</Grid>
</Grid>
</Window>

View File

@ -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
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows10.0.19041.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
<SupportedOSPlatformVersion>7.0</SupportedOSPlatformVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="iNKORE.UI.WPF" Version="1.2.7.1" />
<PackageReference Include="iNKORE.UI.WPF.Modern" Version="0.9.27" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows10.0.18362.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="iNKORE.UI.WPF" Version="1.2.7.1" />
<PackageReference Include="iNKORE.UI.WPF.Modern" Version="0.9.27" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows10.0.18362.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
<SupportedOSPlatformVersion>7.0</SupportedOSPlatformVersion>
</PropertyGroup>
<ItemGroup>
<None Remove="resources\icc.png" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="iNKORE.UI.WPF" Version="1.2.7.1" />
<PackageReference Include="iNKORE.UI.WPF.Modern" Version="0.9.27" />
</ItemGroup>
<ItemGroup>
<Resource Include="resources\icc.png" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<_LastSelectedProfileId>D:\vs\ica\PeroInstaller\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId>
</PropertyGroup>
<ItemGroup>
<ApplicationDefinition Update="App.xaml">
<SubType>Designer</SubType>
</ApplicationDefinition>
</ItemGroup>
<ItemGroup>
<Page Update="InstallerConfig.xaml">
<SubType>Designer</SubType>
</Page>
<Page Update="MainWindow.xaml">
<SubType>Designer</SubType>
</Page>
</ItemGroup>
</Project>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>bin\dist\</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<_TargetId>Folder</_TargetId>
<TargetFramework>net6.0-windows</TargetFramework>
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>true</PublishSingleFile>
<PublishReadyToRun>true</PublishReadyToRun>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
</Project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB