2022-01-23 13:12:17 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Threading.Tasks;
|
2022-02-11 21:39:34 +00:00
|
|
|
|
using Image.Core;
|
2022-02-12 19:45:59 +00:00
|
|
|
|
using Image.Files;
|
2022-01-23 13:12:17 +00:00
|
|
|
|
using ImageMagick;
|
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
|
|
|
|
2022-02-12 19:45:59 +00:00
|
|
|
|
namespace Image.Tasks
|
2022-01-23 13:12:17 +00:00
|
|
|
|
{
|
2022-01-23 17:30:05 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// TaskExecutor is a helper class for executing tasks in parallel.
|
|
|
|
|
/// </summary>
|
2022-01-23 13:12:17 +00:00
|
|
|
|
public class TaskExecutor
|
|
|
|
|
{
|
|
|
|
|
public static ILogger Logger = NullLogger.Instance;
|
|
|
|
|
private readonly TaskExecutorOptions _options;
|
|
|
|
|
|
2022-01-23 17:30:05 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Creates a new instance of TaskExecutor.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="options">The TaskExecutor options.</param>
|
|
|
|
|
/// <exception cref="ArgumentException">Raised when the options are null.</exception>
|
2022-01-23 13:12:17 +00:00
|
|
|
|
private TaskExecutor(TaskExecutorOptions options)
|
|
|
|
|
{
|
|
|
|
|
_options = options ?? throw new ArgumentException("Options cannot be null!");
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-23 17:30:05 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Creates a new instance of TaskExecutor by calling the private constructor.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="options">The TaskExecutor options.</param>
|
2022-01-23 13:12:17 +00:00
|
|
|
|
public static TaskExecutor Create(TaskExecutorOptions options)
|
|
|
|
|
{
|
|
|
|
|
return new TaskExecutor(options);
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-23 17:30:05 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Cleans an image. Errors are silenced by default.
|
|
|
|
|
/// </summary>
|
2022-02-12 19:45:59 +00:00
|
|
|
|
/// <param name="filePath">The file path of the image to be cleaned.</param>
|
|
|
|
|
/// <param name="newFilePath">The new file path of the cleaned image.</param>
|
2022-01-23 17:30:05 +00:00
|
|
|
|
/// <returns>True of the image was cleaned, false otherwise.</returns>
|
2022-02-12 19:45:59 +00:00
|
|
|
|
public bool CleanImage(string filePath, string newFilePath)
|
2022-01-23 13:12:17 +00:00
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2022-02-12 19:45:59 +00:00
|
|
|
|
var fileExists = FileSystemHelpers.CheckIfFileExists(newFilePath);
|
|
|
|
|
if (fileExists)
|
|
|
|
|
{
|
|
|
|
|
Logger.LogWarning($"File {newFilePath} exists, skipping");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-01-23 13:12:17 +00:00
|
|
|
|
ICompressor compressor = NullCompressor.Instance;
|
2022-02-12 19:45:59 +00:00
|
|
|
|
var imageMagick = new MagickImage(filePath);
|
2022-01-23 17:30:05 +00:00
|
|
|
|
if (_options.EnableCompression) compressor = LosslessCompressor.Instance;
|
2022-01-23 13:12:17 +00:00
|
|
|
|
|
|
|
|
|
Logger.LogDebug(
|
2022-02-12 20:12:57 +00:00
|
|
|
|
$"Cleaning {filePath}, compression {_options.EnableCompression}, outputFormatter {nameof(_options.OutputSink)}.");
|
|
|
|
|
IMetadataRemover metadataRemover = new ExifRemoverAndCompressor(imageMagick, compressor);
|
2022-02-12 19:45:59 +00:00
|
|
|
|
metadataRemover.CleanImage(newFilePath);
|
2022-01-23 13:12:17 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
Logger.LogError(e.ToString());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-23 17:30:05 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Cleans images in parallel using the built in Task Parallel Library.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="fileNames">An enumerable of file names.</param>
|
2022-01-23 13:12:17 +00:00
|
|
|
|
public void ParallelCleanImages(IEnumerable<string> 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<Task<bool>>();
|
|
|
|
|
foreach (var fileName in filenamesArray)
|
|
|
|
|
{
|
|
|
|
|
var task = new Task<bool>(() =>
|
2022-02-12 20:12:57 +00:00
|
|
|
|
CleanImage(fileName, _options.OutputSink.GetOutputPath(fileName)));
|
2022-01-23 13:12:17 +00:00
|
|
|
|
tasks.Add(task);
|
|
|
|
|
task.Start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var result = Task.WhenAll(tasks);
|
|
|
|
|
result.Wait();
|
|
|
|
|
|
2022-02-12 19:45:59 +00:00
|
|
|
|
var successTasks = tasks.Count(t => t.IsCompleted && t.Result);
|
2022-01-27 21:22:10 +00:00
|
|
|
|
var errorTasks = tasks.Count - successTasks;
|
2022-02-12 19:45:59 +00:00
|
|
|
|
Logger.LogInformation($"All tasks completed. Success: {successTasks}, Failures: {errorTasks}");
|
2022-01-23 13:12:17 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|