improve:截图
This commit is contained in:
@@ -154,51 +154,91 @@ namespace Ink_Canvas.Helpers
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取当前帧的Bitmap
|
/// 获取当前帧的BitmapSource(WPF格式),直接返回可用的WPF位图
|
||||||
/// </summary>
|
|
||||||
public Bitmap GetCurrentFrame()
|
|
||||||
{
|
|
||||||
lock (_frameLock)
|
|
||||||
{
|
|
||||||
return _currentFrame?.Clone() as Bitmap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前帧的BitmapSource(WPF格式)
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public BitmapSource GetCurrentFrameAsBitmapSource()
|
public BitmapSource GetCurrentFrameAsBitmapSource()
|
||||||
{
|
{
|
||||||
lock (_frameLock)
|
lock (_frameLock)
|
||||||
{
|
{
|
||||||
if (_currentFrame == null)
|
if (_currentFrame == null)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile("GetCurrentFrameAsBitmapSource: _currentFrame为null");
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var memory = new MemoryStream())
|
LogHelper.WriteLogToFile($"GetCurrentFrameAsBitmapSource: 开始处理帧,类型={_currentFrame.GetType().FullName}");
|
||||||
|
LogHelper.WriteLogToFile($"GetCurrentFrameAsBitmapSource: 帧HashCode={_currentFrame.GetHashCode()}");
|
||||||
|
|
||||||
|
// 验证当前帧的有效性
|
||||||
|
var width = _currentFrame.Width;
|
||||||
|
var height = _currentFrame.Height;
|
||||||
|
LogHelper.WriteLogToFile($"GetCurrentFrameAsBitmapSource: 当前帧尺寸={width}x{height}");
|
||||||
|
|
||||||
|
// 验证位图有效性
|
||||||
|
if (width <= 0 || height <= 0)
|
||||||
{
|
{
|
||||||
_currentFrame.Save(memory, ImageFormat.Png);
|
LogHelper.WriteLogToFile("当前帧无效: 尺寸为0", LogHelper.LogType.Warning);
|
||||||
memory.Position = 0;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
var bitmapImage = new BitmapImage();
|
// 使用更安全的方法转换位图
|
||||||
bitmapImage.BeginInit();
|
var bitmapData = _currentFrame.LockBits(
|
||||||
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
|
new Rectangle(0, 0, width, height),
|
||||||
bitmapImage.StreamSource = memory;
|
ImageLockMode.ReadOnly,
|
||||||
bitmapImage.EndInit();
|
_currentFrame.PixelFormat);
|
||||||
bitmapImage.Freeze();
|
|
||||||
|
|
||||||
return bitmapImage;
|
try
|
||||||
|
{
|
||||||
|
// 根据像素格式选择合适的WPF像素格式
|
||||||
|
System.Windows.Media.PixelFormat wpfPixelFormat;
|
||||||
|
switch (_currentFrame.PixelFormat)
|
||||||
|
{
|
||||||
|
case PixelFormat.Format24bppRgb:
|
||||||
|
wpfPixelFormat = System.Windows.Media.PixelFormats.Bgr24;
|
||||||
|
break;
|
||||||
|
case PixelFormat.Format32bppArgb:
|
||||||
|
wpfPixelFormat = System.Windows.Media.PixelFormats.Bgra32;
|
||||||
|
break;
|
||||||
|
case PixelFormat.Format32bppRgb:
|
||||||
|
wpfPixelFormat = System.Windows.Media.PixelFormats.Bgr32;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
wpfPixelFormat = System.Windows.Media.PixelFormats.Bgr24;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var bitmapSource = System.Windows.Media.Imaging.BitmapSource.Create(
|
||||||
|
bitmapData.Width,
|
||||||
|
bitmapData.Height,
|
||||||
|
_currentFrame.HorizontalResolution,
|
||||||
|
_currentFrame.VerticalResolution,
|
||||||
|
wpfPixelFormat,
|
||||||
|
null,
|
||||||
|
bitmapData.Scan0,
|
||||||
|
bitmapData.Stride * bitmapData.Height,
|
||||||
|
bitmapData.Stride);
|
||||||
|
|
||||||
|
bitmapSource.Freeze();
|
||||||
|
LogHelper.WriteLogToFile($"GetCurrentFrameAsBitmapSource: 成功创建BitmapSource");
|
||||||
|
return bitmapSource;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_currentFrame.UnlockBits(bitmapData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
LogHelper.WriteLogToFile($"转换帧为BitmapSource失败: {ex.Message}", LogHelper.LogType.Error);
|
LogHelper.WriteLogToFile($"转换帧为BitmapSource失败: {ex.Message}", LogHelper.LogType.Error);
|
||||||
|
LogHelper.WriteLogToFile($"异常详情: {ex}", LogHelper.LogType.Error);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 视频源新帧事件处理
|
/// 视频源新帧事件处理
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -206,13 +246,52 @@ namespace Ink_Canvas.Helpers
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
LogHelper.WriteLogToFile($"VideoSource_NewFrame: 接收到新帧");
|
||||||
|
|
||||||
lock (_frameLock)
|
lock (_frameLock)
|
||||||
{
|
{
|
||||||
// 释放之前的帧
|
// 释放之前的帧
|
||||||
_currentFrame?.Dispose();
|
_currentFrame?.Dispose();
|
||||||
|
|
||||||
// 克隆新帧
|
// 创建新的位图,避免Clone的问题
|
||||||
_currentFrame = eventArgs.Frame.Clone() as Bitmap;
|
var sourceFrame = eventArgs.Frame;
|
||||||
|
LogHelper.WriteLogToFile($"VideoSource_NewFrame: 源帧类型={sourceFrame?.GetType().FullName}");
|
||||||
|
LogHelper.WriteLogToFile($"VideoSource_NewFrame: 源帧HashCode={sourceFrame?.GetHashCode()}");
|
||||||
|
|
||||||
|
if (sourceFrame != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var width = sourceFrame.Width;
|
||||||
|
var height = sourceFrame.Height;
|
||||||
|
LogHelper.WriteLogToFile($"VideoSource_NewFrame: 源帧尺寸={width}x{height}");
|
||||||
|
|
||||||
|
if (width > 0 && height > 0)
|
||||||
|
{
|
||||||
|
_currentFrame = new Bitmap(width, height, PixelFormat.Format24bppRgb);
|
||||||
|
using (var graphics = Graphics.FromImage(_currentFrame))
|
||||||
|
{
|
||||||
|
graphics.DrawImage(sourceFrame, 0, 0);
|
||||||
|
}
|
||||||
|
LogHelper.WriteLogToFile($"VideoSource_NewFrame: 成功创建新帧,HashCode={_currentFrame.GetHashCode()}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"VideoSource_NewFrame: 源帧尺寸无效");
|
||||||
|
_currentFrame = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception frameEx)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"VideoSource_NewFrame: 处理源帧失败: {frameEx.Message}", LogHelper.LogType.Error);
|
||||||
|
_currentFrame = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"VideoSource_NewFrame: 源帧为null");
|
||||||
|
_currentFrame = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在UI线程中触发事件
|
// 在UI线程中触发事件
|
||||||
|
|||||||
@@ -28,12 +28,14 @@ namespace Ink_Canvas
|
|||||||
public Rectangle Area;
|
public Rectangle Area;
|
||||||
public List<Point> Path;
|
public List<Point> Path;
|
||||||
public Bitmap CameraImage;
|
public Bitmap CameraImage;
|
||||||
|
public System.Windows.Media.Imaging.BitmapSource CameraBitmapSource;
|
||||||
|
|
||||||
public ScreenshotResult(Rectangle area, List<Point> path = null, Bitmap cameraImage = null)
|
public ScreenshotResult(Rectangle area, List<Point> path = null, Bitmap cameraImage = null, System.Windows.Media.Imaging.BitmapSource cameraBitmapSource = null)
|
||||||
{
|
{
|
||||||
Area = area;
|
Area = area;
|
||||||
Path = path;
|
Path = path;
|
||||||
CameraImage = cameraImage;
|
CameraImage = cameraImage;
|
||||||
|
CameraBitmapSource = cameraBitmapSource;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,9 +62,14 @@ namespace Ink_Canvas
|
|||||||
if (screenshotResult.HasValue)
|
if (screenshotResult.HasValue)
|
||||||
{
|
{
|
||||||
// 检查是否是摄像头截图
|
// 检查是否是摄像头截图
|
||||||
if (screenshotResult.Value.CameraImage != null)
|
if (screenshotResult.Value.CameraBitmapSource != null)
|
||||||
{
|
{
|
||||||
// 摄像头截图
|
// 摄像头截图(使用BitmapSource)
|
||||||
|
await InsertBitmapSourceToCanvas(screenshotResult.Value.CameraBitmapSource);
|
||||||
|
}
|
||||||
|
else if (screenshotResult.Value.CameraImage != null)
|
||||||
|
{
|
||||||
|
// 摄像头截图(使用Bitmap)
|
||||||
await InsertScreenshotToCanvas(screenshotResult.Value.CameraImage);
|
await InsertScreenshotToCanvas(screenshotResult.Value.CameraImage);
|
||||||
}
|
}
|
||||||
else if (screenshotResult.Value.Area.Width > 0 && screenshotResult.Value.Area.Height > 0)
|
else if (screenshotResult.Value.Area.Width > 0 && screenshotResult.Value.Area.Height > 0)
|
||||||
@@ -164,7 +171,16 @@ namespace Ink_Canvas
|
|||||||
if (selectorWindow.ShowDialog() == true)
|
if (selectorWindow.ShowDialog() == true)
|
||||||
{
|
{
|
||||||
// 检查是否是摄像头截图
|
// 检查是否是摄像头截图
|
||||||
if (selectorWindow.CameraImage != null)
|
if (selectorWindow.CameraBitmapSource != null)
|
||||||
|
{
|
||||||
|
result = new ScreenshotResult(
|
||||||
|
Rectangle.Empty, // 摄像头截图不需要区域
|
||||||
|
null, // 摄像头截图不需要路径
|
||||||
|
null, // 不再使用Bitmap
|
||||||
|
selectorWindow.CameraBitmapSource // 摄像头BitmapSource
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (selectorWindow.CameraImage != null)
|
||||||
{
|
{
|
||||||
result = new ScreenshotResult(
|
result = new ScreenshotResult(
|
||||||
Rectangle.Empty, // 摄像头截图不需要区域
|
Rectangle.Empty, // 摄像头截图不需要区域
|
||||||
@@ -236,8 +252,40 @@ namespace Ink_Canvas
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// 验证位图有效性
|
||||||
|
if (bitmap == null)
|
||||||
|
{
|
||||||
|
ShowNotification("截图数据无效");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加详细的位图调试信息
|
||||||
|
LogHelper.WriteLogToFile($"InsertScreenshotToCanvas: 开始处理位图");
|
||||||
|
LogHelper.WriteLogToFile($"位图对象类型: {bitmap.GetType().FullName}");
|
||||||
|
LogHelper.WriteLogToFile($"位图对象HashCode: {bitmap.GetHashCode()}");
|
||||||
|
|
||||||
|
// 检查位图是否已被释放
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var testWidth = bitmap.Width;
|
||||||
|
var testHeight = bitmap.Height;
|
||||||
|
LogHelper.WriteLogToFile($"位图尺寸验证成功: {testWidth}x{testHeight}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"位图验证失败: {ex.Message}", LogHelper.LogType.Error);
|
||||||
|
ShowNotification("截图数据已损坏");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 将Bitmap转换为WPF BitmapSource
|
// 将Bitmap转换为WPF BitmapSource
|
||||||
var bitmapSource = ConvertBitmapToBitmapSource(bitmap);
|
var bitmapSource = ConvertBitmapToBitmapSource(bitmap);
|
||||||
|
|
||||||
|
if (bitmapSource == null)
|
||||||
|
{
|
||||||
|
ShowNotification("转换截图失败");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 创建WPF Image控件
|
// 创建WPF Image控件
|
||||||
var image = new Image
|
var image = new Image
|
||||||
@@ -293,6 +341,67 @@ namespace Ink_Canvas
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 将BitmapSource插入到画布(用于摄像头截图)
|
||||||
|
private async Task InsertBitmapSourceToCanvas(System.Windows.Media.Imaging.BitmapSource bitmapSource)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"InsertBitmapSourceToCanvas: 开始处理BitmapSource");
|
||||||
|
|
||||||
|
// 创建WPF Image控件
|
||||||
|
var image = new Image
|
||||||
|
{
|
||||||
|
Source = bitmapSource,
|
||||||
|
Stretch = Stretch.Uniform
|
||||||
|
};
|
||||||
|
RenderOptions.SetBitmapScalingMode(image, BitmapScalingMode.HighQuality);
|
||||||
|
|
||||||
|
// 生成唯一名称
|
||||||
|
string timestamp = "camera_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
|
||||||
|
image.Name = timestamp;
|
||||||
|
|
||||||
|
// 初始化TransformGroup
|
||||||
|
InitializeScreenshotTransform(image);
|
||||||
|
|
||||||
|
// 设置截图属性,避免被InkCanvas选择系统处理
|
||||||
|
image.IsHitTestVisible = true;
|
||||||
|
image.Focusable = false;
|
||||||
|
|
||||||
|
// 初始化InkCanvas选择设置
|
||||||
|
InitializeInkCanvasSelectionSettings();
|
||||||
|
|
||||||
|
// 等待图片加载完成后再进行居中处理
|
||||||
|
image.Loaded += (sender, e) =>
|
||||||
|
{
|
||||||
|
// 确保在UI线程中执行
|
||||||
|
Dispatcher.BeginInvoke(new Action(() =>
|
||||||
|
{
|
||||||
|
CenterAndScaleScreenshot(image);
|
||||||
|
// 绑定事件处理器
|
||||||
|
BindScreenshotEvents(image);
|
||||||
|
}), DispatcherPriority.Loaded);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加到画布
|
||||||
|
inkCanvas.Children.Add(image);
|
||||||
|
|
||||||
|
// 提交历史记录
|
||||||
|
timeMachine.CommitElementInsertHistory(image);
|
||||||
|
|
||||||
|
// 插入图片后切换到选择模式并刷新浮动栏高光显示
|
||||||
|
SetCurrentToolMode(InkCanvasEditingMode.Select);
|
||||||
|
UpdateCurrentToolMode("select");
|
||||||
|
HideSubPanels("select");
|
||||||
|
|
||||||
|
ShowNotification("摄像头截图已插入到画布");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ShowNotification($"插入摄像头截图失败: {ex.Message}");
|
||||||
|
LogHelper.WriteLogToFile($"插入摄像头截图失败: {ex.Message}", LogHelper.LogType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 初始化截图的TransformGroup
|
// 初始化截图的TransformGroup
|
||||||
private void InitializeScreenshotTransform(Image image)
|
private void InitializeScreenshotTransform(Image image)
|
||||||
{
|
{
|
||||||
@@ -501,24 +610,235 @@ namespace Ink_Canvas
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var memory = new MemoryStream())
|
// 验证位图有效性
|
||||||
|
if (bitmap == null)
|
||||||
{
|
{
|
||||||
bitmap.Save(memory, ImageFormat.Png);
|
LogHelper.WriteLogToFile("位图无效: 位图为null", LogHelper.LogType.Warning);
|
||||||
memory.Position = 0;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
var bitmapImage = new BitmapImage();
|
// 尝试访问位图属性,如果失败说明位图已损坏
|
||||||
bitmapImage.BeginInit();
|
int width, height;
|
||||||
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
|
try
|
||||||
bitmapImage.StreamSource = memory;
|
{
|
||||||
bitmapImage.EndInit();
|
width = bitmap.Width;
|
||||||
bitmapImage.Freeze();
|
height = bitmap.Height;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"位图已损坏,无法访问属性: {ex.Message}", LogHelper.LogType.Error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return bitmapImage;
|
if (width <= 0 || height <= 0)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"位图无效: 尺寸为{width}x{height}", LogHelper.LogType.Warning);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogHelper.WriteLogToFile($"开始转换位图: 尺寸={width}x{height}, 格式={bitmap.PixelFormat}, DPI={bitmap.HorizontalResolution}x{bitmap.VerticalResolution}");
|
||||||
|
|
||||||
|
// 使用更安全的方法转换位图
|
||||||
|
var bitmapData = bitmap.LockBits(
|
||||||
|
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||||
|
ImageLockMode.ReadOnly,
|
||||||
|
bitmap.PixelFormat);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"LockBits成功: Stride={bitmapData.Stride}, Scan0={bitmapData.Scan0}");
|
||||||
|
|
||||||
|
// 根据像素格式选择合适的WPF像素格式
|
||||||
|
System.Windows.Media.PixelFormat wpfPixelFormat;
|
||||||
|
switch (bitmap.PixelFormat)
|
||||||
|
{
|
||||||
|
case PixelFormat.Format24bppRgb:
|
||||||
|
wpfPixelFormat = System.Windows.Media.PixelFormats.Bgr24;
|
||||||
|
LogHelper.WriteLogToFile("使用Bgr24像素格式");
|
||||||
|
break;
|
||||||
|
case PixelFormat.Format32bppArgb:
|
||||||
|
wpfPixelFormat = System.Windows.Media.PixelFormats.Bgra32;
|
||||||
|
LogHelper.WriteLogToFile("使用Bgra32像素格式");
|
||||||
|
break;
|
||||||
|
case PixelFormat.Format32bppRgb:
|
||||||
|
wpfPixelFormat = System.Windows.Media.PixelFormats.Bgr32;
|
||||||
|
LogHelper.WriteLogToFile("使用Bgr32像素格式");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// 默认使用Bgr24,如果格式不匹配则转换
|
||||||
|
wpfPixelFormat = System.Windows.Media.PixelFormats.Bgr24;
|
||||||
|
LogHelper.WriteLogToFile($"未知像素格式{bitmap.PixelFormat},使用默认Bgr24");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var bitmapSource = System.Windows.Media.Imaging.BitmapSource.Create(
|
||||||
|
bitmapData.Width,
|
||||||
|
bitmapData.Height,
|
||||||
|
bitmap.HorizontalResolution,
|
||||||
|
bitmap.VerticalResolution,
|
||||||
|
wpfPixelFormat,
|
||||||
|
null,
|
||||||
|
bitmapData.Scan0,
|
||||||
|
bitmapData.Stride * bitmapData.Height,
|
||||||
|
bitmapData.Stride);
|
||||||
|
|
||||||
|
bitmapSource.Freeze();
|
||||||
|
LogHelper.WriteLogToFile("位图转换成功");
|
||||||
|
return bitmapSource;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
bitmap.UnlockBits(bitmapData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
LogHelper.WriteLogToFile($"转换位图失败: {ex.Message}", LogHelper.LogType.Error);
|
LogHelper.WriteLogToFile($"直接转换位图失败: {ex.Message}", LogHelper.LogType.Error);
|
||||||
|
LogHelper.WriteLogToFile($"异常详情: {ex}", LogHelper.LogType.Error);
|
||||||
|
|
||||||
|
// 尝试使用备用方法:内存流转换
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile("尝试使用内存流方式转换位图", LogHelper.LogType.Info);
|
||||||
|
return ConvertBitmapToBitmapSourceFallback(bitmap);
|
||||||
|
}
|
||||||
|
catch (Exception fallbackEx)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"备用转换方法也失败: {fallbackEx.Message}", LogHelper.LogType.Error);
|
||||||
|
LogHelper.WriteLogToFile($"备用方法异常详情: {fallbackEx}", LogHelper.LogType.Error);
|
||||||
|
|
||||||
|
// 最后尝试:使用最简单的转换方法
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile("尝试最简单的转换方法", LogHelper.LogType.Info);
|
||||||
|
return ConvertBitmapToBitmapSourceSimple(bitmap);
|
||||||
|
}
|
||||||
|
catch (Exception simpleEx)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"简单转换方法也失败: {simpleEx.Message}", LogHelper.LogType.Error);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 备用的位图转换方法(使用内存流)
|
||||||
|
private BitmapSource ConvertBitmapToBitmapSourceFallback(Bitmap bitmap)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile("开始备用转换方法");
|
||||||
|
|
||||||
|
// 验证位图有效性
|
||||||
|
if (bitmap == null)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile("备用方法:位图为null", LogHelper.LogType.Warning);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bitmap.Width <= 0 || bitmap.Height <= 0)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"备用方法:位图尺寸无效 {bitmap.Width}x{bitmap.Height}", LogHelper.LogType.Warning);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogHelper.WriteLogToFile($"备用方法:位图尺寸={bitmap.Width}x{bitmap.Height}, 格式={bitmap.PixelFormat}");
|
||||||
|
|
||||||
|
// 创建一个新的位图,确保格式正确
|
||||||
|
using (var convertedBitmap = new Bitmap(bitmap.Width, bitmap.Height, PixelFormat.Format24bppRgb))
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile("创建转换位图成功");
|
||||||
|
|
||||||
|
using (var graphics = Graphics.FromImage(convertedBitmap))
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile("开始绘制到转换位图");
|
||||||
|
graphics.DrawImage(bitmap, 0, 0);
|
||||||
|
LogHelper.WriteLogToFile("绘制完成");
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var memory = new MemoryStream())
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile("开始保存到内存流");
|
||||||
|
convertedBitmap.Save(memory, ImageFormat.Png);
|
||||||
|
LogHelper.WriteLogToFile($"保存完成,内存流大小={memory.Length}");
|
||||||
|
|
||||||
|
memory.Position = 0;
|
||||||
|
|
||||||
|
var bitmapImage = new BitmapImage();
|
||||||
|
bitmapImage.BeginInit();
|
||||||
|
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
|
||||||
|
bitmapImage.StreamSource = memory;
|
||||||
|
bitmapImage.EndInit();
|
||||||
|
bitmapImage.Freeze();
|
||||||
|
|
||||||
|
LogHelper.WriteLogToFile("备用转换方法成功");
|
||||||
|
return bitmapImage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"备用转换方法失败: {ex.Message}", LogHelper.LogType.Error);
|
||||||
|
LogHelper.WriteLogToFile($"备用方法异常详情: {ex}", LogHelper.LogType.Error);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 最简单的位图转换方法
|
||||||
|
private BitmapSource ConvertBitmapToBitmapSourceSimple(Bitmap bitmap)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile("开始简单转换方法");
|
||||||
|
|
||||||
|
if (bitmap == null)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile("简单方法:位图为null", LogHelper.LogType.Warning);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogHelper.WriteLogToFile($"简单方法:位图尺寸={bitmap.Width}x{bitmap.Height}");
|
||||||
|
|
||||||
|
// 使用最基础的方法:直接保存为PNG然后加载
|
||||||
|
var tempFile = System.IO.Path.GetTempFileName() + ".png";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"保存临时文件到: {tempFile}");
|
||||||
|
bitmap.Save(tempFile, ImageFormat.Png);
|
||||||
|
|
||||||
|
LogHelper.WriteLogToFile("开始加载临时文件");
|
||||||
|
var bitmapImage = new BitmapImage();
|
||||||
|
bitmapImage.BeginInit();
|
||||||
|
bitmapImage.UriSource = new Uri(tempFile);
|
||||||
|
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
|
||||||
|
bitmapImage.EndInit();
|
||||||
|
bitmapImage.Freeze();
|
||||||
|
|
||||||
|
LogHelper.WriteLogToFile("简单转换方法成功");
|
||||||
|
return bitmapImage;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// 清理临时文件
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (System.IO.File.Exists(tempFile))
|
||||||
|
{
|
||||||
|
System.IO.File.Delete(tempFile);
|
||||||
|
LogHelper.WriteLogToFile("临时文件已删除");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception deleteEx)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"删除临时文件失败: {deleteEx.Message}", LogHelper.LogType.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"简单转换方法失败: {ex.Message}", LogHelper.LogType.Error);
|
||||||
|
LogHelper.WriteLogToFile($"简单方法异常详情: {ex}", LogHelper.LogType.Error);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ namespace Ink_Canvas
|
|||||||
public DrawingRectangle? SelectedArea { get; private set; }
|
public DrawingRectangle? SelectedArea { get; private set; }
|
||||||
public List<WpfPoint> SelectedPath { get; private set; }
|
public List<WpfPoint> SelectedPath { get; private set; }
|
||||||
public Bitmap CameraImage { get; private set; }
|
public Bitmap CameraImage { get; private set; }
|
||||||
|
public System.Windows.Media.Imaging.BitmapSource CameraBitmapSource { get; private set; }
|
||||||
|
|
||||||
public ScreenshotSelectorWindow()
|
public ScreenshotSelectorWindow()
|
||||||
{
|
{
|
||||||
@@ -156,18 +157,35 @@ namespace Ink_Canvas
|
|||||||
{
|
{
|
||||||
if (_isCameraMode && CameraPreviewImage != null && frame != null)
|
if (_isCameraMode && CameraPreviewImage != null && frame != null)
|
||||||
{
|
{
|
||||||
// 克隆帧以避免在转换过程中被释放
|
try
|
||||||
using (var clonedFrame = frame.Clone() as Bitmap)
|
|
||||||
{
|
{
|
||||||
if (clonedFrame != null)
|
// 验证帧的有效性
|
||||||
|
if (frame.Width <= 0 || frame.Height <= 0)
|
||||||
{
|
{
|
||||||
var bitmapSource = ConvertBitmapToBitmapSource(clonedFrame);
|
LogHelper.WriteLogToFile($"无效的摄像头帧: {frame.Width}x{frame.Height}", LogHelper.LogType.Warning);
|
||||||
if (bitmapSource != null)
|
return;
|
||||||
{
|
|
||||||
CameraPreviewImage.Source = bitmapSource;
|
|
||||||
CameraStatusText.Text = "摄像头已连接";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 创建新的位图,避免Clone的问题
|
||||||
|
var clonedFrame = new Bitmap(frame.Width, frame.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
|
||||||
|
using (var graphics = System.Drawing.Graphics.FromImage(clonedFrame))
|
||||||
|
{
|
||||||
|
graphics.DrawImage(frame, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
var bitmapSource = ConvertBitmapToBitmapSource(clonedFrame);
|
||||||
|
if (bitmapSource != null)
|
||||||
|
{
|
||||||
|
CameraPreviewImage.Source = bitmapSource;
|
||||||
|
CameraStatusText.Text = "摄像头已连接";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 释放临时位图
|
||||||
|
clonedFrame.Dispose();
|
||||||
|
}
|
||||||
|
catch (Exception frameEx)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"处理摄像头帧时出错: {frameEx.Message}", LogHelper.LogType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@@ -197,19 +215,57 @@ namespace Ink_Canvas
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var memory = new System.IO.MemoryStream())
|
// 验证位图有效性
|
||||||
|
if (bitmap == null || bitmap.Width <= 0 || bitmap.Height <= 0)
|
||||||
{
|
{
|
||||||
bitmap.Save(memory, System.Drawing.Imaging.ImageFormat.Png);
|
LogHelper.WriteLogToFile("位图无效: 空位图或尺寸为0", LogHelper.LogType.Warning);
|
||||||
memory.Position = 0;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
var bitmapImage = new System.Windows.Media.Imaging.BitmapImage();
|
// 使用更安全的方法转换位图
|
||||||
bitmapImage.BeginInit();
|
var bitmapData = bitmap.LockBits(
|
||||||
bitmapImage.CacheOption = System.Windows.Media.Imaging.BitmapCacheOption.OnLoad;
|
new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||||
bitmapImage.StreamSource = memory;
|
System.Drawing.Imaging.ImageLockMode.ReadOnly,
|
||||||
bitmapImage.EndInit();
|
bitmap.PixelFormat);
|
||||||
bitmapImage.Freeze();
|
|
||||||
|
|
||||||
return bitmapImage;
|
try
|
||||||
|
{
|
||||||
|
// 根据像素格式选择合适的WPF像素格式
|
||||||
|
System.Windows.Media.PixelFormat wpfPixelFormat;
|
||||||
|
switch (bitmap.PixelFormat)
|
||||||
|
{
|
||||||
|
case System.Drawing.Imaging.PixelFormat.Format24bppRgb:
|
||||||
|
wpfPixelFormat = System.Windows.Media.PixelFormats.Bgr24;
|
||||||
|
break;
|
||||||
|
case System.Drawing.Imaging.PixelFormat.Format32bppArgb:
|
||||||
|
wpfPixelFormat = System.Windows.Media.PixelFormats.Bgra32;
|
||||||
|
break;
|
||||||
|
case System.Drawing.Imaging.PixelFormat.Format32bppRgb:
|
||||||
|
wpfPixelFormat = System.Windows.Media.PixelFormats.Bgr32;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// 默认使用Bgr24,如果格式不匹配则转换
|
||||||
|
wpfPixelFormat = System.Windows.Media.PixelFormats.Bgr24;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var bitmapSource = System.Windows.Media.Imaging.BitmapSource.Create(
|
||||||
|
bitmapData.Width,
|
||||||
|
bitmapData.Height,
|
||||||
|
bitmap.HorizontalResolution,
|
||||||
|
bitmap.VerticalResolution,
|
||||||
|
wpfPixelFormat,
|
||||||
|
null,
|
||||||
|
bitmapData.Scan0,
|
||||||
|
bitmapData.Stride * bitmapData.Height,
|
||||||
|
bitmapData.Stride);
|
||||||
|
|
||||||
|
bitmapSource.Freeze();
|
||||||
|
return bitmapSource;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
bitmap.UnlockBits(bitmapData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -430,12 +486,12 @@ namespace Ink_Canvas
|
|||||||
{
|
{
|
||||||
if (_cameraService != null && _cameraService.IsCapturing)
|
if (_cameraService != null && _cameraService.IsCapturing)
|
||||||
{
|
{
|
||||||
// 获取当前帧
|
// 直接获取BitmapSource,避免Bitmap传递问题
|
||||||
var currentFrame = _cameraService.GetCurrentFrame();
|
var bitmapSource = _cameraService.GetCurrentFrameAsBitmapSource();
|
||||||
if (currentFrame != null)
|
if (bitmapSource != null)
|
||||||
{
|
{
|
||||||
// 保存摄像头图像
|
// 保存BitmapSource而不是Bitmap
|
||||||
CameraImage = currentFrame.Clone() as Bitmap;
|
CameraBitmapSource = bitmapSource;
|
||||||
|
|
||||||
// 停止摄像头预览
|
// 停止摄像头预览
|
||||||
_cameraService.StopPreview();
|
_cameraService.StopPreview();
|
||||||
|
|||||||
Reference in New Issue
Block a user