diff --git a/Ink Canvas/App.xaml.cs b/Ink Canvas/App.xaml.cs index 25f5f817..8bcce6b3 100644 --- a/Ink Canvas/App.xaml.cs +++ b/Ink Canvas/App.xaml.cs @@ -484,7 +484,7 @@ namespace Ink_Canvas // 在应用启动时自动释放IACore相关DLL try { - Helpers.IACoreDllExtractor.ExtractIACoreDlls(); + IACoreDllExtractor.ExtractIACoreDlls(); } catch (Exception ex) { @@ -508,7 +508,7 @@ namespace Ink_Canvas } // 检查是否存在更新标记文件 - string updateMarkerFile = Path.Combine(App.RootPath, "update_in_progress.tmp"); + string updateMarkerFile = Path.Combine(RootPath, "update_in_progress.tmp"); bool isUpdateInProgress = false; // 检查是否以更新模式启动 diff --git a/Ink Canvas/Helpers/AutoUpdateHelper.cs b/Ink Canvas/Helpers/AutoUpdateHelper.cs index e24c1df3..1cd7b7d1 100644 --- a/Ink Canvas/Helpers/AutoUpdateHelper.cs +++ b/Ink Canvas/Helpers/AutoUpdateHelper.cs @@ -12,7 +12,6 @@ using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Reflection; -using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; diff --git a/Ink Canvas/Helpers/GlobalHotkeyManager.cs b/Ink Canvas/Helpers/GlobalHotkeyManager.cs index 467adec2..07d62a59 100644 --- a/Ink Canvas/Helpers/GlobalHotkeyManager.cs +++ b/Ink Canvas/Helpers/GlobalHotkeyManager.cs @@ -472,7 +472,7 @@ namespace Ink_Canvas.Helpers { // 通过反射访问主窗口的penType字段 var penTypeField = _mainWindow.GetType().GetField("penType", - System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + BindingFlags.NonPublic | BindingFlags.Instance); if (penTypeField != null) { @@ -480,7 +480,7 @@ namespace Ink_Canvas.Helpers // 调用CheckPenTypeUIState方法更新UI状态 var checkPenTypeMethod = _mainWindow.GetType().GetMethod("CheckPenTypeUIState", - System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + BindingFlags.NonPublic | BindingFlags.Instance); if (checkPenTypeMethod != null) { diff --git a/Ink Canvas/Helpers/InkFadeManager.cs b/Ink Canvas/Helpers/InkFadeManager.cs index 1a1e6b49..1bd3d9c2 100644 --- a/Ink Canvas/Helpers/InkFadeManager.cs +++ b/Ink Canvas/Helpers/InkFadeManager.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Windows; using System.Windows.Media.Animation; using System.Windows.Threading; @@ -107,7 +106,7 @@ namespace Ink_Canvas.Helpers { // 将墨迹添加到 inkCanvas 的父容器中,而不是 inkCanvas.Children // 这样可以避免坐标系统问题 - var parent = _mainWindow.inkCanvas.Parent as System.Windows.Controls.Panel; + var parent = _mainWindow.inkCanvas.Parent as Panel; if (parent != null) { parent.Children.Add(strokeVisual); @@ -154,7 +153,7 @@ namespace Ink_Canvas.Helpers try { // 从父容器中移除墨迹 - var parent = _mainWindow.inkCanvas?.Parent as System.Windows.Controls.Panel; + var parent = _mainWindow.inkCanvas?.Parent as Panel; if (parent != null && parent.Children.Contains(visual)) { parent.Children.Remove(visual); @@ -202,7 +201,7 @@ namespace Ink_Canvas.Helpers { if (_mainWindow.inkCanvas != null) { - var parent = _mainWindow.inkCanvas.Parent as System.Windows.Controls.Panel; + var parent = _mainWindow.inkCanvas.Parent as Panel; foreach (var visual in _strokeVisuals.Values) { if (parent != null && parent.Children.Contains(visual)) @@ -454,7 +453,7 @@ namespace Ink_Canvas.Helpers originalVisual.Visibility = Visibility.Hidden; var segments = new List(); - var parent = _mainWindow.inkCanvas?.Parent as System.Windows.Controls.Panel; + var parent = _mainWindow.inkCanvas?.Parent as Panel; if (parent == null) { // 如果父容器不是Panel,直接使用InkCanvas @@ -676,7 +675,7 @@ namespace Ink_Canvas.Helpers try { // 移除所有分段 - var parent = _mainWindow.inkCanvas?.Parent as System.Windows.Controls.Panel; + var parent = _mainWindow.inkCanvas?.Parent as Panel; foreach (var segment in segments) { @@ -811,7 +810,7 @@ namespace Ink_Canvas.Helpers try { // 从父容器中移除墨迹 - var parent = _mainWindow.inkCanvas?.Parent as System.Windows.Controls.Panel; + var parent = _mainWindow.inkCanvas?.Parent as Panel; if (parent != null && parent.Children.Contains(visual)) { parent.Children.Remove(visual); diff --git a/Ink Canvas/Helpers/PPTManager.cs b/Ink Canvas/Helpers/PPTManager.cs index c51fa589..76c3f4e9 100644 --- a/Ink Canvas/Helpers/PPTManager.cs +++ b/Ink Canvas/Helpers/PPTManager.cs @@ -340,7 +340,7 @@ namespace Ink_Canvas.Helpers LogHelper.WriteLogToFile($"PPT事件注册失败: {ex}", LogHelper.LogType.Error); throw; // 重新抛出异常,让外层处理 } - }, DispatcherPriority.Normal, System.Threading.CancellationToken.None, TimeSpan.FromSeconds(2)); + }, DispatcherPriority.Normal, CancellationToken.None, TimeSpan.FromSeconds(2)); // 获取当前演示文稿信息 UpdateCurrentPresentationInfo(); @@ -407,7 +407,7 @@ namespace Ink_Canvas.Helpers // COM对象类型转换失败,通常是因为对象已经被释放 LogHelper.WriteLogToFile("PPT COM对象已被释放,跳过事件注册取消", LogHelper.LogType.Trace); } - }, DispatcherPriority.Normal, System.Threading.CancellationToken.None, TimeSpan.FromSeconds(1)); + }, DispatcherPriority.Normal, CancellationToken.None, TimeSpan.FromSeconds(1)); } } catch (Exception ex) diff --git a/Ink Canvas/Helpers/Plugins/EnhancedPluginBase.cs b/Ink Canvas/Helpers/Plugins/EnhancedPluginBase.cs index cf3c0b47..3b62137f 100644 --- a/Ink Canvas/Helpers/Plugins/EnhancedPluginBase.cs +++ b/Ink Canvas/Helpers/Plugins/EnhancedPluginBase.cs @@ -1,4 +1,3 @@ -using System; using System.Windows.Controls; namespace Ink_Canvas.Helpers.Plugins diff --git a/Ink Canvas/Helpers/Plugins/IEnhancedPlugin.cs b/Ink Canvas/Helpers/Plugins/IEnhancedPlugin.cs index 270064db..6ee5e9d5 100644 --- a/Ink Canvas/Helpers/Plugins/IEnhancedPlugin.cs +++ b/Ink Canvas/Helpers/Plugins/IEnhancedPlugin.cs @@ -1,4 +1,3 @@ -using System; using System.Windows.Controls; namespace Ink_Canvas.Helpers.Plugins diff --git a/Ink Canvas/Helpers/Plugins/IPluginService.cs b/Ink Canvas/Helpers/Plugins/IPluginService.cs index 3063f85f..2df665f5 100644 --- a/Ink Canvas/Helpers/Plugins/IPluginService.cs +++ b/Ink Canvas/Helpers/Plugins/IPluginService.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Windows; using System.Windows.Controls; -using System.Windows.Ink; using System.Windows.Media; namespace Ink_Canvas.Helpers.Plugins diff --git a/Ink Canvas/Helpers/Plugins/PluginConfigurationManager.cs b/Ink Canvas/Helpers/Plugins/PluginConfigurationManager.cs index c328b642..dfa342b2 100644 --- a/Ink Canvas/Helpers/Plugins/PluginConfigurationManager.cs +++ b/Ink Canvas/Helpers/Plugins/PluginConfigurationManager.cs @@ -1,4 +1,3 @@ -using Ink_Canvas.Helpers; using Newtonsoft.Json; using System; using System.Collections.Generic; diff --git a/Ink Canvas/Helpers/Plugins/PluginServiceManager.cs b/Ink Canvas/Helpers/Plugins/PluginServiceManager.cs index 1748fc1e..e3e2d3e5 100644 --- a/Ink Canvas/Helpers/Plugins/PluginServiceManager.cs +++ b/Ink Canvas/Helpers/Plugins/PluginServiceManager.cs @@ -1,10 +1,7 @@ -using Ink_Canvas.Helpers; -using Ink_Canvas.Windows; using System; using System.Collections.Generic; using System.Windows; using System.Windows.Controls; -using System.Windows.Ink; using System.Windows.Media; using System.Linq; diff --git a/Ink Canvas/MainWindow.xaml.cs b/Ink Canvas/MainWindow.xaml.cs index 043d046f..33c4260e 100644 --- a/Ink Canvas/MainWindow.xaml.cs +++ b/Ink Canvas/MainWindow.xaml.cs @@ -237,8 +237,8 @@ namespace Ink_Canvas ApplyAlwaysOnTop(); // 添加窗口激活事件处理,确保置顶状态在窗口重新激活时得到保持 - this.Activated += Window_Activated; - this.Deactivated += Window_Deactivated; + Activated += Window_Activated; + Deactivated += Window_Deactivated; // 为浮动栏按钮添加触摸事件支持 AddTouchSupportToFloatingBarButtons(); @@ -1911,7 +1911,7 @@ namespace Ink_Canvas Dispatcher.BeginInvoke(new Action(() => { ApplyAlwaysOnTop(); - }), System.Windows.Threading.DispatcherPriority.Loaded); + }), DispatcherPriority.Loaded); } } @@ -1927,7 +1927,7 @@ namespace Ink_Canvas Dispatcher.BeginInvoke(new Action(() => { ApplyAlwaysOnTop(); - }), System.Windows.Threading.DispatcherPriority.Loaded); + }), DispatcherPriority.Loaded); } } diff --git a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs index 439ca3a5..ae4e514e 100644 --- a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs +++ b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs @@ -13,7 +13,6 @@ using System.Windows.Interop; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Media.Imaging; -using System.Windows.Threading; using Application = System.Windows.Application; using Button = System.Windows.Controls.Button; using HorizontalAlignment = System.Windows.HorizontalAlignment; @@ -2806,8 +2805,8 @@ namespace Ink_Canvas // Wait a bit for the panel to hide await Task.Delay(100); - // Capture screenshot and copy to clipboard - await CaptureScreenshotToClipboard(); + // Capture screenshot and insert to canvas + await CaptureScreenshotAndInsert(); } private async void ImageOptionSelectFile_MouseUp(object sender, MouseButtonEventArgs e) diff --git a/Ink Canvas/MainWindow_cs/MW_Hotkeys.cs b/Ink Canvas/MainWindow_cs/MW_Hotkeys.cs index a0cbc550..dc19ff5f 100644 --- a/Ink Canvas/MainWindow_cs/MW_Hotkeys.cs +++ b/Ink Canvas/MainWindow_cs/MW_Hotkeys.cs @@ -1,9 +1,5 @@ using System.Windows; using System.Windows.Input; -using System.Diagnostics; -using System; -using System.Linq; -using System.Runtime.InteropServices; namespace Ink_Canvas { diff --git a/Ink Canvas/MainWindow_cs/MW_ImageInsert.cs b/Ink Canvas/MainWindow_cs/MW_ImageInsert.cs new file mode 100644 index 00000000..9a0b08d3 --- /dev/null +++ b/Ink Canvas/MainWindow_cs/MW_ImageInsert.cs @@ -0,0 +1,331 @@ +using Ink_Canvas.Helpers; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Forms; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using Application = System.Windows.Application; +using PixelFormat = System.Drawing.Imaging.PixelFormat; +using Size = System.Drawing.Size; + +namespace Ink_Canvas +{ + // 截图结果结构体 + public struct ScreenshotResult + { + public Rectangle Area; + public List Path; + + public ScreenshotResult(Rectangle area, List path = null) + { + Area = area; + Path = path; + } + } + + public partial class MainWindow : Window + { + // 截图并插入到画布 + private async Task CaptureScreenshotAndInsert() + { + try + { + // 隐藏主窗口以避免截图包含窗口本身 + var originalVisibility = Visibility; + Visibility = Visibility.Hidden; + + // 等待窗口隐藏 + await Task.Delay(200); + + // 启动区域选择截图 + var screenshotResult = await ShowScreenshotSelector(); + + // 恢复窗口显示 + Visibility = originalVisibility; + + if (screenshotResult.HasValue && screenshotResult.Value.Area.Width > 0 && screenshotResult.Value.Area.Height > 0) + { + // 截取选定区域 + using (var originalBitmap = CaptureScreenArea(screenshotResult.Value.Area)) + { + if (originalBitmap != null) + { + Bitmap finalBitmap = originalBitmap; + bool needDisposeFinalBitmap = false; + + try + { + // 如果有路径信息,应用形状遮罩 + if (screenshotResult.Value.Path != null && screenshotResult.Value.Path.Count > 0) + { + finalBitmap = ApplyShapeMask(originalBitmap, screenshotResult.Value.Path, screenshotResult.Value.Area); + needDisposeFinalBitmap = true; // 标记需要释放新创建的位图 + } + + // 将截图转换为WPF Image并插入到画布 + await InsertScreenshotToCanvas(finalBitmap); + } + finally + { + // 如果创建了新的位图,需要释放它 + if (needDisposeFinalBitmap && finalBitmap != originalBitmap) + { + finalBitmap.Dispose(); + } + } + } + } + } + else + { + ShowNotification("截图已取消"); + } + } + catch (Exception ex) + { + ShowNotification($"截图失败: {ex.Message}"); + Visibility = Visibility.Visible; + } + } + + // 显示截图区域选择器 + private async Task ShowScreenshotSelector() + { + ScreenshotResult? result = null; + + try + { + await Application.Current.Dispatcher.InvokeAsync(() => + { + var selectorWindow = new ScreenshotSelectorWindow(); + if (selectorWindow.ShowDialog() == true) + { + result = new ScreenshotResult( + selectorWindow.SelectedArea.Value, + selectorWindow.SelectedPath + ); + } + }); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"显示截图选择器失败: {ex.Message}", LogHelper.LogType.Error); + } + + return result; + } + + // 截取指定屏幕区域 + private Bitmap CaptureScreenArea(Rectangle area) + { + try + { + // 确保区域在有效范围内 + var virtualScreen = SystemInformation.VirtualScreen; + + // 调整区域边界,确保不超出屏幕范围 + int x = Math.Max(area.X, virtualScreen.X); + int y = Math.Max(area.Y, virtualScreen.Y); + int right = Math.Min(area.Right, virtualScreen.Right); + int bottom = Math.Min(area.Bottom, virtualScreen.Bottom); + + int width = Math.Max(1, right - x); + int height = Math.Max(1, bottom - y); + + // 创建支持透明度的位图 + var bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); + using (var graphics = Graphics.FromImage(bitmap)) + { + // 设置高质量渲染 + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.CompositingMode = CompositingMode.SourceOver; + + // 截取屏幕区域 + graphics.CopyFromScreen(x, y, 0, 0, new Size(width, height), CopyPixelOperation.SourceCopy); + } + + LogHelper.WriteLogToFile($"成功截取区域: X={x}, Y={y}, Width={width}, Height={height}"); + return bitmap; + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"截取屏幕区域失败: {ex.Message}", LogHelper.LogType.Error); + return null; + } + } + + // 将截图插入到画布 + private async Task InsertScreenshotToCanvas(Bitmap bitmap) + { + try + { + // 将Bitmap转换为WPF BitmapSource + var bitmapSource = ConvertBitmapToBitmapSource(bitmap); + + // 创建WPF Image控件 + var image = new System.Windows.Controls.Image + { + Source = bitmapSource, + Stretch = Stretch.Uniform + }; + RenderOptions.SetBitmapScalingMode(image, BitmapScalingMode.HighQuality); + + // 生成唯一名称 + string timestamp = "screenshot_" + 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); + + ShowNotification("截图已插入到画布"); + } + catch (Exception ex) + { + ShowNotification($"插入截图失败: {ex.Message}"); + LogHelper.WriteLogToFile($"插入截图失败: {ex.Message}", LogHelper.LogType.Error); + } + } + + // 应用形状遮罩到截图 + private Bitmap ApplyShapeMask(Bitmap bitmap, List path, Rectangle area) + { + try + { + // 验证路径参数 + if (path == null || path.Count < 3) + { + LogHelper.WriteLogToFile("路径点数不足,无法应用形状遮罩", LogHelper.LogType.Warning); + return bitmap; + } + + // 获取DPI缩放比例 + var dpiScale = GetDpiScale(); + var virtualScreen = SystemInformation.VirtualScreen; + + // 创建结果位图,确保支持透明度 + var resultBitmap = new Bitmap(bitmap.Width, bitmap.Height, PixelFormat.Format32bppArgb); + + // 首先将整个位图设置为透明 + using (var resultGraphics = Graphics.FromImage(resultBitmap)) + { + // 清除位图,设置为完全透明 + resultGraphics.Clear(System.Drawing.Color.Transparent); + + // 设置高质量渲染 + resultGraphics.SmoothingMode = SmoothingMode.AntiAlias; + resultGraphics.CompositingQuality = CompositingQuality.HighQuality; + resultGraphics.CompositingMode = CompositingMode.SourceOver; + + // 创建路径 + using (var pathGraphics = new GraphicsPath()) + { + // 转换WPF坐标到GDI+坐标,考虑DPI缩放和屏幕偏移 + var points = new PointF[path.Count]; + for (int i = 0; i < path.Count; i++) + { + // 将WPF坐标转换为实际屏幕坐标,然后相对于截图区域计算偏移 + double screenX = (path[i].X * dpiScale) + virtualScreen.Left; + double screenY = (path[i].Y * dpiScale) + virtualScreen.Top; + + // 计算相对于截图区域的坐标 + float relativeX = (float)(screenX - area.X); + float relativeY = (float)(screenY - area.Y); + + // 确保坐标在有效范围内 + relativeX = Math.Max(0, Math.Min(relativeX, bitmap.Width - 1)); + relativeY = Math.Max(0, Math.Min(relativeY, bitmap.Height - 1)); + + points[i] = new PointF(relativeX, relativeY); + } + + // 添加路径 - 使用FillMode.Winding确保路径正确填充 + pathGraphics.FillMode = FillMode.Winding; + pathGraphics.AddPolygon(points); + + // 验证路径是否有效 + if (!pathGraphics.IsVisible(0, 0) && pathGraphics.GetBounds().Width > 0 && pathGraphics.GetBounds().Height > 0) + { + // 设置裁剪区域为路径内部 + resultGraphics.SetClip(pathGraphics); + + // 在裁剪区域内绘制原始图像 + resultGraphics.DrawImage(bitmap, 0, 0); + + // 重置裁剪区域,确保后续操作不受影响 + resultGraphics.ResetClip(); + } + else + { + LogHelper.WriteLogToFile("生成的路径无效,返回透明图像", LogHelper.LogType.Warning); + // 如果路径无效,返回透明图像 + return resultBitmap; + } + } + } + + return resultBitmap; + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"应用形状遮罩失败: {ex.Message}", LogHelper.LogType.Error); + return bitmap; + } + } + + // 将System.Drawing.Bitmap转换为WPF BitmapSource + private BitmapSource ConvertBitmapToBitmapSource(Bitmap bitmap) + { + try + { + using (var memory = new MemoryStream()) + { + bitmap.Save(memory, ImageFormat.Png); + memory.Position = 0; + + var bitmapImage = new BitmapImage(); + bitmapImage.BeginInit(); + bitmapImage.CacheOption = BitmapCacheOption.OnLoad; + bitmapImage.StreamSource = memory; + bitmapImage.EndInit(); + bitmapImage.Freeze(); + + return bitmapImage; + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"转换位图失败: {ex.Message}", LogHelper.LogType.Error); + throw; + } + } + + // 获取DPI缩放比例 + private double GetDpiScale() + { + var source = PresentationSource.FromVisual(this); + if (source?.CompositionTarget != null) + { + return source.CompositionTarget.TransformToDevice.M11; + } + return 1.0; // 默认DPI + } + } +} \ No newline at end of file diff --git a/Ink Canvas/MainWindow_cs/MW_Screenshot.cs b/Ink Canvas/MainWindow_cs/MW_Screenshot.cs index 00e537fd..05b5cf89 100644 --- a/Ink Canvas/MainWindow_cs/MW_Screenshot.cs +++ b/Ink Canvas/MainWindow_cs/MW_Screenshot.cs @@ -1,33 +1,12 @@ -using Ink_Canvas.Helpers; using System; -using System.Collections.Generic; using System.Drawing; -using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; -using System.Threading.Tasks; using System.Windows; using System.Windows.Forms; -using System.Windows.Media.Imaging; -using Application = System.Windows.Application; -using Clipboard = System.Windows.Clipboard; -using Size = System.Drawing.Size; namespace Ink_Canvas { - // 截图结果结构体 - public struct ScreenshotResult - { - public System.Drawing.Rectangle Area; - public List Path; - - public ScreenshotResult(System.Drawing.Rectangle area, List path = null) - { - Area = area; - Path = path; - } - } - public partial class MainWindow : Window { private void SaveScreenShot(bool isHideNotification, string fileName = null) @@ -120,312 +99,5 @@ namespace Ink_Canvas 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 screenshotResult = await ShowScreenshotSelector(); - - // 恢复窗口显示 - this.Visibility = originalVisibility; - - if (screenshotResult.HasValue && screenshotResult.Value.Area.Width > 0 && screenshotResult.Value.Area.Height > 0) - { - // 截取选定区域 - using (var originalBitmap = CaptureScreenArea(screenshotResult.Value.Area)) - { - if (originalBitmap != null) - { - Bitmap finalBitmap = originalBitmap; - bool needDisposeFinalBitmap = false; - - try - { - // 如果有路径信息,应用形状遮罩 - if (screenshotResult.Value.Path != null && screenshotResult.Value.Path.Count > 0) - { - finalBitmap = ApplyShapeMask(originalBitmap, screenshotResult.Value.Path, screenshotResult.Value.Area); - needDisposeFinalBitmap = true; // 标记需要释放新创建的位图 - } - - // 将截图复制到剪贴板 - CopyBitmapToClipboard(finalBitmap); - - // 等待窗口完全显示后自动粘贴 - await Task.Delay(100); - await AutoPasteScreenshot(); - } - finally - { - // 如果创建了新的位图,需要释放它 - if (needDisposeFinalBitmap && finalBitmap != originalBitmap) - { - finalBitmap.Dispose(); - } - } - } - } - } - else - { - ShowNotification("截图已取消"); - } - } - catch (Exception ex) - { - ShowNotification($"截图失败: {ex.Message}"); - this.Visibility = Visibility.Visible; - } - } - - // 显示截图区域选择器 - private async Task ShowScreenshotSelector() - { - ScreenshotResult? result = null; - - try - { - await Application.Current.Dispatcher.InvokeAsync(() => - { - var selectorWindow = new ScreenshotSelectorWindow(); - if (selectorWindow.ShowDialog() == true) - { - result = new ScreenshotResult( - selectorWindow.SelectedArea.Value, - selectorWindow.SelectedPath - ); - } - }); - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"显示截图选择器失败: {ex.Message}", LogHelper.LogType.Error); - } - - return result; - } - - // 截取指定屏幕区域 - private Bitmap CaptureScreenArea(System.Drawing.Rectangle area) - { - try - { - // 确保区域在有效范围内 - var virtualScreen = SystemInformation.VirtualScreen; - - // 调整区域边界,确保不超出屏幕范围 - int x = Math.Max(area.X, virtualScreen.X); - int y = Math.Max(area.Y, virtualScreen.Y); - int right = Math.Min(area.Right, virtualScreen.Right); - int bottom = Math.Min(area.Bottom, virtualScreen.Bottom); - - int width = Math.Max(1, right - x); - int height = Math.Max(1, bottom - y); - - // 创建支持透明度的位图 - var bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); - using (var graphics = Graphics.FromImage(bitmap)) - { - // 设置高质量渲染 - graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality; - graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; - graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; - graphics.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver; - - // 截取屏幕区域 - graphics.CopyFromScreen(x, y, 0, 0, new Size(width, height), CopyPixelOperation.SourceCopy); - } - - LogHelper.WriteLogToFile($"成功截取区域: X={x}, Y={y}, Width={width}, Height={height}", LogHelper.LogType.Info); - return bitmap; - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"截取屏幕区域失败: {ex.Message}", LogHelper.LogType.Error); - return null; - } - } - - // 自动粘贴截图到画布 - 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}"); - } - } - - // 应用形状遮罩到截图 - private Bitmap ApplyShapeMask(Bitmap bitmap, List path, System.Drawing.Rectangle area) - { - try - { - // 验证路径参数 - if (path == null || path.Count < 3) - { - LogHelper.WriteLogToFile("路径点数不足,无法应用形状遮罩", LogHelper.LogType.Warning); - return bitmap; - } - - // 获取DPI缩放比例 - var dpiScale = GetDpiScale(); - var virtualScreen = SystemInformation.VirtualScreen; - - // 创建结果位图,确保支持透明度 - var resultBitmap = new Bitmap(bitmap.Width, bitmap.Height, PixelFormat.Format32bppArgb); - - // 首先将整个位图设置为透明 - using (var resultGraphics = Graphics.FromImage(resultBitmap)) - { - // 清除位图,设置为完全透明 - resultGraphics.Clear(System.Drawing.Color.Transparent); - - // 设置高质量渲染 - resultGraphics.SmoothingMode = SmoothingMode.AntiAlias; - resultGraphics.CompositingQuality = CompositingQuality.HighQuality; - resultGraphics.CompositingMode = CompositingMode.SourceOver; - - // 创建路径 - using (var pathGraphics = new GraphicsPath()) - { - // 转换WPF坐标到GDI+坐标,考虑DPI缩放和屏幕偏移 - var points = new PointF[path.Count]; - for (int i = 0; i < path.Count; i++) - { - // 将WPF坐标转换为实际屏幕坐标,然后相对于截图区域计算偏移 - double screenX = (path[i].X * dpiScale) + virtualScreen.Left; - double screenY = (path[i].Y * dpiScale) + virtualScreen.Top; - - // 计算相对于截图区域的坐标 - float relativeX = (float)(screenX - area.X); - float relativeY = (float)(screenY - area.Y); - - // 确保坐标在有效范围内 - relativeX = Math.Max(0, Math.Min(relativeX, bitmap.Width - 1)); - relativeY = Math.Max(0, Math.Min(relativeY, bitmap.Height - 1)); - - points[i] = new PointF(relativeX, relativeY); - } - - // 添加路径 - 使用FillMode.Winding确保路径正确填充 - pathGraphics.FillMode = FillMode.Winding; - pathGraphics.AddPolygon(points); - - // 验证路径是否有效 - if (!pathGraphics.IsVisible(0, 0) && pathGraphics.GetBounds().Width > 0 && pathGraphics.GetBounds().Height > 0) - { - // 设置裁剪区域为路径内部 - resultGraphics.SetClip(pathGraphics); - - // 在裁剪区域内绘制原始图像 - resultGraphics.DrawImage(bitmap, 0, 0); - - // 重置裁剪区域,确保后续操作不受影响 - resultGraphics.ResetClip(); - } - else - { - LogHelper.WriteLogToFile("生成的路径无效,返回原始图像", LogHelper.LogType.Warning); - // 如果路径无效,返回透明图像 - return resultBitmap; - } - } - } - - LogHelper.WriteLogToFile($"成功应用形状遮罩,路径点数: {path.Count}", LogHelper.LogType.Info); - return resultBitmap; - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"应用形状遮罩失败: {ex.Message}", LogHelper.LogType.Error); - // 返回完全透明的图像而不是原始图像 - var transparentBitmap = new Bitmap(bitmap.Width, bitmap.Height, PixelFormat.Format32bppArgb); - using (var g = Graphics.FromImage(transparentBitmap)) - { - g.Clear(System.Drawing.Color.Transparent); - } - return transparentBitmap; - } - } - - // 获取DPI缩放比例 - private double GetDpiScale() - { - var source = PresentationSource.FromVisual(this); - if (source?.CompositionTarget != null) - { - return source.CompositionTarget.TransformToDevice.M11; - } - return 1.0; // 默认DPI - } - - // 将System.Drawing.Bitmap转换为WPF BitmapSource - private BitmapSource ConvertBitmapToBitmapSource(Bitmap bitmap) - { - try - { - using (var memory = new MemoryStream()) - { - // 使用PNG格式保存,确保透明度信息不丢失 - 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; - } - } - catch (Exception ex) - { - LogHelper.WriteLogToFile($"转换位图失败: {ex.Message}", LogHelper.LogType.Error); - throw; - } - } } } diff --git a/Ink Canvas/MainWindow_cs/MW_TouchEvents.cs b/Ink Canvas/MainWindow_cs/MW_TouchEvents.cs index d24d6f42..9c1a8393 100644 --- a/Ink Canvas/MainWindow_cs/MW_TouchEvents.cs +++ b/Ink Canvas/MainWindow_cs/MW_TouchEvents.cs @@ -1,7 +1,6 @@ using Ink_Canvas.Helpers; using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using System.Windows; diff --git a/Ink Canvas/Windows/HotkeySettingsWindow.xaml.cs b/Ink Canvas/Windows/HotkeySettingsWindow.xaml.cs index 31289032..5539d553 100644 --- a/Ink Canvas/Windows/HotkeySettingsWindow.xaml.cs +++ b/Ink Canvas/Windows/HotkeySettingsWindow.xaml.cs @@ -30,7 +30,7 @@ namespace Ink_Canvas.Windows InitializeHotkeyItems(); // 延迟加载快捷键,确保快捷键管理器已完全初始化 - this.Loaded += (s, e) => + Loaded += (s, e) => { try { @@ -48,7 +48,7 @@ namespace Ink_Canvas.Windows }; // 注册窗口关闭事件 - this.Closed += HotkeySettingsWindow_Closed; + Closed += HotkeySettingsWindow_Closed; } #endregion @@ -440,7 +440,7 @@ namespace Ink_Canvas.Windows if (settingsBorder != null) { - settingsBorder.Visibility = System.Windows.Visibility.Collapsed; + settingsBorder.Visibility = Visibility.Collapsed; } // 隐藏设置蒙版 @@ -449,7 +449,7 @@ namespace Ink_Canvas.Windows if (settingsMask != null) { - settingsMask.Visibility = System.Windows.Visibility.Collapsed; + settingsMask.Visibility = Visibility.Collapsed; } } catch (Exception ex) @@ -471,7 +471,7 @@ namespace Ink_Canvas.Windows if (settingsBorder != null) { - settingsBorder.Visibility = System.Windows.Visibility.Visible; + settingsBorder.Visibility = Visibility.Visible; } // 显示设置蒙版 @@ -480,7 +480,7 @@ namespace Ink_Canvas.Windows if (settingsMask != null) { - settingsMask.Visibility = System.Windows.Visibility.Visible; + settingsMask.Visibility = Visibility.Visible; } } catch (Exception ex) diff --git a/Ink Canvas/Windows/ScreenshotSelectorWindow.xaml.cs b/Ink Canvas/Windows/ScreenshotSelectorWindow.xaml.cs index ee5aa49e..205f7fce 100644 --- a/Ink Canvas/Windows/ScreenshotSelectorWindow.xaml.cs +++ b/Ink Canvas/Windows/ScreenshotSelectorWindow.xaml.cs @@ -16,13 +16,13 @@ namespace Ink_Canvas { private bool _isSelecting = false; private bool _isFreehandMode = false; - private System.Windows.Point _startPoint; - private System.Windows.Point _currentPoint; - private List _freehandPoints; + private Point _startPoint; + private Point _currentPoint; + private List _freehandPoints; private Polyline _freehandPolyline; public DrawingRectangle? SelectedArea { get; private set; } - public List SelectedPath { get; private set; } + public List SelectedPath { get; private set; } public ScreenshotSelectorWindow() { @@ -47,7 +47,7 @@ namespace Ink_Canvas private void InitializeFreehandMode() { - _freehandPoints = new List(); + _freehandPoints = new List(); _freehandPolyline = new Polyline { Stroke = Brushes.Red, @@ -65,10 +65,10 @@ namespace Ink_Canvas // 转换为WPF坐标系统 var dpiScale = GetDpiScale(); - this.Left = virtualScreen.Left / dpiScale; - this.Top = virtualScreen.Top / dpiScale; - this.Width = virtualScreen.Width / dpiScale; - this.Height = virtualScreen.Height / dpiScale; + Left = virtualScreen.Left / dpiScale; + Top = virtualScreen.Top / dpiScale; + Width = virtualScreen.Width / dpiScale; + Height = virtualScreen.Height / dpiScale; } private double GetDpiScale() @@ -186,7 +186,7 @@ namespace Ink_Canvas if (_freehandPoints.Count > 3) // 至少需要3个点形成有效路径 { // 创建路径的副本,避免修改原始列表 - var pathPoints = new List(_freehandPoints); + var pathPoints = new List(_freehandPoints); // 确保路径闭合(如果最后一个点不是起始点,则添加起始点) if (pathPoints.Count > 0 && @@ -284,7 +284,7 @@ namespace Ink_Canvas return new Rect(x, y, width, height); } - private Rect CalculatePathBounds(List points) + private Rect CalculatePathBounds(List points) { if (points == null || points.Count == 0) return new Rect(); @@ -306,12 +306,12 @@ namespace Ink_Canvas } // 优化路径:移除重复点和过于接近的点,提高路径质量 - private List OptimizePath(List originalPath) + private List OptimizePath(List originalPath) { if (originalPath == null || originalPath.Count < 3) return originalPath; - var optimizedPath = new List(); + var optimizedPath = new List(); const double minDistance = 2.0; // 最小距离阈值 // 添加第一个点