2024-10-14 23:25:35 +02:00
|
|
|
|
using ImageCatalog_2.Commands;
|
|
|
|
|
|
using ImageCatalog_2.Services;
|
2024-10-14 23:05:18 +02:00
|
|
|
|
using System;
|
2026-02-04 23:16:06 +01:00
|
|
|
|
using System.Collections.Concurrent;
|
2024-10-14 22:55:52 +02:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.ComponentModel;
|
2024-10-14 23:25:35 +02:00
|
|
|
|
using System.Diagnostics;
|
2026-02-04 19:48:03 +01:00
|
|
|
|
using System.Drawing.Text;
|
2024-10-14 22:55:52 +02:00
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Text;
|
2026-02-04 23:16:06 +01:00
|
|
|
|
using System.Threading;
|
2024-10-14 22:55:52 +02:00
|
|
|
|
using System.Threading.Tasks;
|
2026-02-04 23:16:06 +01:00
|
|
|
|
using System.Windows.Forms;
|
2024-10-14 23:25:35 +02:00
|
|
|
|
using System.Windows.Input;
|
2026-02-04 23:16:06 +01:00
|
|
|
|
using AutoMapper;
|
|
|
|
|
|
using MaddoShared;
|
2025-07-29 11:07:49 +02:00
|
|
|
|
using Microsoft.Extensions.Logging;
|
2024-10-14 22:55:52 +02:00
|
|
|
|
|
|
|
|
|
|
namespace ImageCatalog_2
|
|
|
|
|
|
{
|
|
|
|
|
|
public class DataModel : ViewModelBase
|
|
|
|
|
|
{
|
2024-10-14 23:25:35 +02:00
|
|
|
|
public ICommand TestCommand { get; }
|
|
|
|
|
|
public ICommand AsyncTestCommand { get; }
|
2025-07-29 11:07:49 +02:00
|
|
|
|
public ICommand AsyncCancelOperationCommand { get; }
|
2025-07-23 17:16:06 +02:00
|
|
|
|
public ICommand ProcessImagesCommand { get; }
|
2026-02-04 19:48:03 +01:00
|
|
|
|
public ICommand SelectSourceFolderCommand { get; }
|
|
|
|
|
|
public ICommand SelectDestinationFolderCommand { get; }
|
|
|
|
|
|
public ICommand SelectLogoFileCommand { get; }
|
|
|
|
|
|
public ICommand SaveSettingsCommand { get; }
|
|
|
|
|
|
public ICommand LoadSettingsCommand { get; }
|
|
|
|
|
|
public ICommand SelectColorCommand { get; }
|
2026-02-15 11:13:23 +01:00
|
|
|
|
public ICommand SelectTransparentColorCommand { get; }
|
2024-10-14 23:25:35 +02:00
|
|
|
|
|
2024-10-14 23:05:18 +02:00
|
|
|
|
private readonly ITestService _service;
|
2025-07-29 11:10:54 +02:00
|
|
|
|
private readonly ILogger<DataModel> _logger;
|
2026-02-04 19:48:03 +01:00
|
|
|
|
private readonly ISettingsService _settingsService;
|
2026-02-04 23:16:06 +01:00
|
|
|
|
private readonly ImageCreationStuff _imageCreationService;
|
|
|
|
|
|
private readonly PicSettings _picSettings;
|
|
|
|
|
|
private readonly IMapper _mapper;
|
2026-02-04 19:48:03 +01:00
|
|
|
|
|
|
|
|
|
|
// ComboBox collections
|
|
|
|
|
|
public List<string> AvailableFonts { get; }
|
|
|
|
|
|
public List<string> VerticalPositions { get; } = new() { "Alto", "Centro", "Basso" };
|
|
|
|
|
|
public List<string> HorizontalAlignments { get; } = new() { "Sinistra", "Centro", "Destra" };
|
2025-07-29 11:10:54 +02:00
|
|
|
|
|
2026-02-04 23:16:06 +01:00
|
|
|
|
public DataModel(ITestService testService, ISettingsService settingsService,
|
|
|
|
|
|
ImageCreationStuff imageCreationService, PicSettings picSettings,
|
2026-02-14 22:18:56 +01:00
|
|
|
|
IMapper mapper, ILogger<DataModel> logger, MaddoShared.IVersionProvider? versionProvider = null)
|
2024-10-14 23:05:18 +02:00
|
|
|
|
{
|
|
|
|
|
|
_service = testService;
|
2025-07-29 11:07:49 +02:00
|
|
|
|
_logger = logger;
|
2026-02-04 19:48:03 +01:00
|
|
|
|
_settingsService = settingsService;
|
2026-02-04 23:16:06 +01:00
|
|
|
|
_imageCreationService = imageCreationService;
|
|
|
|
|
|
_picSettings = picSettings;
|
|
|
|
|
|
_mapper = mapper;
|
2026-02-14 22:18:56 +01:00
|
|
|
|
// Populate AppVersion from version provider when available
|
|
|
|
|
|
AppVersion = versionProvider?.GetVersionString() ?? string.Empty;
|
2024-10-14 23:25:35 +02:00
|
|
|
|
|
|
|
|
|
|
TestCommand = new RelayCommand(Test);
|
|
|
|
|
|
AsyncTestCommand = new AsyncCommand(TestAsync);
|
2025-07-29 11:07:49 +02:00
|
|
|
|
AsyncCancelOperationCommand = new AsyncCommand(CancelOperation);
|
2025-07-23 17:16:06 +02:00
|
|
|
|
ProcessImagesCommand = new AsyncCommand(ProcessImages);
|
2026-02-04 19:48:03 +01:00
|
|
|
|
|
|
|
|
|
|
SelectSourceFolderCommand = new RelayCommand(SelectSourceFolder);
|
|
|
|
|
|
SelectDestinationFolderCommand = new RelayCommand(SelectDestinationFolder);
|
|
|
|
|
|
SelectLogoFileCommand = new RelayCommand(SelectLogoFile);
|
|
|
|
|
|
SaveSettingsCommand = new RelayCommand(SaveSettings);
|
|
|
|
|
|
LoadSettingsCommand = new RelayCommand(LoadSettings);
|
|
|
|
|
|
SelectColorCommand = new RelayCommand(SelectColor);
|
2026-02-15 11:13:23 +01:00
|
|
|
|
SelectTransparentColorCommand = new RelayCommand(SelectTransparentColor);
|
2026-02-04 19:48:03 +01:00
|
|
|
|
|
|
|
|
|
|
// Load available fonts
|
|
|
|
|
|
AvailableFonts = LoadAvailableFonts();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private List<string> LoadAvailableFonts()
|
|
|
|
|
|
{
|
|
|
|
|
|
var fonts = new List<string>();
|
|
|
|
|
|
using (var installedFonts = new InstalledFontCollection())
|
|
|
|
|
|
{
|
|
|
|
|
|
fonts.AddRange(installedFonts.Families.Select(f => f.Name));
|
|
|
|
|
|
}
|
|
|
|
|
|
return fonts;
|
2024-10-14 23:05:18 +02:00
|
|
|
|
}
|
2024-10-14 22:55:52 +02:00
|
|
|
|
|
2025-07-29 11:07:49 +02:00
|
|
|
|
private CancellationTokenSource? _mainToken;
|
|
|
|
|
|
|
|
|
|
|
|
public CancellationTokenSource? MainToken
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _mainToken;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_mainToken = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-10-14 22:55:52 +02:00
|
|
|
|
private string _sourcePath;
|
|
|
|
|
|
|
|
|
|
|
|
public string SourcePath
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _sourcePath;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_sourcePath = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private string _destinationPath;
|
2025-07-29 11:10:54 +02:00
|
|
|
|
|
2024-10-14 22:55:52 +02:00
|
|
|
|
public string DestinationPath
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _destinationPath;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_destinationPath = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-28 09:49:55 +02:00
|
|
|
|
private string _horizontalText;
|
|
|
|
|
|
|
|
|
|
|
|
public string HorizontalText
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _horizontalText;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_horizontalText = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-29 11:10:54 +02:00
|
|
|
|
|
2025-07-28 10:34:03 +02:00
|
|
|
|
private string _verticalText;
|
2025-07-29 11:10:54 +02:00
|
|
|
|
|
2025-07-28 10:34:03 +02:00
|
|
|
|
public string VerticalText
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _verticalText;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_verticalText = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-28 09:49:55 +02:00
|
|
|
|
|
2025-07-28 14:45:03 +02:00
|
|
|
|
private bool _overwriteImages;
|
|
|
|
|
|
|
|
|
|
|
|
public bool OverwriteImages
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _overwriteImages;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_overwriteImages = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-10-14 23:48:21 +02:00
|
|
|
|
private bool _uiEnabled = true;
|
|
|
|
|
|
|
|
|
|
|
|
public bool UiEnabled
|
|
|
|
|
|
{
|
2025-07-28 10:34:03 +02:00
|
|
|
|
get => _uiEnabled;
|
2024-10-14 23:48:21 +02:00
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_uiEnabled = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
2026-02-04 21:12:27 +01:00
|
|
|
|
NotifyPropertyChanged(nameof(UiDisabled));
|
2024-10-14 23:48:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-29 11:10:54 +02:00
|
|
|
|
|
2025-07-29 10:34:23 +02:00
|
|
|
|
public bool UiDisabled => !_uiEnabled;
|
|
|
|
|
|
|
|
|
|
|
|
private string _speedCounter = "-";
|
|
|
|
|
|
|
|
|
|
|
|
public string SpeedCounter
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _speedCounter;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_speedCounter = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-10-14 23:48:21 +02:00
|
|
|
|
|
2025-09-19 09:53:31 +02:00
|
|
|
|
private int _chunkSize;
|
|
|
|
|
|
|
|
|
|
|
|
public int ChunkSize
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _chunkSize;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_chunkSize = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int _threadsCount;
|
|
|
|
|
|
|
|
|
|
|
|
public int ThreadsCount
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _threadsCount;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_threadsCount = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-04 19:48:03 +01:00
|
|
|
|
// Thumbnail settings
|
|
|
|
|
|
private string _thumbnailPrefix = "tn_";
|
|
|
|
|
|
public string ThumbnailPrefix
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _thumbnailPrefix;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_thumbnailPrefix = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int _thumbnailHeight = 350;
|
|
|
|
|
|
public int ThumbnailHeight
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _thumbnailHeight;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_thumbnailHeight = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int _thumbnailWidth = 350;
|
|
|
|
|
|
public int ThumbnailWidth
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _thumbnailWidth;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_thumbnailWidth = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Big photo settings
|
|
|
|
|
|
private int _photoBigHeight = 2240;
|
|
|
|
|
|
public int PhotoBigHeight
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _photoBigHeight;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_photoBigHeight = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int _photoBigWidth = 2240;
|
|
|
|
|
|
public int PhotoBigWidth
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _photoBigWidth;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_photoBigWidth = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Font settings
|
|
|
|
|
|
private int _fontSize = 20;
|
|
|
|
|
|
public int FontSize
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _fontSize;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_fontSize = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int _fontSizeThumbnail = 50;
|
|
|
|
|
|
public int FontSizeThumbnail
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _fontSizeThumbnail;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_fontSizeThumbnail = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private string _fontName = "Arial";
|
|
|
|
|
|
public string FontName
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _fontName;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_fontName = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool _fontBold = false;
|
|
|
|
|
|
public bool FontBold
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _fontBold;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_fontBold = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Text settings
|
|
|
|
|
|
private int _textTransparency = 0;
|
|
|
|
|
|
public int TextTransparency
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _textTransparency;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_textTransparency = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int _textMargin = 8;
|
|
|
|
|
|
public int TextMargin
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _textMargin;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_textMargin = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private string _textColorRGB = "Yellow";
|
|
|
|
|
|
public string TextColorRGB
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _textColorRGB;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_textColorRGB = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-15 11:13:23 +01:00
|
|
|
|
private string _transparentColor = "#FFFFFF";
|
|
|
|
|
|
public string TransparentColor
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _transparentColor;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_transparentColor = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool _useTransparentColor;
|
|
|
|
|
|
public bool UseTransparentColor
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _useTransparentColor;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_useTransparentColor = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-04 19:48:03 +01:00
|
|
|
|
// Logo/Watermark settings
|
|
|
|
|
|
private string _logoFile = "";
|
|
|
|
|
|
public string LogoFile
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _logoFile;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_logoFile = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int _logoHeight = 430;
|
|
|
|
|
|
public int LogoHeight
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _logoHeight;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_logoHeight = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int _logoWidth = 430;
|
|
|
|
|
|
public int LogoWidth
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _logoWidth;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_logoWidth = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int _logoMargin = 290;
|
|
|
|
|
|
public int LogoMargin
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _logoMargin;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_logoMargin = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int _logoTransparency = 100;
|
|
|
|
|
|
public int LogoTransparency
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _logoTransparency;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_logoTransparency = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-15 01:03:26 +01:00
|
|
|
|
// Image library selection (UI radio buttons bind to the boolean helpers)
|
|
|
|
|
|
private string _imageLibrary = "System.Graphics";
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// The selected image processing library. Possible values: "System.Graphics" or "ImageSharp".
|
|
|
|
|
|
/// This value is mirrored into PicSettings.ImageCreatorProvider so the runtime mapper picks the implementation.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public string ImageLibrary
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _imageLibrary;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_imageLibrary == value) return;
|
|
|
|
|
|
_imageLibrary = value;
|
|
|
|
|
|
// Reflect selection into PicSettings so mapper can resolve at runtime
|
|
|
|
|
|
_picSettings.ImageCreatorProvider = string.Equals(value, "ImageSharp", StringComparison.OrdinalIgnoreCase)
|
|
|
|
|
|
? "ALTERNATE"
|
|
|
|
|
|
: "Sharp";
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
NotifyPropertyChanged(nameof(UseSystemGraphics));
|
|
|
|
|
|
NotifyPropertyChanged(nameof(UseImageSharp));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public bool UseSystemGraphics
|
|
|
|
|
|
{
|
|
|
|
|
|
get => string.Equals(ImageLibrary, "System.Graphics", StringComparison.OrdinalIgnoreCase);
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
if (value) ImageLibrary = "System.Graphics";
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public bool UseImageSharp
|
|
|
|
|
|
{
|
|
|
|
|
|
get => string.Equals(ImageLibrary, "ImageSharp", StringComparison.OrdinalIgnoreCase);
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
if (value) ImageLibrary = "ImageSharp";
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-04 19:48:03 +01:00
|
|
|
|
// Folder division settings
|
|
|
|
|
|
private int _filesPerFolder = 99;
|
|
|
|
|
|
public int FilesPerFolder
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _filesPerFolder;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_filesPerFolder = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private string _folderSuffix = "";
|
|
|
|
|
|
public string FolderSuffix
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _folderSuffix;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_folderSuffix = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int _counterDigits = 2;
|
|
|
|
|
|
public int CounterDigits
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _counterDigits;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_counterDigits = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Vertical text settings
|
|
|
|
|
|
private int _verticalTextSize = 20;
|
|
|
|
|
|
public int VerticalTextSize
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _verticalTextSize;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_verticalTextSize = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int _verticalTextMargin = 6;
|
|
|
|
|
|
public int VerticalTextMargin
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _verticalTextMargin;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_verticalTextMargin = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// JPEG compression settings
|
|
|
|
|
|
private int _jpegQuality = 85;
|
|
|
|
|
|
public int JpegQuality
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _jpegQuality;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_jpegQuality = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int _jpegQualityThumbnail = 30;
|
|
|
|
|
|
public int JpegQualityThumbnail
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _jpegQualityThumbnail;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_jpegQualityThumbnail = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// CheckBox settings
|
|
|
|
|
|
private bool _createThumbnails = true;
|
|
|
|
|
|
public bool CreateThumbnails
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _createThumbnails;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_createThumbnails = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool _automaticRotation;
|
|
|
|
|
|
public bool AutomaticRotation
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _automaticRotation;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_automaticRotation = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool _forceJpeg;
|
|
|
|
|
|
public bool ForceJpeg
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _forceJpeg;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_forceJpeg = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool _updateSubdirectories;
|
|
|
|
|
|
public bool UpdateSubdirectories
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _updateSubdirectories;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_updateSubdirectories = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool _createSubfolders;
|
|
|
|
|
|
public bool CreateSubfolders
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _createSubfolders;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_createSubfolders = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool _addTime;
|
|
|
|
|
|
public bool AddTime
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _addTime;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_addTime = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool _addRaceTime;
|
|
|
|
|
|
public bool AddRaceTime
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _addRaceTime;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_addRaceTime = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool _addLogo;
|
|
|
|
|
|
public bool AddLogo
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _addLogo;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_addLogo = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool _keepOriginalDimensions;
|
|
|
|
|
|
public bool KeepOriginalDimensions
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _keepOriginalDimensions;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_keepOriginalDimensions = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool _showDate;
|
|
|
|
|
|
public bool ShowDate
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _showDate;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_showDate = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool _showPhotoNumber;
|
|
|
|
|
|
public bool ShowPhotoNumber
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _showPhotoNumber;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_showPhotoNumber = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool _shutdownSystem;
|
|
|
|
|
|
public bool ShutdownSystem
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _shutdownSystem;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_shutdownSystem = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ComboBox position/alignment settings
|
|
|
|
|
|
private string _verticalPosition = "Basso";
|
|
|
|
|
|
public string VerticalPosition
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _verticalPosition;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_verticalPosition = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private string _horizontalAlignment = "Centro";
|
|
|
|
|
|
public string HorizontalAlignment
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _horizontalAlignment;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_horizontalAlignment = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private string _logoHorizontalPosition = "Destra";
|
|
|
|
|
|
public string LogoHorizontalPosition
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _logoHorizontalPosition;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_logoHorizontalPosition = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private string _logoVerticalPosition = "Basso";
|
|
|
|
|
|
public string LogoVerticalPosition
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _logoVerticalPosition;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_logoVerticalPosition = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// RadioButton settings
|
|
|
|
|
|
private bool _useProgressiveNumbering = true;
|
|
|
|
|
|
public bool UseProgressiveNumbering
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _useProgressiveNumbering;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_useProgressiveNumbering = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool _useFileNumbering;
|
|
|
|
|
|
public bool UseFileNumbering
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _useFileNumbering;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_useFileNumbering = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool _useParallelProcessing = true;
|
|
|
|
|
|
public bool UseParallelProcessing
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _useParallelProcessing;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_useParallelProcessing = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool _useSequentialProcessing;
|
|
|
|
|
|
public bool UseSequentialProcessing
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _useSequentialProcessing;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_useSequentialProcessing = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Additional settings that were missing
|
|
|
|
|
|
private bool _addTimeToThumbnails;
|
|
|
|
|
|
public bool AddTimeToThumbnails
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _addTimeToThumbnails;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_addTimeToThumbnails = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool _showFileNameOnThumbnails;
|
|
|
|
|
|
public bool ShowFileNameOnThumbnails
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _showFileNameOnThumbnails;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_showFileNameOnThumbnails = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private DateTime _raceStartDate = DateTime.Now;
|
|
|
|
|
|
public DateTime RaceStartDate
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _raceStartDate;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_raceStartDate = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private string _timeLabel = "";
|
|
|
|
|
|
public string TimeLabel
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _timeLabel;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_timeLabel = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-04 22:10:16 +01:00
|
|
|
|
private string _bigPhotoSuffix = "";
|
|
|
|
|
|
public string BigPhotoSuffix
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _bigPhotoSuffix;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_bigPhotoSuffix = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool _addTextToThumbnails;
|
|
|
|
|
|
public bool AddTextToThumbnails
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _addTextToThumbnails;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_addTextToThumbnails = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool _addRaceTimeToThumbnails;
|
|
|
|
|
|
public bool AddRaceTimeToThumbnails
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _addRaceTimeToThumbnails;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_addRaceTimeToThumbnails = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool _addNumberAndTimeToThumbnails;
|
|
|
|
|
|
public bool AddNumberAndTimeToThumbnails
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _addNumberAndTimeToThumbnails;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_addNumberAndTimeToThumbnails = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-04 23:16:06 +01:00
|
|
|
|
// Image processing progress and status
|
|
|
|
|
|
private string _processingStatus = "";
|
|
|
|
|
|
public string ProcessingStatus
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _processingStatus;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_processingStatus = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int _processedImagesCount = 0;
|
|
|
|
|
|
public int ProcessedImagesCount
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _processedImagesCount;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_processedImagesCount = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int _totalImagesCount = 0;
|
|
|
|
|
|
public int TotalImagesCount
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _totalImagesCount;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_totalImagesCount = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int _progressBarValue = 0;
|
|
|
|
|
|
public int ProgressBarValue
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _progressBarValue;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_progressBarValue = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int _progressBarMaximum = 100;
|
|
|
|
|
|
public int ProgressBarMaximum
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _progressBarMaximum;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_progressBarMaximum = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private ConcurrentBag<string> _results = new();
|
|
|
|
|
|
private int _currentAmount = 0;
|
|
|
|
|
|
private int _previousAmount = 0;
|
2026-02-10 21:18:46 +01:00
|
|
|
|
// Atomic counter for processed images — avoids expensive ConcurrentBag.Count enumerations
|
|
|
|
|
|
private int _processedAtomic = 0;
|
2026-02-04 23:16:06 +01:00
|
|
|
|
private System.Threading.Timer? _speedTimer;
|
2026-02-14 19:36:58 +01:00
|
|
|
|
// Stopwatch used to compute run-wide averages
|
|
|
|
|
|
private Stopwatch? _speedWatch;
|
|
|
|
|
|
// Recent diffs queue to smooth short-term fluctuations
|
|
|
|
|
|
private readonly Queue<int> _recentDiffs = new();
|
|
|
|
|
|
private int _recentWindowSize = 5; // average over last 5 samples (~5s)
|
2026-02-04 23:16:06 +01:00
|
|
|
|
|
2024-10-14 23:25:35 +02:00
|
|
|
|
private void Test(object parameter)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.WriteLine("Yep");
|
2024-10-14 23:48:21 +02:00
|
|
|
|
this.UiEnabled = !this.UiEnabled;
|
2024-10-14 23:25:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async Task TestAsync()
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.WriteLine("Yep c");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-23 17:16:06 +02:00
|
|
|
|
private async Task ProcessImages()
|
|
|
|
|
|
{
|
2026-02-04 23:16:06 +01:00
|
|
|
|
_logger.LogInformation("Avvio elaborazione...");
|
|
|
|
|
|
UiEnabled = false;
|
|
|
|
|
|
|
|
|
|
|
|
MainToken?.Dispose();
|
|
|
|
|
|
MainToken = new CancellationTokenSource();
|
|
|
|
|
|
var token = MainToken.Token;
|
|
|
|
|
|
|
|
|
|
|
|
// Fix paths
|
|
|
|
|
|
FixPaths();
|
|
|
|
|
|
|
|
|
|
|
|
// Reset counters
|
|
|
|
|
|
ProcessingStatus = "Elaborazione in corso...";
|
|
|
|
|
|
TotalImagesCount = 0;
|
|
|
|
|
|
ProcessedImagesCount = 0;
|
2026-02-10 21:18:46 +01:00
|
|
|
|
SpeedCounter = "-f/s";
|
2026-02-04 23:16:06 +01:00
|
|
|
|
ProgressBarValue = 0;
|
|
|
|
|
|
ProgressBarMaximum = 100;
|
|
|
|
|
|
|
|
|
|
|
|
// Update PicSettings from DataModel using AutoMapper
|
|
|
|
|
|
_mapper.Map(this, _picSettings);
|
|
|
|
|
|
|
|
|
|
|
|
var imageCreationOptions = new ImageCreationStuff.Options
|
|
|
|
|
|
{
|
|
|
|
|
|
AggiornaSottodirectory = UpdateSubdirectories,
|
|
|
|
|
|
CreaSottocartelle = CreateSubfolders,
|
|
|
|
|
|
FilePerCartella = FilesPerFolder,
|
|
|
|
|
|
SuffissoCartelle = FolderSuffix,
|
|
|
|
|
|
CifreContatore = CounterDigits,
|
|
|
|
|
|
NumerazioneType = UseProgressiveNumbering ? NumerazioneType.Progressiva : NumerazioneType.Files,
|
|
|
|
|
|
SourcePath = SourcePath,
|
|
|
|
|
|
DestinationPath = DestinationPath,
|
|
|
|
|
|
MaxThreads = ThreadsCount,
|
|
|
|
|
|
ChunksSize = ChunkSize,
|
|
|
|
|
|
LinearExecution = UseSequentialProcessing
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
_results = new ConcurrentBag<string>();
|
|
|
|
|
|
_currentAmount = 0;
|
|
|
|
|
|
_previousAmount = 0;
|
2026-02-10 21:18:46 +01:00
|
|
|
|
_processedAtomic = 0;
|
2026-02-04 23:16:06 +01:00
|
|
|
|
|
2026-02-10 21:18:46 +01:00
|
|
|
|
// Start speed timer (sample every second using lightweight atomic reads)
|
2026-02-14 19:36:58 +01:00
|
|
|
|
_speedWatch = Stopwatch.StartNew();
|
|
|
|
|
|
_recentDiffs.Clear();
|
2026-02-10 21:18:46 +01:00
|
|
|
|
_speedTimer = new System.Threading.Timer(UpdateSpeedCounter, null, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
|
2026-02-04 23:16:06 +01:00
|
|
|
|
|
|
|
|
|
|
var time = await _imageCreationService.CreaCatalogoParallel(
|
|
|
|
|
|
imageCreationOptions,
|
|
|
|
|
|
_results,
|
|
|
|
|
|
OnImageProcessed,
|
|
|
|
|
|
token);
|
|
|
|
|
|
|
2026-02-14 19:36:58 +01:00
|
|
|
|
// Compute final averages and show only averages (do not show raw seconds)
|
|
|
|
|
|
var finalProcessed = System.Threading.Volatile.Read(ref _processedAtomic);
|
|
|
|
|
|
double overallAvg = 0.0;
|
|
|
|
|
|
double overallPerMin = 0.0;
|
|
|
|
|
|
if (_speedWatch is not null && _speedWatch.Elapsed.TotalSeconds > 0.0)
|
|
|
|
|
|
{
|
|
|
|
|
|
overallAvg = finalProcessed / _speedWatch.Elapsed.TotalSeconds;
|
|
|
|
|
|
overallPerMin = overallAvg * 60.0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Compute elapsed time as h m s and show final averages (no raw seconds parentheses)
|
|
|
|
|
|
var finalElapsed = _speedWatch?.Elapsed ?? TimeSpan.Zero;
|
|
|
|
|
|
int fh = (int)finalElapsed.TotalHours;
|
|
|
|
|
|
int fm = finalElapsed.Minutes;
|
|
|
|
|
|
int fs = finalElapsed.Seconds;
|
|
|
|
|
|
|
|
|
|
|
|
SpeedCounter = $"{fh}h {fm}m {fs}s{Environment.NewLine}media: {overallAvg:0.00} f/s{Environment.NewLine}media: {overallPerMin:0.00} f/m";
|
|
|
|
|
|
|
2026-02-04 23:16:06 +01:00
|
|
|
|
_speedTimer?.Dispose();
|
|
|
|
|
|
_speedTimer = null;
|
2026-02-14 19:36:58 +01:00
|
|
|
|
_speedWatch?.Stop();
|
|
|
|
|
|
_speedWatch = null;
|
2026-02-04 23:16:06 +01:00
|
|
|
|
}
|
|
|
|
|
|
catch (OperationCanceledException)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogInformation("Operazione Cancellata");
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError(ex, "Errore durante l'elaborazione delle immagini");
|
|
|
|
|
|
ProcessingStatus = $"Errore: {ex.Message}";
|
|
|
|
|
|
}
|
|
|
|
|
|
finally
|
|
|
|
|
|
{
|
|
|
|
|
|
MainToken?.Dispose();
|
|
|
|
|
|
MainToken = null;
|
|
|
|
|
|
_speedTimer?.Dispose();
|
|
|
|
|
|
_speedTimer = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ProcessingStatus = "Finito";
|
|
|
|
|
|
UiEnabled = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void UpdateSpeedCounter(object? state)
|
|
|
|
|
|
{
|
2026-02-14 19:36:58 +01:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
_previousAmount = _currentAmount;
|
|
|
|
|
|
// Read the atomic counter without enumerating the ConcurrentBag
|
|
|
|
|
|
_currentAmount = System.Threading.Volatile.Read(ref _processedAtomic);
|
|
|
|
|
|
int diff = _currentAmount - _previousAmount;
|
|
|
|
|
|
|
|
|
|
|
|
// Protect against negative or spurious diffs
|
|
|
|
|
|
if (diff < 0) diff = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// Maintain a small sliding window of recent diffs to smooth the display
|
|
|
|
|
|
lock (_recentDiffs)
|
|
|
|
|
|
{
|
|
|
|
|
|
_recentDiffs.Enqueue(diff);
|
|
|
|
|
|
if (_recentDiffs.Count > _recentWindowSize)
|
|
|
|
|
|
_recentDiffs.Dequeue();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
double avgRecent;
|
|
|
|
|
|
lock (_recentDiffs)
|
|
|
|
|
|
{
|
|
|
|
|
|
avgRecent = _recentDiffs.Count == 0 ? 0.0 : _recentDiffs.Average();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Compute overall average (since start) if we have a stopwatch
|
|
|
|
|
|
double overall = 0.0;
|
|
|
|
|
|
if (_speedWatch is not null && _speedWatch.Elapsed.TotalSeconds >= 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
var elapsedSeconds = _speedWatch.Elapsed.TotalSeconds;
|
|
|
|
|
|
var total = System.Threading.Volatile.Read(ref _processedAtomic);
|
|
|
|
|
|
overall = elapsedSeconds > 0 ? total / elapsedSeconds : 0.0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Recent per-minute estimate
|
|
|
|
|
|
var recentPerMin = avgRecent * 60.0;
|
|
|
|
|
|
var overallPerMin = overall * 60.0;
|
|
|
|
|
|
|
|
|
|
|
|
// Build a two-line display plus elapsed time: first line shows f/s with overall media and elapsed time,
|
|
|
|
|
|
// second line shows recent photos per minute (media)
|
|
|
|
|
|
var elapsed = _speedWatch?.Elapsed ?? TimeSpan.Zero;
|
|
|
|
|
|
int hours = (int)elapsed.TotalHours;
|
|
|
|
|
|
int minutes = elapsed.Minutes;
|
|
|
|
|
|
int seconds = elapsed.Seconds;
|
|
|
|
|
|
var elapsedStr = $"{hours}h {minutes}m {seconds}s";
|
|
|
|
|
|
|
|
|
|
|
|
SpeedCounter = $"{avgRecent:0.00} f/s (media: {overall:0.00} f/s) - {elapsedStr}{Environment.NewLine}media: {recentPerMin:0.00} f/m";
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
// Swallow unlikely errors from timing/queue operations but keep UI responsive
|
|
|
|
|
|
}
|
2026-02-04 23:16:06 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void OnImageProcessed(object? sender, Tuple<string, int> args)
|
|
|
|
|
|
{
|
2026-02-10 21:18:46 +01:00
|
|
|
|
// Increment atomic processed counter once and use its value for all UI updates
|
|
|
|
|
|
var processed = System.Threading.Interlocked.Increment(ref _processedAtomic);
|
|
|
|
|
|
ProcessedImagesCount = processed;
|
2026-02-04 23:16:06 +01:00
|
|
|
|
TotalImagesCount = args.Item2;
|
|
|
|
|
|
ProgressBarMaximum = args.Item2;
|
2026-02-10 21:18:46 +01:00
|
|
|
|
ProgressBarValue = processed;
|
2026-02-04 23:16:06 +01:00
|
|
|
|
ProcessingStatus = args.Item1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void FixPaths()
|
|
|
|
|
|
{
|
|
|
|
|
|
SourcePath = FixPath(SourcePath);
|
|
|
|
|
|
DestinationPath = FixPath(DestinationPath);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private string FixPath(string path)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(path))
|
|
|
|
|
|
{
|
|
|
|
|
|
return string.Empty;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Trim leading/trailing quotes
|
|
|
|
|
|
path = path.Trim().Trim('"');
|
|
|
|
|
|
|
|
|
|
|
|
// Normalize directory separators
|
|
|
|
|
|
path = path.Replace('/', System.IO.Path.DirectorySeparatorChar)
|
|
|
|
|
|
.Replace('\\', System.IO.Path.DirectorySeparatorChar);
|
|
|
|
|
|
|
|
|
|
|
|
// Remove trailing separators then add one back
|
|
|
|
|
|
path = path.TrimEnd(System.IO.Path.DirectorySeparatorChar) + System.IO.Path.DirectorySeparatorChar;
|
|
|
|
|
|
|
|
|
|
|
|
return path;
|
2025-07-23 17:16:06 +02:00
|
|
|
|
}
|
2025-07-29 11:07:49 +02:00
|
|
|
|
|
|
|
|
|
|
private async Task CancelOperation()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
await MainToken?.CancelAsync();
|
|
|
|
|
|
|
|
|
|
|
|
UiEnabled = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError(e.Message, "Error canceling the token");
|
|
|
|
|
|
_logger.LogInformation("Ignora questo errore");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-02-04 19:48:03 +01:00
|
|
|
|
|
|
|
|
|
|
// Note: These commands will trigger events that the View will handle to show dialogs
|
|
|
|
|
|
// since dialogs require UI context
|
|
|
|
|
|
public event EventHandler SelectSourceFolderRequested;
|
|
|
|
|
|
public event EventHandler SelectDestinationFolderRequested;
|
|
|
|
|
|
public event EventHandler SelectLogoFileRequested;
|
|
|
|
|
|
public event EventHandler<string> SaveSettingsRequested;
|
|
|
|
|
|
public event EventHandler<string> LoadSettingsRequested;
|
|
|
|
|
|
public event EventHandler SelectColorRequested;
|
2026-02-14 19:20:25 +01:00
|
|
|
|
// Request that the View shows a message to the user (message, caption, icon)
|
|
|
|
|
|
public event EventHandler<Tuple<string, string, MessageBoxIcon>> ShowMessageRequested;
|
2026-02-15 11:13:23 +01:00
|
|
|
|
public event EventHandler SelectTransparentColorRequested;
|
2026-02-04 19:48:03 +01:00
|
|
|
|
|
|
|
|
|
|
private void SelectSourceFolder(object parameter)
|
|
|
|
|
|
{
|
|
|
|
|
|
SelectSourceFolderRequested?.Invoke(this, EventArgs.Empty);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void SelectDestinationFolder(object parameter)
|
|
|
|
|
|
{
|
|
|
|
|
|
SelectDestinationFolderRequested?.Invoke(this, EventArgs.Empty);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void SelectLogoFile(object parameter)
|
|
|
|
|
|
{
|
|
|
|
|
|
SelectLogoFileRequested?.Invoke(this, EventArgs.Empty);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void SaveSettings(object parameter)
|
|
|
|
|
|
{
|
|
|
|
|
|
SaveSettingsRequested?.Invoke(this, null);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void LoadSettings(object parameter)
|
|
|
|
|
|
{
|
|
|
|
|
|
LoadSettingsRequested?.Invoke(this, null);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void SelectColor(object parameter)
|
|
|
|
|
|
{
|
|
|
|
|
|
SelectColorRequested?.Invoke(this, EventArgs.Empty);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-15 11:13:23 +01:00
|
|
|
|
private void SelectTransparentColor(object parameter)
|
|
|
|
|
|
{
|
|
|
|
|
|
SelectTransparentColorRequested?.Invoke(this, EventArgs.Empty);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-04 19:48:03 +01:00
|
|
|
|
public async Task SaveSettingsToFileAsync(string filePath)
|
|
|
|
|
|
{
|
|
|
|
|
|
await _settingsService.SaveSettingsAsync(filePath, this);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public async Task LoadSettingsFromFileAsync(string filePath)
|
|
|
|
|
|
{
|
|
|
|
|
|
await _settingsService.LoadSettingsAsync(filePath, this);
|
|
|
|
|
|
}
|
2026-02-14 22:18:56 +01:00
|
|
|
|
|
|
|
|
|
|
private string _appVersion = string.Empty;
|
|
|
|
|
|
public string AppVersion
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _appVersion;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_appVersion = value;
|
|
|
|
|
|
NotifyPropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-10-14 22:55:52 +02:00
|
|
|
|
}
|
2026-02-10 21:18:46 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|