243 lines
8.6 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|
|
}
|