Files
XplorePlane/XplorePlane/ViewModels/ImageProcessing/ImageProcessingViewModel.cs
T
2026-03-15 00:24:02 +08:00

243 lines
8.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Windows.Media.Imaging;
using Microsoft.Win32;
using Prism.Commands;
using Prism.Mvvm;
using Serilog;
using XplorePlane.Services;
namespace XplorePlane.ViewModels
{
/// <summary>算子列表项:持有注册 key 和本地化显示名</summary>
public class ProcessorItem
{
public string Key { get; }
public string DisplayName { get; }
public ProcessorItem(string key, string displayName) { Key = key; DisplayName = displayName; }
public override string ToString() => DisplayName;
}
public class ImageProcessingViewModel : BindableBase
{
private readonly IImageProcessingService _imageProcessingService;
private readonly ILogger _logger;
private ProcessorItem _selectedProcessorItem;
private BitmapSource _currentImage;
private BitmapSource _originalImage;
private double _processingProgress;
private bool _isProcessing;
private string _statusMessage;
public ImageProcessingViewModel(IImageProcessingService imageProcessingService, ILogger logger)
{
_imageProcessingService = imageProcessingService;
_logger = logger;
AvailableProcessors = new ObservableCollection<ProcessorItem>();
CurrentParameters = new ObservableCollection<ProcessorParameterVM>();
foreach (var key in _imageProcessingService.GetAvailableProcessors())
AvailableProcessors.Add(new ProcessorItem(key, _imageProcessingService.GetProcessorDisplayName(key)));
SelectProcessorCommand = new DelegateCommand<string>(OnSelectProcessor);
ApplyProcessingCommand = new DelegateCommand(OnApplyProcessing);
ResetImageCommand = new DelegateCommand(OnResetImage);
LoadImageCommand = new DelegateCommand(OnLoadImage);
SaveResultCommand = new DelegateCommand(OnSaveResult, () => CurrentImage != null);
}
public ObservableCollection<ProcessorItem> AvailableProcessors { get; }
public ObservableCollection<ProcessorParameterVM> CurrentParameters { get; }
public ProcessorItem SelectedProcessorItem
{
get => _selectedProcessorItem;
set
{
SetProperty(ref _selectedProcessorItem, value);
if (value != null) OnSelectProcessor(value.Key);
}
}
// Keep SelectedProcessor as the key string for service calls
public string SelectedProcessor => _selectedProcessorItem?.Key;
public BitmapSource CurrentImage
{
get => _currentImage;
set
{
SetProperty(ref _currentImage, value);
SaveResultCommand?.RaiseCanExecuteChanged();
}
}
public BitmapSource OriginalImage
{
get => _originalImage;
set => SetProperty(ref _originalImage, value);
}
public double ProcessingProgress
{
get => _processingProgress;
set => SetProperty(ref _processingProgress, value);
}
public bool IsProcessing
{
get => _isProcessing;
set => SetProperty(ref _isProcessing, value);
}
public string StatusMessage
{
get => _statusMessage;
set => SetProperty(ref _statusMessage, value);
}
public DelegateCommand<string> SelectProcessorCommand { get; }
public DelegateCommand ApplyProcessingCommand { get; }
public DelegateCommand ResetImageCommand { get; }
public DelegateCommand LoadImageCommand { get; }
public DelegateCommand SaveResultCommand { get; }
private void OnSelectProcessor(string processorName)
{
if (string.IsNullOrEmpty(processorName)) return;
try
{
var parameters = _imageProcessingService.GetProcessorParameters(processorName);
CurrentParameters.Clear();
foreach (var param in parameters)
CurrentParameters.Add(new ProcessorParameterVM(param));
}
catch (ArgumentException ex)
{
StatusMessage = $"Error loading parameters: {ex.Message}";
_logger.Warning(ex, "Failed to load parameters for processor: {ProcessorName}", processorName);
}
}
private async void OnApplyProcessing()
{
if (CurrentImage == null || string.IsNullOrEmpty(SelectedProcessor)) return;
IsProcessing = true;
ProcessingProgress = 0;
try
{
var parameters = new Dictionary<string, object>();
foreach (var param in CurrentParameters)
parameters[param.Name] = param.Value;
var progress = new Progress<double>(p => ProcessingProgress = p);
var result = await _imageProcessingService.ProcessImageAsync(
CurrentImage,
SelectedProcessor,
parameters,
progress);
CurrentImage = result;
StatusMessage = $"Processing complete: {SelectedProcessor}";
_logger.Information("Image processing completed: {ProcessorName}", SelectedProcessor);
}
catch (ArgumentException ex)
{
StatusMessage = $"Processing error: {ex.Message}";
_logger.Warning(ex, "Processing failed for processor: {ProcessorName}", SelectedProcessor);
// CurrentImage unchanged
}
catch (OperationCanceledException)
{
StatusMessage = "Processing cancelled";
_logger.Information("Image processing cancelled");
// CurrentImage unchanged
}
catch (ImageProcessingException ex)
{
StatusMessage = $"Processing failed: {ex.Message}";
_logger.Error(ex, "Image processing exception for processor: {ProcessorName}", SelectedProcessor);
// CurrentImage unchanged
}
finally
{
IsProcessing = false;
}
}
private void OnResetImage()
{
CurrentImage = OriginalImage;
StatusMessage = "Image reset to original";
ProcessingProgress = 0;
}
private void OnLoadImage()
{
var dlg = new OpenFileDialog
{
Title = "加载图像",
Filter = "图像文件|*.bmp;*.png;*.jpg;*.jpeg;*.tif;*.tiff|所有文件|*.*"
};
if (dlg.ShowDialog() != true) return;
try
{
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = new Uri(dlg.FileName);
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
bitmap.Freeze();
OriginalImage = bitmap;
CurrentImage = bitmap;
StatusMessage = $"已加载:{Path.GetFileName(dlg.FileName)}";
ProcessingProgress = 0;
}
catch (Exception ex)
{
StatusMessage = $"加载失败:{ex.Message}";
_logger.Error(ex, "Failed to load image: {Path}", dlg.FileName);
}
}
private void OnSaveResult()
{
if (CurrentImage == null) return;
var dlg = new SaveFileDialog
{
Title = "保存结果",
Filter = "PNG 图像|*.png|BMP 图像|*.bmp|JPEG 图像|*.jpg",
DefaultExt = ".png"
};
if (dlg.ShowDialog() != true) return;
try
{
BitmapEncoder encoder = Path.GetExtension(dlg.FileName).ToLower() switch
{
".bmp" => new BmpBitmapEncoder(),
".jpg" or ".jpeg" => new JpegBitmapEncoder(),
_ => new PngBitmapEncoder()
};
encoder.Frames.Add(BitmapFrame.Create(CurrentImage));
using var stream = File.OpenWrite(dlg.FileName);
encoder.Save(stream);
StatusMessage = $"已保存:{Path.GetFileName(dlg.FileName)}";
}
catch (Exception ex)
{
StatusMessage = $"保存失败:{ex.Message}";
_logger.Error(ex, "Failed to save image: {Path}", dlg.FileName);
}
}
}
}