From 9730a996ca7f85b422b292ebdeee169dffa4aa9e Mon Sep 17 00:00:00 2001 From: Denis Nutiu Date: Sun, 23 Jan 2022 19:30:05 +0200 Subject: [PATCH] Add code documentation. --- ConsoleInterface/Program.cs | 36 ++++++++++--- ImageCore/FilesRetriever.cs | 27 ---------- ImageCore/ICompressor.cs | 7 +++ ImageCore/IFileOutputPathFormatter.cs | 15 ++++++ ImageCore/IFilesRetriever.cs | 17 ++++++ ImageCore/IMetadataRemover.cs | 9 +++- ImageCore/IOutputFormatter.cs | 7 --- ImageCore/ImageCore.csproj | 6 +-- ImageCore/LocalSystemFilesRetriever.cs | 35 +++++++++++++ ImageCore/LosslessCompressor.cs | 8 ++- ImageCore/MetadataRemover.cs | 18 +++++-- ImageCore/NullCompressor.cs | 8 ++- ...OriginalFilenameFileOutputPathFormatter.cs | 52 +++++++++++++++++++ ImageCore/OriginalFilenameOutputFormatter.cs | 35 ------------- ImageCore/TaskExecutor.cs | 31 ++++++++--- ImageCore/TaskExecutorOptions.cs | 18 +++++-- 16 files changed, 233 insertions(+), 96 deletions(-) delete mode 100644 ImageCore/FilesRetriever.cs create mode 100644 ImageCore/IFileOutputPathFormatter.cs create mode 100644 ImageCore/IFilesRetriever.cs delete mode 100644 ImageCore/IOutputFormatter.cs create mode 100644 ImageCore/LocalSystemFilesRetriever.cs create mode 100644 ImageCore/OriginalFilenameFileOutputPathFormatter.cs delete mode 100644 ImageCore/OriginalFilenameOutputFormatter.cs diff --git a/ConsoleInterface/Program.cs b/ConsoleInterface/Program.cs index de28a1c..ee408d6 100644 --- a/ConsoleInterface/Program.cs +++ b/ConsoleInterface/Program.cs @@ -10,40 +10,60 @@ namespace ConsoleInterface { internal static class Program { + /// + /// The console interface for the project and the main entrypoint. + /// + /// Command line provided args. private static void Main(string[] args) { Parser.Default.ParseArguments(args).WithParsed(RunOptions); } + /// + /// RunOptions will be called after the command-line arguments were successfully parsed. + /// private static void RunOptions(Options options) { var loggerFactory = LoggerFactory.Create(b => b.AddConsole()); TaskExecutor.Logger = loggerFactory.CreateLogger(nameof(TaskExecutor)); - FilesRetriever.Logger = loggerFactory.CreateLogger(nameof(FilesRetriever)); - OriginalFilenameOutputFormatter.Logger = - loggerFactory.CreateLogger(nameof(OriginalFilenameOutputFormatter)); + LocalSystemFilesRetriever.Logger = loggerFactory.CreateLogger(nameof(LocalSystemFilesRetriever)); + OriginalFilenameFileOutputPathFormatter.Logger = + loggerFactory.CreateLogger(nameof(OriginalFilenameFileOutputPathFormatter)); - var outputFormatter = OriginalFilenameOutputFormatter.Create(options.DestinationDirectory); + var outputFormatter = OriginalFilenameFileOutputPathFormatter.Create(options.DestinationDirectory); var executor = TaskExecutor.Create(new TaskExecutorOptions { EnableCompression = options.CompressFiles is true, - OutputFormatter = outputFormatter + FileOutputPathFormatter = outputFormatter }); - var filesRetriever = FilesRetriever.Create(); + var filesRetriever = LocalSystemFilesRetriever.Create(); executor.ParallelCleanImages(filesRetriever.GetFilenamesFromPath(options.SourceDirectory)); } + /// + /// Options is a class defining command line options supported by this program. + /// public class Options { + /// + /// CompressFiles indicates whether files should be compressed after being cleaned. + /// [Option('c', "compress", Required = false, HelpText = "Compress images after cleaning.", Default = true)] public bool? CompressFiles { get; set; } - [Option('d', "dest", Required = false, HelpText = "The destination directory.", Default = "./cleaned")] + /// + /// DestinationDirectory represents the destination directory for the cleaned images. + /// + [Option('d', "dest", Required = false, HelpText = "The destination directory for the cleaned images.", + Default = "./cleaned")] public string DestinationDirectory { get; set; } - [Value(0, MetaName = "source", HelpText = "The source directory.", Default = ".")] + /// + /// SourceDirectory represents the source directory of images. + /// + [Value(0, MetaName = "source", HelpText = "The source directory of images.", Default = ".")] public string SourceDirectory { get; set; } } } diff --git a/ImageCore/FilesRetriever.cs b/ImageCore/FilesRetriever.cs deleted file mode 100644 index c54f0bd..0000000 --- a/ImageCore/FilesRetriever.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; - -namespace Image -{ - public class FilesRetriever - { - public static ILogger Logger = NullLogger.Instance; - - private FilesRetriever() - { - } - - public static FilesRetriever Create() - { - return new FilesRetriever(); - } - - public IEnumerable GetFilenamesFromPath(string path) - { - Logger.LogInformation($"Getting files from {path}."); - return Directory.GetFiles(path, "*.*"); - } - } -} \ No newline at end of file diff --git a/ImageCore/ICompressor.cs b/ImageCore/ICompressor.cs index 3cbfec1..8750779 100644 --- a/ImageCore/ICompressor.cs +++ b/ImageCore/ICompressor.cs @@ -1,7 +1,14 @@ namespace Image { + /// + /// ICompressor is an interface for implementing image compressors. + /// public interface ICompressor { + /// + /// The method compresses an image in place. + /// + /// The file name of the image to be compressed. public void Compress(string fileName); } } \ No newline at end of file diff --git a/ImageCore/IFileOutputPathFormatter.cs b/ImageCore/IFileOutputPathFormatter.cs new file mode 100644 index 0000000..8c1eae7 --- /dev/null +++ b/ImageCore/IFileOutputPathFormatter.cs @@ -0,0 +1,15 @@ +namespace Image +{ + /// + /// IOutputFormatter is an interface for generating the output path and destination file name. + /// + public interface IFileOutputPathFormatter + { + /// + /// Generates an absolute output path given the initial absolute file path. + /// + /// The initial file path. + /// The formatted absolute output path. + string GetOutputPath(string initialFilePath); + } +} \ No newline at end of file diff --git a/ImageCore/IFilesRetriever.cs b/ImageCore/IFilesRetriever.cs new file mode 100644 index 0000000..d04a732 --- /dev/null +++ b/ImageCore/IFilesRetriever.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; + +namespace Image +{ + /// + /// An to interface enabling implementation of filename retrievers. + /// + public interface IFilesRetriever + { + /// + /// Returns all filenames from given path. + /// + /// The path. + /// An enumerable containing all file names. + IEnumerable GetFilenamesFromPath(string directoryPath); + } +} \ No newline at end of file diff --git a/ImageCore/IMetadataRemover.cs b/ImageCore/IMetadataRemover.cs index 22b83d7..8d3fa27 100644 --- a/ImageCore/IMetadataRemover.cs +++ b/ImageCore/IMetadataRemover.cs @@ -1,7 +1,14 @@ namespace Image { + /// + /// Interface for implementing metadata removers. + /// public interface IMetadataRemover { - void CleanImage(string newFileName); + /// + /// CleanImage cleans an image and saves it.. + /// + /// The file path to save the clean image. + void CleanImage(string newFilePath); } } \ No newline at end of file diff --git a/ImageCore/IOutputFormatter.cs b/ImageCore/IOutputFormatter.cs deleted file mode 100644 index bcb263c..0000000 --- a/ImageCore/IOutputFormatter.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Image -{ - public interface IOutputFormatter - { - string FormatOutputPath(string filePath); - } -} \ No newline at end of file diff --git a/ImageCore/ImageCore.csproj b/ImageCore/ImageCore.csproj index 99bc5d3..0b78338 100644 --- a/ImageCore/ImageCore.csproj +++ b/ImageCore/ImageCore.csproj @@ -6,9 +6,9 @@ - - - + + + diff --git a/ImageCore/LocalSystemFilesRetriever.cs b/ImageCore/LocalSystemFilesRetriever.cs new file mode 100644 index 0000000..55d47ac --- /dev/null +++ b/ImageCore/LocalSystemFilesRetriever.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using System.IO; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; + +namespace Image +{ + /// + /// LocalSystemFilesRetriever reads files from the provided directory on the local system. + /// + public class LocalSystemFilesRetriever : IFilesRetriever + { + public static ILogger Logger = NullLogger.Instance; + + private LocalSystemFilesRetriever() + { + } + + /// + /// Give a directory path it returns all the filenames. + /// + /// An absolute path pointing to a directory. + /// A list of file names found in the directory. + public IEnumerable GetFilenamesFromPath(string directoryPath) + { + Logger.LogInformation($"Getting files from {directoryPath}."); + return Directory.GetFiles(directoryPath, "*.*"); + } + + public static LocalSystemFilesRetriever Create() + { + return new LocalSystemFilesRetriever(); + } + } +} \ No newline at end of file diff --git a/ImageCore/LosslessCompressor.cs b/ImageCore/LosslessCompressor.cs index 098429b..52e17e9 100644 --- a/ImageCore/LosslessCompressor.cs +++ b/ImageCore/LosslessCompressor.cs @@ -2,6 +2,9 @@ namespace Image { + /// + /// LosslessCompressor compresses an image using lossless compression provided by ImageMagick. + /// public class LosslessCompressor : ICompressor { public static readonly LosslessCompressor Instance = new LosslessCompressor(); @@ -11,7 +14,10 @@ namespace Image { _imageOptimizer = new ImageOptimizer(); } - + + /// + /// + /// public void Compress(string fileName) { _imageOptimizer.LosslessCompress(fileName); diff --git a/ImageCore/MetadataRemover.cs b/ImageCore/MetadataRemover.cs index 4fe6733..0f1716f 100644 --- a/ImageCore/MetadataRemover.cs +++ b/ImageCore/MetadataRemover.cs @@ -2,22 +2,34 @@ namespace Image { + /// + /// MetadataRemover removes metadata from an image. The exif profile. + /// public class MetadataRemover : IMetadataRemover { private readonly ICompressor _compressor; private readonly IMagickImage _magickImage; + /// + /// Constructs an instance of MetadataRemover. + /// + /// MagicImage instance. + /// Compressor instance. public MetadataRemover(IMagickImage magickImage, ICompressor compressor) { _magickImage = magickImage; _compressor = compressor; } - public void CleanImage(string newFileName) + /// + /// Cleans the images and compresses it. + /// + /// The file path to save the clean image. + public void CleanImage(string newFilePath) { _magickImage.RemoveProfile("exif"); - _magickImage.Write(newFileName); - _compressor.Compress(newFileName); + _magickImage.Write(newFilePath); + _compressor.Compress(newFilePath); } } } \ No newline at end of file diff --git a/ImageCore/NullCompressor.cs b/ImageCore/NullCompressor.cs index cdd7dd5..9435cd2 100644 --- a/ImageCore/NullCompressor.cs +++ b/ImageCore/NullCompressor.cs @@ -1,9 +1,15 @@ namespace Image { + /// + /// Does nothing. Using this Compressor will have no effect. + /// public class NullCompressor : ICompressor { public static readonly NullCompressor Instance = new NullCompressor(); - + + /// + /// + /// public void Compress(string fileName) { } diff --git a/ImageCore/OriginalFilenameFileOutputPathFormatter.cs b/ImageCore/OriginalFilenameFileOutputPathFormatter.cs new file mode 100644 index 0000000..9921d5a --- /dev/null +++ b/ImageCore/OriginalFilenameFileOutputPathFormatter.cs @@ -0,0 +1,52 @@ +using System.IO; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; + +namespace Image +{ + /// + /// OriginalFilenameFileOutputPathFormatter keeps the original file name of the image when formatting the new output + /// path. + /// + public class OriginalFilenameFileOutputPathFormatter : IFileOutputPathFormatter + { + public static ILogger Logger = NullLogger.Instance; + private readonly string _outputDirectory; + + /// + /// Creates an instance of OriginalFilenameFileOutputPathFormatter. + /// + /// The output directory. + public OriginalFilenameFileOutputPathFormatter(string outputDirectory) + { + if (!Directory.Exists(outputDirectory)) + { + Logger.LogWarning("Output directory does not exists. Creating."); + Directory.CreateDirectory(outputDirectory); + } + + _outputDirectory = outputDirectory; + } + + /// + /// Returns a path containing the file name in the output directory. + /// + /// The initial path of the image. + /// An absolute path of the form output_directory/initialFileName.jpg + public string GetOutputPath(string initialFilePath) + { + var fileName = Path.GetFileName(initialFilePath)?.Split(".")[0]; + var path = Path.Join(_outputDirectory, $"{fileName}.jpg"); + return path; + } + + /// + /// Creates an instance of OriginalFilenameFileOutputPathFormatter. + /// + /// The output directory. + public static OriginalFilenameFileOutputPathFormatter Create(string outputDirectory) + { + return new OriginalFilenameFileOutputPathFormatter(outputDirectory); + } + } +} \ No newline at end of file diff --git a/ImageCore/OriginalFilenameOutputFormatter.cs b/ImageCore/OriginalFilenameOutputFormatter.cs deleted file mode 100644 index 0e01e1a..0000000 --- a/ImageCore/OriginalFilenameOutputFormatter.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.IO; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; - -namespace Image -{ - public class OriginalFilenameOutputFormatter : IOutputFormatter - { - public static ILogger Logger = NullLogger.Instance; - private readonly string _rootDirectory; - - public OriginalFilenameOutputFormatter(string rootDirectory) - { - if (!Directory.Exists(rootDirectory)) - { - Logger.LogWarning("Output directory does not exists. Creating."); - Directory.CreateDirectory(rootDirectory); - } - - _rootDirectory = rootDirectory; - } - - public string FormatOutputPath(string filePath) - { - var fileName = Path.GetFileName(filePath)?.Split(".")[0]; - var path = Path.Join(_rootDirectory, $"{fileName}.jpg"); - return path; - } - - public static OriginalFilenameOutputFormatter Create(string rootDirectory) - { - return new OriginalFilenameOutputFormatter(rootDirectory); - } - } -} \ No newline at end of file diff --git a/ImageCore/TaskExecutor.cs b/ImageCore/TaskExecutor.cs index 2711ea2..e64e521 100644 --- a/ImageCore/TaskExecutor.cs +++ b/ImageCore/TaskExecutor.cs @@ -8,34 +8,49 @@ 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; - } + if (_options.EnableCompression) compressor = LosslessCompressor.Instance; Logger.LogDebug( - $"Cleaning {fileName}, compression {_options.EnableCompression}, outputFormatter {nameof(_options.OutputFormatter)}."); + $"Cleaning {fileName}, compression {_options.EnableCompression}, outputFormatter {nameof(_options.FileOutputPathFormatter)}."); IMetadataRemover metadataRemover = new MetadataRemover(imageMagick, compressor); metadataRemover.CleanImage(newFilename); return true; @@ -47,6 +62,10 @@ namespace Image } } + /// + /// 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."); @@ -61,7 +80,7 @@ namespace Image foreach (var fileName in filenamesArray) { var task = new Task(() => - CleanImage(fileName, _options.OutputFormatter.FormatOutputPath(fileName))); + CleanImage(fileName, _options.FileOutputPathFormatter.GetOutputPath(fileName))); tasks.Add(task); task.Start(); } diff --git a/ImageCore/TaskExecutorOptions.cs b/ImageCore/TaskExecutorOptions.cs index 162e5b2..5c514f5 100644 --- a/ImageCore/TaskExecutorOptions.cs +++ b/ImageCore/TaskExecutorOptions.cs @@ -2,16 +2,26 @@ namespace Image { + /// + /// TaskExecutorOptions is a class containing various parameters for the class. + /// public class TaskExecutorOptions { - private IOutputFormatter _outputFormatter; + private IFileOutputPathFormatter _fileOutputPathFormatter; - public IOutputFormatter OutputFormatter + /// + /// The file output path formatter. It cannot be null. + /// A implementation of . + /// + public IFileOutputPathFormatter FileOutputPathFormatter { - get => _outputFormatter; - set => _outputFormatter = value ?? throw new ArgumentException("Output formatter cannot be null!"); + get => _fileOutputPathFormatter; + set => _fileOutputPathFormatter = value ?? throw new ArgumentException("Output formatter cannot be null!"); } + /// + /// A boolean indicating if compression should be performed after cleaning the images. + /// public bool EnableCompression { get; set; } = true; } } \ No newline at end of file