using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Prism.Events;
using XP.Common.Logging.Interfaces;
using XP.Hardware.Detector.Abstractions;
using XP.Hardware.Detector.Abstractions.Events;
namespace XP.Hardware.Detector.Services
{
///
/// 图像服务实现 | Image service implementation
/// 提供最新帧获取和 16 位 TIFF 保存功能
///
public class ImageService : IImageService
{
private readonly IDetectorService _detectorService;
private readonly ILoggerService _logger;
///
/// 最新采集的原始图像数据 | Latest captured raw image data
///
private volatile ImageCapturedEventArgs _latestFrame;
public ImageService(
IDetectorService detectorService,
IEventAggregator eventAggregator,
ILoggerService logger)
{
_detectorService = detectorService ?? throw new ArgumentNullException(nameof(detectorService));
_logger = logger?.ForModule();
// 订阅图像采集事件,缓存最新帧 | Subscribe to image captured event, cache latest frame
if (eventAggregator == null) throw new ArgumentNullException(nameof(eventAggregator));
eventAggregator.GetEvent()
.Subscribe(OnImageCaptured, ThreadOption.BackgroundThread);
}
///
public ImageCapturedEventArgs LatestFrame => _latestFrame;
///
/// 图像采集事件回调,缓存最新帧 | Image captured callback, cache latest frame
///
private void OnImageCaptured(ImageCapturedEventArgs args)
{
if (args?.ImageData != null && args.Width > 0 && args.Height > 0)
_latestFrame = args;
}
///
public Task SaveAsTiffAsync(ushort[] imageData, int width, int height, string filePath)
{
return Task.Run(() =>
{
try
{
if (imageData == null || imageData.Length == 0)
return DetectorResult.Failure("图像数据为空 | Image data is empty");
if (width <= 0 || height <= 0)
return DetectorResult.Failure($"图像尺寸无效:{width}x{height} | Invalid image size: {width}x{height}");
// 确保目录存在 | Ensure directory exists
var directory = Path.GetDirectoryName(filePath);
if (!string.IsNullOrEmpty(directory))
Directory.CreateDirectory(directory);
// 创建 16 位灰度 BitmapSource | Create 16-bit grayscale BitmapSource
int stride = width * sizeof(ushort);
var bitmap = BitmapSource.Create(width, height, 96, 96, PixelFormats.Gray16, null, imageData, stride);
bitmap.Freeze();
// 编码为 TIFF(无压缩)| Encode as TIFF (no compression)
var encoder = new TiffBitmapEncoder { Compression = TiffCompressOption.None };
encoder.Frames.Add(BitmapFrame.Create(bitmap));
using (var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
encoder.Save(stream);
}
_logger?.Info("图像已保存:{FilePath},分辨率:{Width}x{Height} | Image saved: {FilePath}, resolution: {Width}x{Height}", filePath, width, height);
return DetectorResult.Success($"图像已保存 | Image saved: {filePath}");
}
catch (Exception ex)
{
var errorMsg = $"保存图像失败:{ex.Message} | Failed to save image: {ex.Message}";
_logger?.Error(ex, errorMsg);
return DetectorResult.Failure(errorMsg, ex);
}
});
}
///
public Task SaveAsTiffAsync(ushort[] imageData, int width, int height, string saveDirectory, string prefix, int frameNumber)
{
var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss_fff");
var fileName = $"{prefix}_{timestamp}_F{frameNumber}.tif";
var filePath = Path.Combine(saveDirectory, fileName);
return SaveAsTiffAsync(imageData, width, height, filePath);
}
///
public Task SaveLatestFrameAsync(string saveDirectory, string prefix)
{
var frame = _latestFrame;
if (frame?.ImageData == null)
return Task.FromResult(DetectorResult.Failure("无可用的图像数据 | No image data available"));
return SaveAsTiffAsync(frame.ImageData, (int)frame.Width, (int)frame.Height, saveDirectory, prefix, frame.FrameNumber);
}
///
public string GetDefaultSaveDirectory()
{
var config = _detectorService.GetCurrentConfig();
if (config != null && !string.IsNullOrEmpty(config.SavePath))
return config.SavePath;
return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Images");
}
}
}