improve:展台功能

This commit is contained in:
2026-02-20 14:01:53 +08:00
parent 8292b2ef25
commit c1105df271
3 changed files with 75 additions and 17 deletions
+4 -4
View File
@@ -10540,7 +10540,7 @@
</Border> </Border>
<!-- 底部按钮区域 --> <!-- 底部按钮区域 -->
<Grid Grid.Row="4" Height="Auto" Margin="0,0,0,6"> <Grid Grid.Row="4" Margin="0,0,0,6">
<WrapPanel <WrapPanel
Margin="10,5" Margin="10,5"
HorizontalAlignment="Center" HorizontalAlignment="Center"
@@ -10563,14 +10563,14 @@
Text="上屏" /> Text="上屏" />
</ToggleButton> </ToggleButton>
<ToggleButton <ToggleButton
x:Name="CheckBoxEnablePhotoCorrection" x:Name="ToggleBtnPhotoCorrection"
Height="40" Height="40"
Margin="3,0" Margin="3,0"
Background="{DynamicResource FloatBarBackground}" Background="{DynamicResource FloatBarBackground}"
BorderBrush="{DynamicResource FloatBarBorderBrush}" BorderBrush="{DynamicResource FloatBarBorderBrush}"
BorderThickness="1" BorderThickness="1"
Checked="CheckBoxEnablePhotoCorrection_Checked" Checked="ToggleBtnPhotoCorrection_Checked"
Unchecked="CheckBoxEnablePhotoCorrection_Unchecked"> Unchecked="ToggleBtnPhotoCorrection_Unchecked">
<TextBlock <TextBlock
FontSize="12" FontSize="12"
FontWeight="SemiBold" FontWeight="SemiBold"
+12 -4
View File
@@ -26,6 +26,7 @@ namespace Ink_Canvas
private Bitmap _lastFrame; private Bitmap _lastFrame;
private readonly List<CapturedImage> _capturedPhotos = new List<CapturedImage>(); private readonly List<CapturedImage> _capturedPhotos = new List<CapturedImage>();
private const int MaxCapturedPhotos = 50; // 容量上限:比 UI 显示的 30 项多一些,避免频繁清理
// 按页绑定:每一页对应一个“实时画面”元素与布局/设备信息 // 按页绑定:每一页对应一个“实时画面”元素与布局/设备信息
private readonly Dictionary<int, System.Windows.Controls.Image> _liveFrameImageByPage = new Dictionary<int, System.Windows.Controls.Image>(); private readonly Dictionary<int, System.Windows.Controls.Image> _liveFrameImageByPage = new Dictionary<int, System.Windows.Controls.Image>();
@@ -59,9 +60,9 @@ namespace Ink_Canvas
if (BtnCapturePhoto != null) BtnCapturePhoto.IsEnabled = false; if (BtnCapturePhoto != null) BtnCapturePhoto.IsEnabled = false;
RefreshVideoPresenterDeviceList(); 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); var ci = new CapturedImage(bmpImage);
_capturedPhotos.Insert(0, ci); _capturedPhotos.Insert(0, ci);
while (_capturedPhotos.Count > MaxCapturedPhotos)
{
var oldPhoto = _capturedPhotos[_capturedPhotos.Count - 1];
_capturedPhotos.RemoveAt(_capturedPhotos.Count - 1);
}
UpdateCapturedPhotosDisplay(); 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; if (Settings?.Automation == null) return;
Settings.Automation.IsEnablePhotoCorrection = true; Settings.Automation.IsEnablePhotoCorrection = true;
SaveSettingsToFile(); SaveSettingsToFile();
} }
private void CheckBoxEnablePhotoCorrection_Unchecked(object sender, RoutedEventArgs e) private void ToggleBtnPhotoCorrection_Unchecked(object sender, RoutedEventArgs e)
{ {
if (Settings?.Automation == null) return; if (Settings?.Automation == null) return;
Settings.Automation.IsEnablePhotoCorrection = false; Settings.Automation.IsEnablePhotoCorrection = false;
+59 -9
View File
@@ -14,20 +14,28 @@ namespace Ink_Canvas.Models
public CapturedImage(BitmapImage image) public CapturedImage(BitmapImage image)
{ {
Image = image; if (image == null)
Thumbnail = CreateThumbnail(image); throw new ArgumentNullException(nameof(image), "图像不能为空");
// 确保 Image 被冻结,避免跨线程访问风险
Image = EnsureFrozen(image);
Thumbnail = CreateThumbnail(Image);
Strokes = new StrokeCollection(); 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; FilePath = null;
} }
public CapturedImage(BitmapImage image, string filePath) public CapturedImage(BitmapImage image, string filePath)
{ {
Image = image; if (image == null)
Thumbnail = CreateThumbnail(image); throw new ArgumentNullException(nameof(image), "图像不能为空");
// 确保 Image 被冻结,避免跨线程访问风险
Image = EnsureFrozen(image);
Thumbnail = CreateThumbnail(Image);
Strokes = new StrokeCollection(); Strokes = new StrokeCollection();
FilePath = filePath; 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) private static string TryExtractTimestampFromFilePath(string filePath)
@@ -43,7 +51,7 @@ namespace Ink_Canvas.Models
System.Globalization.DateTimeStyles.None, System.Globalization.DateTimeStyles.None,
out var dt)) 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) if (name.Length >= 23)
{ {
@@ -55,7 +63,7 @@ namespace Ink_Canvas.Models
System.Globalization.DateTimeStyles.None, System.Globalization.DateTimeStyles.None,
out var dt2)) out var dt2))
{ {
return dt2.ToString("yyyy-MM-dd HH:mm:ss"); return dt2.ToString("yyyy-MM-dd HH:mm:ss.fff");
} }
} }
return null; 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 targetWidth = 290.0;
double targetHeight = 180.0; double targetHeight = 180.0;
double scale = Math.Min(targetWidth / original.PixelWidth, targetHeight / original.PixelHeight); 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 thumbnail = new TransformedBitmap(original, new System.Windows.Media.ScaleTransform(scale, scale));
var bmp = new JpegBitmapEncoder { QualityLevel = 85 }; var bmp = new JpegBitmapEncoder { QualityLevel = 85 };