From a2dfa55dbde1d9cb27dc2be1c6cb3dcf999509f1 Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Thu, 31 Jul 2025 10:27:19 +0800
Subject: [PATCH] =?UTF-8?q?improve:=E6=8F=92=E5=85=A5=E5=9B=BE=E7=89=87?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/MainWindow.xaml | 88 +++++++++
.../MainWindow_cs/MW_FloatingBarIcons.cs | 50 +++++
Ink Canvas/MainWindow_cs/MW_Screenshot.cs | 102 +++++++++-
.../Windows/ScreenshotSelectorWindow.xaml | 36 +++-
.../Windows/ScreenshotSelectorWindow.xaml.cs | 183 +++++++++++++++---
5 files changed, 422 insertions(+), 37 deletions(-)
diff --git a/Ink Canvas/MainWindow.xaml b/Ink Canvas/MainWindow.xaml
index 19b38b3f..8a747298 100644
--- a/Ink Canvas/MainWindow.xaml
+++ b/Ink Canvas/MainWindow.xaml
@@ -5335,6 +5335,94 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -281,6 +282,7 @@ namespace Ink_Canvas {
AnimationsHelper.HideWithSlideAndFade(BoardBorderLeftPageListView);
AnimationsHelper.HideWithSlideAndFade(BoardBorderRightPageListView);
AnimationsHelper.HideWithSlideAndFade(BoardImageOptionsPanel);
+ AnimationsHelper.HideWithSlideAndFade(ScreenshotOptionsPanel);
// 隐藏背景设置面板
var bgPalette = LogicalTreeHelper.FindLogicalNode(this, "BackgroundPalette") as Border;
@@ -733,8 +735,56 @@ namespace Ink_Canvas {
private async void SymbolIconScreenshot_MouseUp(object sender, MouseButtonEventArgs e) {
HideSubPanelsImmediately();
await Task.Delay(50);
+
+ // 显示截图选项面板
+ ShowScreenshotOptionsPanel();
+ }
+
+ private void ShowScreenshotOptionsPanel() {
+ // 隐藏其他面板
+ HideSubPanelsImmediately();
+
+ // 显示截图选项面板
+ if (ScreenshotOptionsPanel.Visibility == Visibility.Collapsed) {
+ // 添加调试信息
+ LogHelper.WriteLogToFile("显示截图选项面板", LogHelper.LogType.Info);
+
+ // 直接设置可见性,不使用动画
+ ScreenshotOptionsPanel.Visibility = Visibility.Visible;
+
+ // 显示通知确认面板已显示
+ ShowNotification("截图选项面板已显示");
+ } else {
+ LogHelper.WriteLogToFile("隐藏截图选项面板", LogHelper.LogType.Info);
+ ScreenshotOptionsPanel.Visibility = Visibility.Collapsed;
+ }
+ }
+
+ private void CloseScreenshotOptionsPanel_MouseUp(object sender, MouseButtonEventArgs e) {
+ AnimationsHelper.HideWithSlideAndFade(ScreenshotOptionsPanel);
+ }
+
+ private async void FullScreenScreenshot_MouseUp(object sender, MouseButtonEventArgs e) {
+ // 隐藏选项面板
+ AnimationsHelper.HideWithSlideAndFade(ScreenshotOptionsPanel);
+
+ // 等待面板隐藏
+ await Task.Delay(100);
+
+ // 执行全屏截图
SaveScreenShotToDesktop();
}
+
+ private async void AreaScreenshot_MouseUp(object sender, MouseButtonEventArgs e) {
+ // 隐藏选项面板
+ AnimationsHelper.HideWithSlideAndFade(ScreenshotOptionsPanel);
+
+ // 等待面板隐藏
+ await Task.Delay(100);
+
+ // 执行区域截图
+ await CaptureScreenshotToClipboard();
+ }
diff --git a/Ink Canvas/MainWindow_cs/MW_Screenshot.cs b/Ink Canvas/MainWindow_cs/MW_Screenshot.cs
index 26bb7e27..4cd76d90 100644
--- a/Ink Canvas/MainWindow_cs/MW_Screenshot.cs
+++ b/Ink Canvas/MainWindow_cs/MW_Screenshot.cs
@@ -1,5 +1,7 @@
using System;
+using System.Collections.Generic;
using System.Drawing;
+using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Threading.Tasks;
@@ -13,6 +15,19 @@ 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) {
var savePath = Settings.Automation.IsSaveScreenshotsInDateFolders
@@ -99,20 +114,28 @@ namespace Ink_Canvas {
await Task.Delay(200);
// 启动区域选择截图
- var selectedArea = await ShowScreenshotSelector();
+ var screenshotResult = await ShowScreenshotSelector();
// 恢复窗口显示
this.Visibility = originalVisibility;
- if (selectedArea.HasValue && selectedArea.Value.Width > 0 && selectedArea.Value.Height > 0)
+ if (screenshotResult.HasValue && screenshotResult.Value.Area.Width > 0 && screenshotResult.Value.Area.Height > 0)
{
// 截取选定区域
- using (var bitmap = CaptureScreenArea(selectedArea.Value))
+ using (var originalBitmap = CaptureScreenArea(screenshotResult.Value.Area))
{
- if (bitmap != null)
+ if (originalBitmap != null)
{
+ Bitmap finalBitmap = originalBitmap;
+
+ // 如果有路径信息,应用形状遮罩
+ if (screenshotResult.Value.Path != null && screenshotResult.Value.Path.Count > 0)
+ {
+ finalBitmap = ApplyShapeMask(originalBitmap, screenshotResult.Value.Path, screenshotResult.Value.Area);
+ }
+
// 将截图复制到剪贴板
- CopyBitmapToClipboard(bitmap);
+ CopyBitmapToClipboard(finalBitmap);
// 等待窗口完全显示后自动粘贴
await Task.Delay(100);
@@ -132,9 +155,9 @@ namespace Ink_Canvas {
}
// 显示截图区域选择器
- private async Task ShowScreenshotSelector()
+ private async Task ShowScreenshotSelector()
{
- Rectangle? selectedArea = null;
+ ScreenshotResult? result = null;
try
{
@@ -143,7 +166,10 @@ namespace Ink_Canvas {
var selectorWindow = new ScreenshotSelectorWindow();
if (selectorWindow.ShowDialog() == true)
{
- selectedArea = selectorWindow.SelectedArea;
+ result = new ScreenshotResult(
+ selectorWindow.SelectedArea.Value,
+ selectorWindow.SelectedPath
+ );
}
});
}
@@ -152,11 +178,11 @@ namespace Ink_Canvas {
LogHelper.WriteLogToFile($"显示截图选择器失败: {ex.Message}", LogHelper.LogType.Error);
}
- return selectedArea;
+ return result;
}
// 截取指定屏幕区域
- private Bitmap CaptureScreenArea(Rectangle area)
+ private Bitmap CaptureScreenArea(System.Drawing.Rectangle area)
{
try
{
@@ -225,6 +251,62 @@ namespace Ink_Canvas {
}
}
+ // 应用形状遮罩到截图
+ private Bitmap ApplyShapeMask(Bitmap bitmap, List path, System.Drawing.Rectangle area)
+ {
+ try
+ {
+ // 创建遮罩位图
+ using (var maskBitmap = new Bitmap(bitmap.Width, bitmap.Height, PixelFormat.Format32bppArgb))
+ using (var maskGraphics = Graphics.FromImage(maskBitmap))
+ {
+ // 设置高质量渲染
+ maskGraphics.SmoothingMode = SmoothingMode.AntiAlias;
+ maskGraphics.CompositingQuality = CompositingQuality.HighQuality;
+
+ // 创建路径
+ using (var pathGraphics = new GraphicsPath())
+ {
+ // 转换WPF坐标到GDI+坐标
+ var points = new PointF[path.Count];
+ for (int i = 0; i < path.Count; i++)
+ {
+ points[i] = new PointF(
+ (float)(path[i].X - area.X),
+ (float)(path[i].Y - area.Y)
+ );
+ }
+
+ // 添加路径
+ pathGraphics.AddPolygon(points);
+
+ // 填充路径内部为白色(保留区域)
+ maskGraphics.FillPath(Brushes.White, pathGraphics);
+ }
+
+ // 创建结果位图
+ var resultBitmap = new Bitmap(bitmap.Width, bitmap.Height, PixelFormat.Format32bppArgb);
+ using (var resultGraphics = Graphics.FromImage(resultBitmap))
+ {
+ // 设置高质量渲染
+ resultGraphics.SmoothingMode = SmoothingMode.AntiAlias;
+ resultGraphics.CompositingQuality = CompositingQuality.HighQuality;
+
+ // 使用遮罩合成图像
+ resultGraphics.DrawImage(bitmap, 0, 0);
+ resultGraphics.DrawImage(maskBitmap, 0, 0);
+ }
+
+ return resultBitmap;
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"应用形状遮罩失败: {ex.Message}", LogHelper.LogType.Error);
+ return bitmap; // 如果失败,返回原始图像
+ }
+ }
+
// 将System.Drawing.Bitmap转换为WPF BitmapSource
private BitmapSource ConvertBitmapToBitmapSource(Bitmap bitmap) {
using (var memory = new MemoryStream()) {
diff --git a/Ink Canvas/Windows/ScreenshotSelectorWindow.xaml b/Ink Canvas/Windows/ScreenshotSelectorWindow.xaml
index 75806d02..00b0bf05 100644
--- a/Ink Canvas/Windows/ScreenshotSelectorWindow.xaml
+++ b/Ink Canvas/Windows/ScreenshotSelectorWindow.xaml
@@ -22,13 +22,20 @@
+
+
+
+
+
+
+ Margin="0,150,0,0">
diff --git a/Ink Canvas/Windows/ScreenshotSelectorWindow.xaml.cs b/Ink Canvas/Windows/ScreenshotSelectorWindow.xaml.cs
index d69f3bd6..7e85a9dd 100644
--- a/Ink Canvas/Windows/ScreenshotSelectorWindow.xaml.cs
+++ b/Ink Canvas/Windows/ScreenshotSelectorWindow.xaml.cs
@@ -1,22 +1,33 @@
using System;
+using System.Collections.Generic;
using System.Drawing;
+using System.Drawing.Drawing2D;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
+using System.Windows.Shapes;
+using Brushes = System.Windows.Media.Brushes;
+using Color = System.Windows.Media.Color;
// 为了避免命名冲突,使用别名
using WpfCanvas = System.Windows.Controls.Canvas;
+using DrawingRectangle = System.Drawing.Rectangle;
+using WpfRectangle = System.Windows.Shapes.Rectangle;
namespace Ink_Canvas
{
public partial class ScreenshotSelectorWindow : Window
{
private bool _isSelecting = false;
+ private bool _isFreehandMode = false;
private System.Windows.Point _startPoint;
private System.Windows.Point _currentPoint;
+ private List _freehandPoints;
+ private Polyline _freehandPolyline;
- public Rectangle? SelectedArea { get; private set; }
+ public DrawingRectangle? SelectedArea { get; private set; }
+ public List SelectedPath { get; private set; }
public ScreenshotSelectorWindow()
{
@@ -25,9 +36,12 @@ namespace Ink_Canvas
// 设置窗口覆盖所有屏幕
SetupFullScreenOverlay();
+ // 初始化自由绘制模式
+ InitializeFreehandMode();
+
// 隐藏提示文字的定时器
var timer = new System.Windows.Threading.DispatcherTimer();
- timer.Interval = TimeSpan.FromSeconds(3);
+ timer.Interval = TimeSpan.FromSeconds(5);
timer.Tick += (s, e) =>
{
HintText.Visibility = Visibility.Collapsed;
@@ -35,6 +49,18 @@ namespace Ink_Canvas
};
timer.Start();
}
+
+ private void InitializeFreehandMode()
+ {
+ _freehandPoints = new List();
+ _freehandPolyline = new Polyline
+ {
+ Stroke = Brushes.Red,
+ StrokeThickness = 2,
+ Fill = Brushes.Transparent
+ };
+ SelectionCanvas.Children.Add(_freehandPolyline);
+ }
private void SetupFullScreenOverlay()
{
@@ -66,10 +92,38 @@ namespace Ink_Canvas
{
// 取消截图
SelectedArea = null;
+ SelectedPath = null;
DialogResult = false;
Close();
}
}
+
+ private void RectangleModeButton_Click(object sender, RoutedEventArgs e)
+ {
+ _isFreehandMode = false;
+ RectangleModeButton.Background = new SolidColorBrush(Color.FromRgb(37, 99, 235)); // 蓝色
+ FreehandModeButton.Background = new SolidColorBrush(Color.FromRgb(107, 114, 128)); // 灰色
+ HintText.Text = "拖拽鼠标选择矩形区域";
+
+ // 清除自由绘制的内容
+ _freehandPoints.Clear();
+ _freehandPolyline.Points.Clear();
+ SelectionPath.Visibility = Visibility.Collapsed;
+ SelectionRectangle.Visibility = Visibility.Collapsed;
+ }
+
+ private void FreehandModeButton_Click(object sender, RoutedEventArgs e)
+ {
+ _isFreehandMode = true;
+ FreehandModeButton.Background = new SolidColorBrush(Color.FromRgb(37, 99, 235)); // 蓝色
+ RectangleModeButton.Background = new SolidColorBrush(Color.FromRgb(107, 114, 128)); // 灰色
+ HintText.Text = "按住鼠标左键绘制任意形状,松开完成";
+
+ // 清除矩形选择的内容
+ SelectionRectangle.Visibility = Visibility.Collapsed;
+ _freehandPoints.Clear();
+ _freehandPolyline.Points.Clear();
+ }
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
@@ -80,14 +134,28 @@ namespace Ink_Canvas
// 隐藏提示文字
HintText.Visibility = Visibility.Collapsed;
- // 显示选择矩形
- SelectionRectangle.Visibility = Visibility.Visible;
- SizeInfoBorder.Visibility = Visibility.Visible;
+ if (_isFreehandMode)
+ {
+ // 自由绘制模式
+ _freehandPoints.Clear();
+ _freehandPolyline.Points.Clear();
+ _freehandPoints.Add(_startPoint);
+ _freehandPolyline.Points.Add(_startPoint);
+ }
+ else
+ {
+ // 矩形模式
+ SelectionRectangle.Visibility = Visibility.Visible;
+ SizeInfoBorder.Visibility = Visibility.Visible;
+ }
// 捕获鼠标
CaptureMouse();
- UpdateSelection();
+ if (!_isFreehandMode)
+ {
+ UpdateSelection();
+ }
}
private void Window_MouseMove(object sender, MouseEventArgs e)
@@ -95,7 +163,18 @@ namespace Ink_Canvas
if (_isSelecting)
{
_currentPoint = e.GetPosition(this);
- UpdateSelection();
+
+ if (_isFreehandMode)
+ {
+ // 自由绘制模式:添加点到路径
+ _freehandPoints.Add(_currentPoint);
+ _freehandPolyline.Points.Add(_currentPoint);
+ }
+ else
+ {
+ // 矩形模式
+ UpdateSelection();
+ }
}
}
@@ -106,27 +185,62 @@ namespace Ink_Canvas
_isSelecting = false;
ReleaseMouseCapture();
- // 计算选择区域
- var rect = GetSelectionRectangle();
- if (rect.Width > 5 && rect.Height > 5) // 最小尺寸检查
+ if (_isFreehandMode)
{
- // 转换为屏幕坐标,考虑DPI缩放
- var dpiScale = GetDpiScale();
- var virtualScreen = System.Windows.Forms.SystemInformation.VirtualScreen;
-
- // 计算实际屏幕坐标
- int screenX = (int)((rect.X * dpiScale) + virtualScreen.Left);
- int screenY = (int)((rect.Y * dpiScale) + virtualScreen.Top);
- int screenWidth = (int)(rect.Width * dpiScale);
- int screenHeight = (int)(rect.Height * dpiScale);
-
- SelectedArea = new Rectangle(screenX, screenY, screenWidth, screenHeight);
- DialogResult = true;
+ // 自由绘制模式:完成路径
+ if (_freehandPoints.Count > 3) // 至少需要3个点形成有效路径
+ {
+ // 闭合路径
+ _freehandPoints.Add(_startPoint);
+ _freehandPolyline.Points.Add(_startPoint);
+
+ // 保存选择的路径
+ SelectedPath = new List(_freehandPoints);
+
+ // 计算边界矩形用于截图
+ var bounds = CalculatePathBounds(_freehandPoints);
+ var dpiScale = GetDpiScale();
+ var virtualScreen = System.Windows.Forms.SystemInformation.VirtualScreen;
+
+ int screenX = (int)((bounds.X * dpiScale) + virtualScreen.Left);
+ int screenY = (int)((bounds.Y * dpiScale) + virtualScreen.Top);
+ int screenWidth = (int)(bounds.Width * dpiScale);
+ int screenHeight = (int)(bounds.Height * dpiScale);
+
+ SelectedArea = new DrawingRectangle(screenX, screenY, screenWidth, screenHeight);
+ DialogResult = true;
+ }
+ else
+ {
+ SelectedArea = null;
+ SelectedPath = null;
+ DialogResult = false;
+ }
}
else
{
- SelectedArea = null;
- DialogResult = false;
+ // 矩形模式
+ var rect = GetSelectionRectangle();
+ if (rect.Width > 5 && rect.Height > 5) // 最小尺寸检查
+ {
+ // 转换为屏幕坐标,考虑DPI缩放
+ var dpiScale = GetDpiScale();
+ var virtualScreen = System.Windows.Forms.SystemInformation.VirtualScreen;
+
+ // 计算实际屏幕坐标
+ int screenX = (int)((rect.X * dpiScale) + virtualScreen.Left);
+ int screenY = (int)((rect.Y * dpiScale) + virtualScreen.Top);
+ int screenWidth = (int)(rect.Width * dpiScale);
+ int screenHeight = (int)(rect.Height * dpiScale);
+
+ SelectedArea = new DrawingRectangle(screenX, screenY, screenWidth, screenHeight);
+ DialogResult = true;
+ }
+ else
+ {
+ SelectedArea = null;
+ DialogResult = false;
+ }
}
Close();
@@ -164,5 +278,26 @@ namespace Ink_Canvas
return new Rect(x, y, width, height);
}
+
+ private Rect CalculatePathBounds(List points)
+ {
+ if (points == null || points.Count == 0)
+ return new Rect();
+
+ double minX = points[0].X;
+ double minY = points[0].Y;
+ double maxX = points[0].X;
+ double maxY = points[0].Y;
+
+ foreach (var point in points)
+ {
+ minX = Math.Min(minX, point.X);
+ minY = Math.Min(minY, point.Y);
+ maxX = Math.Max(maxX, point.X);
+ maxY = Math.Max(maxY, point.Y);
+ }
+
+ return new Rect(minX, minY, maxX - minX, maxY - minY);
+ }
}
}