using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using ImageMagick; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; namespace Image { /// /// 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 name of the image to be cleaned. /// The new file name of the cleaned image. /// True of the image was cleaned, false otherwise. public bool CleanImage(string fileName, string newFilename) { try { ICompressor compressor = NullCompressor.Instance; var imageMagick = new MagickImage(fileName); if (_options.EnableCompression) compressor = LosslessCompressor.Instance; Logger.LogDebug( $"Cleaning {fileName}, compression {_options.EnableCompression}, outputFormatter {nameof(_options.FileOutputPathFormatter)}."); IMetadataRemover metadataRemover = new MetadataRemover(imageMagick, compressor); metadataRemover.CleanImage(newFilename); return true; } 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.FileOutputPathFormatter.GetOutputPath(fileName))); tasks.Add(task); task.Start(); } var result = Task.WhenAll(tasks); result.Wait(); var successTasks = tasks.Count(t => t.IsCompletedSuccessfully && t.Result); var errorTasks = tasks.Count() - successTasks; Logger.LogInformation($"All tasks completed. Success: {successTasks}, Errors: {errorTasks}"); } } }