From c1105df27198de6ef1c0c2039053589608c04df8 Mon Sep 17 00:00:00 2001 From: CJKmkp <2564608840@qq.com> Date: Fri, 20 Feb 2026 14:01:53 +0800 Subject: [PATCH] =?UTF-8?q?improve:=E5=B1=95=E5=8F=B0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Ink Canvas/MainWindow.xaml | 8 +-- Ink Canvas/MainWindow_cs/MW_VideoPresenter.cs | 16 +++-- Ink Canvas/Models/CapturedImage.cs | 68 ++++++++++++++++--- 3 files changed, 75 insertions(+), 17 deletions(-) diff --git a/Ink Canvas/MainWindow.xaml b/Ink Canvas/MainWindow.xaml index 5b533473..c7e411f7 100644 --- a/Ink Canvas/MainWindow.xaml +++ b/Ink Canvas/MainWindow.xaml @@ -10540,7 +10540,7 @@ - + + Checked="ToggleBtnPhotoCorrection_Checked" + Unchecked="ToggleBtnPhotoCorrection_Unchecked"> _capturedPhotos = new List(); + private const int MaxCapturedPhotos = 50; // 容量上限:比 UI 显示的 30 项多一些,避免频繁清理 // 按页绑定:每一页对应一个“实时画面”元素与布局/设备信息 private readonly Dictionary _liveFrameImageByPage = new Dictionary(); @@ -59,9 +60,9 @@ namespace Ink_Canvas if (BtnCapturePhoto != null) BtnCapturePhoto.IsEnabled = false; RefreshVideoPresenterDeviceList(); - if (CheckBoxEnablePhotoCorrection != null) + if (ToggleBtnPhotoCorrection != null) { - CheckBoxEnablePhotoCorrection.IsChecked = Settings?.Automation?.IsEnablePhotoCorrection ?? false; + ToggleBtnPhotoCorrection.IsChecked = Settings?.Automation?.IsEnablePhotoCorrection ?? false; } // 同步“上屏”按钮状态(按页绑定) @@ -447,6 +448,13 @@ namespace Ink_Canvas { var ci = new CapturedImage(bmpImage); _capturedPhotos.Insert(0, ci); + + while (_capturedPhotos.Count > MaxCapturedPhotos) + { + var oldPhoto = _capturedPhotos[_capturedPhotos.Count - 1]; + _capturedPhotos.RemoveAt(_capturedPhotos.Count - 1); + } + UpdateCapturedPhotosDisplay(); })); } @@ -476,14 +484,14 @@ namespace Ink_Canvas } } - private void CheckBoxEnablePhotoCorrection_Checked(object sender, RoutedEventArgs e) + private void ToggleBtnPhotoCorrection_Checked(object sender, RoutedEventArgs e) { if (Settings?.Automation == null) return; Settings.Automation.IsEnablePhotoCorrection = true; SaveSettingsToFile(); } - private void CheckBoxEnablePhotoCorrection_Unchecked(object sender, RoutedEventArgs e) + private void ToggleBtnPhotoCorrection_Unchecked(object sender, RoutedEventArgs e) { if (Settings?.Automation == null) return; Settings.Automation.IsEnablePhotoCorrection = false; diff --git a/Ink Canvas/Models/CapturedImage.cs b/Ink Canvas/Models/CapturedImage.cs index 60205b87..13de7fa9 100644 --- a/Ink Canvas/Models/CapturedImage.cs +++ b/Ink Canvas/Models/CapturedImage.cs @@ -14,20 +14,28 @@ namespace Ink_Canvas.Models public CapturedImage(BitmapImage image) { - Image = image; - Thumbnail = CreateThumbnail(image); + if (image == null) + throw new ArgumentNullException(nameof(image), "图像不能为空"); + + // 确保 Image 被冻结,避免跨线程访问风险 + Image = EnsureFrozen(image); + Thumbnail = CreateThumbnail(Image); Strokes = new StrokeCollection(); - Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); + Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); FilePath = null; } public CapturedImage(BitmapImage image, string filePath) { - Image = image; - Thumbnail = CreateThumbnail(image); + if (image == null) + throw new ArgumentNullException(nameof(image), "图像不能为空"); + + // 确保 Image 被冻结,避免跨线程访问风险 + Image = EnsureFrozen(image); + Thumbnail = CreateThumbnail(Image); Strokes = new StrokeCollection(); FilePath = filePath; - Timestamp = TryExtractTimestampFromFilePath(filePath) ?? DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); + Timestamp = TryExtractTimestampFromFilePath(filePath) ?? DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); } private static string TryExtractTimestampFromFilePath(string filePath) @@ -43,7 +51,7 @@ namespace Ink_Canvas.Models System.Globalization.DateTimeStyles.None, out var dt)) { - return dt.ToString("yyyy-MM-dd HH:mm:ss"); + return dt.ToString("yyyy-MM-dd HH:mm:ss.fff"); } if (name.Length >= 23) { @@ -55,7 +63,7 @@ namespace Ink_Canvas.Models System.Globalization.DateTimeStyles.None, out var dt2)) { - return dt2.ToString("yyyy-MM-dd HH:mm:ss"); + return dt2.ToString("yyyy-MM-dd HH:mm:ss.fff"); } } return null; @@ -66,11 +74,53 @@ namespace Ink_Canvas.Models } } - private BitmapImage CreateThumbnail(BitmapImage original) + private static BitmapImage EnsureFrozen(BitmapImage image) { + if (image == null) + throw new ArgumentNullException(nameof(image)); + + if (image.IsFrozen) + return image; + + var encoder = new System.Windows.Media.Imaging.PngBitmapEncoder(); + encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(image)); + + var stream = new System.IO.MemoryStream(); + encoder.Save(stream); + stream.Position = 0; + + var frozenCopy = new BitmapImage(); + frozenCopy.BeginInit(); + frozenCopy.CacheOption = BitmapCacheOption.OnLoad; + frozenCopy.StreamSource = stream; + frozenCopy.EndInit(); + frozenCopy.Freeze(); + + return frozenCopy; + } + + private static BitmapImage CreateThumbnail(BitmapImage original) + { + if (original == null) + throw new ArgumentNullException(nameof(original)); + + if (original.PixelWidth <= 0 || original.PixelHeight <= 0) + { + throw new ArgumentException( + $"图像尺寸无效:宽度={original.PixelWidth}, 高度={original.PixelHeight}。图像必须具有有效的像素尺寸。", + nameof(original)); + } + double targetWidth = 290.0; double targetHeight = 180.0; double scale = Math.Min(targetWidth / original.PixelWidth, targetHeight / original.PixelHeight); + + if (double.IsInfinity(scale) || double.IsNaN(scale) || scale <= 0) + { + throw new InvalidOperationException( + $"无法计算有效的缩放比例:scale={scale}, 图像尺寸={original.PixelWidth}x{original.PixelHeight}"); + } + var thumbnail = new TransformedBitmap(original, new System.Windows.Media.ScaleTransform(scale, scale)); var bmp = new JpegBitmapEncoder { QualityLevel = 85 };