From c06be8f50222745bfe82773a900970247c69d792 Mon Sep 17 00:00:00 2001 From: tayasui rainnya! <156585442+Tayasui-rainnya@users.noreply.github.com> Date: Sun, 22 Feb 2026 14:04:11 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B5=AE=E5=8A=A8=E6=A0=8F=E6=88=AA?= =?UTF-8?q?=E5=9B=BE=E4=BF=AE=E6=94=B9=E4=B8=BA=E9=80=89=E5=8C=BA=E6=88=AA?= =?UTF-8?q?=E5=9B=BE=EF=BC=8C=E6=B7=BB=E5=8A=A0=E2=80=9C=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=88=B0=E7=99=BD=E6=9D=BF=E2=80=9D=E6=8C=89=E9=92=AE=20(#377)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 调整截图按钮默认行为为选区/白板全屏 * 截图选择器新增添加到白板按钮并支持新建白板页插入 * 修复添加到白板不生效:改为剪贴板复制粘贴插入 * 修复添加到白板截图时序:先截到内存再进白板 * Fix screenshot insert flow honoring add-to-whiteboard option * Refine screenshot selector freehand confirm and blank double-click full select * Fix freehand whiteboard insert alpha transparency * Fix screenshot insert notification text for whiteboard flow * Adjust screenshot selection: right-click/double-click full-select and keep selector on single click * Show unmasked freehand selection area like rectangle mode * Remove freehand cutout mask rendering from screenshot selector * Restore freehand selected-area unmask behavior in selector --- .../MainWindow_cs/MW_FloatingBarIcons.cs | 13 +- Ink Canvas/MainWindow_cs/MW_ImageInsert.cs | 38 ++- Ink Canvas/MainWindow_cs/MW_Screenshot.cs | 155 +++++++++++++ .../Windows/ScreenshotSelectorWindow.xaml | 12 +- .../Windows/ScreenshotSelectorWindow.xaml.cs | 218 +++++++++++++++--- 5 files changed, 393 insertions(+), 43 deletions(-) diff --git a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs index 83447063..27256f13 100644 --- a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs +++ b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs @@ -1130,7 +1130,16 @@ namespace Ink_Canvas { HideSubPanelsImmediately(); await Task.Delay(50); - SaveScreenShotToDesktop(); + + // 白板模式下默认全屏截图到桌面;其余模式默认调用可选区截图 + if (currentMode == 1) + { + SaveScreenShotToDesktop(); + } + else + { + await SaveAreaScreenShotToDesktop(); + } } /// @@ -4309,4 +4318,4 @@ namespace Ink_Canvas } } -} \ No newline at end of file +} diff --git a/Ink Canvas/MainWindow_cs/MW_ImageInsert.cs b/Ink Canvas/MainWindow_cs/MW_ImageInsert.cs index fab3cc7f..bab3e578 100644 --- a/Ink Canvas/MainWindow_cs/MW_ImageInsert.cs +++ b/Ink Canvas/MainWindow_cs/MW_ImageInsert.cs @@ -29,13 +29,16 @@ namespace Ink_Canvas public List Path; public Bitmap CameraImage; public BitmapSource CameraBitmapSource; + public bool AddToWhiteboard; - public ScreenshotResult(Rectangle area, List path = null, Bitmap cameraImage = null, BitmapSource cameraBitmapSource = null) + public ScreenshotResult(Rectangle area, List path = null, Bitmap cameraImage = null, + BitmapSource cameraBitmapSource = null, bool addToWhiteboard = false) { Area = area; Path = path; CameraImage = cameraImage; CameraBitmapSource = cameraBitmapSource; + AddToWhiteboard = addToWhiteboard; } } @@ -72,11 +75,17 @@ namespace Ink_Canvas if (screenshotResult.HasValue) { + if (screenshotResult.Value.AddToWhiteboard) + { + await AddScreenshotToNewWhiteboardPage(screenshotResult.Value); + return; + } + // 检查是否是摄像头截图 if (screenshotResult.Value.CameraBitmapSource != null) { // 摄像头截图(使用BitmapSource) - await InsertBitmapSourceToCanvas(screenshotResult.Value.CameraBitmapSource); + await InsertBitmapSourceToCanvas(screenshotResult.Value.CameraBitmapSource, "摄像头截图已插入到画布", "插入摄像头截图失败"); } else if (screenshotResult.Value.CameraImage != null) { @@ -208,7 +217,8 @@ namespace Ink_Canvas Rectangle.Empty, // 摄像头截图不需要区域 null, // 摄像头截图不需要路径 null, // 不再使用Bitmap - selectorWindow.CameraBitmapSource // 摄像头BitmapSource + selectorWindow.CameraBitmapSource, // 摄像头BitmapSource + selectorWindow.ShouldAddToWhiteboard ); } else if (selectorWindow.CameraImage != null) @@ -216,14 +226,19 @@ namespace Ink_Canvas result = new ScreenshotResult( Rectangle.Empty, // 摄像头截图不需要区域 null, // 摄像头截图不需要路径 - selectorWindow.CameraImage // 摄像头图像 + selectorWindow.CameraImage, // 摄像头图像 + null, + selectorWindow.ShouldAddToWhiteboard ); } else { result = new ScreenshotResult( selectorWindow.SelectedArea.Value, - selectorWindow.SelectedPath + selectorWindow.SelectedPath, + null, + null, + selectorWindow.ShouldAddToWhiteboard ); } } @@ -403,7 +418,7 @@ namespace Ink_Canvas /// 8. 提交历史记录 /// 9. 插入图片后切换到选择模式并刷新浮动栏高光显示 /// - private async Task InsertBitmapSourceToCanvas(BitmapSource bitmapSource) + private async Task InsertBitmapSourceToCanvas(BitmapSource bitmapSource, string successMessage = "截图已插入到画布", string failureMessagePrefix = "插入截图失败") { try { @@ -452,11 +467,11 @@ namespace Ink_Canvas UpdateCurrentToolMode("select"); HideSubPanels("select"); - ShowNotification("摄像头截图已插入到画布"); + ShowNotification(successMessage); } catch (Exception ex) { - ShowNotification($"插入摄像头截图失败: {ex.Message}"); + ShowNotification($"{failureMessagePrefix}: {ex.Message}"); LogHelper.WriteLogToFile($"插入摄像头截图失败: {ex.Message}", LogHelper.LogType.Error); } } @@ -841,11 +856,12 @@ namespace Ink_Canvas if (bitmap == null || bitmap.Width <= 0 || bitmap.Height <= 0) return null; - // 创建一个新的位图,确保格式正确 - using (var convertedBitmap = new Bitmap(bitmap.Width, bitmap.Height, PixelFormat.Format24bppRgb)) + // 创建一个新的位图,确保保留Alpha通道 + using (var convertedBitmap = new Bitmap(bitmap.Width, bitmap.Height, PixelFormat.Format32bppArgb)) { using (var graphics = Graphics.FromImage(convertedBitmap)) { + graphics.CompositingMode = CompositingMode.SourceCopy; graphics.DrawImage(bitmap, 0, 0); } @@ -951,4 +967,4 @@ namespace Ink_Canvas 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 2738517d..ae7ac7c1 100644 --- a/Ink Canvas/MainWindow_cs/MW_Screenshot.cs +++ b/Ink Canvas/MainWindow_cs/MW_Screenshot.cs @@ -6,6 +6,7 @@ using System.IO; using System.Threading.Tasks; using System.Windows; using System.Windows.Forms; +using System.Windows.Media.Imaging; using System.Windows.Ink; using Ink_Canvas.Helpers; @@ -159,6 +160,160 @@ namespace Ink_Canvas SaveInkCanvasStrokes(false); } + internal async Task SaveAreaScreenShotToDesktop() + { + try + { + var originalVisibility = Visibility; + Visibility = Visibility.Hidden; + await Task.Delay(200); + + var screenshotResult = await ShowScreenshotSelector(); + Visibility = originalVisibility; + + if (!screenshotResult.HasValue) + { + ShowNotification("截图已取消"); + return; + } + + if (screenshotResult.Value.AddToWhiteboard) + { + await AddScreenshotToNewWhiteboardPage(screenshotResult.Value); + return; + } + + if (screenshotResult.Value.Area.Width <= 0 || screenshotResult.Value.Area.Height <= 0) + { + ShowNotification("未选择有效截图区域"); + return; + } + + var desktopPath = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), + $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.png"); + + using (var originalBitmap = CaptureScreenArea(screenshotResult.Value.Area)) + { + if (originalBitmap == null) + { + ShowNotification("截图失败"); + return; + } + + 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; + } + + var directory = Path.GetDirectoryName(desktopPath); + if (!Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } + + finalBitmap.Save(desktopPath, ImageFormat.Png); + ShowNotification($"截图成功保存至 {desktopPath}"); + } + finally + { + if (needDisposeFinalBitmap && finalBitmap != originalBitmap) + { + finalBitmap.Dispose(); + } + } + } + + if (Settings.Automation.IsAutoSaveStrokesAtScreenshot) + SaveInkCanvasStrokes(false); + } + catch (Exception ex) + { + Visibility = Visibility.Visible; + ShowNotification($"截图失败: {ex.Message}"); + } + } + + private async Task AddScreenshotToNewWhiteboardPage(ScreenshotResult screenshotResult) + { + // 先在当前场景准备截图数据,再进白板,避免误截到白板页面 + BitmapSource bitmapSourceForClipboard = null; + + // 摄像头截图(BitmapSource) + if (screenshotResult.CameraBitmapSource != null) + { + bitmapSourceForClipboard = screenshotResult.CameraBitmapSource; + } + // 摄像头截图(Bitmap) + else if (screenshotResult.CameraImage != null) + { + bitmapSourceForClipboard = ConvertBitmapToBitmapSource(screenshotResult.CameraImage); + } + else + { + if (screenshotResult.Area.Width <= 0 || screenshotResult.Area.Height <= 0) + { + ShowNotification("未选择有效截图区域"); + return; + } + + using (var originalBitmap = CaptureScreenArea(screenshotResult.Area)) + { + if (originalBitmap == null) + { + ShowNotification("截图失败"); + return; + } + + Bitmap finalBitmap = originalBitmap; + bool needDisposeFinalBitmap = false; + + try + { + if (screenshotResult.Path != null && screenshotResult.Path.Count > 0) + { + finalBitmap = ApplyShapeMask(originalBitmap, screenshotResult.Path, screenshotResult.Area); + needDisposeFinalBitmap = true; + } + + bitmapSourceForClipboard = ConvertBitmapToBitmapSource(finalBitmap); + } + finally + { + if (needDisposeFinalBitmap && finalBitmap != originalBitmap) + { + finalBitmap.Dispose(); + } + } + } + } + + if (bitmapSourceForClipboard == null) + { + ShowNotification("截图转换失败"); + return; + } + + // 图像已拷贝到内存后再进入白板 + bitmapSourceForClipboard.Freeze(); + + if (currentMode != 1) + { + SwitchToBoardMode(); + await Task.Delay(150); + } + + BtnWhiteBoardAdd_Click(null, EventArgs.Empty); + + await InsertBitmapSourceToCanvas(bitmapSourceForClipboard); + } + /// /// 提取公共的截图和保存逻辑 /// diff --git a/Ink Canvas/Windows/ScreenshotSelectorWindow.xaml b/Ink Canvas/Windows/ScreenshotSelectorWindow.xaml index 97c4804f..0e9584d8 100644 --- a/Ink Canvas/Windows/ScreenshotSelectorWindow.xaml +++ b/Ink Canvas/Windows/ScreenshotSelectorWindow.xaml @@ -11,6 +11,7 @@ Cursor="Cross" KeyDown="Window_KeyDown" MouseLeftButtonDown="Window_MouseLeftButtonDown" + MouseRightButtonDown="Window_MouseRightButtonDown" MouseMove="Window_MouseMove" MouseLeftButtonUp="Window_MouseLeftButtonUp"> @@ -149,6 +150,15 @@ BorderThickness="0" FontWeight="Medium" Click="ConfirmButton_Click" /> +