improve:截图

This commit is contained in:
2025-09-13 13:59:54 +08:00
parent a7d1de5ee3
commit 98d4a4213c
6 changed files with 700 additions and 37 deletions
+261
View File
@@ -0,0 +1,261 @@
using AForge.Video;
using AForge.Video.DirectShow;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
namespace Ink_Canvas.Helpers
{
public class CameraService : IDisposable
{
private VideoCaptureDevice _videoSource;
private bool _isCapturing;
private Bitmap _currentFrame;
private readonly object _frameLock = new object();
private Dispatcher _dispatcher;
public event EventHandler<Bitmap> FrameReceived;
public event EventHandler<string> ErrorOccurred;
public bool IsCapturing => _isCapturing;
public List<FilterInfo> AvailableCameras { get; private set; }
public FilterInfo CurrentCamera { get; private set; }
public CameraService()
{
_dispatcher = Dispatcher.CurrentDispatcher;
AvailableCameras = new List<FilterInfo>();
RefreshCameraList();
}
/// <summary>
/// 刷新可用摄像头列表
/// </summary>
public void RefreshCameraList()
{
try
{
AvailableCameras.Clear();
var videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
foreach (FilterInfo device in videoDevices)
{
AvailableCameras.Add(device);
}
LogHelper.WriteLogToFile($"发现 {AvailableCameras.Count} 个摄像头设备");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"刷新摄像头列表失败: {ex.Message}", LogHelper.LogType.Error);
ErrorOccurred?.Invoke(this, $"刷新摄像头列表失败: {ex.Message}");
}
}
/// <summary>
/// 开始摄像头预览
/// </summary>
/// <param name="cameraIndex">摄像头索引</param>
public bool StartPreview(int cameraIndex = 0)
{
try
{
if (AvailableCameras.Count == 0)
{
RefreshCameraList();
if (AvailableCameras.Count == 0)
{
ErrorOccurred?.Invoke(this, "未找到可用的摄像头设备");
return false;
}
}
if (cameraIndex < 0 || cameraIndex >= AvailableCameras.Count)
{
ErrorOccurred?.Invoke(this, "摄像头索引超出范围");
return false;
}
// 停止当前预览
StopPreview();
CurrentCamera = AvailableCameras[cameraIndex];
_videoSource = new VideoCaptureDevice(CurrentCamera.MonikerString);
// 设置视频源事件处理
_videoSource.NewFrame += VideoSource_NewFrame;
// 启动视频源
_videoSource.Start();
_isCapturing = true;
LogHelper.WriteLogToFile($"开始摄像头预览: {CurrentCamera.Name}");
return true;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"启动摄像头预览失败: {ex.Message}", LogHelper.LogType.Error);
ErrorOccurred?.Invoke(this, $"启动摄像头预览失败: {ex.Message}");
return false;
}
}
/// <summary>
/// 停止摄像头预览
/// </summary>
public void StopPreview()
{
try
{
if (_videoSource != null && _videoSource.IsRunning)
{
_videoSource.SignalToStop();
_videoSource.WaitForStop();
_videoSource.NewFrame -= VideoSource_NewFrame;
_videoSource = null;
}
_isCapturing = false;
LogHelper.WriteLogToFile("摄像头预览已停止");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"停止摄像头预览失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 切换到指定摄像头
/// </summary>
/// <param name="cameraIndex">摄像头索引</param>
public bool SwitchCamera(int cameraIndex)
{
try
{
if (cameraIndex < 0 || cameraIndex >= AvailableCameras.Count)
{
ErrorOccurred?.Invoke(this, "摄像头索引超出范围");
return false;
}
return StartPreview(cameraIndex);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"切换摄像头失败: {ex.Message}", LogHelper.LogType.Error);
ErrorOccurred?.Invoke(this, $"切换摄像头失败: {ex.Message}");
return false;
}
}
/// <summary>
/// 获取当前帧的Bitmap
/// </summary>
public Bitmap GetCurrentFrame()
{
lock (_frameLock)
{
return _currentFrame?.Clone() as Bitmap;
}
}
/// <summary>
/// 获取当前帧的BitmapSourceWPF格式)
/// </summary>
public BitmapSource GetCurrentFrameAsBitmapSource()
{
lock (_frameLock)
{
if (_currentFrame == null)
return null;
try
{
using (var memory = new MemoryStream())
{
_currentFrame.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($"转换帧为BitmapSource失败: {ex.Message}", LogHelper.LogType.Error);
return null;
}
}
}
/// <summary>
/// 视频源新帧事件处理
/// </summary>
private void VideoSource_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
try
{
lock (_frameLock)
{
// 释放之前的帧
_currentFrame?.Dispose();
// 克隆新帧
_currentFrame = eventArgs.Frame.Clone() as Bitmap;
}
// 在UI线程中触发事件
_dispatcher.BeginInvoke(new Action(() =>
{
FrameReceived?.Invoke(this, _currentFrame);
}));
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理新帧失败: {ex.Message}", LogHelper.LogType.Error);
ErrorOccurred?.Invoke(this, $"处理新帧失败: {ex.Message}");
}
}
/// <summary>
/// 获取摄像头名称列表
/// </summary>
public List<string> GetCameraNames()
{
return AvailableCameras.Select(camera => camera.Name).ToList();
}
/// <summary>
/// 检查是否有可用摄像头
/// </summary>
public bool HasAvailableCameras()
{
if (AvailableCameras.Count == 0)
{
RefreshCameraList();
}
return AvailableCameras.Count > 0;
}
public void Dispose()
{
StopPreview();
lock (_frameLock)
{
_currentFrame?.Dispose();
}
}
}
}
+2
View File
@@ -158,6 +158,8 @@
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="NHotkey.Wpf" Version="3.0.0" /> <PackageReference Include="NHotkey.Wpf" Version="3.0.0" />
<PackageReference Include="OSVersionExt" Version="3.0.0" /> <PackageReference Include="OSVersionExt" Version="3.0.0" />
<PackageReference Include="AForge.Video" Version="2.2.5" />
<PackageReference Include="AForge.Video.DirectShow" Version="2.2.5" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<COMReference Include="IWshRuntimeLibrary"> <COMReference Include="IWshRuntimeLibrary">
+49 -26
View File
@@ -27,11 +27,13 @@ namespace Ink_Canvas
{ {
public Rectangle Area; public Rectangle Area;
public List<Point> Path; public List<Point> Path;
public Bitmap CameraImage;
public ScreenshotResult(Rectangle area, List<Point> path = null) public ScreenshotResult(Rectangle area, List<Point> path = null, Bitmap cameraImage = null)
{ {
Area = area; Area = area;
Path = path; Path = path;
CameraImage = cameraImage;
} }
} }
@@ -55,34 +57,43 @@ namespace Ink_Canvas
// 恢复窗口显示 // 恢复窗口显示
Visibility = originalVisibility; Visibility = originalVisibility;
if (screenshotResult.HasValue && screenshotResult.Value.Area.Width > 0 && screenshotResult.Value.Area.Height > 0) if (screenshotResult.HasValue)
{ {
// 截取选定区域 // 检查是否是摄像头截图
using (var originalBitmap = CaptureScreenArea(screenshotResult.Value.Area)) if (screenshotResult.Value.CameraImage != null)
{ {
if (originalBitmap != null) // 摄像头截图
await InsertScreenshotToCanvas(screenshotResult.Value.CameraImage);
}
else if (screenshotResult.Value.Area.Width > 0 && screenshotResult.Value.Area.Height > 0)
{
// 屏幕截图
using (var originalBitmap = CaptureScreenArea(screenshotResult.Value.Area))
{ {
Bitmap finalBitmap = originalBitmap; if (originalBitmap != null)
bool needDisposeFinalBitmap = false;
try
{ {
// 如果有路径信息,应用形状遮罩 Bitmap finalBitmap = originalBitmap;
if (screenshotResult.Value.Path != null && screenshotResult.Value.Path.Count > 0) bool needDisposeFinalBitmap = false;
try
{ {
finalBitmap = ApplyShapeMask(originalBitmap, screenshotResult.Value.Path, screenshotResult.Value.Area); // 如果有路径信息,应用形状遮罩
needDisposeFinalBitmap = true; // 标记需要释放新创建的位图 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
// 将截图转换为WPF Image并插入到画布
await InsertScreenshotToCanvas(finalBitmap);
}
finally
{
// 如果创建了新的位图,需要释放它
if (needDisposeFinalBitmap && finalBitmap != originalBitmap)
{ {
finalBitmap.Dispose(); // 如果创建了新的位图,需要释放它
if (needDisposeFinalBitmap && finalBitmap != originalBitmap)
{
finalBitmap.Dispose();
}
} }
} }
} }
@@ -152,10 +163,22 @@ namespace Ink_Canvas
var selectorWindow = new ScreenshotSelectorWindow(); var selectorWindow = new ScreenshotSelectorWindow();
if (selectorWindow.ShowDialog() == true) if (selectorWindow.ShowDialog() == true)
{ {
result = new ScreenshotResult( // 检查是否是摄像头截图
selectorWindow.SelectedArea.Value, if (selectorWindow.CameraImage != null)
selectorWindow.SelectedPath {
); result = new ScreenshotResult(
Rectangle.Empty, // 摄像头截图不需要区域
null, // 摄像头截图不需要路径
selectorWindow.CameraImage // 摄像头图像
);
}
else
{
result = new ScreenshotResult(
selectorWindow.SelectedArea.Value,
selectorWindow.SelectedPath
);
}
} }
}); });
} }
@@ -124,6 +124,15 @@
BorderThickness="0" BorderThickness="0"
FontWeight="Medium" FontWeight="Medium"
Click="FullScreenButton_Click" /> Click="FullScreenButton_Click" />
<Button Name="CameraModeButton"
Content="摄像头截图"
Margin="4,0"
Padding="12,6"
Background="#6b7280"
Foreground="White"
BorderThickness="0"
FontWeight="Medium"
Click="CameraModeButton_Click" />
<!-- 分隔线 --> <!-- 分隔线 -->
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" <Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}"
@@ -152,6 +161,68 @@
</StackPanel> </StackPanel>
</Border> </Border>
<!-- 摄像头预览区域 -->
<Border Name="CameraPreviewBorder"
Background="#1a1a1a"
Opacity="0.95"
CornerRadius="8"
Padding="8"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Width="640"
Height="480"
Visibility="Collapsed"
Panel.ZIndex="1000">
<Grid>
<!-- 摄像头预览画面 -->
<Image Name="CameraPreviewImage"
Stretch="Uniform"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<!-- 摄像头控制面板 -->
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
Margin="0,0,0,8">
<!-- 摄像头选择下拉框 -->
<ComboBox Name="CameraSelectionComboBox"
Width="200"
Margin="4,0"
Background="#2d2d2d"
Foreground="White"
BorderBrush="#404040"
SelectionChanged="CameraSelectionComboBox_SelectionChanged" />
<!-- 切换摄像头按钮 -->
<Button Name="SwitchCameraButton"
Content="切换摄像头"
Margin="4,0"
Padding="8,4"
Background="#3b82f6"
Foreground="White"
BorderThickness="0"
FontWeight="Medium"
Click="SwitchCameraButton_Click" />
</StackPanel>
<!-- 摄像头状态指示 -->
<Border Background="#1a1a1a"
Opacity="0.9"
CornerRadius="4"
Padding="8,4"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="8">
<TextBlock Name="CameraStatusText"
Foreground="White"
FontSize="12"
FontWeight="Medium"
Text="摄像头未连接" />
</Border>
</Grid>
</Border>
<!-- 统一提示文字区域 --> <!-- 统一提示文字区域 -->
<Border Name="HintTextBorder" <Border Name="HintTextBorder"
Background="#1a1a1a" Background="#1a1a1a"
@@ -7,9 +7,13 @@ using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Shapes; using System.Windows.Shapes;
using System.Windows.Threading; using System.Windows.Threading;
using System.Drawing;
using Ink_Canvas.Helpers;
using Brushes = System.Windows.Media.Brushes; using Brushes = System.Windows.Media.Brushes;
using Color = System.Windows.Media.Color; using Color = System.Windows.Media.Color;
using DrawingRectangle = System.Drawing.Rectangle; using DrawingRectangle = System.Drawing.Rectangle;
using DrawingPoint = System.Drawing.Point;
using WpfPoint = System.Windows.Point;
using KeyEventArgs = System.Windows.Input.KeyEventArgs; using KeyEventArgs = System.Windows.Input.KeyEventArgs;
using MouseEventArgs = System.Windows.Input.MouseEventArgs; using MouseEventArgs = System.Windows.Input.MouseEventArgs;
using WpfCanvas = System.Windows.Controls.Canvas; using WpfCanvas = System.Windows.Controls.Canvas;
@@ -22,13 +26,16 @@ namespace Ink_Canvas
private bool _isFreehandMode; private bool _isFreehandMode;
private bool _isAdjusting; private bool _isAdjusting;
private bool _isMoving; private bool _isMoving;
private Point _startPoint; private bool _isCameraMode;
private Point _currentPoint; private WpfPoint _startPoint;
private Point _lastMousePosition; private WpfPoint _currentPoint;
private List<Point> _freehandPoints; private WpfPoint _lastMousePosition;
private List<WpfPoint> _freehandPoints;
private Polyline _freehandPolyline; private Polyline _freehandPolyline;
private Rect _currentSelection; private Rect _currentSelection;
private ControlPointType _activeControlPoint = ControlPointType.None; private ControlPointType _activeControlPoint = ControlPointType.None;
private CameraService _cameraService;
private Bitmap _capturedCameraImage;
// 控制点类型枚举 // 控制点类型枚举
private enum ControlPointType private enum ControlPointType
@@ -40,7 +47,8 @@ namespace Ink_Canvas
} }
public DrawingRectangle? SelectedArea { get; private set; } public DrawingRectangle? SelectedArea { get; private set; }
public List<Point> SelectedPath { get; private set; } public List<WpfPoint> SelectedPath { get; private set; }
public Bitmap CameraImage { get; private set; }
public ScreenshotSelectorWindow() public ScreenshotSelectorWindow()
{ {
@@ -58,6 +66,9 @@ namespace Ink_Canvas
// 初始化按钮状态 // 初始化按钮状态
InitializeButtonStates(); InitializeButtonStates();
// 初始化摄像头服务
InitializeCameraService();
// 隐藏提示文字的定时器 // 隐藏提示文字的定时器
var timer = new DispatcherTimer(); var timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(5); timer.Interval = TimeSpan.FromSeconds(5);
@@ -71,7 +82,7 @@ namespace Ink_Canvas
private void InitializeFreehandMode() private void InitializeFreehandMode()
{ {
_freehandPoints = new List<Point>(); _freehandPoints = new List<WpfPoint>();
_freehandPolyline = new Polyline _freehandPolyline = new Polyline
{ {
Stroke = Brushes.White, Stroke = Brushes.White,
@@ -86,6 +97,126 @@ namespace Ink_Canvas
RectangleModeButton.Background = new SolidColorBrush(Color.FromRgb(107, 114, 128)); // 灰色 RectangleModeButton.Background = new SolidColorBrush(Color.FromRgb(107, 114, 128)); // 灰色
FreehandModeButton.Background = new SolidColorBrush(Color.FromRgb(107, 114, 128)); // 灰色 FreehandModeButton.Background = new SolidColorBrush(Color.FromRgb(107, 114, 128)); // 灰色
FullScreenButton.Background = new SolidColorBrush(Color.FromRgb(107, 114, 128)); // 灰色 FullScreenButton.Background = new SolidColorBrush(Color.FromRgb(107, 114, 128)); // 灰色
CameraModeButton.Background = new SolidColorBrush(Color.FromRgb(107, 114, 128)); // 灰色
}
private void InitializeCameraService()
{
try
{
_cameraService = new CameraService();
_cameraService.FrameReceived += CameraService_FrameReceived;
_cameraService.ErrorOccurred += CameraService_ErrorOccurred;
// 初始化摄像头选择下拉框
RefreshCameraComboBox();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"初始化摄像头服务失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private void RefreshCameraComboBox()
{
try
{
CameraSelectionComboBox.Items.Clear();
if (_cameraService.HasAvailableCameras())
{
var cameraNames = _cameraService.GetCameraNames();
foreach (var name in cameraNames)
{
CameraSelectionComboBox.Items.Add(name);
}
if (cameraNames.Count > 0)
{
CameraSelectionComboBox.SelectedIndex = 0;
}
}
else
{
CameraSelectionComboBox.Items.Add("未找到摄像头设备");
CameraSelectionComboBox.SelectedIndex = 0;
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"刷新摄像头列表失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private void CameraService_FrameReceived(object sender, Bitmap frame)
{
try
{
Dispatcher.BeginInvoke(new Action(() =>
{
if (_isCameraMode && CameraPreviewImage != null && frame != null)
{
// 克隆帧以避免在转换过程中被释放
using (var clonedFrame = frame.Clone() as Bitmap)
{
if (clonedFrame != null)
{
var bitmapSource = ConvertBitmapToBitmapSource(clonedFrame);
if (bitmapSource != null)
{
CameraPreviewImage.Source = bitmapSource;
CameraStatusText.Text = "摄像头已连接";
}
}
}
}
}));
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理摄像头帧失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private void CameraService_ErrorOccurred(object sender, string error)
{
try
{
Dispatcher.BeginInvoke(new Action(() =>
{
CameraStatusText.Text = $"摄像头错误: {error}";
}));
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理摄像头错误失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private System.Windows.Media.Imaging.BitmapSource ConvertBitmapToBitmapSource(Bitmap bitmap)
{
try
{
using (var memory = new System.IO.MemoryStream())
{
bitmap.Save(memory, System.Drawing.Imaging.ImageFormat.Png);
memory.Position = 0;
var bitmapImage = new System.Windows.Media.Imaging.BitmapImage();
bitmapImage.BeginInit();
bitmapImage.CacheOption = System.Windows.Media.Imaging.BitmapCacheOption.OnLoad;
bitmapImage.StreamSource = memory;
bitmapImage.EndInit();
bitmapImage.Freeze();
return bitmapImage;
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"转换位图失败: {ex.Message}", LogHelper.LogType.Error);
return null;
}
} }
private void BindControlPointEvents() private void BindControlPointEvents()
@@ -181,14 +312,100 @@ namespace Ink_Canvas
// 设置全屏截图模式 // 设置全屏截图模式
_isFreehandMode = false; _isFreehandMode = false;
_isCameraMode = false;
FullScreenButton.Background = new SolidColorBrush(Color.FromRgb(37, 99, 235)); // 蓝色 FullScreenButton.Background = new SolidColorBrush(Color.FromRgb(37, 99, 235)); // 蓝色
RectangleModeButton.Background = new SolidColorBrush(Color.FromRgb(107, 114, 128)); // 灰色 RectangleModeButton.Background = new SolidColorBrush(Color.FromRgb(107, 114, 128)); // 灰色
FreehandModeButton.Background = new SolidColorBrush(Color.FromRgb(107, 114, 128)); // 灰色 FreehandModeButton.Background = new SolidColorBrush(Color.FromRgb(107, 114, 128)); // 灰色
CameraModeButton.Background = new SolidColorBrush(Color.FromRgb(107, 114, 128)); // 灰色
// 隐藏摄像头预览
CameraPreviewBorder.Visibility = Visibility.Collapsed;
// 直接执行全屏截图 // 直接执行全屏截图
PerformFullScreenCapture(); PerformFullScreenCapture();
} }
private void CameraModeButton_Click(object sender, RoutedEventArgs e)
{
try
{
// 重置所有选择状态
ResetSelectionState();
// 设置摄像头模式
_isFreehandMode = false;
_isCameraMode = true;
CameraModeButton.Background = new SolidColorBrush(Color.FromRgb(37, 99, 235)); // 蓝色
RectangleModeButton.Background = new SolidColorBrush(Color.FromRgb(107, 114, 128)); // 灰色
FreehandModeButton.Background = new SolidColorBrush(Color.FromRgb(107, 114, 128)); // 灰色
FullScreenButton.Background = new SolidColorBrush(Color.FromRgb(107, 114, 128)); // 灰色
// 显示摄像头预览
CameraPreviewBorder.Visibility = Visibility.Visible;
HintText.Text = "摄像头预览模式,点击确认截图按钮进行截图";
HintTextBorder.Visibility = Visibility.Visible;
// 启动摄像头预览
if (_cameraService != null && _cameraService.HasAvailableCameras())
{
var selectedIndex = CameraSelectionComboBox.SelectedIndex;
if (selectedIndex >= 0 && selectedIndex < _cameraService.GetCameraNames().Count)
{
_cameraService.StartPreview(selectedIndex);
}
}
else
{
CameraStatusText.Text = "未找到摄像头设备";
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"启动摄像头模式失败: {ex.Message}", LogHelper.LogType.Error);
CameraStatusText.Text = $"启动摄像头失败: {ex.Message}";
}
}
private void CameraSelectionComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
try
{
if (_isCameraMode && _cameraService != null)
{
var selectedIndex = CameraSelectionComboBox.SelectedIndex;
if (selectedIndex >= 0 && selectedIndex < _cameraService.GetCameraNames().Count)
{
_cameraService.SwitchCamera(selectedIndex);
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"切换摄像头失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private void SwitchCameraButton_Click(object sender, RoutedEventArgs e)
{
try
{
if (_cameraService != null && _cameraService.HasAvailableCameras())
{
var cameraNames = _cameraService.GetCameraNames();
if (cameraNames.Count > 1)
{
var currentIndex = CameraSelectionComboBox.SelectedIndex;
var nextIndex = (currentIndex + 1) % cameraNames.Count;
CameraSelectionComboBox.SelectedIndex = nextIndex;
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"切换摄像头失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private void ConfirmButton_Click(object sender, RoutedEventArgs e) private void ConfirmButton_Click(object sender, RoutedEventArgs e)
{ {
// 在自由绘制模式下,确认按钮不执行任何操作 // 在自由绘制模式下,确认按钮不执行任何操作
@@ -197,9 +414,53 @@ namespace Ink_Canvas
return; return;
} }
// 在摄像头模式下,执行摄像头截图
if (_isCameraMode)
{
ConfirmCameraCapture();
return;
}
ConfirmSelection(); ConfirmSelection();
} }
private void ConfirmCameraCapture()
{
try
{
if (_cameraService != null && _cameraService.IsCapturing)
{
// 获取当前帧
var currentFrame = _cameraService.GetCurrentFrame();
if (currentFrame != null)
{
// 保存摄像头图像
CameraImage = currentFrame.Clone() as Bitmap;
// 停止摄像头预览
_cameraService.StopPreview();
// 设置结果并关闭窗口
DialogResult = true;
Close();
}
else
{
CameraStatusText.Text = "无法获取摄像头画面";
}
}
else
{
CameraStatusText.Text = "摄像头未启动";
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"摄像头截图失败: {ex.Message}", LogHelper.LogType.Error);
CameraStatusText.Text = $"摄像头截图失败: {ex.Message}";
}
}
private void CancelButton_Click(object sender, RoutedEventArgs e) private void CancelButton_Click(object sender, RoutedEventArgs e)
{ {
CancelSelection(); CancelSelection();
@@ -317,7 +578,7 @@ namespace Ink_Canvas
if (_freehandPoints.Count > 1) // 只要有点就可以截图 if (_freehandPoints.Count > 1) // 只要有点就可以截图
{ {
// 创建路径的副本,避免修改原始列表 // 创建路径的副本,避免修改原始列表
var pathPoints = new List<Point>(_freehandPoints); var pathPoints = new List<WpfPoint>(_freehandPoints);
// 简化路径处理,不强制闭合 // 简化路径处理,不强制闭合
// 如果路径没有闭合,自动添加起始点 // 如果路径没有闭合,自动添加起始点
@@ -661,13 +922,20 @@ namespace Ink_Canvas
private void CancelSelection() private void CancelSelection()
{ {
// 停止摄像头预览
if (_cameraService != null)
{
_cameraService.StopPreview();
}
SelectedArea = null; SelectedArea = null;
SelectedPath = null; SelectedPath = null;
CameraImage = null;
DialogResult = false; DialogResult = false;
Close(); Close();
} }
private Rect CalculatePathBounds(List<Point> points) private Rect CalculatePathBounds(List<WpfPoint> points)
{ {
if (points == null || points.Count == 0) if (points == null || points.Count == 0)
return new Rect(); return new Rect();
@@ -688,12 +956,12 @@ namespace Ink_Canvas
return new Rect(minX, minY, maxX - minX, maxY - minY); return new Rect(minX, minY, maxX - minX, maxY - minY);
} }
private List<Point> OptimizePath(List<Point> points) private List<WpfPoint> OptimizePath(List<WpfPoint> points)
{ {
if (points == null || points.Count < 3) if (points == null || points.Count < 3)
return points; return points;
var optimized = new List<Point>(); var optimized = new List<WpfPoint>();
optimized.Add(points[0]); optimized.Add(points[0]);
for (int i = 1; i < points.Count - 1; i++) for (int i = 1; i < points.Count - 1; i++)
@@ -716,7 +984,7 @@ namespace Ink_Canvas
return optimized; return optimized;
} }
private double DistanceToLine(Point point, Point lineStart, Point lineEnd) private double DistanceToLine(WpfPoint point, WpfPoint lineStart, WpfPoint lineEnd)
{ {
var A = point.X - lineStart.X; var A = point.X - lineStart.X;
var B = point.Y - lineStart.Y; var B = point.Y - lineStart.Y;
@@ -844,8 +1112,15 @@ namespace Ink_Canvas
_isSelecting = false; _isSelecting = false;
_isAdjusting = false; _isAdjusting = false;
_isMoving = false; _isMoving = false;
_isCameraMode = false;
_activeControlPoint = ControlPointType.None; _activeControlPoint = ControlPointType.None;
// 停止摄像头预览
if (_cameraService != null)
{
_cameraService.StopPreview();
}
// 清除自由绘制的内容 // 清除自由绘制的内容
_freehandPoints.Clear(); _freehandPoints.Clear();
_freehandPolyline.Points.Clear(); _freehandPolyline.Points.Clear();
@@ -859,6 +1134,9 @@ namespace Ink_Canvas
SelectionPath.Visibility = Visibility.Collapsed; SelectionPath.Visibility = Visibility.Collapsed;
HintTextBorder.Visibility = Visibility.Collapsed; HintTextBorder.Visibility = Visibility.Collapsed;
// 隐藏摄像头预览
CameraPreviewBorder.Visibility = Visibility.Collapsed;
// 重置遮罩 // 重置遮罩
TransparentSelectionMask.Visibility = Visibility.Collapsed; TransparentSelectionMask.Visibility = Visibility.Collapsed;
OverlayRectangle.Visibility = Visibility.Visible; OverlayRectangle.Visibility = Visibility.Visible;
@@ -879,10 +1157,38 @@ namespace Ink_Canvas
_currentSelection = new Rect(); _currentSelection = new Rect();
SelectedArea = null; SelectedArea = null;
SelectedPath = null; SelectedPath = null;
CameraImage = null;
RectangleModeButton.Background = new SolidColorBrush(Color.FromRgb(107, 114, 128)); // 灰色 RectangleModeButton.Background = new SolidColorBrush(Color.FromRgb(107, 114, 128)); // 灰色
FreehandModeButton.Background = new SolidColorBrush(Color.FromRgb(107, 114, 128)); // 灰色 FreehandModeButton.Background = new SolidColorBrush(Color.FromRgb(107, 114, 128)); // 灰色
FullScreenButton.Background = new SolidColorBrush(Color.FromRgb(107, 114, 128)); // 灰色 FullScreenButton.Background = new SolidColorBrush(Color.FromRgb(107, 114, 128)); // 灰色
CameraModeButton.Background = new SolidColorBrush(Color.FromRgb(107, 114, 128)); // 灰色
}
protected override void OnClosed(EventArgs e)
{
try
{
// 清理摄像头资源
if (_cameraService != null)
{
_cameraService.StopPreview();
_cameraService.Dispose();
_cameraService = null;
}
// 清理摄像头图像
_capturedCameraImage?.Dispose();
CameraImage?.Dispose();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清理资源失败: {ex.Message}", LogHelper.LogType.Error);
}
finally
{
base.OnClosed(e);
}
} }
} }
} }