Integrates optional AI/OCR (AIFotoONLUS.Core) support to extract numbers from images after processing. Adds new "AI" tab in the UI for enabling extraction, selecting models folder, specifying CSV output, and previewing results. Results can be exported to CSV. Uses reflection for AI library invocation, with fallback simulation if unavailable. Persists new AI settings. Updates related NuGet packages and adds theme resources.
279 lines
11 KiB
C#
279 lines
11 KiB
C#
using System.Windows;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using System;
|
|
using System.IO;
|
|
using System.Windows.Media.Imaging;
|
|
using Microsoft.Win32;
|
|
using System.Windows.Forms;
|
|
|
|
namespace ImageCatalog_2
|
|
{
|
|
public partial class MainWindow : Window
|
|
{
|
|
private readonly DataModel _model;
|
|
public MainWindow(DataModel model)
|
|
{
|
|
InitializeComponent();
|
|
_model = model;
|
|
DataContext = _model;
|
|
// Apply theme based on user preference or system setting (default to light)
|
|
ApplyTheme(isDark: false);
|
|
// Subscribe to DataModel events that require UI dialogs
|
|
_model.SelectSourceFolderRequested += Model_SelectSourceFolderRequested;
|
|
_model.SelectDestinationFolderRequested += Model_SelectDestinationFolderRequested;
|
|
_model.SelectLogoFileRequested += Model_SelectLogoFileRequested;
|
|
_model.SaveSettingsRequested += Model_SaveSettingsRequested;
|
|
_model.LoadSettingsRequested += Model_LoadSettingsRequested;
|
|
_model.SelectColorRequested += Model_SelectColorRequested;
|
|
_model.SelectTransparentColorRequested += Model_SelectTransparentColorRequested;
|
|
_model.SelectModelsFolderRequested += Model_SelectModelsFolderRequested;
|
|
_model.SelectCsvOutputRequested += Model_SelectCsvOutputRequested;
|
|
|
|
// Watch for logo changes to update preview
|
|
_model.PropertyChanged += Model_PropertyChanged;
|
|
}
|
|
|
|
private void ApplyTheme(bool isDark)
|
|
{
|
|
try
|
|
{
|
|
var rd = isDark ? (ResourceDictionary)Resources["DarkTheme"] : (ResourceDictionary)Resources["LightTheme"];
|
|
foreach (var key in rd.Keys)
|
|
{
|
|
Resources[key] = rd[key];
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// ignore theme failures
|
|
}
|
|
}
|
|
|
|
private void Model_SelectModelsFolderRequested(object? sender, EventArgs e)
|
|
{
|
|
var dlg = new System.Windows.Forms.FolderBrowserDialog();
|
|
var starting = string.IsNullOrWhiteSpace(_model.ModelsFolderPath) ? Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) : _model.ModelsFolderPath;
|
|
dlg.SelectedPath = starting;
|
|
if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
|
{
|
|
_model.ModelsFolderPath = dlg.SelectedPath + Path.DirectorySeparatorChar;
|
|
}
|
|
}
|
|
|
|
private void OpenModelsFolder_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
var path = _model.ModelsFolderPath;
|
|
if (string.IsNullOrWhiteSpace(path)) return;
|
|
path = path.Trim().Trim('"');
|
|
if (File.Exists(path))
|
|
{
|
|
System.Diagnostics.Process.Start("explorer.exe", $"/select,\"{path}\"");
|
|
return;
|
|
}
|
|
if (Directory.Exists(path))
|
|
{
|
|
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo { FileName = path, UseShellExecute = true });
|
|
return;
|
|
}
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
private void Model_SelectCsvOutputRequested(object? sender, EventArgs e)
|
|
{
|
|
var dlg = new Microsoft.Win32.SaveFileDialog();
|
|
dlg.Filter = "CSV file (*.csv)|*.csv|All files (*.*)|*.*";
|
|
if (!string.IsNullOrWhiteSpace(_model.CsvOutputPath)) dlg.FileName = _model.CsvOutputPath;
|
|
var result = dlg.ShowDialog(this);
|
|
if (result == true)
|
|
{
|
|
_model.CsvOutputPath = dlg.FileName;
|
|
}
|
|
}
|
|
|
|
private void OpenCsvOutputFolder_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
var path = _model.CsvOutputPath;
|
|
if (string.IsNullOrWhiteSpace(path)) return;
|
|
path = path.Trim().Trim('"');
|
|
if (File.Exists(path))
|
|
{
|
|
System.Diagnostics.Process.Start("explorer.exe", $"/select,\"{path}\"");
|
|
return;
|
|
}
|
|
var dir = Path.GetDirectoryName(path);
|
|
if (!string.IsNullOrWhiteSpace(dir) && Directory.Exists(dir))
|
|
{
|
|
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo { FileName = dir, UseShellExecute = true });
|
|
return;
|
|
}
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
private void Model_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
|
|
{
|
|
if (e is null || string.IsNullOrWhiteSpace(e.PropertyName)) return;
|
|
if (e.PropertyName == nameof(_model.LogoFile))
|
|
{
|
|
UpdateLogoPreview(_model.LogoFile);
|
|
}
|
|
}
|
|
|
|
private void Model_SelectSourceFolderRequested(object? sender, EventArgs e)
|
|
{
|
|
var dlg = new System.Windows.Forms.FolderBrowserDialog();
|
|
var starting = string.IsNullOrWhiteSpace(_model.SourcePath) ? Environment.GetFolderPath(Environment.SpecialFolder.MyPictures) : _model.SourcePath;
|
|
dlg.SelectedPath = starting;
|
|
if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
|
{
|
|
_model.SourcePath = dlg.SelectedPath + Path.DirectorySeparatorChar;
|
|
}
|
|
}
|
|
|
|
private void OpenSourceFolder_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
var path = _model.SourcePath;
|
|
if (string.IsNullOrWhiteSpace(path)) return;
|
|
path = path.Trim().Trim('"');
|
|
if (File.Exists(path))
|
|
{
|
|
System.Diagnostics.Process.Start("explorer.exe", $"/select,\"{path}\"");
|
|
return;
|
|
}
|
|
if (Directory.Exists(path))
|
|
{
|
|
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo { FileName = path, UseShellExecute = true });
|
|
return;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// ignore for now, or could show a message
|
|
}
|
|
}
|
|
|
|
private void Model_SelectDestinationFolderRequested(object? sender, EventArgs e)
|
|
{
|
|
var dlg = new System.Windows.Forms.FolderBrowserDialog();
|
|
var starting = string.IsNullOrWhiteSpace(_model.DestinationPath) ? Environment.GetFolderPath(Environment.SpecialFolder.MyPictures) : _model.DestinationPath;
|
|
dlg.SelectedPath = starting;
|
|
if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
|
{
|
|
_model.DestinationPath = dlg.SelectedPath + Path.DirectorySeparatorChar;
|
|
}
|
|
|
|
}
|
|
|
|
private void OpenDestinationFolder_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
var path = _model.DestinationPath;
|
|
if (string.IsNullOrWhiteSpace(path)) return;
|
|
path = path.Trim().Trim('"');
|
|
if (File.Exists(path))
|
|
{
|
|
System.Diagnostics.Process.Start("explorer.exe", $"/select,\"{path}\"");
|
|
return;
|
|
}
|
|
if (Directory.Exists(path))
|
|
{
|
|
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo { FileName = path, UseShellExecute = true });
|
|
return;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// ignore for now
|
|
}
|
|
}
|
|
|
|
private void Model_SelectLogoFileRequested(object? sender, EventArgs e)
|
|
{
|
|
var dlg = new Microsoft.Win32.OpenFileDialog();
|
|
dlg.Filter = "Image Files|*.jpg;*.jpeg;*.png;*.bmp;*.gif";
|
|
if (!string.IsNullOrWhiteSpace(_model.LogoFile)) dlg.FileName = _model.LogoFile;
|
|
var result = dlg.ShowDialog(this);
|
|
if (result == true)
|
|
{
|
|
_model.LogoFile = dlg.FileName;
|
|
}
|
|
}
|
|
|
|
private async void Model_SaveSettingsRequested(object? sender, string filePath)
|
|
{
|
|
var dlg = new Microsoft.Win32.SaveFileDialog();
|
|
dlg.Filter = "Setup (*.xml)|*.xml|All valid files (*.*)|*.*";
|
|
var result = dlg.ShowDialog(this);
|
|
if (result == true)
|
|
{
|
|
await _model.SaveSettingsToFileAsync(dlg.FileName);
|
|
}
|
|
}
|
|
|
|
private async void Model_LoadSettingsRequested(object? sender, string filePath)
|
|
{
|
|
var dlg = new Microsoft.Win32.OpenFileDialog();
|
|
dlg.Filter = "Setup (*.xml)|*.xml|All valid files (*.*)|*.*";
|
|
var result = dlg.ShowDialog(this);
|
|
if (result == true)
|
|
{
|
|
await _model.LoadSettingsFromFileAsync(dlg.FileName);
|
|
}
|
|
}
|
|
|
|
private void Model_SelectColorRequested(object? sender, EventArgs e)
|
|
{
|
|
var dlg = new System.Windows.Forms.ColorDialog { AllowFullOpen = true };
|
|
if (!string.IsNullOrWhiteSpace(_model.TextColorRGB))
|
|
{
|
|
try { dlg.Color = System.Drawing.ColorTranslator.FromHtml(_model.TextColorRGB); } catch { }
|
|
}
|
|
if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
|
{
|
|
_model.TextColorRGB = System.Drawing.ColorTranslator.ToHtml(dlg.Color);
|
|
}
|
|
}
|
|
|
|
private void Model_SelectTransparentColorRequested(object? sender, EventArgs e)
|
|
{
|
|
var dlg = new System.Windows.Forms.ColorDialog { AllowFullOpen = true };
|
|
try { dlg.Color = System.Drawing.ColorTranslator.FromHtml(_model.TransparentColor); } catch { }
|
|
if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
|
{
|
|
_model.TransparentColor = System.Drawing.ColorTranslator.ToHtml(dlg.Color);
|
|
}
|
|
}
|
|
|
|
private void UpdateLogoPreview(string? path)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(path) || !File.Exists(path))
|
|
{
|
|
LogoPreview.Source = null;
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
var bitmap = new BitmapImage();
|
|
bitmap.BeginInit();
|
|
bitmap.CacheOption = BitmapCacheOption.OnLoad;
|
|
bitmap.UriSource = new Uri(path);
|
|
bitmap.EndInit();
|
|
LogoPreview.Source = bitmap;
|
|
}
|
|
catch
|
|
{
|
|
LogoPreview.Source = null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|