add:截图功能

This commit is contained in:
2025-07-30 19:56:22 +08:00
parent 9f9775e585
commit 00554e066b
5 changed files with 522 additions and 5 deletions
+92 -1
View File
@@ -60,6 +60,7 @@
<RoutedUICommand x:Key="HotKey_ChangeToPen4" Text=" " />
<RoutedUICommand x:Key="HotKey_ChangeToPen5" Text=" " />
<RoutedUICommand x:Key="HotKey_DrawLine" Text=" " />
<RoutedUICommand x:Key="HotKey_Paste" Text=" " />
<RoutedUICommand x:Key="NothingWillHappened" Text=" " />
<!-- Navigation Button Style -->
@@ -148,6 +149,7 @@
<KeyBinding Modifiers="Alt" Key="D4" Command="{StaticResource HotKey_ChangeToPen4}" />
<KeyBinding Modifiers="Alt" Key="D5" Command="{StaticResource HotKey_ChangeToPen5}" />
<KeyBinding Modifiers="Alt" Key="L" Command="{StaticResource HotKey_DrawLine}" />
<KeyBinding Modifiers="Control" Key="V" Command="{StaticResource HotKey_Paste}" />
<KeyBinding Modifiers="Alt" Key="F4" Command="{StaticResource NothingWillHappened}" />
</Window.InputBindings>
<!--命令执行方法绑定-->
@@ -175,6 +177,8 @@
Executed="KeyHide" />
<CommandBinding CanExecute="CommandBinding_CanExecute" Command="{StaticResource HotKey_DrawLine}"
Executed="KeyDrawLine" />
<CommandBinding CanExecute="CommandBinding_CanExecute" Command="{StaticResource HotKey_Paste}"
Executed="HandleGlobalPaste" />
</Window.CommandBindings>
<Grid x:Name="Main_Grid">
@@ -4916,7 +4920,7 @@
</Border>
</Border>
<Border x:Name="BoardInsertImage" Width="60" Height="50" MouseDown="Border_MouseDown"
MouseUp="InsertImage_MouseUp" BorderThickness="0,1,0,1"
MouseUp="InsertImageOptions_MouseUp" BorderThickness="0,1,0,1"
BorderBrush="#a1a1aa"
Background="#f4f4f5"
Opacity="0.95">
@@ -5244,6 +5248,93 @@
</ui:SimpleStackPanel>
</ui:SimpleStackPanel>
</Border>
<!-- Image Insertion Options Panel -->
<Border ClipToBounds="True" Name="BoardImageOptionsPanel" Visibility="Collapsed"
Margin="-80,-90,-14,33.5"
CornerRadius="5" Background="#fafafa" Opacity="1"
BorderThickness="1"
BorderBrush="#2563eb">
<ui:SimpleStackPanel Margin="0">
<Border BorderBrush="#1e3a8a" BorderThickness="0,0,0,1"
CornerRadius="5,5,0,0" Background="#2563eb"
Padding="8,4">
<ui:SimpleStackPanel Orientation="Horizontal"
HorizontalAlignment="Stretch">
<TextBlock Text="插入图片" Foreground="White"
FontSize="10" FontWeight="Bold"
VerticalAlignment="Center" />
<Image Margin="8,0,0,0"
Source="/Resources/new-icons/close-white.png"
RenderOptions.BitmapScalingMode="HighQuality"
Height="12" Width="12"
MouseDown="Border_MouseDown"
MouseUp="CloseImageOptionsPanel_MouseUp" />
</ui:SimpleStackPanel>
</Border>
<ui:SimpleStackPanel Margin="6,4,6,4" Spacing="2">
<!-- Screenshot Option -->
<Border MouseDown="Border_MouseDown" MouseUp="ImageOptionScreenshot_MouseUp"
Background="Transparent" CornerRadius="3" Padding="6,4">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="Transparent"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#f0f9ff"/>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<ui:SimpleStackPanel Orientation="Horizontal" Spacing="6">
<Image Height="16" Width="16">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V24 H24 V0 H0 Z">
<GeometryDrawing Brush="#2563eb"
Geometry="F0 M24,24z M0,0z M9,3C8.46957,3 7.96086,3.21071 7.58579,3.58579 7.21071,3.96086 7,4.46957 7,5 7,5.26522 6.89464,5.51957 6.70711,5.70711 6.51957,5.89464 6.26522,6 6,6L5,6C4.20435,6 3.44129,6.31607 2.87868,6.87868 2.31607,7.44129 2,8.20435 2,9L2,18C2,18.7956 2.31607,19.5587 2.87868,20.1213 3.44129,20.6839 4.20435,21 5,21L19,21C19.7957,21 20.5587,20.6839 21.1213,20.1213 21.6839,19.5587 22,18.7957 22,18L22,9C22,8.20435 21.6839,7.44129 21.1213,6.87868 20.5587,6.31607 19.7957,6 19,6L18,6C17.7348,6 17.4804,5.89464 17.2929,5.70711 17.1054,5.51957 17,5.26522 17,5 17,4.46957 16.7893,3.96086 16.4142,3.58579 16.0391,3.21071 15.5304,3 15,3L9,3z M9,5L15,5C15,5.79565 15.3161,6.55871 15.8787,7.12132 16.4413,7.68393 17.2044,8 18,8L19,8C19.2652,8 19.5196,8.10536 19.7071,8.29289 19.8946,8.48043 20,8.73478 20,9L20,18C20,18.2652 19.8946,18.5196 19.7071,18.7071 19.5196,18.8946 19.2652,19 19,19L5,19C4.73478,19 4.48043,18.8946 4.29289,18.7071 4.10536,18.5196 4,18.2652 4,18L4,9C4,8.73478 4.10536,8.48043 4.29289,8.29289 4.48043,8.10536 4.73478,8 5,8L6,8C6.79565,8 7.55871,7.68393 8.12132,7.12132 8.68393,6.55871 9,5.79565 9,5z M12,9C10.9391,9 9.92172,9.42143 9.17157,10.1716 8.42143,10.9217 8,11.9391 8,13 8,14.0609 8.42143,15.0783 9.17157,15.8284 9.92172,16.5786 10.9391,17 12,17 13.0609,17 14.0783,16.5786 14.8284,15.8284 15.5786,15.0783 16,14.0609 16,13 16,11.9391 15.5786,10.9217 14.8284,10.1716 14.0783,9.42143 13.0609,9 12,9z M10.5858,11.5858C10.9609,11.2107 11.4696,11 12,11 12.5304,11 13.0391,11.2107 13.4142,11.5858 13.7893,11.9609 14,12.4696 14,13 14,13.5304 13.7893,14.0391 13.4142,14.4142 13.0391,14.7893 12.5304,15 12,15 11.4696,15 10.9609,14.7893 10.5858,14.4142 10.2107,14.0391 10,13.5304 10,13 10,12.4696 10.2107,11.9609 10.5858,11.5858z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
<TextBlock Text="截图" FontSize="11" FontWeight="SemiBold"
Foreground="#1f2937" VerticalAlignment="Center"/>
</ui:SimpleStackPanel>
</Border>
<!-- Select Image Option -->
<Border MouseDown="Border_MouseDown" MouseUp="ImageOptionSelectFile_MouseUp"
Background="Transparent" CornerRadius="3" Padding="6,4">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="Transparent"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#f0f9ff"/>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<ui:SimpleStackPanel Orientation="Horizontal" Spacing="6">
<Image Height="16" Width="16">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V24 H24 V0 H0 Z">
<GeometryDrawing Brush="#2563eb"
Geometry="F1 M24,24z M0,0z M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2-0.9 2-2V5C21,3.9 20.1,3 19,3zM19,19H5V5h14V19z M17,7c-1.1,0-2,0.9-2,2s0.9,2 2,2 2-0.9 2-2S18.1,7 17,7zM7,17l2.5-3.01 1.96,2.36 2.54-3.21L17,17H7z"/>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
<TextBlock Text="选择图片" FontSize="11" FontWeight="SemiBold"
Foreground="#1f2937" VerticalAlignment="Center"/>
</ui:SimpleStackPanel>
</Border>
</ui:SimpleStackPanel>
</ui:SimpleStackPanel>
</Border>
</Grid>
</Border>
<Border Width="60" Height="50" MouseDown="Border_MouseDown"
+8
View File
@@ -127,6 +127,7 @@ namespace Ink_Canvas {
// 注册输入事件
inkCanvas.PreviewMouseDown += inkCanvas_PreviewMouseDown;
inkCanvas.StylusDown += inkCanvas_StylusDown;
inkCanvas.MouseRightButtonUp += InkCanvas_MouseRightButtonUp;
// 初始化第一页Canvas
var firstCanvas = new System.Windows.Controls.Canvas();
@@ -427,6 +428,9 @@ namespace Ink_Canvas {
// 初始化UIElement选择系统
InitializeUIElementSelection();
// 初始化剪贴板监控
InitializeClipboardMonitoring();
}
private void SystemEventsOnDisplaySettingsChanged(object sender, EventArgs e) {
@@ -512,6 +516,10 @@ namespace Ink_Canvas {
// 释放PPT管理器资源
DisposePPTManagers();
// 清理剪贴板监控
CleanupClipboardMonitoring();
ClipboardNotification.Stop();
LogHelper.WriteLogToFile("Ink Canvas closed", LogHelper.LogType.Event);
// 检查是否有待安装的更新
@@ -0,0 +1,267 @@
using System;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using Ink_Canvas.Helpers;
namespace Ink_Canvas
{
public partial class MainWindow : Window
{
private bool isClipboardMonitoringEnabled = false;
private BitmapSource lastClipboardImage = null;
// 初始化剪贴板监控
private void InitializeClipboardMonitoring()
{
try
{
// 监听剪贴板变化
ClipboardNotification.ClipboardUpdate += OnClipboardUpdate;
isClipboardMonitoringEnabled = true;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"初始化剪贴板监控失败: {ex.Message}", LogHelper.LogType.Error);
}
}
// 剪贴板内容变化事件处理
private void OnClipboardUpdate()
{
try
{
if (Clipboard.ContainsImage())
{
var clipboardImage = Clipboard.GetImage();
if (clipboardImage != null && clipboardImage != lastClipboardImage)
{
lastClipboardImage = clipboardImage;
// 在白板模式下显示粘贴提示
if (currentMode == 1) // 白板模式
{
ShowPasteNotification();
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理剪贴板更新失败: {ex.Message}", LogHelper.LogType.Error);
}
}
// 显示粘贴提示
private void ShowPasteNotification()
{
try
{
Dispatcher.Invoke(() =>
{
ShowNotification("检测到剪贴板中有图片,右键点击白板可粘贴");
});
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"显示粘贴提示失败: {ex.Message}", LogHelper.LogType.Error);
}
}
// 处理右键菜单显示
private void ShowPasteContextMenu(Point position)
{
try
{
if (!Clipboard.ContainsImage()) return;
// 创建右键菜单
var contextMenu = new ContextMenu();
var pasteMenuItem = new MenuItem
{
Header = "粘贴图片"
};
pasteMenuItem.Click += async (s, e) => await PasteImageFromClipboard(position);
contextMenu.Items.Add(pasteMenuItem);
// 显示菜单
contextMenu.IsOpen = true;
contextMenu.PlacementTarget = inkCanvas;
contextMenu.Placement = System.Windows.Controls.Primitives.PlacementMode.MousePoint;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"显示粘贴菜单失败: {ex.Message}", LogHelper.LogType.Error);
}
}
// 从剪贴板粘贴图片
private async Task PasteImageFromClipboard(Point? position = null)
{
try
{
if (!Clipboard.ContainsImage())
{
ShowNotification("剪贴板中没有图片");
return;
}
var clipboardImage = Clipboard.GetImage();
if (clipboardImage == null)
{
ShowNotification("无法获取剪贴板图片");
return;
}
// 创建Image控件
var image = new Image
{
Source = clipboardImage,
Width = clipboardImage.PixelWidth,
Height = clipboardImage.PixelHeight,
Stretch = System.Windows.Media.Stretch.Fill
};
// 生成唯一名称
string timestamp = "img_clipboard_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
image.Name = timestamp;
// 设置位置
if (position.HasValue)
{
// 在指定位置居中显示
InkCanvas.SetLeft(image, position.Value.X - image.Width / 2);
InkCanvas.SetTop(image, position.Value.Y - image.Height / 2);
}
else
{
// 使用与文件选择相同的居中和缩放逻辑
CenterAndScaleElement(image);
}
// 添加到画布
inkCanvas.Children.Add(image);
// 添加鼠标事件处理
image.MouseDown += UIElement_MouseDown;
image.IsManipulationEnabled = true;
// 提交到历史记录
timeMachine.CommitElementInsertHistory(image);
ShowNotification("图片已从剪贴板粘贴");
}
catch (Exception ex)
{
ShowNotification($"粘贴图片失败: {ex.Message}");
LogHelper.WriteLogToFile($"粘贴图片失败: {ex.Message}", LogHelper.LogType.Error);
}
}
// 处理白板右键事件
private void InkCanvas_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
try
{
// 只在白板模式下处理
if (currentMode != 1) return;
// 检查是否有图片在剪贴板中
if (Clipboard.ContainsImage())
{
var position = e.GetPosition(inkCanvas);
ShowPasteContextMenu(position);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理右键事件失败: {ex.Message}", LogHelper.LogType.Error);
}
}
// 处理全局粘贴快捷键
private async void HandleGlobalPaste(object sender, ExecutedRoutedEventArgs e)
{
try
{
// 只在白板模式下处理
if (currentMode != 1) return;
if (Clipboard.ContainsImage())
{
await PasteImageFromClipboard();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理全局粘贴失败: {ex.Message}", LogHelper.LogType.Error);
}
}
// 清理剪贴板监控
private void CleanupClipboardMonitoring()
{
try
{
if (isClipboardMonitoringEnabled)
{
ClipboardNotification.ClipboardUpdate -= OnClipboardUpdate;
isClipboardMonitoringEnabled = false;
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清理剪贴板监控失败: {ex.Message}", LogHelper.LogType.Error);
}
}
}
// 剪贴板通知类
public static class ClipboardNotification
{
public static event Action ClipboardUpdate;
private static System.Windows.Forms.Timer clipboardTimer;
private static string lastClipboardText = "";
private static bool lastHadImage = false;
static ClipboardNotification()
{
clipboardTimer = new System.Windows.Forms.Timer();
clipboardTimer.Interval = 500; // 每500ms检查一次
clipboardTimer.Tick += CheckClipboard;
clipboardTimer.Start();
}
private static void CheckClipboard(object sender, EventArgs e)
{
try
{
bool currentHasImage = Clipboard.ContainsImage();
string currentText = Clipboard.ContainsText() ? Clipboard.GetText() : "";
if (currentHasImage != lastHadImage || currentText != lastClipboardText)
{
lastHadImage = currentHasImage;
lastClipboardText = currentText;
ClipboardUpdate?.Invoke();
}
}
catch
{
// 忽略剪贴板访问错误
}
}
public static void Stop()
{
clipboardTimer?.Stop();
clipboardTimer?.Dispose();
}
}
}
@@ -208,6 +208,7 @@ namespace Ink_Canvas {
BorderSettings.Visibility = Visibility.Collapsed;
BoardBorderLeftPageListView.Visibility = Visibility.Collapsed;
BoardBorderRightPageListView.Visibility = Visibility.Collapsed;
BoardImageOptionsPanel.Visibility = Visibility.Collapsed;
}
/// <summary>
@@ -279,7 +280,8 @@ namespace Ink_Canvas {
AnimationsHelper.HideWithSlideAndFade(BorderDrawShape);
AnimationsHelper.HideWithSlideAndFade(BoardBorderLeftPageListView);
AnimationsHelper.HideWithSlideAndFade(BoardBorderRightPageListView);
AnimationsHelper.HideWithSlideAndFade(BoardImageOptionsPanel);
// 隐藏背景设置面板
var bgPalette = LogicalTreeHelper.FindLogicalNode(this, "BackgroundPalette") as Border;
if (bgPalette != null)
@@ -2065,6 +2067,71 @@ namespace Ink_Canvas {
#endregion
private void InsertImageOptions_MouseUp(object sender, MouseButtonEventArgs e)
{
// Hide other sub-panels first
HideSubPanelsImmediately();
// Show the image options panel
if (BoardImageOptionsPanel.Visibility == Visibility.Collapsed)
{
AnimationsHelper.ShowWithSlideFromBottomAndFade(BoardImageOptionsPanel);
}
else
{
AnimationsHelper.HideWithSlideAndFade(BoardImageOptionsPanel);
}
}
private void CloseImageOptionsPanel_MouseUp(object sender, MouseButtonEventArgs e)
{
AnimationsHelper.HideWithSlideAndFade(BoardImageOptionsPanel);
}
private async void ImageOptionScreenshot_MouseUp(object sender, MouseButtonEventArgs e)
{
// Hide the options panel
AnimationsHelper.HideWithSlideAndFade(BoardImageOptionsPanel);
// Wait a bit for the panel to hide
await Task.Delay(100);
// Capture screenshot and copy to clipboard
await CaptureScreenshotToClipboard();
}
private async void ImageOptionSelectFile_MouseUp(object sender, MouseButtonEventArgs e)
{
// Hide the options panel
AnimationsHelper.HideWithSlideAndFade(BoardImageOptionsPanel);
// Open file dialog to select image
var dialog = new OpenFileDialog
{
Filter = "图片文件|*.jpg;*.jpeg;*.png;*.bmp;*.gif"
};
if (dialog.ShowDialog() == true)
{
string filePath = dialog.FileName;
Image image = await CreateAndCompressImageAsync(filePath);
if (image != null)
{
string timestamp = "img_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
image.Name = timestamp;
CenterAndScaleElement(image);
inkCanvas.Children.Add(image);
// 添加鼠标事件处理,使图片可以被选择
image.MouseDown += UIElement_MouseDown;
image.IsManipulationEnabled = true;
timeMachine.CommitElementInsertHistory(image);
}
}
}
// Keep the old method for backward compatibility
private async void InsertImage_MouseUp(object sender, MouseButtonEventArgs e)
{
var dialog = new OpenFileDialog
+87 -3
View File
@@ -2,8 +2,12 @@ using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Media.Imaging;
using Ink_Canvas.Helpers;
using Clipboard = System.Windows.Clipboard;
namespace Ink_Canvas {
public partial class MainWindow : Window {
@@ -71,14 +75,94 @@ namespace Ink_Canvas {
private string GetDefaultFolderPath() {
var basePath = Settings.Automation.AutoSavedStrokesLocation;
var screenshotsFolder = Path.Combine(basePath, "Auto Saved - Screenshots");
if (!Directory.Exists(screenshotsFolder)) {
Directory.CreateDirectory(screenshotsFolder);
}
return Path.Combine(
screenshotsFolder,
screenshotsFolder,
$"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.png");
}
// 截图并复制到剪贴板
private async Task CaptureScreenshotToClipboard() {
try {
// 隐藏主窗口以避免截图包含窗口本身
var originalVisibility = this.Visibility;
this.Visibility = Visibility.Hidden;
// 等待窗口隐藏
await Task.Delay(200);
var rc = SystemInformation.VirtualScreen;
using (var bitmap = new Bitmap(rc.Width, rc.Height, PixelFormat.Format32bppArgb))
using (var memoryGraphics = Graphics.FromImage(bitmap)) {
memoryGraphics.CopyFromScreen(rc.X, rc.Y, 0, 0, rc.Size, CopyPixelOperation.SourceCopy);
// 将截图复制到剪贴板
CopyBitmapToClipboard(bitmap);
// 恢复窗口显示
this.Visibility = originalVisibility;
// 等待窗口完全显示后自动粘贴
await Task.Delay(100);
await AutoPasteScreenshot();
}
}
catch (Exception ex) {
ShowNotification($"截图失败: {ex.Message}");
this.Visibility = Visibility.Visible;
}
}
// 自动粘贴截图到画布
private async Task AutoPasteScreenshot() {
try {
// 只在白板模式下自动粘贴
if (currentMode == 1) {
await PasteImageFromClipboard();
ShowNotification("截图已自动插入到画布");
} else {
ShowNotification("截图已复制到剪贴板,可在白板模式下粘贴");
}
}
catch (Exception ex) {
ShowNotification($"自动粘贴截图失败: {ex.Message}");
LogHelper.WriteLogToFile($"自动粘贴截图失败: {ex.Message}", LogHelper.LogType.Error);
}
}
// 将Bitmap复制到剪贴板
private void CopyBitmapToClipboard(Bitmap bitmap) {
try {
// 将System.Drawing.Bitmap转换为WPF BitmapSource
var bitmapSource = ConvertBitmapToBitmapSource(bitmap);
// 复制到剪贴板
Clipboard.SetImage(bitmapSource);
}
catch (Exception ex) {
ShowNotification($"复制到剪贴板失败: {ex.Message}");
}
}
// 将System.Drawing.Bitmap转换为WPF BitmapSource
private BitmapSource ConvertBitmapToBitmapSource(Bitmap bitmap) {
using (var memory = new MemoryStream()) {
bitmap.Save(memory, ImageFormat.Png);
memory.Position = 0;
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
bitmapImage.Freeze();
return bitmapImage;
}
}
}
}