Initial commit

This commit is contained in:
Denis-Cosmin Nutiu 2022-01-22 19:06:10 +02:00
commit 8a9217aede
19 changed files with 382 additions and 0 deletions

116
.gitignore vendored Normal file
View file

@ -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

View file

@ -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

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Image\Image.csproj"/>
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0"/>
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0"/>
</ItemGroup>
</Project>

View file

@ -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);
}
}
}

38
Image/Cleaner.cs Normal file
View file

@ -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);
}
}
}

9
Image/ICleaner.cs Normal file
View file

@ -0,0 +1,9 @@
namespace Image
{
public interface ICleaner
{
void CleanImage(string newFileName);
void OptimizeImage(string fileName);
public void RemoveExifData(string newFilename);
}
}

7
Image/ICompressor.cs Normal file
View file

@ -0,0 +1,7 @@
namespace Image
{
public interface ICompressor
{
public void Compress(string fileName);
}
}

View file

@ -0,0 +1,7 @@
namespace Image
{
public interface IOutputFormatter
{
string FormatOutputPath(string filePath);
}
}

14
Image/Image.csproj Normal file
View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>Image</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Magick.NET-Q16-AnyCPU" Version="8.6.1"/>
<PackageReference Include="Magick.NET.Core" Version="8.6.1"/>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0"/>
</ItemGroup>
</Project>

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

43
Image/TasksExecutor.cs Normal file
View file

@ -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<string> fileNames, IOutputFormatter outputFormatter)
{
Logger.LogInformation("Starting parallel image cleaning.");
var tasks = new List<Task>();
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}");
}
}
}

22
ImgMetadataRemover.sln Normal file
View file

@ -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

View file

@ -0,0 +1,5 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/Environment/AssemblyExplorer/XmlDocument/@EntryValue">&lt;AssemblyExplorer&gt;&#xD;
&lt;Assembly Path="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\3.1.0\ref\netcoreapp3.1\System.Net.Mail.dll" /&gt;&#xD;
&lt;Assembly Path="C:\Users\nutiu\.nuget\packages\magick.net.core\8.6.1\lib\netstandard21\Magick.NET.Core.dll" /&gt;&#xD;
&lt;/AssemblyExplorer&gt;</s:String></wpf:ResourceDictionary>

BIN
README.md Normal file

Binary file not shown.

7
global.json Normal file
View file

@ -0,0 +1,7 @@
{
"sdk": {
"version": "3.1",
"rollForward": "latestMajor",
"allowPrerelease": false
}
}