2026-05-26 21:47:55 +02:00
|
|
|
using System.Globalization;
|
|
|
|
|
using System.Xml.Linq;
|
|
|
|
|
using MaddoShared;
|
2026-05-28 20:27:05 +02:00
|
|
|
using SixLabors.ImageSharp;
|
|
|
|
|
using SixLabors.ImageSharp.PixelFormats;
|
2026-05-26 21:47:55 +02:00
|
|
|
|
|
|
|
|
namespace CatalogLite;
|
|
|
|
|
|
|
|
|
|
public sealed class CatalogConfigurationLoader
|
|
|
|
|
{
|
|
|
|
|
public CatalogLiteConfiguration Load(string filePath, PicSettings picSettings)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrWhiteSpace(filePath))
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentException("Percorso configurazione non valido.", nameof(filePath));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!File.Exists(filePath))
|
|
|
|
|
{
|
|
|
|
|
throw new FileNotFoundException("File configurazione non trovato.", filePath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var values = ConfigurationValues.Load(filePath);
|
|
|
|
|
ApplyPicSettings(values, picSettings);
|
|
|
|
|
|
|
|
|
|
var sourcePath = LiteCatalogViewModel.NormalizeDirectoryPath(values.GetString("DirSorgente"));
|
|
|
|
|
var destinationPath = LiteCatalogViewModel.NormalizeDirectoryPath(values.GetString("DirDestinazione"));
|
|
|
|
|
|
|
|
|
|
picSettings.DirectorySorgente = sourcePath;
|
|
|
|
|
picSettings.DirectoryDestinazione = destinationPath;
|
|
|
|
|
picSettings.DestDir = string.IsNullOrWhiteSpace(destinationPath)
|
|
|
|
|
? new DirectoryInfo(Environment.CurrentDirectory)
|
|
|
|
|
: new DirectoryInfo(destinationPath);
|
|
|
|
|
|
|
|
|
|
return new CatalogLiteConfiguration
|
|
|
|
|
{
|
|
|
|
|
FilePath = filePath,
|
|
|
|
|
SourcePath = sourcePath,
|
|
|
|
|
DestinationPath = destinationPath,
|
|
|
|
|
Options = BuildOptions(values, sourcePath, destinationPath)
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static ImageCreationService.Options CloneOptions(ImageCreationService.Options options, string sourcePath, string destinationPath)
|
|
|
|
|
{
|
|
|
|
|
return new ImageCreationService.Options
|
|
|
|
|
{
|
|
|
|
|
AggiornaSottodirectory = options.AggiornaSottodirectory,
|
|
|
|
|
CreaSottocartelle = options.CreaSottocartelle,
|
|
|
|
|
FilePerCartella = options.FilePerCartella,
|
|
|
|
|
SuffissoCartelle = options.SuffissoCartelle,
|
|
|
|
|
CifreContatore = options.CifreContatore,
|
|
|
|
|
NumerazioneType = options.NumerazioneType,
|
|
|
|
|
SourcePath = sourcePath,
|
|
|
|
|
DestinationPath = destinationPath,
|
|
|
|
|
MaxThreads = Math.Max(1, options.MaxThreads),
|
|
|
|
|
ChunksSize = options.ChunksSize,
|
|
|
|
|
LinearExecution = options.LinearExecution
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void ApplyPicSettings(ConfigurationValues values, PicSettings settings)
|
|
|
|
|
{
|
|
|
|
|
settings.DirectorySorgente = values.GetString("DirSorgente");
|
|
|
|
|
settings.DirectoryDestinazione = values.GetString("DirDestinazione");
|
|
|
|
|
settings.TestoFirmaStart = values.GetString("TestoTesto");
|
|
|
|
|
settings.TestoFirmaStartV = values.GetString("TestoVerticale");
|
|
|
|
|
settings.DataPartenza = values.GetDateTime("DataPartenza", DateTime.Now);
|
|
|
|
|
settings.TestoOrario = values.GetString("EtichettaOrario");
|
|
|
|
|
settings.DimStandard = values.GetInt("FontDimensione", 20);
|
|
|
|
|
settings.DimStandardMiniatura = values.GetInt("FontDimensioneMiniatura", 50);
|
|
|
|
|
settings.NomeData = values.GetBool("DataFoto");
|
|
|
|
|
settings.TestoNome = values.GetBool("NumeroFoto");
|
|
|
|
|
settings.UsaOrarioMiniatura = IsThumbnailMode(values, "Time") || values.GetBool("MiniatureAddOrario");
|
|
|
|
|
settings.UsaOrarioTestoApplicare = values.GetBool("Orario");
|
|
|
|
|
settings.UsaTempoGaraTestoApplicare = values.GetBool("TempoGara");
|
|
|
|
|
settings.UsaRotazioneAutomatica = values.GetBool("GeneraleRotazioneAutomatica");
|
|
|
|
|
settings.UsaForzaJpg = values.GetBool("GeneraleForzaJpg");
|
|
|
|
|
settings.LarghezzaSmall = values.GetInt("MiniatureLarghezza", 350);
|
|
|
|
|
settings.AltezzaSmall = values.GetInt("MiniatureAltezza", 350);
|
|
|
|
|
settings.CreaMiniature = values.GetBool("MiniatureCrea", true);
|
|
|
|
|
settings.AggiungiScritteMiniature = IsThumbnailMode(values, "Text") || values.GetBool("MiniatureAddScritta");
|
|
|
|
|
settings.Suffisso = values.GetString("MiniatureSuffisso", "tn_");
|
|
|
|
|
settings.Codice = values.GetString("FotoCodice");
|
|
|
|
|
settings.Trasparenza = values.GetInt("TestoTrasparente", 0);
|
|
|
|
|
settings.IlFont = values.GetString("FontNome", "Arial");
|
|
|
|
|
settings.Grassetto = values.GetBool("FontBold");
|
|
|
|
|
settings.Posizione = values.GetString("TestoPosizione", "Basso");
|
|
|
|
|
settings.Allineamento = values.GetString("TestoAllineamento", "Centro");
|
|
|
|
|
settings.Margine = values.GetInt("TestoMargine", 8);
|
|
|
|
|
settings.LogoAltezza = values.GetInt("MarchioAltezza", 430);
|
|
|
|
|
settings.LogoLarghezza = values.GetInt("MarchioLarghezza", 430);
|
2026-05-28 20:27:05 +02:00
|
|
|
settings.FontColoreRGB = ParseColor(values.GetString("ColoreTestoRGB", "Yellow"), new Rgba32(255, 255, 0, 255));
|
2026-05-26 21:47:55 +02:00
|
|
|
settings.LogoAggiungi = values.GetBool("MarchioAggiungi");
|
|
|
|
|
settings.LogoNomeFile = values.GetString("MarchioFile");
|
|
|
|
|
settings.LogoTrasparenza = values.GetInt("MarchioTrasparenza", 100).ToString(CultureInfo.InvariantCulture);
|
|
|
|
|
settings.LogoMargine = values.GetString("MarchioMargine", "0");
|
|
|
|
|
settings.LogoPosizioneH = values.GetString("MarchioAllOrizzontale", "Destra");
|
|
|
|
|
settings.LogoPosizioneV = values.GetString("MarchioAllVerticale", "Basso");
|
|
|
|
|
settings.TransparentColor = values.GetString("ColoreTrasparente", "#FFFFFF");
|
|
|
|
|
settings.UseTransparentColor = values.GetBool("UsaColoreTrasparente");
|
|
|
|
|
settings.FotoGrandeDimOrigina = values.GetBool("FotoDimOriginali");
|
|
|
|
|
settings.AltezzaBig = values.GetInt("FotoAltezza", 2240);
|
|
|
|
|
settings.LarghezzaBig = values.GetInt("FotoLarghezza", 2240);
|
|
|
|
|
settings.DimVert = values.GetInt("GrandezzaVerticale", 20);
|
|
|
|
|
settings.MargVert = values.GetInt("MargineVerticale", 6);
|
|
|
|
|
settings.TestoMin = IsThumbnailMode(values, "FileName") || values.GetBool("NomeMiniatura");
|
|
|
|
|
settings.DimMin = values.GetInt("FontDimensioneMiniatura", 50);
|
|
|
|
|
settings.SecretDefault = false;
|
|
|
|
|
settings.SecretBig = false;
|
|
|
|
|
settings.SecretSmall = false;
|
|
|
|
|
settings.SecretPathSmall = string.Empty;
|
|
|
|
|
settings.SecretPathBig = string.Empty;
|
|
|
|
|
settings.AggTempoGaraMin = IsThumbnailMode(values, "RaceTime") || values.GetBool("TempoSmall");
|
|
|
|
|
settings.AggNumTempMin = IsThumbnailMode(values, "FileNameAndTime") || values.GetBool("NumTempoSmall");
|
|
|
|
|
settings.JpegQuality = values.GetLong("CompressioneJpeg", 85);
|
|
|
|
|
settings.JpegQualityMin = values.GetLong("CompressioneJpegMiniatura", 30);
|
|
|
|
|
settings.FotoRuotaADestra = false;
|
|
|
|
|
settings.FotoRuotaASinistra = false;
|
|
|
|
|
settings.TempMinText = string.Empty;
|
|
|
|
|
settings.OverwriteFiles = values.GetBool("GeneraleSovrascriviFile");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static ImageCreationService.Options BuildOptions(ConfigurationValues values, string sourcePath, string destinationPath)
|
|
|
|
|
{
|
|
|
|
|
var threads = values.GetInt("ThreadsCount", Environment.ProcessorCount);
|
|
|
|
|
if (threads <= 0)
|
|
|
|
|
{
|
|
|
|
|
threads = Environment.ProcessorCount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new ImageCreationService.Options
|
|
|
|
|
{
|
|
|
|
|
AggiornaSottodirectory = values.GetBool("DirSottoDirectory"),
|
|
|
|
|
CreaSottocartelle = values.GetBool("DirCreaSottocartelle", values.GetBool("CreateSubfolders")),
|
|
|
|
|
FilePerCartella = Math.Max(1, values.GetInt("DirDividiNumFile", 99)),
|
|
|
|
|
SuffissoCartelle = values.GetString("DirDividiSuffisso"),
|
|
|
|
|
CifreContatore = Math.Max(1, values.GetInt("DirDividiNumCifre", 2)),
|
|
|
|
|
NumerazioneType = values.GetBool("DirNumerazioneProgressiva", true) ? NumerazioneType.Progressiva : NumerazioneType.Files,
|
|
|
|
|
SourcePath = sourcePath,
|
|
|
|
|
DestinationPath = destinationPath,
|
|
|
|
|
MaxThreads = Math.Max(1, threads),
|
|
|
|
|
ChunksSize = Math.Max(0, values.GetInt("ChunkSize", 0)),
|
|
|
|
|
LinearExecution = values.GetBool("UseSequentialProcessing")
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static bool IsThumbnailMode(ConfigurationValues values, string mode)
|
|
|
|
|
{
|
|
|
|
|
return string.Equals(values.GetString("MiniatureModalita"), mode, StringComparison.OrdinalIgnoreCase);
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-28 20:27:05 +02:00
|
|
|
private static Rgba32 ParseColor(string value, Rgba32 fallback)
|
2026-05-26 21:47:55 +02:00
|
|
|
{
|
|
|
|
|
if (string.IsNullOrWhiteSpace(value))
|
|
|
|
|
{
|
|
|
|
|
return fallback;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var normalized = value.Trim();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (normalized.StartsWith('#') && normalized.Length == 7)
|
|
|
|
|
{
|
2026-05-28 20:27:05 +02:00
|
|
|
return new Rgba32(
|
|
|
|
|
Convert.ToByte(normalized[1..3], 16),
|
|
|
|
|
Convert.ToByte(normalized[3..5], 16),
|
|
|
|
|
Convert.ToByte(normalized[5..7], 16),
|
|
|
|
|
255);
|
2026-05-26 21:47:55 +02:00
|
|
|
}
|
|
|
|
|
|
2026-05-28 20:27:05 +02:00
|
|
|
if (normalized.Length == 6 && normalized.All(Uri.IsHexDigit))
|
|
|
|
|
{
|
|
|
|
|
normalized = "#" + normalized;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Color.Parse(normalized).ToPixel<Rgba32>();
|
2026-05-26 21:47:55 +02:00
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
return fallback;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private sealed class ConfigurationValues
|
|
|
|
|
{
|
|
|
|
|
private readonly Dictionary<string, string> _values;
|
|
|
|
|
|
|
|
|
|
private ConfigurationValues(Dictionary<string, string> values)
|
|
|
|
|
{
|
|
|
|
|
_values = values;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static ConfigurationValues Load(string filePath)
|
|
|
|
|
{
|
|
|
|
|
var document = XDocument.Load(filePath);
|
|
|
|
|
var values = document
|
|
|
|
|
.Descendants("Setup")
|
|
|
|
|
.Where(element => element.Element("Nome") is not null)
|
|
|
|
|
.GroupBy(element => element.Element("Nome")!.Value, StringComparer.OrdinalIgnoreCase)
|
|
|
|
|
.ToDictionary(
|
|
|
|
|
group => group.Key,
|
|
|
|
|
group => group.Last().Element("Valore")?.Value ?? string.Empty,
|
|
|
|
|
StringComparer.OrdinalIgnoreCase);
|
|
|
|
|
|
|
|
|
|
if (values.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
values = document.Root?
|
|
|
|
|
.Descendants()
|
|
|
|
|
.Where(element => !element.HasElements)
|
|
|
|
|
.GroupBy(element => element.Name.LocalName, StringComparer.OrdinalIgnoreCase)
|
|
|
|
|
.ToDictionary(group => group.Key, group => group.Last().Value, StringComparer.OrdinalIgnoreCase)
|
|
|
|
|
?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new ConfigurationValues(values);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string GetString(string name, string defaultValue = "")
|
|
|
|
|
{
|
|
|
|
|
return _values.TryGetValue(name, out var value) && !string.IsNullOrWhiteSpace(value)
|
|
|
|
|
? value.Trim()
|
|
|
|
|
: defaultValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool GetBool(string name, bool defaultValue = false)
|
|
|
|
|
{
|
|
|
|
|
var value = GetString(name);
|
|
|
|
|
if (string.IsNullOrWhiteSpace(value))
|
|
|
|
|
{
|
|
|
|
|
return defaultValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return value.Trim().ToUpperInvariant() switch
|
|
|
|
|
{
|
|
|
|
|
"TRUE" or "OK" or "SI" or "SÌ" or "1" or "YES" or "VERO" => true,
|
|
|
|
|
"FALSE" or "NO" or "0" or "FALSO" => false,
|
|
|
|
|
_ => defaultValue
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int GetInt(string name, int defaultValue = 0)
|
|
|
|
|
{
|
|
|
|
|
return int.TryParse(GetString(name), NumberStyles.Integer, CultureInfo.InvariantCulture, out var value)
|
|
|
|
|
? value
|
|
|
|
|
: defaultValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public long GetLong(string name, long defaultValue = 0)
|
|
|
|
|
{
|
|
|
|
|
return long.TryParse(GetString(name), NumberStyles.Integer, CultureInfo.InvariantCulture, out var value)
|
|
|
|
|
? value
|
|
|
|
|
: defaultValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public DateTime GetDateTime(string name, DateTime defaultValue)
|
|
|
|
|
{
|
|
|
|
|
var value = GetString(name);
|
|
|
|
|
if (DateTime.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var invariantDate))
|
|
|
|
|
{
|
|
|
|
|
return invariantDate;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return DateTime.TryParse(value, CultureInfo.CurrentCulture, DateTimeStyles.AssumeLocal, out var localDate)
|
|
|
|
|
? localDate
|
|
|
|
|
: defaultValue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|