From 8a9217aede2a8d0b692b721091daa80ef3a67fac Mon Sep 17 00:00:00 2001 From: Denis Nutiu Date: Sat, 22 Jan 2022 19:06:10 +0200 Subject: [PATCH] Initial commit --- .gitignore | 116 ++++++++++++++++++ .../.idea.ImgMetadataRemover/.idea/.gitignore | 13 ++ .../.idea/encodings.xml | 4 + .../.idea/indexLayout.xml | 8 ++ .idea/.idea.ImgMetadataRemover/.idea/vcs.xml | 6 + ConsoleInterface/ConsoleInterface.csproj | 14 +++ ConsoleInterface/Program.cs | 23 ++++ Image/Cleaner.cs | 38 ++++++ Image/ICleaner.cs | 9 ++ Image/ICompressor.cs | 7 ++ Image/IOutputFormatter.cs | 7 ++ Image/Image.csproj | 14 +++ Image/LosslessCompressor.cs | 19 +++ Image/OriginalFilenameOutputFormatter.cs | 27 ++++ Image/TasksExecutor.cs | 43 +++++++ ImgMetadataRemover.sln | 22 ++++ ImgMetadataRemover.sln.DotSettings.user | 5 + README.md | Bin 0 -> 120 bytes global.json | 7 ++ 19 files changed, 382 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.idea.ImgMetadataRemover/.idea/.gitignore create mode 100644 .idea/.idea.ImgMetadataRemover/.idea/encodings.xml create mode 100644 .idea/.idea.ImgMetadataRemover/.idea/indexLayout.xml create mode 100644 .idea/.idea.ImgMetadataRemover/.idea/vcs.xml create mode 100644 ConsoleInterface/ConsoleInterface.csproj create mode 100644 ConsoleInterface/Program.cs create mode 100644 Image/Cleaner.cs create mode 100644 Image/ICleaner.cs create mode 100644 Image/ICompressor.cs create mode 100644 Image/IOutputFormatter.cs create mode 100644 Image/Image.csproj create mode 100644 Image/LosslessCompressor.cs create mode 100644 Image/OriginalFilenameOutputFormatter.cs create mode 100644 Image/TasksExecutor.cs create mode 100644 ImgMetadataRemover.sln create mode 100644 ImgMetadataRemover.sln.DotSettings.user create mode 100644 README.md create mode 100644 global.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0dbfbed --- /dev/null +++ b/.gitignore @@ -0,0 +1,116 @@ +bin/ +obj/ +/packages/ +riderModule.iml +/_ReSharper.Caches/ + + +# Created by https://www.toptal.com/developers/gitignore/api/rider,windows +# Edit at https://www.toptal.com/developers/gitignore?templates=rider,windows + +### Rider ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# End of https://www.toptal.com/developers/gitignore/api/rider,windows \ No newline at end of file diff --git a/.idea/.idea.ImgMetadataRemover/.idea/.gitignore b/.idea/.idea.ImgMetadataRemover/.idea/.gitignore new file mode 100644 index 0000000..7a975b9 --- /dev/null +++ b/.idea/.idea.ImgMetadataRemover/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/projectSettingsUpdater.xml +/contentModel.xml +/modules.xml +/.idea.ImgMetadataRemover.iml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/.idea.ImgMetadataRemover/.idea/encodings.xml b/.idea/.idea.ImgMetadataRemover/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/.idea/.idea.ImgMetadataRemover/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.ImgMetadataRemover/.idea/indexLayout.xml b/.idea/.idea.ImgMetadataRemover/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/.idea/.idea.ImgMetadataRemover/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.ImgMetadataRemover/.idea/vcs.xml b/.idea/.idea.ImgMetadataRemover/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/.idea.ImgMetadataRemover/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/ConsoleInterface/ConsoleInterface.csproj b/ConsoleInterface/ConsoleInterface.csproj new file mode 100644 index 0000000..0d1c7af --- /dev/null +++ b/ConsoleInterface/ConsoleInterface.csproj @@ -0,0 +1,14 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + diff --git a/ConsoleInterface/Program.cs b/ConsoleInterface/Program.cs new file mode 100644 index 0000000..49617d7 --- /dev/null +++ b/ConsoleInterface/Program.cs @@ -0,0 +1,23 @@ +using Image; +using Microsoft.Extensions.Logging; + +namespace ConsoleInterface +{ + internal static class Program + { + private static void Main(string[] args) + { + var loggerFactory = LoggerFactory.Create(b => b.AddConsole()); + var outputFormatter = OriginalFilenameOutputFormatter.Create(@"C:\Users\nutiu\Downloads\Photos-001\clean"); + var executor = TasksExecutor.Create(); + executor.Logger = loggerFactory.CreateLogger("Executor"); + executor.ParallelCleanImages(new[] + { + @"C:\Users\nutiu\Downloads\Photos-001\IMG_0138.HEIC", + @"C:\Users\nutiu\Downloads\Photos-001\IMG_0137.HEIC", + @"C:\Users\nutiu\Downloads\Photos-001\IMG_0140.HEIC", + @"C:\Users\nutiu\Downloads\Photos-001\12382975864_09e6e069e7_o.jpg" + }, outputFormatter); + } + } +} \ No newline at end of file diff --git a/Image/Cleaner.cs b/Image/Cleaner.cs new file mode 100644 index 0000000..2930e85 --- /dev/null +++ b/Image/Cleaner.cs @@ -0,0 +1,38 @@ +using ImageMagick; + +namespace Image +{ + public class Cleaner : ICleaner + { + private readonly ICompressor _compressor; + private readonly IMagickImage _magickImage; + + public Cleaner(IMagickImage magickImage, ICompressor compressor) + { + _magickImage = magickImage; + _compressor = compressor; + } + + public Cleaner(string fileName) : this(new MagickImage(fileName), new LosslessCompressor()) + { + } + + public void CleanImage(string newFileName) + { + _magickImage.RemoveProfile("exif"); + _magickImage.Write(newFileName); + _compressor.Compress(newFileName); + } + + public void RemoveExifData(string newFilename) + { + _magickImage.RemoveProfile("exif"); + _magickImage.Write(newFilename); + } + + public void OptimizeImage(string fileName) + { + _compressor.Compress(fileName); + } + } +} \ No newline at end of file diff --git a/Image/ICleaner.cs b/Image/ICleaner.cs new file mode 100644 index 0000000..327a135 --- /dev/null +++ b/Image/ICleaner.cs @@ -0,0 +1,9 @@ +namespace Image +{ + public interface ICleaner + { + void CleanImage(string newFileName); + void OptimizeImage(string fileName); + public void RemoveExifData(string newFilename); + } +} \ No newline at end of file diff --git a/Image/ICompressor.cs b/Image/ICompressor.cs new file mode 100644 index 0000000..3cbfec1 --- /dev/null +++ b/Image/ICompressor.cs @@ -0,0 +1,7 @@ +namespace Image +{ + public interface ICompressor + { + public void Compress(string fileName); + } +} \ No newline at end of file diff --git a/Image/IOutputFormatter.cs b/Image/IOutputFormatter.cs new file mode 100644 index 0000000..bcb263c --- /dev/null +++ b/Image/IOutputFormatter.cs @@ -0,0 +1,7 @@ +namespace Image +{ + public interface IOutputFormatter + { + string FormatOutputPath(string filePath); + } +} \ No newline at end of file diff --git a/Image/Image.csproj b/Image/Image.csproj new file mode 100644 index 0000000..0b78338 --- /dev/null +++ b/Image/Image.csproj @@ -0,0 +1,14 @@ + + + + netcoreapp3.1 + Image + + + + + + + + + diff --git a/Image/LosslessCompressor.cs b/Image/LosslessCompressor.cs new file mode 100644 index 0000000..392c550 --- /dev/null +++ b/Image/LosslessCompressor.cs @@ -0,0 +1,19 @@ +using ImageMagick; + +namespace Image +{ + public class LosslessCompressor : ICompressor + { + private readonly ImageOptimizer _imageOptimizer; + + public LosslessCompressor() + { + _imageOptimizer = new ImageOptimizer(); + } + + public void Compress(string fileName) + { + _imageOptimizer.LosslessCompress(fileName); + } + } +} \ No newline at end of file diff --git a/Image/OriginalFilenameOutputFormatter.cs b/Image/OriginalFilenameOutputFormatter.cs new file mode 100644 index 0000000..a02cdbf --- /dev/null +++ b/Image/OriginalFilenameOutputFormatter.cs @@ -0,0 +1,27 @@ +using System.IO; + +namespace Image +{ + public class OriginalFilenameOutputFormatter : IOutputFormatter + { + private readonly string _rootDirectory; + + public OriginalFilenameOutputFormatter(string rootDirectory) + { + if (!Directory.Exists(rootDirectory)) Directory.CreateDirectory(rootDirectory); + _rootDirectory = rootDirectory; + } + + public string FormatOutputPath(string filePath) + { + var fileName = Path.GetFileName(filePath); + 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/Image/TasksExecutor.cs b/Image/TasksExecutor.cs new file mode 100644 index 0000000..ecc9745 --- /dev/null +++ b/Image/TasksExecutor.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; + +namespace Image +{ + public class TasksExecutor + { + public ILogger Logger = NullLogger.Instance; + + public static TasksExecutor Create() + { + return new TasksExecutor(); + } + + public void CleanImage(string fileName, string newFilename) + { + ICleaner cleaner = new Cleaner(fileName); + cleaner.CleanImage(newFilename); + } + + public void ParallelCleanImages(IEnumerable fileNames, IOutputFormatter outputFormatter) + { + Logger.LogInformation("Starting parallel image cleaning."); + var tasks = new List(); + foreach (var fileName in fileNames) + { + var task = new Task(() => { CleanImage(fileName, outputFormatter.FormatOutputPath(fileName)); }); + tasks.Add(task); + task.Start(); + } + + var result = Task.WhenAll(tasks); + result.Wait(); + + var successTasks = tasks.Count(t => t.IsCompletedSuccessfully); + var errorTasks = tasks.Count() - successTasks; + Logger.LogInformation($"All tasks completed. Success: {successTasks}, Errors: {errorTasks}"); + } + } +} \ No newline at end of file diff --git a/ImgMetadataRemover.sln b/ImgMetadataRemover.sln new file mode 100644 index 0000000..26bce1f --- /dev/null +++ b/ImgMetadataRemover.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Image", "Image\Image.csproj", "{10AD7910-C8AA-43ED-9231-EBE267AC270F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleInterface", "ConsoleInterface\ConsoleInterface.csproj", "{F04E0337-23D3-4209-9BDE-B798090A7A63}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {10AD7910-C8AA-43ED-9231-EBE267AC270F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {10AD7910-C8AA-43ED-9231-EBE267AC270F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {10AD7910-C8AA-43ED-9231-EBE267AC270F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {10AD7910-C8AA-43ED-9231-EBE267AC270F}.Release|Any CPU.Build.0 = Release|Any CPU + {F04E0337-23D3-4209-9BDE-B798090A7A63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F04E0337-23D3-4209-9BDE-B798090A7A63}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F04E0337-23D3-4209-9BDE-B798090A7A63}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F04E0337-23D3-4209-9BDE-B798090A7A63}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/ImgMetadataRemover.sln.DotSettings.user b/ImgMetadataRemover.sln.DotSettings.user new file mode 100644 index 0000000..e0977c7 --- /dev/null +++ b/ImgMetadataRemover.sln.DotSettings.user @@ -0,0 +1,5 @@ + + <AssemblyExplorer> + <Assembly Path="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\3.1.0\ref\netcoreapp3.1\System.Net.Mail.dll" /> + <Assembly Path="C:\Users\nutiu\.nuget\packages\magick.net.core\8.6.1\lib\netstandard21\Magick.NET.Core.dll" /> +</AssemblyExplorer> \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..109dffc543f5c5f14a356bba95939112a8aa08bf GIT binary patch literal 120 zcmW-ZyAD7=5JgWd@edL;daWp_{D4=iupzA9$KB1%OmXg+`QDfaKWRup#l_6TisKHA pZ!;2%h~pG3DU>BRhKGTikpn9_vFqN-a{APZG}_)B+2pm