优化代码

This commit is contained in:
2025-08-30 19:40:14 +08:00
parent 636769c0ef
commit 96c51cd7ff
18 changed files with 368 additions and 380 deletions
+2 -2
View File
@@ -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;
// 检查是否以更新模式启动
-1
View File
@@ -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;
+2 -2
View File
@@ -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)
{
+6 -7
View File
@@ -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<UIElement>();
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);
+2 -2
View File
@@ -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)
@@ -1,4 +1,3 @@
using System;
using System.Windows.Controls;
namespace Ink_Canvas.Helpers.Plugins
@@ -1,4 +1,3 @@
using System;
using System.Windows.Controls;
namespace Ink_Canvas.Helpers.Plugins
@@ -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
@@ -1,4 +1,3 @@
using Ink_Canvas.Helpers;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
@@ -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;
+4 -4
View File
@@ -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);
}
}
@@ -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)
-4
View File
@@ -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
{
+331
View File
@@ -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<System.Windows.Point> Path;
public ScreenshotResult(Rectangle area, List<System.Windows.Point> 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<ScreenshotResult?> 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<System.Windows.Point> 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
}
}
}
-328
View File
@@ -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<System.Windows.Point> Path;
public ScreenshotResult(System.Drawing.Rectangle area, List<System.Windows.Point> 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<ScreenshotResult?> 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<System.Windows.Point> 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;
}
}
}
}
@@ -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;
@@ -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)
@@ -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<System.Windows.Point> _freehandPoints;
private Point _startPoint;
private Point _currentPoint;
private List<Point> _freehandPoints;
private Polyline _freehandPolyline;
public DrawingRectangle? SelectedArea { get; private set; }
public List<System.Windows.Point> SelectedPath { get; private set; }
public List<Point> SelectedPath { get; private set; }
public ScreenshotSelectorWindow()
{
@@ -47,7 +47,7 @@ namespace Ink_Canvas
private void InitializeFreehandMode()
{
_freehandPoints = new List<System.Windows.Point>();
_freehandPoints = new List<Point>();
_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<System.Windows.Point>(_freehandPoints);
var pathPoints = new List<Point>(_freehandPoints);
// 确保路径闭合(如果最后一个点不是起始点,则添加起始点)
if (pathPoints.Count > 0 &&
@@ -284,7 +284,7 @@ namespace Ink_Canvas
return new Rect(x, y, width, height);
}
private Rect CalculatePathBounds(List<System.Windows.Point> points)
private Rect CalculatePathBounds(List<Point> points)
{
if (points == null || points.Count == 0)
return new Rect();
@@ -306,12 +306,12 @@ namespace Ink_Canvas
}
// 优化路径:移除重复点和过于接近的点,提高路径质量
private List<System.Windows.Point> OptimizePath(List<System.Windows.Point> originalPath)
private List<Point> OptimizePath(List<Point> originalPath)
{
if (originalPath == null || originalPath.Count < 3)
return originalPath;
var optimizedPath = new List<System.Windows.Point>();
var optimizedPath = new List<Point>();
const double minDistance = 2.0; // 最小距离阈值
// 添加第一个点