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"); } } }