From e48c0d266bf56f6547aab50eaa12d29fb790d0e0 Mon Sep 17 00:00:00 2001 From: MaddoScientisto Date: Sun, 15 Feb 2026 00:14:04 +0100 Subject: [PATCH] Add IImageCreator abstraction and runtime provider selection Introduce IImageCreator interface for image creation, and update ImageCreatorSharp to implement it. Add ImageCreatorAlternate (adapter) and ImageCreatorMapper (runtime selector) classes. Extend PicSettings with ImageCreatorProvider to control backend selection. Update DI registrations and refactor ImageCreationStuff to depend on IImageCreator, enabling backend switching via configuration. --- MaddoShared/IImageCreator.cs | 9 +++++ MaddoShared/ImageCreationStuff.cs | 2 +- MaddoShared/ImageCreatorAlternate.cs | 25 ++++++++++++++ MaddoShared/ImageCreatorMapper.cs | 49 ++++++++++++++++++++++++++++ MaddoShared/ImageCreatorSharp.cs | 2 +- MaddoShared/PicSettings.cs | 2 ++ imagecatalog/Program.cs | 5 +++ 7 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 MaddoShared/IImageCreator.cs create mode 100644 MaddoShared/ImageCreatorAlternate.cs create mode 100644 MaddoShared/ImageCreatorMapper.cs diff --git a/MaddoShared/IImageCreator.cs b/MaddoShared/IImageCreator.cs new file mode 100644 index 0000000..6fd85a5 --- /dev/null +++ b/MaddoShared/IImageCreator.cs @@ -0,0 +1,9 @@ +using System.Drawing; +using System.Threading.Tasks; + +namespace MaddoShared; + +public interface IImageCreator +{ + Task CreateImageAsync(ImageState imgState, Image logo); +} diff --git a/MaddoShared/ImageCreationStuff.cs b/MaddoShared/ImageCreationStuff.cs index 7aef4d4..b688f3a 100644 --- a/MaddoShared/ImageCreationStuff.cs +++ b/MaddoShared/ImageCreationStuff.cs @@ -18,7 +18,7 @@ namespace MaddoShared public class ImageCreationStuff( ILogger logger, PicSettings picSettings, - ImageCreatorSharp imageCreatorService) + IImageCreator imageCreatorService) { public class Options { diff --git a/MaddoShared/ImageCreatorAlternate.cs b/MaddoShared/ImageCreatorAlternate.cs new file mode 100644 index 0000000..2c945e8 --- /dev/null +++ b/MaddoShared/ImageCreatorAlternate.cs @@ -0,0 +1,25 @@ +using System.Drawing; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; + +namespace MaddoShared; + +// Minimal alternate adapter that currently delegates to ImageCreatorSharp. +// Later this can be replaced with a different library implementation. +public class ImageCreatorAlternate : IImageCreator +{ + private readonly ImageCreatorSharp _inner; + private readonly ILogger _logger; + + public ImageCreatorAlternate(ImageCreatorSharp inner, ILogger logger) + { + _inner = inner; + _logger = logger; + } + + public Task CreateImageAsync(ImageState imgState, Image logo) + { + _logger.LogDebug("Using alternate image creator adapter"); + return _inner.CreateImageAsync(imgState, logo); + } +} diff --git a/MaddoShared/ImageCreatorMapper.cs b/MaddoShared/ImageCreatorMapper.cs new file mode 100644 index 0000000..8ee07cf --- /dev/null +++ b/MaddoShared/ImageCreatorMapper.cs @@ -0,0 +1,49 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; + +namespace MaddoShared; + +/// +/// Dynamically resolves the concrete IImageCreator implementation at call time +/// based on current PicSettings.ImageCreatorProvider. +/// +public class ImageCreatorMapper : IImageCreator +{ + private readonly IServiceProvider _sp; + private readonly PicSettings _settings; + private readonly ILogger _logger; + + public ImageCreatorMapper(IServiceProvider sp, PicSettings settings, ILogger logger) + { + _sp = sp ?? throw new ArgumentNullException(nameof(sp)); + _settings = settings ?? throw new ArgumentNullException(nameof(settings)); + _logger = logger; + } + + public Task CreateImageAsync(ImageState imgState, System.Drawing.Image logo) + { + var provider = (_settings.ImageCreatorProvider ?? "Sharp").Trim(); + _logger?.LogDebug("Resolving IImageCreator for provider '{Provider}'", provider); + + return provider.Equals("ALTERNATE", StringComparison.OrdinalIgnoreCase) + ? ResolveAndCall(imgState, logo) + : ResolveAndCall(imgState, logo); + } + + private Task ResolveAndCall(ImageState imgState, System.Drawing.Image logo) where T : IImageCreator + { + // Resolve the concrete implementation and forward the call + var impl = (IImageCreator)_sp.GetService(typeof(T)); + if (impl is null) + { + _logger?.LogWarning("Requested image creator {Type} is not registered. Falling back to ImageCreatorSharp.", typeof(T).Name); + impl = (IImageCreator)_sp.GetService(typeof(ImageCreatorSharp)); + } + + if (impl is null) + throw new InvalidOperationException("No IImageCreator implementation is registered."); + + return impl.CreateImageAsync(imgState, logo); + } +} diff --git a/MaddoShared/ImageCreatorSharp.cs b/MaddoShared/ImageCreatorSharp.cs index 0fdb25e..cfd54e2 100644 --- a/MaddoShared/ImageCreatorSharp.cs +++ b/MaddoShared/ImageCreatorSharp.cs @@ -15,7 +15,7 @@ using SixLabors.ImageSharp.Metadata.Profiles.Exif; namespace MaddoShared; [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")] -public class ImageCreatorSharp(PicSettings picSettings, ILogger logger) +public class ImageCreatorSharp(PicSettings picSettings, ILogger logger) : IImageCreator { public async Task CreateImageAsync(ImageState imgState, Image logo) { diff --git a/MaddoShared/PicSettings.cs b/MaddoShared/PicSettings.cs index 7472b63..d16cf5f 100644 --- a/MaddoShared/PicSettings.cs +++ b/MaddoShared/PicSettings.cs @@ -66,4 +66,6 @@ public class PicSettings public bool FotoRuotaASinistra { get; set; } = false; public string TempMinText { get; set; } = string.Empty; public bool OverwriteFiles { get; set; } = false; + // Which image creator to use: "Sharp" for current implementation, "Alternate" for alternate library + public string ImageCreatorProvider { get; set; } = "Sharp"; } \ No newline at end of file diff --git a/imagecatalog/Program.cs b/imagecatalog/Program.cs index 451afbd..c14bca6 100644 --- a/imagecatalog/Program.cs +++ b/imagecatalog/Program.cs @@ -103,6 +103,11 @@ static class Program services.AddTransient(); services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + + // Register IImageCreator to be resolved via ImageCreatorMapper which selects concrete implementation at call time + services.AddTransient(sp => sp.GetRequiredService()); // Register a ParametriSetup singleton that persists user preferences in LocalApplicationData var userPrefsPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),