improve:展台功能
This commit is contained in:
@@ -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"
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 };
|
||||||
|
|||||||
Reference in New Issue
Block a user