using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Image; using Image.Core; using ImageMagick; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; namespace ConsoleInterface { /// /// TaskExecutor is a helper class for executing tasks in parallel. /// public class TaskExecutor { public static ILogger Logger = NullLogger.Instance; private readonly TaskExecutorOptions _options; /// /// Creates a new instance of TaskExecutor. /// /// The TaskExecutor options. /// Raised when the options are null. private TaskExecutor(TaskExecutorOptions options) { _options = options ?? throw new ArgumentException("Options cannot be null!"); } /// /// Creates a new instance of TaskExecutor by calling the private constructor. /// /// The TaskExecutor options. public static TaskExecutor Create(TaskExecutorOptions options) { return new TaskExecutor(options); } /// /// Cleans an image. Errors are silenced by default. /// /// The file path of the image to be cleaned. /// The output sink for the image.. /// True of the image was cleaned, false otherwise. public bool CleanImage(string filePath, IOutputSink outputSink) { try { Logger.LogDebug( $"Cleaning {filePath}, compression {_options.EnableCompression}, outputFormatter {nameof(_options.OutputSink)}."); ICompressor compressor = NullCompressor.Instance; if (_options.EnableCompression) { compressor = LosslessCompressor.Instance; } var imageMagick = new MagickImage(filePath); IMetadataRemover metadataRemover = new ExifRemoverAndCompressor(imageMagick, compressor); return outputSink.Save(metadataRemover); } catch (Exception e) { Logger.LogError(e.ToString()); return false; } } /// /// Cleans images in parallel using the built in Task Parallel Library. /// /// An enumerable of file names. public void ParallelCleanImages(IEnumerable fileNames) { Logger.LogInformation("Starting parallel image cleaning."); var filenamesArray = fileNames as string[] ?? fileNames.ToArray(); if (!filenamesArray.Any()) { Logger.LogWarning("Empty fileNames, nothing to do."); return; } var tasks = new List>(); foreach (var fileName in filenamesArray) { var task = new Task(() => CleanImage(fileName, _options.OutputSink)); tasks.Add(task); task.Start(); } var result = Task.WhenAll(tasks); result.Wait(); var successTasks = tasks.Count(t => t.IsCompleted && t.Result); var errorTasks = tasks.Count - successTasks; Logger.LogInformation($"All tasks completed. Success: {successTasks}, Failures: {errorTasks}"); } } }